1/* Generate code from machine description to perform peephole optimizations.
2   Copyright (C) 1987-2020 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 match_rtx (rtx, struct link *, int);
50static void print_path (struct link *);
51static void print_code (RTX_CODE);
52
53static void
54gen_peephole (md_rtx_info *info)
55{
56  rtx peep = info->def;
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", info->index);
70	  printf ("  while (NOTE_P (insn)\n");
71	  printf ("\t || (NONJUMP_INSN_P (insn)\n");
72	  printf ("\t     && (GET_CODE (PATTERN (insn)) == USE\n");
73	  printf ("\t\t || GET_CODE (PATTERN (insn)) == CLOBBER)));\n");
74
75	  printf ("  if (LABEL_P (insn)\n\
76      || BARRIER_P (insn))\n    goto L%d;\n", info->index);
77	}
78
79      printf ("  pat = PATTERN (insn);\n");
80
81      /* Walk the insn's pattern, remembering at all times the path
82	 down to the walking point.  */
83
84      match_rtx (XVECEXP (peep, 0, i), NULL, info->index);
85    }
86
87  /* We get this far if the pattern matches.
88     Now test the extra condition.  */
89
90  if (XSTR (peep, 1) && XSTR (peep, 1)[0])
91    printf ("  if (! (%s)) goto L%d;\n",
92	    XSTR (peep, 1), info->index);
93
94  /* If that matches, construct new pattern and put it in the first insn.
95     This new pattern will never be matched.
96     It exists only so that insn-extract can get the operands back.
97     So use a simple regular form: a PARALLEL containing a vector
98     of all the operands.  */
99
100  printf ("  PATTERN (ins1) = gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (%d, operands));\n", n_operands);
101
102  /* Record this define_peephole's insn code in the insn,
103     as if it had been recognized to match this.  */
104  printf ("  INSN_CODE (ins1) = %d;\n", info->index);
105
106  /* Delete the remaining insns.  */
107  if (ninsns > 1)
108    printf ("  delete_for_peephole (NEXT_INSN (ins1), insn);\n");
109
110  /* See reload1.c for insertion of NOTE which guarantees that this
111     cannot be zero.  */
112  printf ("  return NEXT_INSN (insn);\n");
113
114  printf (" L%d:\n\n", info->index);
115}
116
117static void
118match_rtx (rtx x, struct link *path, int fail_label)
119{
120  RTX_CODE code;
121  int i;
122  int len;
123  const char *fmt;
124  struct link link;
125
126  if (x == 0)
127    return;
128
129
130  code = GET_CODE (x);
131
132  switch (code)
133    {
134    case MATCH_OPERAND:
135      if (XINT (x, 0) > max_opno)
136	max_opno = XINT (x, 0);
137      if (XINT (x, 0) >= n_operands)
138	n_operands = 1 + XINT (x, 0);
139
140      printf ("  x = ");
141      print_path (path);
142      printf (";\n");
143
144      printf ("  operands[%d] = x;\n", XINT (x, 0));
145      if (XSTR (x, 1) && XSTR (x, 1)[0])
146	printf ("  if (! %s (x, %smode)) goto L%d;\n",
147		XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label);
148      return;
149
150    case MATCH_DUP:
151    case MATCH_PAR_DUP:
152      printf ("  x = ");
153      print_path (path);
154      printf (";\n");
155
156      printf ("  if (!rtx_equal_p (operands[%d], x)) goto L%d;\n",
157	      XINT (x, 0), fail_label);
158      return;
159
160    case MATCH_OP_DUP:
161      printf ("  x = ");
162      print_path (path);
163      printf (";\n");
164
165      printf ("  if (GET_CODE (operands[%d]) != GET_CODE (x)\n", XINT (x, 0));
166      printf ("      || GET_MODE (operands[%d]) != GET_MODE (x)) goto L%d;\n",
167	      XINT (x, 0), fail_label);
168      printf ("  operands[%d] = x;\n", XINT (x, 0));
169      link.next = path;
170      link.vecelt = -1;
171      for (i = 0; i < XVECLEN (x, 1); i++)
172	{
173	  link.pos = i;
174	  match_rtx (XVECEXP (x, 1, i), &link, fail_label);
175	}
176      return;
177
178    case MATCH_OPERATOR:
179      if (XINT (x, 0) > max_opno)
180	max_opno = XINT (x, 0);
181      if (XINT (x, 0) >= n_operands)
182	n_operands = 1 + XINT (x, 0);
183
184      printf ("  x = ");
185      print_path (path);
186      printf (";\n");
187
188      printf ("  operands[%d] = x;\n", XINT (x, 0));
189      if (XSTR (x, 1) && XSTR (x, 1)[0])
190	printf ("  if (! %s (x, %smode)) goto L%d;\n",
191		XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label);
192      link.next = path;
193      link.vecelt = -1;
194      for (i = 0; i < XVECLEN (x, 2); i++)
195	{
196	  link.pos = i;
197	  match_rtx (XVECEXP (x, 2, i), &link, fail_label);
198	}
199      return;
200
201    case MATCH_PARALLEL:
202      if (XINT (x, 0) > max_opno)
203	max_opno = XINT (x, 0);
204      if (XINT (x, 0) >= n_operands)
205	n_operands = 1 + XINT (x, 0);
206
207      printf ("  x = ");
208      print_path (path);
209      printf (";\n");
210
211      printf ("  if (GET_CODE (x) != PARALLEL) goto L%d;\n", fail_label);
212      printf ("  operands[%d] = x;\n", XINT (x, 0));
213      if (XSTR (x, 1) && XSTR (x, 1)[0])
214	printf ("  if (! %s (x, %smode)) goto L%d;\n",
215		XSTR (x, 1), GET_MODE_NAME (GET_MODE (x)), fail_label);
216      link.next = path;
217      link.pos = 0;
218      for (i = 0; i < XVECLEN (x, 2); i++)
219	{
220	  link.vecelt = i;
221	  match_rtx (XVECEXP (x, 2, i), &link, fail_label);
222	}
223      return;
224
225    default:
226      break;
227    }
228
229  printf ("  x = ");
230  print_path (path);
231  printf (";\n");
232
233  printf ("  if (GET_CODE (x) != ");
234  print_code (code);
235  printf (") goto L%d;\n", fail_label);
236
237  if (GET_MODE (x) != VOIDmode)
238    {
239      printf ("  if (GET_MODE (x) != %smode) goto L%d;\n",
240	      GET_MODE_NAME (GET_MODE (x)), fail_label);
241    }
242
243  link.next = path;
244  link.vecelt = -1;
245  fmt = GET_RTX_FORMAT (code);
246  len = GET_RTX_LENGTH (code);
247  for (i = 0; i < len; i++)
248    {
249      link.pos = i;
250      if (fmt[i] == 'e' || fmt[i] == 'u')
251	match_rtx (XEXP (x, i), &link, fail_label);
252      else if (fmt[i] == 'E')
253	{
254	  int j;
255	  printf ("  if (XVECLEN (x, %d) != %d) goto L%d;\n",
256		  i, XVECLEN (x, i), fail_label);
257	  for (j = 0; j < XVECLEN (x, i); j++)
258	    {
259	      link.vecelt = j;
260	      match_rtx (XVECEXP (x, i, j), &link, fail_label);
261	    }
262	}
263      else if (fmt[i] == 'i')
264	{
265	  /* Make sure that at run time `x' is the RTX we want to test.  */
266	  if (i != 0)
267	    {
268	      printf ("  x = ");
269	      print_path (path);
270	      printf (";\n");
271	    }
272
273	  printf ("  if (XINT (x, %d) != %d) goto L%d;\n",
274		  i, XINT (x, i), fail_label);
275	}
276      else if (fmt[i] == 'r')
277	{
278	  gcc_assert (i == 0);
279	  printf ("  if (REGNO (x) != %d) goto L%d;\n",
280		  REGNO (x), fail_label);
281	}
282      else if (fmt[i] == 'w')
283	{
284	  /* Make sure that at run time `x' is the RTX we want to test.  */
285	  if (i != 0)
286	    {
287	      printf ("  x = ");
288	      print_path (path);
289	      printf (";\n");
290	    }
291
292	  printf ("  if (XWINT (x, %d) != ", i);
293	  printf (HOST_WIDE_INT_PRINT_DEC, XWINT (x, i));
294	  printf (") goto L%d;\n", fail_label);
295	}
296      else if (fmt[i] == 's')
297	{
298	  /* Make sure that at run time `x' is the RTX we want to test.  */
299	  if (i != 0)
300	    {
301	      printf ("  x = ");
302	      print_path (path);
303	      printf (";\n");
304	    }
305
306	  printf ("  if (strcmp (XSTR (x, %d), \"%s\")) goto L%d;\n",
307		  i, XSTR (x, i), fail_label);
308	}
309      else if (fmt[i] == 'p')
310	/* Not going to support subregs for legacy define_peeholes.  */
311	gcc_unreachable ();
312    }
313}
314
315/* Given a PATH, representing a path down the instruction's
316   pattern from the root to a certain point, output code to
317   evaluate to the rtx at that point.  */
318
319static void
320print_path (struct link *path)
321{
322  if (path == 0)
323    printf ("pat");
324  else if (path->vecelt >= 0)
325    {
326      printf ("XVECEXP (");
327      print_path (path->next);
328      printf (", %d, %d)", path->pos, path->vecelt);
329    }
330  else
331    {
332      printf ("XEXP (");
333      print_path (path->next);
334      printf (", %d)", path->pos);
335    }
336}
337
338static void
339print_code (RTX_CODE code)
340{
341  const char *p1;
342  for (p1 = GET_RTX_NAME (code); *p1; p1++)
343    putchar (TOUPPER (*p1));
344}
345
346extern int main (int, const char **);
347
348int
349main (int argc, const char **argv)
350{
351  max_opno = -1;
352
353  progname = "genpeep";
354
355  if (!init_rtx_reader_args (argc, argv))
356    return (FATAL_EXIT_CODE);
357
358  printf ("/* Generated automatically by the program `genpeep'\n\
359from the machine description file `md'.  */\n\n");
360
361  printf ("#define IN_TARGET_CODE 1\n");
362  printf ("#include \"config.h\"\n");
363  printf ("#include \"system.h\"\n");
364  printf ("#include \"coretypes.h\"\n");
365  printf ("#include \"backend.h\"\n");
366  printf ("#include \"tree.h\"\n");
367  printf ("#include \"rtl.h\"\n");
368  printf ("#include \"insn-config.h\"\n");
369  printf ("#include \"alias.h\"\n");
370  printf ("#include \"varasm.h\"\n");
371  printf ("#include \"stor-layout.h\"\n");
372  printf ("#include \"calls.h\"\n");
373  printf ("#include \"memmodel.h\"\n");
374  printf ("#include \"tm_p.h\"\n");
375  printf ("#include \"regs.h\"\n");
376  printf ("#include \"output.h\"\n");
377  printf ("#include \"recog.h\"\n");
378  printf ("#include \"except.h\"\n");
379  printf ("#include \"diagnostic-core.h\"\n");
380  printf ("#include \"flags.h\"\n");
381  printf ("#include \"tm-constrs.h\"\n\n");
382
383  printf ("extern rtx peep_operand[];\n\n");
384  printf ("#define operands peep_operand\n\n");
385
386  printf ("rtx_insn *\npeephole (rtx_insn *ins1)\n{\n");
387  printf ("  rtx_insn *insn ATTRIBUTE_UNUSED;\n");
388  printf ("  rtx x ATTRIBUTE_UNUSED, pat ATTRIBUTE_UNUSED;\n\n");
389
390  /* Early out: no peepholes for insns followed by barriers.  */
391  printf ("  if (NEXT_INSN (ins1)\n");
392  printf ("      && BARRIER_P (NEXT_INSN (ins1)))\n");
393  printf ("    return 0;\n\n");
394
395  /* Read the machine description.  */
396
397  md_rtx_info info;
398  while (read_md_rtx (&info))
399    switch (GET_CODE (info.def))
400      {
401      case DEFINE_PEEPHOLE:
402	gen_peephole (&info);
403	break;
404
405      default:
406	break;
407      }
408
409  printf ("  return 0;\n}\n\n");
410
411  if (max_opno == -1)
412    max_opno = 1;
413
414  printf ("rtx peep_operand[%d];\n", max_opno + 1);
415
416  fflush (stdout);
417  return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
418}
419