]>
Commit | Line | Data |
---|---|---|
32f30c53 | 1 | /* Generate code from machine description to perform peephole optimizations. |
9dcd6f09 NC |
2 | Copyright (C) 1987, 1989, 1992, 1997, 1998, 1999, 2000, 2003, 2004, |
3 | 2007 Free Software Foundation, Inc. | |
32f30c53 | 4 | |
1322177d | 5 | This file is part of GCC. |
32f30c53 | 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. |
32f30c53 | 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. | |
32f30c53 TW |
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/>. */ | |
32f30c53 TW |
20 | |
21 | ||
4977bab6 | 22 | #include "bconfig.h" |
0b93b64e | 23 | #include "system.h" |
4977bab6 ZW |
24 | #include "coretypes.h" |
25 | #include "tm.h" | |
32f30c53 | 26 | #include "rtl.h" |
f8b6598e | 27 | #include "errors.h" |
c88c0d42 | 28 | #include "gensupport.h" |
32f30c53 | 29 | |
32f30c53 | 30 | |
32f30c53 TW |
31 | /* While tree-walking an instruction pattern, we keep a chain |
32 | of these `struct link's to record how to get down to the | |
33 | current position. In each one, POS is the operand number, | |
34 | and if the operand is a vector VEC is the element number. | |
35 | VEC is -1 if the operand is not a vector. */ | |
36 | ||
37 | struct link | |
38 | { | |
39 | struct link *next; | |
40 | int pos; | |
41 | int vecelt; | |
42 | }; | |
43 | ||
32f30c53 TW |
44 | static int max_opno; |
45 | ||
46 | /* Number of operands used in current peephole definition. */ | |
47 | ||
48 | static int n_operands; | |
49 | ||
50 | /* Peephole optimizations get insn codes just like insn patterns. | |
51 | Count them so we know the code of the define_peephole we are handling. */ | |
52 | ||
53 | static int insn_code_number = 0; | |
54 | ||
3d7aafde AJ |
55 | static void gen_peephole (rtx); |
56 | static void match_rtx (rtx, struct link *, int); | |
57 | static void print_path (struct link *); | |
58 | static void print_code (RTX_CODE); | |
32f30c53 TW |
59 | \f |
60 | static void | |
3d7aafde | 61 | gen_peephole (rtx peep) |
32f30c53 TW |
62 | { |
63 | int ninsns = XVECLEN (peep, 0); | |
64 | int i; | |
65 | ||
66 | n_operands = 0; | |
67 | ||
68 | printf (" insn = ins1;\n"); | |
32f30c53 TW |
69 | |
70 | for (i = 0; i < ninsns; i++) | |
71 | { | |
72 | if (i > 0) | |
73 | { | |
74 | printf (" do { insn = NEXT_INSN (insn);\n"); | |
75 | printf (" if (insn == 0) goto L%d; }\n", | |
76 | insn_code_number); | |
4b4bf941 JQ |
77 | printf (" while (NOTE_P (insn)\n"); |
78 | printf ("\t || (NONJUMP_INSN_P (insn)\n"); | |
32f30c53 TW |
79 | printf ("\t && (GET_CODE (PATTERN (insn)) == USE\n"); |
80 | printf ("\t\t || GET_CODE (PATTERN (insn)) == CLOBBER)));\n"); | |
81 | ||
4b4bf941 JQ |
82 | printf (" if (LABEL_P (insn)\n\ |
83 | || BARRIER_P (insn))\n goto L%d;\n", | |
3d7aafde | 84 | insn_code_number); |
32f30c53 TW |
85 | } |
86 | ||
32f30c53 TW |
87 | printf (" pat = PATTERN (insn);\n"); |
88 | ||
89 | /* Walk the insn's pattern, remembering at all times the path | |
90 | down to the walking point. */ | |
91 | ||
9714cf43 | 92 | match_rtx (XVECEXP (peep, 0, i), NULL, insn_code_number); |
32f30c53 TW |
93 | } |
94 | ||
95 | /* We get this far if the pattern matches. | |
96 | Now test the extra condition. */ | |
97 | ||
98 | if (XSTR (peep, 1) && XSTR (peep, 1)[0]) | |
99 | printf (" if (! (%s)) goto L%d;\n", | |
100 | XSTR (peep, 1), insn_code_number); | |
101 | ||
102 | /* If that matches, construct new pattern and put it in the first insn. | |
103 | This new pattern will never be matched. | |
104 | It exists only so that insn-extract can get the operands back. | |
105 | So use a simple regular form: a PARALLEL containing a vector | |
106 | of all the operands. */ | |
107 | ||
38a448ca | 108 | printf (" PATTERN (ins1) = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (%d, operands));\n", n_operands); |
32f30c53 | 109 | |
32f30c53 TW |
110 | /* Record this define_peephole's insn code in the insn, |
111 | as if it had been recognized to match this. */ | |
112 | printf (" INSN_CODE (ins1) = %d;\n", | |
113 | insn_code_number); | |
114 | ||
115 | /* Delete the remaining insns. */ | |
116 | if (ninsns > 1) | |
117 | printf (" delete_for_peephole (NEXT_INSN (ins1), insn);\n"); | |
118 | ||
119 | /* See reload1.c for insertion of NOTE which guarantees that this | |
120 | cannot be zero. */ | |
121 | printf (" return NEXT_INSN (insn);\n"); | |
122 | ||
123 | printf (" L%d:\n\n", insn_code_number); | |
124 | } | |
125 | \f | |
126 | static void | |
3d7aafde | 127 | match_rtx (rtx x, struct link *path, int fail_label) |
32f30c53 | 128 | { |
b3694847 SS |
129 | RTX_CODE code; |
130 | int i; | |
131 | int len; | |
132 | const char *fmt; | |
32f30c53 TW |
133 | struct link link; |
134 | ||
135 | if (x == 0) | |
136 | return; | |
137 | ||
138 | ||
139 | code = GET_CODE (x); | |
140 | ||
141 | switch (code) | |
142 | { | |
143 | case MATCH_OPERAND: | |
144 | if (XINT (x, 0) > max_opno) | |
145 | max_opno = XINT (x, 0); | |
146 | if (XINT (x, 0) >= n_operands) | |
147 | n_operands = 1 + XINT (x, 0); | |
148 | ||
149 | printf (" x = "); | |
150 | print_path (path); | |
151 | printf (";\n"); | |
152 | ||
153 | printf (" operands[%d] = x;\n", XINT (x, 0)); | |
154 | if (XSTR (x, 1) && XSTR (x, 1)[0]) | |
155 | printf (" if (! %s (x, %smode)) goto L%d;\n", | |
156 | XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label); | |
157 | return; | |
158 | ||
159 | case MATCH_DUP: | |
693fb02f | 160 | case MATCH_PAR_DUP: |
32f30c53 TW |
161 | printf (" x = "); |
162 | print_path (path); | |
163 | printf (";\n"); | |
164 | ||
165 | printf (" if (!rtx_equal_p (operands[%d], x)) goto L%d;\n", | |
166 | XINT (x, 0), fail_label); | |
167 | return; | |
168 | ||
169 | case MATCH_OP_DUP: | |
170 | printf (" x = "); | |
171 | print_path (path); | |
172 | printf (";\n"); | |
173 | ||
174 | printf (" if (GET_CODE (operands[%d]) != GET_CODE (x)\n", XINT (x, 0)); | |
175 | printf (" || GET_MODE (operands[%d]) != GET_MODE (x)) goto L%d;\n", | |
176 | XINT (x, 0), fail_label); | |
177 | printf (" operands[%d] = x;\n", XINT (x, 0)); | |
178 | link.next = path; | |
179 | link.vecelt = -1; | |
180 | for (i = 0; i < XVECLEN (x, 1); i++) | |
181 | { | |
182 | link.pos = i; | |
183 | match_rtx (XVECEXP (x, 1, i), &link, fail_label); | |
184 | } | |
185 | return; | |
186 | ||
187 | case MATCH_OPERATOR: | |
188 | if (XINT (x, 0) > max_opno) | |
189 | max_opno = XINT (x, 0); | |
190 | if (XINT (x, 0) >= n_operands) | |
191 | n_operands = 1 + XINT (x, 0); | |
192 | ||
193 | printf (" x = "); | |
194 | print_path (path); | |
195 | printf (";\n"); | |
196 | ||
197 | printf (" operands[%d] = x;\n", XINT (x, 0)); | |
198 | if (XSTR (x, 1) && XSTR (x, 1)[0]) | |
199 | printf (" if (! %s (x, %smode)) goto L%d;\n", | |
200 | XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label); | |
201 | link.next = path; | |
202 | link.vecelt = -1; | |
203 | for (i = 0; i < XVECLEN (x, 2); i++) | |
204 | { | |
205 | link.pos = i; | |
206 | match_rtx (XVECEXP (x, 2, i), &link, fail_label); | |
207 | } | |
208 | return; | |
209 | ||
210 | case MATCH_PARALLEL: | |
211 | if (XINT (x, 0) > max_opno) | |
212 | max_opno = XINT (x, 0); | |
213 | if (XINT (x, 0) >= n_operands) | |
214 | n_operands = 1 + XINT (x, 0); | |
215 | ||
216 | printf (" x = "); | |
217 | print_path (path); | |
218 | printf (";\n"); | |
219 | ||
220 | printf (" if (GET_CODE (x) != PARALLEL) goto L%d;\n", fail_label); | |
221 | printf (" operands[%d] = x;\n", XINT (x, 0)); | |
222 | if (XSTR (x, 1) && XSTR (x, 1)[0]) | |
223 | printf (" if (! %s (x, %smode)) goto L%d;\n", | |
224 | XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label); | |
225 | link.next = path; | |
226 | link.pos = 0; | |
227 | for (i = 0; i < XVECLEN (x, 2); i++) | |
228 | { | |
229 | link.vecelt = i; | |
230 | match_rtx (XVECEXP (x, 2, i), &link, fail_label); | |
231 | } | |
232 | return; | |
233 | ||
234 | case ADDRESS: | |
235 | match_rtx (XEXP (x, 0), path, fail_label); | |
236 | return; | |
3d7aafde | 237 | |
38a448ca RH |
238 | default: |
239 | break; | |
32f30c53 TW |
240 | } |
241 | ||
242 | printf (" x = "); | |
243 | print_path (path); | |
244 | printf (";\n"); | |
245 | ||
246 | printf (" if (GET_CODE (x) != "); | |
247 | print_code (code); | |
248 | printf (") goto L%d;\n", fail_label); | |
249 | ||
250 | if (GET_MODE (x) != VOIDmode) | |
251 | { | |
252 | printf (" if (GET_MODE (x) != %smode) goto L%d;\n", | |
253 | GET_MODE_NAME (GET_MODE (x)), fail_label); | |
254 | } | |
255 | ||
256 | link.next = path; | |
257 | link.vecelt = -1; | |
258 | fmt = GET_RTX_FORMAT (code); | |
259 | len = GET_RTX_LENGTH (code); | |
260 | for (i = 0; i < len; i++) | |
261 | { | |
262 | link.pos = i; | |
263 | if (fmt[i] == 'e' || fmt[i] == 'u') | |
264 | match_rtx (XEXP (x, i), &link, fail_label); | |
265 | else if (fmt[i] == 'E') | |
266 | { | |
267 | int j; | |
268 | printf (" if (XVECLEN (x, %d) != %d) goto L%d;\n", | |
269 | i, XVECLEN (x, i), fail_label); | |
4231508a | 270 | for (j = 0; j < XVECLEN (x, i); j++) |
32f30c53 TW |
271 | { |
272 | link.vecelt = j; | |
273 | match_rtx (XVECEXP (x, i, j), &link, fail_label); | |
274 | } | |
275 | } | |
276 | else if (fmt[i] == 'i') | |
277 | { | |
278 | /* Make sure that at run time `x' is the RTX we want to test. */ | |
279 | if (i != 0) | |
280 | { | |
281 | printf (" x = "); | |
282 | print_path (path); | |
283 | printf (";\n"); | |
284 | } | |
285 | ||
286 | printf (" if (XINT (x, %d) != %d) goto L%d;\n", | |
287 | i, XINT (x, i), fail_label); | |
288 | } | |
52a5538b RS |
289 | else if (fmt[i] == 'w') |
290 | { | |
291 | /* Make sure that at run time `x' is the RTX we want to test. */ | |
292 | if (i != 0) | |
293 | { | |
294 | printf (" x = "); | |
295 | print_path (path); | |
296 | printf (";\n"); | |
297 | } | |
298 | ||
76d31c63 JL |
299 | printf (" if (XWINT (x, %d) != ", i); |
300 | printf (HOST_WIDE_INT_PRINT_DEC, XWINT (x, i)); | |
301 | printf (") goto L%d;\n", fail_label); | |
52a5538b | 302 | } |
32f30c53 TW |
303 | else if (fmt[i] == 's') |
304 | { | |
305 | /* Make sure that at run time `x' is the RTX we want to test. */ | |
306 | if (i != 0) | |
307 | { | |
308 | printf (" x = "); | |
309 | print_path (path); | |
310 | printf (";\n"); | |
311 | } | |
312 | ||
313 | printf (" if (strcmp (XSTR (x, %d), \"%s\")) goto L%d;\n", | |
314 | i, XSTR (x, i), fail_label); | |
315 | } | |
316 | } | |
317 | } | |
318 | ||
319 | /* Given a PATH, representing a path down the instruction's | |
320 | pattern from the root to a certain point, output code to | |
321 | evaluate to the rtx at that point. */ | |
322 | ||
323 | static void | |
3d7aafde | 324 | print_path (struct link *path) |
32f30c53 TW |
325 | { |
326 | if (path == 0) | |
327 | printf ("pat"); | |
328 | else if (path->vecelt >= 0) | |
329 | { | |
330 | printf ("XVECEXP ("); | |
331 | print_path (path->next); | |
332 | printf (", %d, %d)", path->pos, path->vecelt); | |
333 | } | |
334 | else | |
335 | { | |
336 | printf ("XEXP ("); | |
337 | print_path (path->next); | |
338 | printf (", %d)", path->pos); | |
339 | } | |
340 | } | |
341 | \f | |
342 | static void | |
3d7aafde | 343 | print_code (RTX_CODE code) |
32f30c53 | 344 | { |
b3694847 | 345 | const char *p1; |
32f30c53 | 346 | for (p1 = GET_RTX_NAME (code); *p1; p1++) |
92a438d1 | 347 | putchar (TOUPPER(*p1)); |
32f30c53 | 348 | } |
32f30c53 | 349 | |
3d7aafde | 350 | extern int main (int, char **); |
c1b59dce | 351 | |
32f30c53 | 352 | int |
3d7aafde | 353 | main (int argc, char **argv) |
32f30c53 TW |
354 | { |
355 | rtx desc; | |
32f30c53 TW |
356 | |
357 | max_opno = -1; | |
358 | ||
f8b6598e | 359 | progname = "genpeep"; |
32f30c53 | 360 | |
04d8aa70 | 361 | if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE) |
c88c0d42 | 362 | return (FATAL_EXIT_CODE); |
32f30c53 | 363 | |
32f30c53 TW |
364 | printf ("/* Generated automatically by the program `genpeep'\n\ |
365 | from the machine description file `md'. */\n\n"); | |
366 | ||
367 | printf ("#include \"config.h\"\n"); | |
729da3f5 | 368 | printf ("#include \"system.h\"\n"); |
4977bab6 ZW |
369 | printf ("#include \"coretypes.h\"\n"); |
370 | printf ("#include \"tm.h\"\n"); | |
7f7f8214 | 371 | printf ("#include \"insn-config.h\"\n"); |
32f30c53 | 372 | printf ("#include \"rtl.h\"\n"); |
bd9f1972 | 373 | printf ("#include \"tm_p.h\"\n"); |
32f30c53 TW |
374 | printf ("#include \"regs.h\"\n"); |
375 | printf ("#include \"output.h\"\n"); | |
41fe085f | 376 | printf ("#include \"real.h\"\n"); |
7f7f8214 | 377 | printf ("#include \"recog.h\"\n"); |
279bb624 DE |
378 | printf ("#include \"except.h\"\n"); |
379 | printf ("#include \"function.h\"\n"); | |
f160357f | 380 | printf ("#include \"toplev.h\"\n"); |
ce92b223 | 381 | printf ("#include \"flags.h\"\n"); |
279bb624 | 382 | printf ("#include \"tm-constrs.h\"\n\n"); |
32f30c53 | 383 | |
ede7cd44 | 384 | printf ("#ifdef HAVE_peephole\n"); |
32f30c53 TW |
385 | printf ("extern rtx peep_operand[];\n\n"); |
386 | printf ("#define operands peep_operand\n\n"); | |
387 | ||
6906ba40 | 388 | printf ("rtx\npeephole (rtx ins1)\n{\n"); |
296433e1 | 389 | printf (" rtx insn ATTRIBUTE_UNUSED, x ATTRIBUTE_UNUSED, pat ATTRIBUTE_UNUSED;\n\n"); |
32f30c53 TW |
390 | |
391 | /* Early out: no peepholes for insns followed by barriers. */ | |
392 | printf (" if (NEXT_INSN (ins1)\n"); | |
4b4bf941 | 393 | printf (" && BARRIER_P (NEXT_INSN (ins1)))\n"); |
32f30c53 TW |
394 | printf (" return 0;\n\n"); |
395 | ||
396 | /* Read the machine description. */ | |
397 | ||
398 | while (1) | |
399 | { | |
c88c0d42 CP |
400 | int line_no, rtx_number = 0; |
401 | ||
402 | desc = read_md_rtx (&line_no, &rtx_number); | |
403 | if (desc == NULL) | |
32f30c53 | 404 | break; |
32f30c53 | 405 | |
c88c0d42 | 406 | if (GET_CODE (desc) == DEFINE_PEEPHOLE) |
32f30c53 TW |
407 | { |
408 | gen_peephole (desc); | |
409 | insn_code_number++; | |
410 | } | |
411 | if (GET_CODE (desc) == DEFINE_INSN | |
412 | || GET_CODE (desc) == DEFINE_EXPAND | |
003661dd DC |
413 | || GET_CODE (desc) == DEFINE_SPLIT |
414 | || GET_CODE (desc) == DEFINE_PEEPHOLE2) | |
32f30c53 TW |
415 | { |
416 | insn_code_number++; | |
417 | } | |
418 | } | |
419 | ||
420 | printf (" return 0;\n}\n\n"); | |
421 | ||
422 | if (max_opno == -1) | |
423 | max_opno = 1; | |
424 | ||
425 | printf ("rtx peep_operand[%d];\n", max_opno + 1); | |
ede7cd44 | 426 | printf ("#endif\n"); |
32f30c53 TW |
427 | |
428 | fflush (stdout); | |
c1b59dce | 429 | return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); |
32f30c53 | 430 | } |