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