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