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