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