xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/genextract.c (revision e6c7e151de239c49d2e38720a061ed9d1fa99309)
1 /* Generate code from machine description to extract operands from insn as rtl.
2    Copyright (C) 1987-2017 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 "read-md.h"
28 #include "gensupport.h"
29 
30 /* This structure contains all the information needed to describe one
31    set of extractions methods.  Each method may be used by more than
32    one pattern if the operands are in the same place.
33 
34    The string for each operand describes that path to the operand and
35    contains `0' through `9' when going into an expression and `a' through
36    `z' when going into a vector.  We assume here that only the first operand
37    of an rtl expression is a vector.  genrecog.c makes the same assumption
38    (and uses the same representation) and it is currently true.  */
39 
40 typedef char *locstr;
41 
42 struct extraction
43 {
44   unsigned int op_count;
45   unsigned int dup_count;
46   locstr *oplocs;
47   locstr *duplocs;
48   int *dupnums;
49   struct code_ptr *insns;
50   struct extraction *next;
51 };
52 
53 /* Holds a single insn code that uses an extraction method.  */
54 struct code_ptr
55 {
56   int insn_code;
57   struct code_ptr *next;
58 };
59 
60 /* All extractions needed for this machine description.  */
61 static struct extraction *extractions;
62 
63 /* All insn codes for old-style peepholes.  */
64 static struct code_ptr *peepholes;
65 
66 /* This structure is used by gen_insn and walk_rtx to accumulate the
67    data that will be used to produce an extractions structure.  */
68 
69 
70 struct accum_extract
71 {
72   accum_extract () : oplocs (10), duplocs (10), dupnums (10), pathstr (20) {}
73 
74   auto_vec<locstr> oplocs;
75   auto_vec<locstr> duplocs;
76   auto_vec<int> dupnums;
77   auto_vec<char> pathstr;
78 };
79 
80 /* Forward declarations.  */
81 static void walk_rtx (md_rtx_info *, rtx, struct accum_extract *);
82 
83 static void
84 gen_insn (md_rtx_info *info)
85 {
86   int i;
87   unsigned int op_count, dup_count, j;
88   struct extraction *p;
89   struct code_ptr *link;
90   struct accum_extract acc;
91 
92   /* Walk the insn's pattern, remembering at all times the path
93      down to the walking point.  */
94 
95   rtx insn = info->def;
96   if (XVECLEN (insn, 1) == 1)
97     walk_rtx (info, XVECEXP (insn, 1, 0), &acc);
98   else
99     for (i = XVECLEN (insn, 1) - 1; i >= 0; i--)
100       {
101 	acc.pathstr.safe_push ('a' + i);
102 	walk_rtx (info, XVECEXP (insn, 1, i), &acc);
103 	acc.pathstr.pop ();
104       }
105 
106   link = XNEW (struct code_ptr);
107   link->insn_code = info->index;
108 
109   /* See if we find something that already had this extraction method.  */
110 
111   op_count = acc.oplocs.length ();
112   dup_count = acc.duplocs.length ();
113   gcc_assert (dup_count == acc.dupnums.length ());
114 
115   for (p = extractions; p; p = p->next)
116     {
117       if (p->op_count != op_count || p->dup_count != dup_count)
118 	continue;
119 
120       for (j = 0; j < op_count; j++)
121 	{
122 	  char *a = p->oplocs[j];
123 	  char *b = acc.oplocs[j];
124 	  if (a != b && (!a || !b || strcmp (a, b)))
125 	    break;
126 	}
127 
128       if (j != op_count)
129 	continue;
130 
131       for (j = 0; j < dup_count; j++)
132 	if (p->dupnums[j] != acc.dupnums[j]
133 	    || strcmp (p->duplocs[j], acc.duplocs[j]))
134 	  break;
135 
136       if (j != dup_count)
137 	continue;
138 
139       /* This extraction is the same as ours.  Just link us in.  */
140       link->next = p->insns;
141       p->insns = link;
142       return;
143     }
144 
145   /* Otherwise, make a new extraction method.  We stash the arrays
146      after the extraction structure in memory.  */
147 
148   p = XNEWVAR (struct extraction, sizeof (struct extraction)
149 	       + op_count*sizeof (char *)
150 	       + dup_count*sizeof (char *)
151 	       + dup_count*sizeof (int));
152   p->op_count = op_count;
153   p->dup_count = dup_count;
154   p->next = extractions;
155   extractions = p;
156   p->insns = link;
157   link->next = 0;
158 
159   p->oplocs = (char **)((char *)p + sizeof (struct extraction));
160   p->duplocs = p->oplocs + op_count;
161   p->dupnums = (int *)(p->duplocs + dup_count);
162 
163   memcpy (p->oplocs, acc.oplocs.address (), op_count * sizeof (locstr));
164   memcpy (p->duplocs, acc.duplocs.address (), dup_count * sizeof (locstr));
165   memcpy (p->dupnums, acc.dupnums.address (), dup_count * sizeof (int));
166 }
167 
168 /* Helper subroutine of walk_rtx: given a vec<locstr>, an index, and a
169    string, insert the string at the index, which should either already
170    exist and be NULL, or not yet exist within the vector.  In the latter
171    case the vector is enlarged as appropriate.  INFO describes the
172    containing define_* expression.  */
173 static void
174 VEC_safe_set_locstr (md_rtx_info *info, vec<locstr> *vp,
175 		     unsigned int ix, char *str)
176 {
177   if (ix < (*vp).length ())
178     {
179       if ((*vp)[ix])
180 	{
181 	  message_at (info->loc, "repeated operand number %d", ix);
182 	  have_error = 1;
183 	}
184       else
185         (*vp)[ix] = str;
186     }
187   else
188     {
189       while (ix > (*vp).length ())
190 	vp->safe_push (NULL);
191       vp->safe_push (str);
192     }
193 }
194 
195 /* Another helper subroutine of walk_rtx: given a vec<char>, convert it
196    to a NUL-terminated string in malloc memory.  */
197 static char *
198 VEC_char_to_string (vec<char> v)
199 {
200   size_t n = v.length ();
201   char *s = XNEWVEC (char, n + 1);
202   memcpy (s, v.address (), n);
203   s[n] = '\0';
204   return s;
205 }
206 
207 static void
208 walk_rtx (md_rtx_info *info, rtx x, struct accum_extract *acc)
209 {
210   RTX_CODE code;
211   int i, len, base;
212   const char *fmt;
213 
214   if (x == 0)
215     return;
216 
217   code = GET_CODE (x);
218   switch (code)
219     {
220     case PC:
221     case CC0:
222     case CONST_INT:
223     case SYMBOL_REF:
224       return;
225 
226     case MATCH_OPERAND:
227     case MATCH_SCRATCH:
228       VEC_safe_set_locstr (info, &acc->oplocs, XINT (x, 0),
229 			   VEC_char_to_string (acc->pathstr));
230       break;
231 
232     case MATCH_OPERATOR:
233     case MATCH_PARALLEL:
234       VEC_safe_set_locstr (info, &acc->oplocs, XINT (x, 0),
235 			   VEC_char_to_string (acc->pathstr));
236 
237       base = (code == MATCH_OPERATOR ? '0' : 'a');
238       for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
239 	{
240 	  acc->pathstr.safe_push (base + i);
241 	  walk_rtx (info, XVECEXP (x, 2, i), acc);
242 	  acc->pathstr.pop ();
243         }
244       return;
245 
246     case MATCH_DUP:
247     case MATCH_PAR_DUP:
248     case MATCH_OP_DUP:
249       acc->duplocs.safe_push (VEC_char_to_string (acc->pathstr));
250       acc->dupnums.safe_push (XINT (x, 0));
251 
252       if (code == MATCH_DUP)
253 	break;
254 
255       base = (code == MATCH_OP_DUP ? '0' : 'a');
256       for (i = XVECLEN (x, 1) - 1; i >= 0; i--)
257         {
258 	  acc->pathstr.safe_push (base + i);
259 	  walk_rtx (info, XVECEXP (x, 1, i), acc);
260 	  acc->pathstr.pop ();
261         }
262       return;
263 
264     default:
265       break;
266     }
267 
268   fmt = GET_RTX_FORMAT (code);
269   len = GET_RTX_LENGTH (code);
270   for (i = 0; i < len; i++)
271     {
272       if (fmt[i] == 'e' || fmt[i] == 'u')
273 	{
274 	  acc->pathstr.safe_push ('0' + i);
275 	  walk_rtx (info, XEXP (x, i), acc);
276 	  acc->pathstr.pop ();
277 	}
278       else if (fmt[i] == 'E')
279 	{
280 	  int j;
281 	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
282 	    {
283 	      acc->pathstr.safe_push ('a' + j);
284 	      walk_rtx (info, XVECEXP (x, i, j), acc);
285 	      acc->pathstr.pop ();
286 	    }
287 	}
288     }
289 }
290 
291 /* Given a PATH, representing a path down the instruction's
292    pattern from the root to a certain point, output code to
293    evaluate to the rtx at that point.  */
294 
295 static void
296 print_path (const char *path)
297 {
298   int len = strlen (path);
299   int i;
300 
301   if (len == 0)
302     {
303       /* Don't emit "pat", since we may try to take the address of it,
304 	 which isn't what is intended.  */
305       fputs ("PATTERN (insn)", stdout);
306       return;
307     }
308 
309   /* We first write out the operations (XEXP or XVECEXP) in reverse
310      order, then write "pat", then the indices in forward order.  */
311 
312   for (i = len - 1; i >= 0 ; i--)
313     {
314       if (ISLOWER (path[i]))
315 	fputs ("XVECEXP (", stdout);
316       else if (ISDIGIT (path[i]))
317 	fputs ("XEXP (", stdout);
318       else
319 	gcc_unreachable ();
320     }
321 
322   fputs ("pat", stdout);
323 
324   for (i = 0; i < len; i++)
325     {
326       if (ISLOWER (path[i]))
327 	printf (", 0, %d)", path[i] - 'a');
328       else if (ISDIGIT (path[i]))
329 	printf (", %d)", path[i] - '0');
330       else
331 	gcc_unreachable ();
332     }
333 }
334 
335 static void
336 print_header (void)
337 {
338   /* N.B. Code below avoids putting squiggle braces in column 1 inside
339      a string, because this confuses some editors' syntax highlighting
340      engines.  */
341 
342   puts ("\
343 /* Generated automatically by the program `genextract'\n\
344    from the machine description file `md'.  */\n\
345 \n\
346 #include \"config.h\"\n\
347 #include \"system.h\"\n\
348 #include \"coretypes.h\"\n\
349 #include \"tm.h\"\n\
350 #include \"rtl.h\"\n\
351 #include \"insn-config.h\"\n\
352 #include \"recog.h\"\n\
353 #include \"diagnostic-core.h\"\n\
354 \n\
355 /* This variable is used as the \"location\" of any missing operand\n\
356    whose numbers are skipped by a given pattern.  */\n\
357 static rtx junk ATTRIBUTE_UNUSED;\n");
358 
359   puts ("\
360 void\n\
361 insn_extract (rtx_insn *insn)\n{\n\
362   rtx *ro = recog_data.operand;\n\
363   rtx **ro_loc = recog_data.operand_loc;\n\
364   rtx pat = PATTERN (insn);\n\
365   int i ATTRIBUTE_UNUSED; /* only for peepholes */\n\
366 \n\
367   if (flag_checking)\n\
368     {\n\
369       memset (ro, 0xab, sizeof (*ro) * MAX_RECOG_OPERANDS);\n\
370       memset (ro_loc, 0xab, sizeof (*ro_loc) * MAX_RECOG_OPERANDS);\n\
371     }\n");
372 
373   puts ("\
374   switch (INSN_CODE (insn))\n\
375     {\n\
376     default:\n\
377       /* Control reaches here if insn_extract has been called with an\n\
378          unrecognizable insn (code -1), or an insn whose INSN_CODE\n\
379          corresponds to a DEFINE_EXPAND in the machine description;\n\
380          either way, a bug.  */\n\
381       if (INSN_CODE (insn) < 0)\n\
382         fatal_insn (\"unrecognizable insn:\", insn);\n\
383       else\n\
384         fatal_insn (\"insn with invalid code number:\", insn);\n");
385 }
386 
387 int
388 main (int argc, const char **argv)
389 {
390   unsigned int i;
391   struct extraction *p;
392   struct code_ptr *link;
393   const char *name;
394 
395   progname = "genextract";
396 
397   if (!init_rtx_reader_args (argc, argv))
398     return (FATAL_EXIT_CODE);
399 
400   /* Read the machine description.  */
401 
402   md_rtx_info info;
403   while (read_md_rtx (&info))
404     switch (GET_CODE (info.def))
405       {
406       case DEFINE_INSN:
407 	gen_insn (&info);
408 	break;
409 
410       case DEFINE_PEEPHOLE:
411 	{
412 	  struct code_ptr *link = XNEW (struct code_ptr);
413 
414 	  link->insn_code = info.index;
415 	  link->next = peepholes;
416 	  peepholes = link;
417 	}
418 	break;
419 
420       default:
421 	break;
422     }
423 
424   if (have_error)
425     return FATAL_EXIT_CODE;
426 
427   print_header ();
428 
429   /* Write out code to handle peepholes and the insn_codes that it should
430      be called for.  */
431   if (peepholes)
432     {
433       for (link = peepholes; link; link = link->next)
434 	printf ("    case %d:\n", link->insn_code);
435 
436       /* The vector in the insn says how many operands it has.
437 	 And all it contains are operands.  In fact, the vector was
438 	 created just for the sake of this function.  We need to set the
439 	 location of the operands for sake of simplifications after
440 	 extraction, like eliminating subregs.  */
441       puts ("      for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n"
442 	    "          ro[i] = *(ro_loc[i] = &XVECEXP (pat, 0, i));\n"
443 	    "      break;\n");
444     }
445 
446   /* Write out all the ways to extract insn operands.  */
447   for (p = extractions; p; p = p->next)
448     {
449       for (link = p->insns; link; link = link->next)
450 	{
451 	  i = link->insn_code;
452 	  name = get_insn_name (i);
453 	  if (name)
454 	    printf ("    case %d:  /* %s */\n", i, name);
455 	  else
456 	    printf ("    case %d:\n", i);
457 	}
458 
459       for (i = 0; i < p->op_count; i++)
460 	{
461 	  if (p->oplocs[i] == 0)
462 	    {
463 	      printf ("      ro[%d] = const0_rtx;\n", i);
464 	      printf ("      ro_loc[%d] = &junk;\n", i);
465 	    }
466 	  else
467 	    {
468 	      printf ("      ro[%d] = *(ro_loc[%d] = &", i, i);
469 	      print_path (p->oplocs[i]);
470 	      puts (");");
471 	    }
472 	}
473 
474       for (i = 0; i < p->dup_count; i++)
475 	{
476 	  printf ("      recog_data.dup_loc[%d] = &", i);
477 	  print_path (p->duplocs[i]);
478 	  puts (";");
479 	  printf ("      recog_data.dup_num[%d] = %d;\n", i, p->dupnums[i]);
480 	}
481 
482       puts ("      break;\n");
483     }
484 
485   puts ("    }\n}");
486   fflush (stdout);
487   return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
488 }
489