analyzer: fix feasibility false +ve on jumps through function ptrs [PR107582]
[platform/upstream/gcc.git] / gcc / genpeep.cc
1 /* Generate code from machine description to perform peephole optimizations.
2    Copyright (C) 1987-2022 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
9 version.
10
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along 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
36 struct link
37 {
38   struct link *next;
39   int pos;
40   int vecelt;
41 };
42
43 static int max_opno;
44
45 /* Number of operands used in current peephole definition.  */
46
47 static int n_operands;
48
49 static void match_rtx (rtx, struct link *, int);
50 static void print_path (struct link *);
51 static void print_code (RTX_CODE);
52 \f
53 static void
54 gen_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.cc 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 \f
117 static void
118 match_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
319 static void
320 print_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 \f
338 static void
339 print_code (RTX_CODE code)
340 {
341   const char *p1;
342   for (p1 = GET_RTX_NAME (code); *p1; p1++)
343     putchar (TOUPPER (*p1));
344 }
345
346 extern int main (int, const char **);
347
348 int
349 main (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\
359 from 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 }