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