]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/genpeep.c
backport: Makefile.in (STAGESTUFF): Add *.peephole2.
[thirdparty/gcc.git] / gcc / genpeep.c
1 /* Generate code from machine description to perform peephole optimizations.
2 Copyright (C) 1987, 89, 92, 97, 98, 1999 Free Software Foundation, Inc.
3
4 This file is part of GNU CC.
5
6 GNU CC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU CC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21
22 #include "hconfig.h"
23 #include "system.h"
24 #include "rtl.h"
25 #include "obstack.h"
26 #include "errors.h"
27
28 static struct obstack obstack;
29 struct obstack *rtl_obstack = &obstack;
30
31 #define obstack_chunk_alloc xmalloc
32 #define obstack_chunk_free free
33
34 /* Define this so we can link with print-rtl.o to get debug_rtx function. */
35 char **insn_name_ptr = 0;
36
37 /* While tree-walking an instruction pattern, we keep a chain
38 of these `struct link's to record how to get down to the
39 current position. In each one, POS is the operand number,
40 and if the operand is a vector VEC is the element number.
41 VEC is -1 if the operand is not a vector. */
42
43 struct link
44 {
45 struct link *next;
46 int pos;
47 int vecelt;
48 };
49
50 static int max_opno;
51
52 /* Number of operands used in current peephole definition. */
53
54 static int n_operands;
55
56 /* Peephole optimizations get insn codes just like insn patterns.
57 Count them so we know the code of the define_peephole we are handling. */
58
59 static int insn_code_number = 0;
60
61 static void gen_peephole PROTO((rtx));
62 static void match_rtx PROTO((rtx, struct link *, int));
63 static void print_path PROTO((struct link *));
64 static void print_code PROTO((RTX_CODE));
65 \f
66 static void
67 gen_peephole (peep)
68 rtx peep;
69 {
70 int ninsns = XVECLEN (peep, 0);
71 int i;
72
73 n_operands = 0;
74
75 printf (" insn = ins1;\n");
76 #if 0
77 printf (" want_jump = 0;\n");
78 #endif
79
80 for (i = 0; i < ninsns; i++)
81 {
82 if (i > 0)
83 {
84 printf (" do { insn = NEXT_INSN (insn);\n");
85 printf (" if (insn == 0) goto L%d; }\n",
86 insn_code_number);
87 printf (" while (GET_CODE (insn) == NOTE\n");
88 printf ("\t || (GET_CODE (insn) == INSN\n");
89 printf ("\t && (GET_CODE (PATTERN (insn)) == USE\n");
90 printf ("\t\t || GET_CODE (PATTERN (insn)) == CLOBBER)));\n");
91
92 printf (" if (GET_CODE (insn) == CODE_LABEL\n\
93 || GET_CODE (insn) == BARRIER)\n goto L%d;\n",
94 insn_code_number);
95 }
96
97 #if 0
98 printf (" if (GET_CODE (insn) == JUMP_INSN)\n");
99 printf (" want_jump = JUMP_LABEL (insn);\n");
100 #endif
101
102 printf (" pat = PATTERN (insn);\n");
103
104 /* Walk the insn's pattern, remembering at all times the path
105 down to the walking point. */
106
107 match_rtx (XVECEXP (peep, 0, i), NULL_PTR, insn_code_number);
108 }
109
110 /* We get this far if the pattern matches.
111 Now test the extra condition. */
112
113 if (XSTR (peep, 1) && XSTR (peep, 1)[0])
114 printf (" if (! (%s)) goto L%d;\n",
115 XSTR (peep, 1), insn_code_number);
116
117 /* If that matches, construct new pattern and put it in the first insn.
118 This new pattern will never be matched.
119 It exists only so that insn-extract can get the operands back.
120 So use a simple regular form: a PARALLEL containing a vector
121 of all the operands. */
122
123 printf (" PATTERN (ins1) = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (%d, operands));\n", n_operands);
124
125 #if 0
126 printf (" if (want_jump && GET_CODE (ins1) != JUMP_INSN)\n");
127 printf (" {\n");
128 printf (" rtx insn2 = emit_jump_insn_before (PATTERN (ins1), ins1);\n");
129 printf (" delete_insn (ins1);\n");
130 printf (" ins1 = ins2;\n");
131 printf (" }\n");
132 #endif
133
134 /* Record this define_peephole's insn code in the insn,
135 as if it had been recognized to match this. */
136 printf (" INSN_CODE (ins1) = %d;\n",
137 insn_code_number);
138
139 /* Delete the remaining insns. */
140 if (ninsns > 1)
141 printf (" delete_for_peephole (NEXT_INSN (ins1), insn);\n");
142
143 /* See reload1.c for insertion of NOTE which guarantees that this
144 cannot be zero. */
145 printf (" return NEXT_INSN (insn);\n");
146
147 printf (" L%d:\n\n", insn_code_number);
148 }
149 \f
150 static void
151 match_rtx (x, path, fail_label)
152 rtx x;
153 struct link *path;
154 int fail_label;
155 {
156 register RTX_CODE code;
157 register int i;
158 register int len;
159 register const char *fmt;
160 struct link link;
161
162 if (x == 0)
163 return;
164
165
166 code = GET_CODE (x);
167
168 switch (code)
169 {
170 case MATCH_OPERAND:
171 if (XINT (x, 0) > max_opno)
172 max_opno = XINT (x, 0);
173 if (XINT (x, 0) >= n_operands)
174 n_operands = 1 + XINT (x, 0);
175
176 printf (" x = ");
177 print_path (path);
178 printf (";\n");
179
180 printf (" operands[%d] = x;\n", XINT (x, 0));
181 if (XSTR (x, 1) && XSTR (x, 1)[0])
182 printf (" if (! %s (x, %smode)) goto L%d;\n",
183 XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label);
184 return;
185
186 case MATCH_DUP:
187 case MATCH_PAR_DUP:
188 printf (" x = ");
189 print_path (path);
190 printf (";\n");
191
192 printf (" if (!rtx_equal_p (operands[%d], x)) goto L%d;\n",
193 XINT (x, 0), fail_label);
194 return;
195
196 case MATCH_OP_DUP:
197 printf (" x = ");
198 print_path (path);
199 printf (";\n");
200
201 printf (" if (GET_CODE (operands[%d]) != GET_CODE (x)\n", XINT (x, 0));
202 printf (" || GET_MODE (operands[%d]) != GET_MODE (x)) goto L%d;\n",
203 XINT (x, 0), fail_label);
204 printf (" operands[%d] = x;\n", XINT (x, 0));
205 link.next = path;
206 link.vecelt = -1;
207 for (i = 0; i < XVECLEN (x, 1); i++)
208 {
209 link.pos = i;
210 match_rtx (XVECEXP (x, 1, i), &link, fail_label);
211 }
212 return;
213
214 case MATCH_OPERATOR:
215 if (XINT (x, 0) > max_opno)
216 max_opno = XINT (x, 0);
217 if (XINT (x, 0) >= n_operands)
218 n_operands = 1 + XINT (x, 0);
219
220 printf (" x = ");
221 print_path (path);
222 printf (";\n");
223
224 printf (" operands[%d] = x;\n", XINT (x, 0));
225 if (XSTR (x, 1) && XSTR (x, 1)[0])
226 printf (" if (! %s (x, %smode)) goto L%d;\n",
227 XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label);
228 link.next = path;
229 link.vecelt = -1;
230 for (i = 0; i < XVECLEN (x, 2); i++)
231 {
232 link.pos = i;
233 match_rtx (XVECEXP (x, 2, i), &link, fail_label);
234 }
235 return;
236
237 case MATCH_PARALLEL:
238 if (XINT (x, 0) > max_opno)
239 max_opno = XINT (x, 0);
240 if (XINT (x, 0) >= n_operands)
241 n_operands = 1 + XINT (x, 0);
242
243 printf (" x = ");
244 print_path (path);
245 printf (";\n");
246
247 printf (" if (GET_CODE (x) != PARALLEL) goto L%d;\n", fail_label);
248 printf (" operands[%d] = x;\n", XINT (x, 0));
249 if (XSTR (x, 1) && XSTR (x, 1)[0])
250 printf (" if (! %s (x, %smode)) goto L%d;\n",
251 XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label);
252 link.next = path;
253 link.pos = 0;
254 for (i = 0; i < XVECLEN (x, 2); i++)
255 {
256 link.vecelt = i;
257 match_rtx (XVECEXP (x, 2, i), &link, fail_label);
258 }
259 return;
260
261 case ADDRESS:
262 match_rtx (XEXP (x, 0), path, fail_label);
263 return;
264
265 default:
266 break;
267 }
268
269 printf (" x = ");
270 print_path (path);
271 printf (";\n");
272
273 printf (" if (GET_CODE (x) != ");
274 print_code (code);
275 printf (") goto L%d;\n", fail_label);
276
277 if (GET_MODE (x) != VOIDmode)
278 {
279 printf (" if (GET_MODE (x) != %smode) goto L%d;\n",
280 GET_MODE_NAME (GET_MODE (x)), fail_label);
281 }
282
283 link.next = path;
284 link.vecelt = -1;
285 fmt = GET_RTX_FORMAT (code);
286 len = GET_RTX_LENGTH (code);
287 for (i = 0; i < len; i++)
288 {
289 link.pos = i;
290 if (fmt[i] == 'e' || fmt[i] == 'u')
291 match_rtx (XEXP (x, i), &link, fail_label);
292 else if (fmt[i] == 'E')
293 {
294 int j;
295 printf (" if (XVECLEN (x, %d) != %d) goto L%d;\n",
296 i, XVECLEN (x, i), fail_label);
297 for (j = 0; j < XVECLEN (x, i); j++)
298 {
299 link.vecelt = j;
300 match_rtx (XVECEXP (x, i, j), &link, fail_label);
301 }
302 }
303 else if (fmt[i] == 'i')
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 (XINT (x, %d) != %d) goto L%d;\n",
314 i, XINT (x, i), fail_label);
315 }
316 else if (fmt[i] == 'w')
317 {
318 /* Make sure that at run time `x' is the RTX we want to test. */
319 if (i != 0)
320 {
321 printf (" x = ");
322 print_path (path);
323 printf (";\n");
324 }
325
326 printf (" if (XWINT (x, %d) != ", i);
327 printf (HOST_WIDE_INT_PRINT_DEC, XWINT (x, i));
328 printf (") goto L%d;\n", fail_label);
329 }
330 else if (fmt[i] == 's')
331 {
332 /* Make sure that at run time `x' is the RTX we want to test. */
333 if (i != 0)
334 {
335 printf (" x = ");
336 print_path (path);
337 printf (";\n");
338 }
339
340 printf (" if (strcmp (XSTR (x, %d), \"%s\")) goto L%d;\n",
341 i, XSTR (x, i), fail_label);
342 }
343 }
344 }
345
346 /* Given a PATH, representing a path down the instruction's
347 pattern from the root to a certain point, output code to
348 evaluate to the rtx at that point. */
349
350 static void
351 print_path (path)
352 struct link *path;
353 {
354 if (path == 0)
355 printf ("pat");
356 else if (path->vecelt >= 0)
357 {
358 printf ("XVECEXP (");
359 print_path (path->next);
360 printf (", %d, %d)", path->pos, path->vecelt);
361 }
362 else
363 {
364 printf ("XEXP (");
365 print_path (path->next);
366 printf (", %d)", path->pos);
367 }
368 }
369 \f
370 static void
371 print_code (code)
372 RTX_CODE code;
373 {
374 register const char *p1;
375 for (p1 = GET_RTX_NAME (code); *p1; p1++)
376 {
377 if (*p1 >= 'a' && *p1 <= 'z')
378 putchar (*p1 + 'A' - 'a');
379 else
380 putchar (*p1);
381 }
382 }
383 \f
384 PTR
385 xmalloc (size)
386 size_t size;
387 {
388 register PTR val = (PTR) malloc (size);
389
390 if (val == 0)
391 fatal ("virtual memory exhausted");
392 return val;
393 }
394
395 PTR
396 xrealloc (old, size)
397 PTR old;
398 size_t size;
399 {
400 register PTR ptr;
401 if (old)
402 ptr = (PTR) realloc (old, size);
403 else
404 ptr = (PTR) malloc (size);
405 if (!ptr)
406 fatal ("virtual memory exhausted");
407 return ptr;
408 }
409
410 int
411 main (argc, argv)
412 int argc;
413 char **argv;
414 {
415 rtx desc;
416 FILE *infile;
417 register int c;
418
419 max_opno = -1;
420
421 progname = "genpeep";
422 obstack_init (rtl_obstack);
423
424 if (argc <= 1)
425 fatal ("No input file name.");
426
427 infile = fopen (argv[1], "r");
428 if (infile == 0)
429 {
430 perror (argv[1]);
431 exit (FATAL_EXIT_CODE);
432 }
433
434 printf ("/* Generated automatically by the program `genpeep'\n\
435 from the machine description file `md'. */\n\n");
436
437 printf ("#include \"config.h\"\n");
438 printf ("#include \"system.h\"\n");
439 printf ("#include \"insn-config.h\"\n");
440 printf ("#include \"rtl.h\"\n");
441 printf ("#include \"regs.h\"\n");
442 printf ("#include \"output.h\"\n");
443 printf ("#include \"real.h\"\n");
444 printf ("#include \"recog.h\"\n");
445 printf ("#include \"except.h\"\n\n");
446 printf ("#include \"function.h\"\n\n");
447
448 printf ("#ifdef HAVE_peephole\n");
449 printf ("extern rtx peep_operand[];\n\n");
450 printf ("#define operands peep_operand\n\n");
451
452 printf ("rtx\npeephole (ins1)\n rtx ins1;\n{\n");
453 printf (" rtx insn ATTRIBUTE_UNUSED, x ATTRIBUTE_UNUSED, pat ATTRIBUTE_UNUSED;\n\n");
454
455 /* Early out: no peepholes for insns followed by barriers. */
456 printf (" if (NEXT_INSN (ins1)\n");
457 printf (" && GET_CODE (NEXT_INSN (ins1)) == BARRIER)\n");
458 printf (" return 0;\n\n");
459
460 /* Read the machine description. */
461
462 while (1)
463 {
464 c = read_skip_spaces (infile);
465 if (c == EOF)
466 break;
467 ungetc (c, infile);
468
469 desc = read_rtx (infile);
470 if (GET_CODE (desc) == DEFINE_PEEPHOLE)
471 {
472 gen_peephole (desc);
473 insn_code_number++;
474 }
475 if (GET_CODE (desc) == DEFINE_INSN
476 || GET_CODE (desc) == DEFINE_EXPAND
477 || GET_CODE (desc) == DEFINE_SPLIT)
478 {
479 insn_code_number++;
480 }
481 }
482
483 printf (" return 0;\n}\n\n");
484
485 if (max_opno == -1)
486 max_opno = 1;
487
488 printf ("rtx peep_operand[%d];\n", max_opno + 1);
489 printf ("#endif\n");
490
491 fflush (stdout);
492 exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
493 /* NOTREACHED */
494 return 0;
495 }