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