]>
Commit | Line | Data |
---|---|---|
1 | /* Generate code from machine description to emit insns as rtl. | |
2 | Copyright (C) 1987, 1988, 1991, 1994, 1995, 1997, 1998, 1999, 2000, 2001, | |
3 | 2003, 2004, 2005, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. | |
4 | ||
5 | This file is part of GCC. | |
6 | ||
7 | GCC is free software; you can redistribute it and/or modify it under | |
8 | the terms of the GNU General Public License as published by the Free | |
9 | Software Foundation; either version 3, or (at your option) any later | |
10 | version. | |
11 | ||
12 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
15 | for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with GCC; see the file COPYING3. If not see | |
19 | <http://www.gnu.org/licenses/>. */ | |
20 | ||
21 | ||
22 | #include "bconfig.h" | |
23 | #include "system.h" | |
24 | #include "coretypes.h" | |
25 | #include "tm.h" | |
26 | #include "rtl.h" | |
27 | #include "errors.h" | |
28 | #include "read-md.h" | |
29 | #include "gensupport.h" | |
30 | ||
31 | ||
32 | static int insn_code_number; | |
33 | static int insn_index_number; | |
34 | ||
35 | /* Data structure for recording the patterns of insns that have CLOBBERs. | |
36 | We use this to output a function that adds these CLOBBERs to a | |
37 | previously-allocated PARALLEL expression. */ | |
38 | ||
39 | struct clobber_pat | |
40 | { | |
41 | struct clobber_ent *insns; | |
42 | rtx pattern; | |
43 | int first_clobber; | |
44 | struct clobber_pat *next; | |
45 | int has_hard_reg; | |
46 | } *clobber_list; | |
47 | ||
48 | /* Records one insn that uses the clobber list. */ | |
49 | ||
50 | struct clobber_ent | |
51 | { | |
52 | int code_number; /* Counts only insns. */ | |
53 | struct clobber_ent *next; | |
54 | }; | |
55 | ||
56 | static void print_code (RTX_CODE); | |
57 | static void gen_exp (rtx, enum rtx_code, char *); | |
58 | static void gen_insn (rtx, int); | |
59 | static void gen_expand (rtx); | |
60 | static void gen_split (rtx); | |
61 | static void output_add_clobbers (void); | |
62 | static void output_added_clobbers_hard_reg_p (void); | |
63 | static void gen_rtx_scratch (rtx, enum rtx_code); | |
64 | static void output_peephole2_scratches (rtx); | |
65 | ||
66 | \f | |
67 | static void | |
68 | print_code (RTX_CODE code) | |
69 | { | |
70 | const char *p1; | |
71 | for (p1 = GET_RTX_NAME (code); *p1; p1++) | |
72 | putchar (TOUPPER(*p1)); | |
73 | } | |
74 | ||
75 | static void | |
76 | gen_rtx_scratch (rtx x, enum rtx_code subroutine_type) | |
77 | { | |
78 | if (subroutine_type == DEFINE_PEEPHOLE2) | |
79 | { | |
80 | printf ("operand%d", XINT (x, 0)); | |
81 | } | |
82 | else | |
83 | { | |
84 | printf ("gen_rtx_SCRATCH (%smode)", GET_MODE_NAME (GET_MODE (x))); | |
85 | } | |
86 | } | |
87 | ||
88 | /* Print a C expression to construct an RTX just like X, | |
89 | substituting any operand references appearing within. */ | |
90 | ||
91 | static void | |
92 | gen_exp (rtx x, enum rtx_code subroutine_type, char *used) | |
93 | { | |
94 | RTX_CODE code; | |
95 | int i; | |
96 | int len; | |
97 | const char *fmt; | |
98 | ||
99 | if (x == 0) | |
100 | { | |
101 | printf ("NULL_RTX"); | |
102 | return; | |
103 | } | |
104 | ||
105 | code = GET_CODE (x); | |
106 | ||
107 | switch (code) | |
108 | { | |
109 | case MATCH_OPERAND: | |
110 | case MATCH_DUP: | |
111 | if (used) | |
112 | { | |
113 | if (used[XINT (x, 0)]) | |
114 | { | |
115 | printf ("copy_rtx (operand%d)", XINT (x, 0)); | |
116 | return; | |
117 | } | |
118 | used[XINT (x, 0)] = 1; | |
119 | } | |
120 | printf ("operand%d", XINT (x, 0)); | |
121 | return; | |
122 | ||
123 | case MATCH_OP_DUP: | |
124 | printf ("gen_rtx_fmt_"); | |
125 | for (i = 0; i < XVECLEN (x, 1); i++) | |
126 | printf ("e"); | |
127 | printf (" (GET_CODE (operand%d), ", XINT (x, 0)); | |
128 | if (GET_MODE (x) == VOIDmode) | |
129 | printf ("GET_MODE (operand%d)", XINT (x, 0)); | |
130 | else | |
131 | printf ("%smode", GET_MODE_NAME (GET_MODE (x))); | |
132 | for (i = 0; i < XVECLEN (x, 1); i++) | |
133 | { | |
134 | printf (",\n\t\t"); | |
135 | gen_exp (XVECEXP (x, 1, i), subroutine_type, used); | |
136 | } | |
137 | printf (")"); | |
138 | return; | |
139 | ||
140 | case MATCH_OPERATOR: | |
141 | printf ("gen_rtx_fmt_"); | |
142 | for (i = 0; i < XVECLEN (x, 2); i++) | |
143 | printf ("e"); | |
144 | printf (" (GET_CODE (operand%d)", XINT (x, 0)); | |
145 | printf (", %smode", GET_MODE_NAME (GET_MODE (x))); | |
146 | for (i = 0; i < XVECLEN (x, 2); i++) | |
147 | { | |
148 | printf (",\n\t\t"); | |
149 | gen_exp (XVECEXP (x, 2, i), subroutine_type, used); | |
150 | } | |
151 | printf (")"); | |
152 | return; | |
153 | ||
154 | case MATCH_PARALLEL: | |
155 | case MATCH_PAR_DUP: | |
156 | printf ("operand%d", XINT (x, 0)); | |
157 | return; | |
158 | ||
159 | case MATCH_SCRATCH: | |
160 | gen_rtx_scratch (x, subroutine_type); | |
161 | return; | |
162 | ||
163 | case ADDRESS: | |
164 | fatal ("ADDRESS expression code used in named instruction pattern"); | |
165 | ||
166 | case PC: | |
167 | printf ("pc_rtx"); | |
168 | return; | |
169 | case CLOBBER: | |
170 | if (REG_P (XEXP (x, 0))) | |
171 | { | |
172 | printf ("gen_hard_reg_clobber (%smode, %i)", GET_MODE_NAME (GET_MODE (XEXP (x, 0))), | |
173 | REGNO (XEXP (x, 0))); | |
174 | return; | |
175 | } | |
176 | break; | |
177 | ||
178 | case CC0: | |
179 | printf ("cc0_rtx"); | |
180 | return; | |
181 | ||
182 | case CONST_INT: | |
183 | if (INTVAL (x) == 0) | |
184 | printf ("const0_rtx"); | |
185 | else if (INTVAL (x) == 1) | |
186 | printf ("const1_rtx"); | |
187 | else if (INTVAL (x) == -1) | |
188 | printf ("constm1_rtx"); | |
189 | else if (-MAX_SAVED_CONST_INT <= INTVAL (x) | |
190 | && INTVAL (x) <= MAX_SAVED_CONST_INT) | |
191 | printf ("const_int_rtx[MAX_SAVED_CONST_INT + (%d)]", | |
192 | (int) INTVAL (x)); | |
193 | else if (INTVAL (x) == STORE_FLAG_VALUE) | |
194 | printf ("const_true_rtx"); | |
195 | else | |
196 | { | |
197 | printf ("GEN_INT ("); | |
198 | printf (HOST_WIDE_INT_PRINT_DEC_C, INTVAL (x)); | |
199 | printf (")"); | |
200 | } | |
201 | return; | |
202 | ||
203 | case CONST_DOUBLE: | |
204 | case CONST_FIXED: | |
205 | /* These shouldn't be written in MD files. Instead, the appropriate | |
206 | routines in varasm.c should be called. */ | |
207 | gcc_unreachable (); | |
208 | ||
209 | default: | |
210 | break; | |
211 | } | |
212 | ||
213 | printf ("gen_rtx_"); | |
214 | print_code (code); | |
215 | printf (" (%smode", GET_MODE_NAME (GET_MODE (x))); | |
216 | ||
217 | fmt = GET_RTX_FORMAT (code); | |
218 | len = GET_RTX_LENGTH (code); | |
219 | for (i = 0; i < len; i++) | |
220 | { | |
221 | if (fmt[i] == '0') | |
222 | break; | |
223 | printf (",\n\t"); | |
224 | switch (fmt[i]) | |
225 | { | |
226 | case 'e': case 'u': | |
227 | gen_exp (XEXP (x, i), subroutine_type, used); | |
228 | break; | |
229 | ||
230 | case 'i': | |
231 | printf ("%u", XINT (x, i)); | |
232 | break; | |
233 | ||
234 | case 's': | |
235 | printf ("\"%s\"", XSTR (x, i)); | |
236 | break; | |
237 | ||
238 | case 'E': | |
239 | { | |
240 | int j; | |
241 | printf ("gen_rtvec (%d", XVECLEN (x, i)); | |
242 | for (j = 0; j < XVECLEN (x, i); j++) | |
243 | { | |
244 | printf (",\n\t\t"); | |
245 | gen_exp (XVECEXP (x, i, j), subroutine_type, used); | |
246 | } | |
247 | printf (")"); | |
248 | break; | |
249 | } | |
250 | ||
251 | default: | |
252 | gcc_unreachable (); | |
253 | } | |
254 | } | |
255 | printf (")"); | |
256 | } | |
257 | \f | |
258 | /* Generate the `gen_...' function for a DEFINE_INSN. */ | |
259 | ||
260 | static void | |
261 | gen_insn (rtx insn, int lineno) | |
262 | { | |
263 | struct pattern_stats stats; | |
264 | int i; | |
265 | ||
266 | /* See if the pattern for this insn ends with a group of CLOBBERs of (hard) | |
267 | registers or MATCH_SCRATCHes. If so, store away the information for | |
268 | later. */ | |
269 | ||
270 | if (XVEC (insn, 1)) | |
271 | { | |
272 | int has_hard_reg = 0; | |
273 | ||
274 | for (i = XVECLEN (insn, 1) - 1; i > 0; i--) | |
275 | { | |
276 | if (GET_CODE (XVECEXP (insn, 1, i)) != CLOBBER) | |
277 | break; | |
278 | ||
279 | if (REG_P (XEXP (XVECEXP (insn, 1, i), 0))) | |
280 | has_hard_reg = 1; | |
281 | else if (GET_CODE (XEXP (XVECEXP (insn, 1, i), 0)) != MATCH_SCRATCH) | |
282 | break; | |
283 | } | |
284 | ||
285 | if (i != XVECLEN (insn, 1) - 1) | |
286 | { | |
287 | struct clobber_pat *p; | |
288 | struct clobber_ent *link = XNEW (struct clobber_ent); | |
289 | int j; | |
290 | ||
291 | link->code_number = insn_code_number; | |
292 | ||
293 | /* See if any previous CLOBBER_LIST entry is the same as this | |
294 | one. */ | |
295 | ||
296 | for (p = clobber_list; p; p = p->next) | |
297 | { | |
298 | if (p->first_clobber != i + 1 | |
299 | || XVECLEN (p->pattern, 1) != XVECLEN (insn, 1)) | |
300 | continue; | |
301 | ||
302 | for (j = i + 1; j < XVECLEN (insn, 1); j++) | |
303 | { | |
304 | rtx old_rtx = XEXP (XVECEXP (p->pattern, 1, j), 0); | |
305 | rtx new_rtx = XEXP (XVECEXP (insn, 1, j), 0); | |
306 | ||
307 | /* OLD and NEW_INSN are the same if both are to be a SCRATCH | |
308 | of the same mode, | |
309 | or if both are registers of the same mode and number. */ | |
310 | if (! (GET_MODE (old_rtx) == GET_MODE (new_rtx) | |
311 | && ((GET_CODE (old_rtx) == MATCH_SCRATCH | |
312 | && GET_CODE (new_rtx) == MATCH_SCRATCH) | |
313 | || (REG_P (old_rtx) && REG_P (new_rtx) | |
314 | && REGNO (old_rtx) == REGNO (new_rtx))))) | |
315 | break; | |
316 | } | |
317 | ||
318 | if (j == XVECLEN (insn, 1)) | |
319 | break; | |
320 | } | |
321 | ||
322 | if (p == 0) | |
323 | { | |
324 | p = XNEW (struct clobber_pat); | |
325 | ||
326 | p->insns = 0; | |
327 | p->pattern = insn; | |
328 | p->first_clobber = i + 1; | |
329 | p->next = clobber_list; | |
330 | p->has_hard_reg = has_hard_reg; | |
331 | clobber_list = p; | |
332 | } | |
333 | ||
334 | link->next = p->insns; | |
335 | p->insns = link; | |
336 | } | |
337 | } | |
338 | ||
339 | /* Don't mention instructions whose names are the null string | |
340 | or begin with '*'. They are in the machine description just | |
341 | to be recognized. */ | |
342 | if (XSTR (insn, 0)[0] == 0 || XSTR (insn, 0)[0] == '*') | |
343 | return; | |
344 | ||
345 | printf ("/* %s:%d */\n", read_md_filename, lineno); | |
346 | ||
347 | /* Find out how many operands this function has. */ | |
348 | get_pattern_stats (&stats, XVEC (insn, 1)); | |
349 | if (stats.max_dup_opno > stats.max_opno) | |
350 | fatal ("match_dup operand number has no match_operand"); | |
351 | ||
352 | /* Output the function name and argument declarations. */ | |
353 | printf ("rtx\ngen_%s (", XSTR (insn, 0)); | |
354 | if (stats.num_generator_args) | |
355 | for (i = 0; i < stats.num_generator_args; i++) | |
356 | if (i) | |
357 | printf (",\n\trtx operand%d ATTRIBUTE_UNUSED", i); | |
358 | else | |
359 | printf ("rtx operand%d ATTRIBUTE_UNUSED", i); | |
360 | else | |
361 | printf ("void"); | |
362 | printf (")\n"); | |
363 | printf ("{\n"); | |
364 | ||
365 | /* Output code to construct and return the rtl for the instruction body. */ | |
366 | ||
367 | if (XVECLEN (insn, 1) == 1) | |
368 | { | |
369 | printf (" return "); | |
370 | gen_exp (XVECEXP (insn, 1, 0), DEFINE_INSN, NULL); | |
371 | printf (";\n}\n\n"); | |
372 | } | |
373 | else | |
374 | { | |
375 | char *used = XCNEWVEC (char, stats.num_generator_args); | |
376 | ||
377 | printf (" return gen_rtx_PARALLEL (VOIDmode, gen_rtvec (%d", | |
378 | XVECLEN (insn, 1)); | |
379 | ||
380 | for (i = 0; i < XVECLEN (insn, 1); i++) | |
381 | { | |
382 | printf (",\n\t\t"); | |
383 | gen_exp (XVECEXP (insn, 1, i), DEFINE_INSN, used); | |
384 | } | |
385 | printf ("));\n}\n\n"); | |
386 | XDELETEVEC (used); | |
387 | } | |
388 | } | |
389 | \f | |
390 | /* Generate the `gen_...' function for a DEFINE_EXPAND. */ | |
391 | ||
392 | static void | |
393 | gen_expand (rtx expand) | |
394 | { | |
395 | struct pattern_stats stats; | |
396 | int i; | |
397 | char *used; | |
398 | ||
399 | if (strlen (XSTR (expand, 0)) == 0) | |
400 | fatal ("define_expand lacks a name"); | |
401 | if (XVEC (expand, 1) == 0) | |
402 | fatal ("define_expand for %s lacks a pattern", XSTR (expand, 0)); | |
403 | ||
404 | /* Find out how many operands this function has. */ | |
405 | get_pattern_stats (&stats, XVEC (expand, 1)); | |
406 | ||
407 | /* Output the function name and argument declarations. */ | |
408 | printf ("rtx\ngen_%s (", XSTR (expand, 0)); | |
409 | if (stats.num_generator_args) | |
410 | for (i = 0; i < stats.num_generator_args; i++) | |
411 | if (i) | |
412 | printf (",\n\trtx operand%d", i); | |
413 | else | |
414 | printf ("rtx operand%d", i); | |
415 | else | |
416 | printf ("void"); | |
417 | printf (")\n"); | |
418 | printf ("{\n"); | |
419 | ||
420 | /* If we don't have any C code to write, only one insn is being written, | |
421 | and no MATCH_DUPs are present, we can just return the desired insn | |
422 | like we do for a DEFINE_INSN. This saves memory. */ | |
423 | if ((XSTR (expand, 3) == 0 || *XSTR (expand, 3) == '\0') | |
424 | && stats.max_opno >= stats.max_dup_opno | |
425 | && XVECLEN (expand, 1) == 1) | |
426 | { | |
427 | printf (" return "); | |
428 | gen_exp (XVECEXP (expand, 1, 0), DEFINE_EXPAND, NULL); | |
429 | printf (";\n}\n\n"); | |
430 | return; | |
431 | } | |
432 | ||
433 | /* For each operand referred to only with MATCH_DUPs, | |
434 | make a local variable. */ | |
435 | for (i = stats.num_generator_args; i <= stats.max_dup_opno; i++) | |
436 | printf (" rtx operand%d;\n", i); | |
437 | for (; i <= stats.max_scratch_opno; i++) | |
438 | printf (" rtx operand%d ATTRIBUTE_UNUSED;\n", i); | |
439 | printf (" rtx _val = 0;\n"); | |
440 | printf (" start_sequence ();\n"); | |
441 | ||
442 | /* The fourth operand of DEFINE_EXPAND is some code to be executed | |
443 | before the actual construction. | |
444 | This code expects to refer to `operands' | |
445 | just as the output-code in a DEFINE_INSN does, | |
446 | but here `operands' is an automatic array. | |
447 | So copy the operand values there before executing it. */ | |
448 | if (XSTR (expand, 3) && *XSTR (expand, 3)) | |
449 | { | |
450 | printf (" {\n"); | |
451 | if (stats.num_operand_vars > 0) | |
452 | printf (" rtx operands[%d];\n", stats.num_operand_vars); | |
453 | ||
454 | /* Output code to copy the arguments into `operands'. */ | |
455 | for (i = 0; i < stats.num_generator_args; i++) | |
456 | printf (" operands[%d] = operand%d;\n", i, i); | |
457 | ||
458 | /* Output the special code to be executed before the sequence | |
459 | is generated. */ | |
460 | print_md_ptr_loc (XSTR (expand, 3)); | |
461 | printf ("%s\n", XSTR (expand, 3)); | |
462 | ||
463 | /* Output code to copy the arguments back out of `operands' | |
464 | (unless we aren't going to use them at all). */ | |
465 | if (XVEC (expand, 1) != 0) | |
466 | { | |
467 | for (i = 0; i < stats.num_operand_vars; i++) | |
468 | { | |
469 | printf (" operand%d = operands[%d];\n", i, i); | |
470 | printf (" (void) operand%d;\n", i); | |
471 | } | |
472 | } | |
473 | printf (" }\n"); | |
474 | } | |
475 | ||
476 | /* Output code to construct the rtl for the instruction bodies. | |
477 | Use emit_insn to add them to the sequence being accumulated. | |
478 | But don't do this if the user's code has set `no_more' nonzero. */ | |
479 | ||
480 | used = XCNEWVEC (char, stats.num_operand_vars); | |
481 | ||
482 | for (i = 0; i < XVECLEN (expand, 1); i++) | |
483 | { | |
484 | rtx next = XVECEXP (expand, 1, i); | |
485 | if ((GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC) | |
486 | || (GET_CODE (next) == PARALLEL | |
487 | && ((GET_CODE (XVECEXP (next, 0, 0)) == SET | |
488 | && GET_CODE (SET_DEST (XVECEXP (next, 0, 0))) == PC) | |
489 | || GET_CODE (XVECEXP (next, 0, 0)) == RETURN)) | |
490 | || GET_CODE (next) == RETURN) | |
491 | printf (" emit_jump_insn ("); | |
492 | else if ((GET_CODE (next) == SET && GET_CODE (SET_SRC (next)) == CALL) | |
493 | || GET_CODE (next) == CALL | |
494 | || (GET_CODE (next) == PARALLEL | |
495 | && GET_CODE (XVECEXP (next, 0, 0)) == SET | |
496 | && GET_CODE (SET_SRC (XVECEXP (next, 0, 0))) == CALL) | |
497 | || (GET_CODE (next) == PARALLEL | |
498 | && GET_CODE (XVECEXP (next, 0, 0)) == CALL)) | |
499 | printf (" emit_call_insn ("); | |
500 | else if (LABEL_P (next)) | |
501 | printf (" emit_label ("); | |
502 | else if (GET_CODE (next) == MATCH_OPERAND | |
503 | || GET_CODE (next) == MATCH_DUP | |
504 | || GET_CODE (next) == MATCH_OPERATOR | |
505 | || GET_CODE (next) == MATCH_OP_DUP | |
506 | || GET_CODE (next) == MATCH_PARALLEL | |
507 | || GET_CODE (next) == MATCH_PAR_DUP | |
508 | || GET_CODE (next) == PARALLEL) | |
509 | printf (" emit ("); | |
510 | else | |
511 | printf (" emit_insn ("); | |
512 | gen_exp (next, DEFINE_EXPAND, used); | |
513 | printf (");\n"); | |
514 | if (GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC | |
515 | && GET_CODE (SET_SRC (next)) == LABEL_REF) | |
516 | printf (" emit_barrier ();"); | |
517 | } | |
518 | ||
519 | XDELETEVEC (used); | |
520 | ||
521 | /* Call `get_insns' to extract the list of all the | |
522 | insns emitted within this gen_... function. */ | |
523 | ||
524 | printf (" _val = get_insns ();\n"); | |
525 | printf (" end_sequence ();\n"); | |
526 | printf (" return _val;\n}\n\n"); | |
527 | } | |
528 | ||
529 | /* Like gen_expand, but generates insns resulting from splitting SPLIT. */ | |
530 | ||
531 | static void | |
532 | gen_split (rtx split) | |
533 | { | |
534 | struct pattern_stats stats; | |
535 | int i; | |
536 | const char *const name = | |
537 | ((GET_CODE (split) == DEFINE_PEEPHOLE2) ? "peephole2" : "split"); | |
538 | const char *unused; | |
539 | char *used; | |
540 | ||
541 | if (XVEC (split, 0) == 0) | |
542 | fatal ("define_%s (definition %d) lacks a pattern", name, | |
543 | insn_index_number); | |
544 | else if (XVEC (split, 2) == 0) | |
545 | fatal ("define_%s (definition %d) lacks a replacement pattern", name, | |
546 | insn_index_number); | |
547 | ||
548 | /* Find out how many operands this function has. */ | |
549 | ||
550 | get_pattern_stats (&stats, XVEC (split, 2)); | |
551 | unused = (stats.num_operand_vars == 0 ? " ATTRIBUTE_UNUSED" : ""); | |
552 | used = XCNEWVEC (char, stats.num_operand_vars); | |
553 | ||
554 | /* Output the prototype, function name and argument declarations. */ | |
555 | if (GET_CODE (split) == DEFINE_PEEPHOLE2) | |
556 | { | |
557 | printf ("extern rtx gen_%s_%d (rtx, rtx *);\n", | |
558 | name, insn_code_number); | |
559 | printf ("rtx\ngen_%s_%d (rtx curr_insn ATTRIBUTE_UNUSED, rtx *operands%s)\n", | |
560 | name, insn_code_number, unused); | |
561 | } | |
562 | else | |
563 | { | |
564 | printf ("extern rtx gen_split_%d (rtx, rtx *);\n", insn_code_number); | |
565 | printf ("rtx\ngen_split_%d (rtx curr_insn ATTRIBUTE_UNUSED, rtx *operands%s)\n", | |
566 | insn_code_number, unused); | |
567 | } | |
568 | printf ("{\n"); | |
569 | ||
570 | /* Declare all local variables. */ | |
571 | for (i = 0; i < stats.num_operand_vars; i++) | |
572 | printf (" rtx operand%d;\n", i); | |
573 | printf (" rtx _val = 0;\n"); | |
574 | ||
575 | if (GET_CODE (split) == DEFINE_PEEPHOLE2) | |
576 | output_peephole2_scratches (split); | |
577 | ||
578 | printf (" start_sequence ();\n"); | |
579 | ||
580 | /* The fourth operand of DEFINE_SPLIT is some code to be executed | |
581 | before the actual construction. */ | |
582 | ||
583 | if (XSTR (split, 3)) | |
584 | { | |
585 | print_md_ptr_loc (XSTR (split, 3)); | |
586 | printf ("%s\n", XSTR (split, 3)); | |
587 | } | |
588 | ||
589 | /* Output code to copy the arguments back out of `operands' */ | |
590 | for (i = 0; i < stats.num_operand_vars; i++) | |
591 | { | |
592 | printf (" operand%d = operands[%d];\n", i, i); | |
593 | printf (" (void) operand%d;\n", i); | |
594 | } | |
595 | ||
596 | /* Output code to construct the rtl for the instruction bodies. | |
597 | Use emit_insn to add them to the sequence being accumulated. | |
598 | But don't do this if the user's code has set `no_more' nonzero. */ | |
599 | ||
600 | for (i = 0; i < XVECLEN (split, 2); i++) | |
601 | { | |
602 | rtx next = XVECEXP (split, 2, i); | |
603 | if ((GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC) | |
604 | || (GET_CODE (next) == PARALLEL | |
605 | && GET_CODE (XVECEXP (next, 0, 0)) == SET | |
606 | && GET_CODE (SET_DEST (XVECEXP (next, 0, 0))) == PC) | |
607 | || GET_CODE (next) == RETURN) | |
608 | printf (" emit_jump_insn ("); | |
609 | else if ((GET_CODE (next) == SET && GET_CODE (SET_SRC (next)) == CALL) | |
610 | || GET_CODE (next) == CALL | |
611 | || (GET_CODE (next) == PARALLEL | |
612 | && GET_CODE (XVECEXP (next, 0, 0)) == SET | |
613 | && GET_CODE (SET_SRC (XVECEXP (next, 0, 0))) == CALL) | |
614 | || (GET_CODE (next) == PARALLEL | |
615 | && GET_CODE (XVECEXP (next, 0, 0)) == CALL)) | |
616 | printf (" emit_call_insn ("); | |
617 | else if (LABEL_P (next)) | |
618 | printf (" emit_label ("); | |
619 | else if (GET_CODE (next) == MATCH_OPERAND | |
620 | || GET_CODE (next) == MATCH_OPERATOR | |
621 | || GET_CODE (next) == MATCH_PARALLEL | |
622 | || GET_CODE (next) == MATCH_OP_DUP | |
623 | || GET_CODE (next) == MATCH_DUP | |
624 | || GET_CODE (next) == PARALLEL) | |
625 | printf (" emit ("); | |
626 | else | |
627 | printf (" emit_insn ("); | |
628 | gen_exp (next, GET_CODE (split), used); | |
629 | printf (");\n"); | |
630 | if (GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC | |
631 | && GET_CODE (SET_SRC (next)) == LABEL_REF) | |
632 | printf (" emit_barrier ();"); | |
633 | } | |
634 | ||
635 | /* Call `get_insns' to make a list of all the | |
636 | insns emitted within this gen_... function. */ | |
637 | ||
638 | printf (" _val = get_insns ();\n"); | |
639 | printf (" end_sequence ();\n"); | |
640 | printf (" return _val;\n}\n\n"); | |
641 | ||
642 | free (used); | |
643 | } | |
644 | \f | |
645 | /* Write a function, `add_clobbers', that is given a PARALLEL of sufficient | |
646 | size for the insn and an INSN_CODE, and inserts the required CLOBBERs at | |
647 | the end of the vector. */ | |
648 | ||
649 | static void | |
650 | output_add_clobbers (void) | |
651 | { | |
652 | struct clobber_pat *clobber; | |
653 | struct clobber_ent *ent; | |
654 | int i; | |
655 | ||
656 | printf ("\n\nvoid\nadd_clobbers (rtx pattern ATTRIBUTE_UNUSED, int insn_code_number)\n"); | |
657 | printf ("{\n"); | |
658 | printf (" switch (insn_code_number)\n"); | |
659 | printf (" {\n"); | |
660 | ||
661 | for (clobber = clobber_list; clobber; clobber = clobber->next) | |
662 | { | |
663 | for (ent = clobber->insns; ent; ent = ent->next) | |
664 | printf (" case %d:\n", ent->code_number); | |
665 | ||
666 | for (i = clobber->first_clobber; i < XVECLEN (clobber->pattern, 1); i++) | |
667 | { | |
668 | printf (" XVECEXP (pattern, 0, %d) = ", i); | |
669 | gen_exp (XVECEXP (clobber->pattern, 1, i), | |
670 | GET_CODE (clobber->pattern), NULL); | |
671 | printf (";\n"); | |
672 | } | |
673 | ||
674 | printf (" break;\n\n"); | |
675 | } | |
676 | ||
677 | printf (" default:\n"); | |
678 | printf (" gcc_unreachable ();\n"); | |
679 | printf (" }\n"); | |
680 | printf ("}\n"); | |
681 | } | |
682 | \f | |
683 | /* Write a function, `added_clobbers_hard_reg_p' that is given an insn_code | |
684 | number that will have clobbers added (as indicated by `recog') and returns | |
685 | 1 if those include a clobber of a hard reg or 0 if all of them just clobber | |
686 | SCRATCH. */ | |
687 | ||
688 | static void | |
689 | output_added_clobbers_hard_reg_p (void) | |
690 | { | |
691 | struct clobber_pat *clobber; | |
692 | struct clobber_ent *ent; | |
693 | int clobber_p, used; | |
694 | ||
695 | printf ("\n\nint\nadded_clobbers_hard_reg_p (int insn_code_number)\n"); | |
696 | printf ("{\n"); | |
697 | printf (" switch (insn_code_number)\n"); | |
698 | printf (" {\n"); | |
699 | ||
700 | for (clobber_p = 0; clobber_p <= 1; clobber_p++) | |
701 | { | |
702 | used = 0; | |
703 | for (clobber = clobber_list; clobber; clobber = clobber->next) | |
704 | if (clobber->has_hard_reg == clobber_p) | |
705 | for (ent = clobber->insns; ent; ent = ent->next) | |
706 | { | |
707 | printf (" case %d:\n", ent->code_number); | |
708 | used++; | |
709 | } | |
710 | ||
711 | if (used) | |
712 | printf (" return %d;\n\n", clobber_p); | |
713 | } | |
714 | ||
715 | printf (" default:\n"); | |
716 | printf (" gcc_unreachable ();\n"); | |
717 | printf (" }\n"); | |
718 | printf ("}\n"); | |
719 | } | |
720 | \f | |
721 | /* Generate code to invoke find_free_register () as needed for the | |
722 | scratch registers used by the peephole2 pattern in SPLIT. */ | |
723 | ||
724 | static void | |
725 | output_peephole2_scratches (rtx split) | |
726 | { | |
727 | int i; | |
728 | int insn_nr = 0; | |
729 | bool first = true; | |
730 | ||
731 | for (i = 0; i < XVECLEN (split, 0); i++) | |
732 | { | |
733 | rtx elt = XVECEXP (split, 0, i); | |
734 | if (GET_CODE (elt) == MATCH_SCRATCH) | |
735 | { | |
736 | int last_insn_nr = insn_nr; | |
737 | int cur_insn_nr = insn_nr; | |
738 | int j; | |
739 | for (j = i + 1; j < XVECLEN (split, 0); j++) | |
740 | if (GET_CODE (XVECEXP (split, 0, j)) == MATCH_DUP) | |
741 | { | |
742 | if (XINT (XVECEXP (split, 0, j), 0) == XINT (elt, 0)) | |
743 | last_insn_nr = cur_insn_nr; | |
744 | } | |
745 | else if (GET_CODE (XVECEXP (split, 0, j)) != MATCH_SCRATCH) | |
746 | cur_insn_nr++; | |
747 | ||
748 | if (first) | |
749 | { | |
750 | printf (" HARD_REG_SET _regs_allocated;\n"); | |
751 | printf (" CLEAR_HARD_REG_SET (_regs_allocated);\n"); | |
752 | first = false; | |
753 | } | |
754 | ||
755 | printf (" if ((operands[%d] = peep2_find_free_register (%d, %d, \"%s\", %smode, &_regs_allocated)) == NULL_RTX)\n\ | |
756 | return NULL;\n", | |
757 | XINT (elt, 0), | |
758 | insn_nr, last_insn_nr, | |
759 | XSTR (elt, 1), | |
760 | GET_MODE_NAME (GET_MODE (elt))); | |
761 | ||
762 | } | |
763 | else if (GET_CODE (elt) != MATCH_DUP) | |
764 | insn_nr++; | |
765 | } | |
766 | } | |
767 | ||
768 | int | |
769 | main (int argc, char **argv) | |
770 | { | |
771 | rtx desc; | |
772 | ||
773 | progname = "genemit"; | |
774 | ||
775 | if (!init_rtx_reader_args (argc, argv)) | |
776 | return (FATAL_EXIT_CODE); | |
777 | ||
778 | /* Assign sequential codes to all entries in the machine description | |
779 | in parallel with the tables in insn-output.c. */ | |
780 | ||
781 | insn_code_number = 0; | |
782 | insn_index_number = 0; | |
783 | ||
784 | printf ("/* Generated automatically by the program `genemit'\n\ | |
785 | from the machine description file `md'. */\n\n"); | |
786 | ||
787 | printf ("#include \"config.h\"\n"); | |
788 | printf ("#include \"system.h\"\n"); | |
789 | printf ("#include \"coretypes.h\"\n"); | |
790 | printf ("#include \"tm.h\"\n"); | |
791 | printf ("#include \"rtl.h\"\n"); | |
792 | printf ("#include \"tm_p.h\"\n"); | |
793 | printf ("#include \"function.h\"\n"); | |
794 | printf ("#include \"expr.h\"\n"); | |
795 | printf ("#include \"optabs.h\"\n"); | |
796 | printf ("#include \"dfp.h\"\n"); | |
797 | printf ("#include \"flags.h\"\n"); | |
798 | printf ("#include \"output.h\"\n"); | |
799 | printf ("#include \"insn-config.h\"\n"); | |
800 | printf ("#include \"hard-reg-set.h\"\n"); | |
801 | printf ("#include \"recog.h\"\n"); | |
802 | printf ("#include \"resource.h\"\n"); | |
803 | printf ("#include \"reload.h\"\n"); | |
804 | printf ("#include \"diagnostic-core.h\"\n"); | |
805 | printf ("#include \"regs.h\"\n"); | |
806 | printf ("#include \"tm-constrs.h\"\n"); | |
807 | printf ("#include \"ggc.h\"\n"); | |
808 | printf ("#include \"basic-block.h\"\n"); | |
809 | printf ("#include \"integrate.h\"\n\n"); | |
810 | printf ("#define FAIL return (end_sequence (), _val)\n"); | |
811 | printf ("#define DONE return (_val = get_insns (), end_sequence (), _val)\n\n"); | |
812 | ||
813 | /* Read the machine description. */ | |
814 | ||
815 | while (1) | |
816 | { | |
817 | int line_no; | |
818 | ||
819 | desc = read_md_rtx (&line_no, &insn_code_number); | |
820 | if (desc == NULL) | |
821 | break; | |
822 | ||
823 | switch (GET_CODE (desc)) | |
824 | { | |
825 | case DEFINE_INSN: | |
826 | gen_insn (desc, line_no); | |
827 | break; | |
828 | ||
829 | case DEFINE_EXPAND: | |
830 | printf ("/* %s:%d */\n", read_md_filename, line_no); | |
831 | gen_expand (desc); | |
832 | break; | |
833 | ||
834 | case DEFINE_SPLIT: | |
835 | printf ("/* %s:%d */\n", read_md_filename, line_no); | |
836 | gen_split (desc); | |
837 | break; | |
838 | ||
839 | case DEFINE_PEEPHOLE2: | |
840 | printf ("/* %s:%d */\n", read_md_filename, line_no); | |
841 | gen_split (desc); | |
842 | break; | |
843 | ||
844 | default: | |
845 | break; | |
846 | } | |
847 | ++insn_index_number; | |
848 | } | |
849 | ||
850 | /* Write out the routines to add CLOBBERs to a pattern and say whether they | |
851 | clobber a hard reg. */ | |
852 | output_add_clobbers (); | |
853 | output_added_clobbers_hard_reg_p (); | |
854 | ||
855 | fflush (stdout); | |
856 | return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); | |
857 | } |