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