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