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