1 /* Generate code from machine description to perform peephole optimizations.
2    Copyright (C) 1987-2018 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 
53 static void
gen_peephole(md_rtx_info * info)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.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 
117 static void
match_rtx(rtx x,struct link * path,int fail_label)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
print_path(struct link * path)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 
338 static void
print_code(RTX_CODE code)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
main(int argc,const char ** argv)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 }
419