xref: /openbsd/gnu/gcc/gcc/genextract.c (revision 5af055cd)
1 /* Generate code from machine description to extract operands from insn as rtl.
2    Copyright (C) 1987, 1991, 1992, 1993, 1997, 1998, 1999, 2000, 2003,
3    2004, 2005
4    Free Software Foundation, Inc.
5 
6 This file is part of GCC.
7 
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
12 
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING.  If not, write to the Free
20 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.  */
22 
23 
24 #include "bconfig.h"
25 #include "system.h"
26 #include "coretypes.h"
27 #include "tm.h"
28 #include "rtl.h"
29 #include "errors.h"
30 #include "gensupport.h"
31 #include "vec.h"
32 #include "vecprim.h"
33 
34 /* This structure contains all the information needed to describe one
35    set of extractions methods.  Each method may be used by more than
36    one pattern if the operands are in the same place.
37 
38    The string for each operand describes that path to the operand and
39    contains `0' through `9' when going into an expression and `a' through
40    `z' when going into a vector.  We assume here that only the first operand
41    of an rtl expression is a vector.  genrecog.c makes the same assumption
42    (and uses the same representation) and it is currently true.  */
43 
44 typedef char *locstr;
45 
46 struct extraction
47 {
48   unsigned int op_count;
49   unsigned int dup_count;
50   locstr *oplocs;
51   locstr *duplocs;
52   int *dupnums;
53   struct code_ptr *insns;
54   struct extraction *next;
55 };
56 
57 /* Holds a single insn code that uses an extraction method.  */
58 struct code_ptr
59 {
60   int insn_code;
61   struct code_ptr *next;
62 };
63 
64 /* All extractions needed for this machine description.  */
65 static struct extraction *extractions;
66 
67 /* All insn codes for old-style peepholes.  */
68 static struct code_ptr *peepholes;
69 
70 /* This structure is used by gen_insn and walk_rtx to accumulate the
71    data that will be used to produce an extractions structure.  */
72 
73 DEF_VEC_P(locstr);
74 DEF_VEC_ALLOC_P(locstr,heap);
75 
76 struct accum_extract
77 {
78   VEC(locstr,heap) *oplocs;
79   VEC(locstr,heap) *duplocs;
80   VEC(int,heap)    *dupnums;
81   VEC(char,heap)   *pathstr;
82 };
83 
84 /* Forward declarations.  */
85 static void walk_rtx (rtx, struct accum_extract *);
86 
87 static void
88 gen_insn (rtx insn, int insn_code_number)
89 {
90   int i;
91   unsigned int op_count, dup_count, j;
92   struct extraction *p;
93   struct code_ptr *link;
94   struct accum_extract acc;
95 
96   acc.oplocs  = VEC_alloc (locstr,heap, 10);
97   acc.duplocs = VEC_alloc (locstr,heap, 10);
98   acc.dupnums = VEC_alloc (int,heap,    10);
99   acc.pathstr = VEC_alloc (char,heap,   20);
100 
101   /* Walk the insn's pattern, remembering at all times the path
102      down to the walking point.  */
103 
104   if (XVECLEN (insn, 1) == 1)
105     walk_rtx (XVECEXP (insn, 1, 0), &acc);
106   else
107     for (i = XVECLEN (insn, 1) - 1; i >= 0; i--)
108       {
109 	VEC_safe_push (char,heap, acc.pathstr, 'a' + i);
110 	walk_rtx (XVECEXP (insn, 1, i), &acc);
111 	VEC_pop (char, acc.pathstr);
112       }
113 
114   link = XNEW (struct code_ptr);
115   link->insn_code = insn_code_number;
116 
117   /* See if we find something that already had this extraction method.  */
118 
119   op_count = VEC_length (locstr, acc.oplocs);
120   dup_count = VEC_length (locstr, acc.duplocs);
121   gcc_assert (dup_count == VEC_length (int, acc.dupnums));
122 
123   for (p = extractions; p; p = p->next)
124     {
125       if (p->op_count != op_count || p->dup_count != dup_count)
126 	continue;
127 
128       for (j = 0; j < op_count; j++)
129 	{
130 	  char *a = p->oplocs[j];
131 	  char *b = VEC_index (locstr, acc.oplocs, j);
132 	  if (a != b && (!a || !b || strcmp (a, b)))
133 	    break;
134 	}
135 
136       if (j != op_count)
137 	continue;
138 
139       for (j = 0; j < dup_count; j++)
140 	if (p->dupnums[j] != VEC_index (int, acc.dupnums, j)
141 	    || strcmp (p->duplocs[j], VEC_index (locstr, acc.duplocs, j)))
142 	  break;
143 
144       if (j != dup_count)
145 	continue;
146 
147       /* This extraction is the same as ours.  Just link us in.  */
148       link->next = p->insns;
149       p->insns = link;
150       goto done;
151     }
152 
153   /* Otherwise, make a new extraction method.  We stash the arrays
154      after the extraction structure in memory.  */
155 
156   p = xmalloc (sizeof (struct extraction)
157 	       + op_count*sizeof (char *)
158 	       + dup_count*sizeof (char *)
159 	       + dup_count*sizeof (int));
160   p->op_count = op_count;
161   p->dup_count = dup_count;
162   p->next = extractions;
163   extractions = p;
164   p->insns = link;
165   link->next = 0;
166 
167   p->oplocs = (char **)((char *)p + sizeof (struct extraction));
168   p->duplocs = p->oplocs + op_count;
169   p->dupnums = (int *)(p->duplocs + dup_count);
170 
171   memcpy(p->oplocs,  VEC_address(locstr,acc.oplocs),   op_count*sizeof(locstr));
172   memcpy(p->duplocs, VEC_address(locstr,acc.duplocs), dup_count*sizeof(locstr));
173   memcpy(p->dupnums, VEC_address(int,   acc.dupnums), dup_count*sizeof(int));
174 
175  done:
176   VEC_free (locstr,heap, acc.oplocs);
177   VEC_free (locstr,heap, acc.duplocs);
178   VEC_free (int,heap,    acc.dupnums);
179   VEC_free (char,heap,   acc.pathstr);
180 }
181 
182 /* Helper subroutine of walk_rtx: given a VEC(locstr), an index, and a
183    string, insert the string at the index, which should either already
184    exist and be NULL, or not yet exist within the vector.  In the latter
185    case the vector is enlarged as appropriate.  */
186 static void
187 VEC_safe_set_locstr (VEC(locstr,heap) **vp, unsigned int ix, char *str)
188 {
189   if (ix < VEC_length (locstr, *vp))
190     {
191       gcc_assert (VEC_index (locstr, *vp, ix) == 0);
192       VEC_replace (locstr, *vp, ix, str);
193     }
194   else
195     {
196       while (ix > VEC_length (locstr, *vp))
197 	VEC_safe_push (locstr, heap, *vp, 0);
198       VEC_safe_push (locstr, heap, *vp, str);
199     }
200 }
201 
202 /* Another helper subroutine of walk_rtx: given a VEC(char), convert it
203    to a NUL-terminated string in malloc memory.  */
204 static char *
205 VEC_char_to_string (VEC(char,heap) *v)
206 {
207   size_t n = VEC_length (char, v);
208   char *s = XNEWVEC (char, n + 1);
209   memcpy (s, VEC_address (char, v), n);
210   s[n] = '\0';
211   return s;
212 }
213 
214 static void
215 walk_rtx (rtx x, struct accum_extract *acc)
216 {
217   RTX_CODE code;
218   int i, len, base;
219   const char *fmt;
220 
221   if (x == 0)
222     return;
223 
224   code = GET_CODE (x);
225   switch (code)
226     {
227     case PC:
228     case CC0:
229     case CONST_INT:
230     case SYMBOL_REF:
231       return;
232 
233     case MATCH_OPERAND:
234     case MATCH_SCRATCH:
235       VEC_safe_set_locstr (&acc->oplocs, XINT (x, 0),
236 			   VEC_char_to_string (acc->pathstr));
237       break;
238 
239     case MATCH_OPERATOR:
240     case MATCH_PARALLEL:
241       VEC_safe_set_locstr (&acc->oplocs, XINT (x, 0),
242 			   VEC_char_to_string (acc->pathstr));
243 
244       base = (code == MATCH_OPERATOR ? '0' : 'a');
245       for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
246 	{
247 	  VEC_safe_push (char,heap, acc->pathstr, base + i);
248 	  walk_rtx (XVECEXP (x, 2, i), acc);
249 	  VEC_pop (char, acc->pathstr);
250         }
251       return;
252 
253     case MATCH_DUP:
254     case MATCH_PAR_DUP:
255     case MATCH_OP_DUP:
256       VEC_safe_push (locstr,heap, acc->duplocs,
257 		     VEC_char_to_string (acc->pathstr));
258       VEC_safe_push (int,heap, acc->dupnums, XINT (x, 0));
259 
260       if (code == MATCH_DUP)
261 	break;
262 
263       base = (code == MATCH_OP_DUP ? '0' : 'a');
264       for (i = XVECLEN (x, 1) - 1; i >= 0; i--)
265         {
266 	  VEC_safe_push (char,heap, acc->pathstr, base + i);
267 	  walk_rtx (XVECEXP (x, 1, i), acc);
268 	  VEC_pop (char, acc->pathstr);
269         }
270       return;
271 
272     default:
273       break;
274     }
275 
276   fmt = GET_RTX_FORMAT (code);
277   len = GET_RTX_LENGTH (code);
278   for (i = 0; i < len; i++)
279     {
280       if (fmt[i] == 'e' || fmt[i] == 'u')
281 	{
282 	  VEC_safe_push (char,heap, acc->pathstr, '0' + i);
283 	  walk_rtx (XEXP (x, i), acc);
284 	  VEC_pop (char, acc->pathstr);
285 	}
286       else if (fmt[i] == 'E')
287 	{
288 	  int j;
289 	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
290 	    {
291 	      VEC_safe_push (char,heap, acc->pathstr, 'a' + j);
292 	      walk_rtx (XVECEXP (x, i, j), acc);
293 	      VEC_pop (char, acc->pathstr);
294 	    }
295 	}
296     }
297 }
298 
299 /* Given a PATH, representing a path down the instruction's
300    pattern from the root to a certain point, output code to
301    evaluate to the rtx at that point.  */
302 
303 static void
304 print_path (const char *path)
305 {
306   int len = strlen (path);
307   int i;
308 
309   if (len == 0)
310     {
311       /* Don't emit "pat", since we may try to take the address of it,
312 	 which isn't what is intended.  */
313       fputs ("PATTERN (insn)", stdout);
314       return;
315     }
316 
317   /* We first write out the operations (XEXP or XVECEXP) in reverse
318      order, then write "pat", then the indices in forward order.  */
319 
320   for (i = len - 1; i >= 0 ; i--)
321     {
322       if (ISLOWER (path[i]))
323 	fputs ("XVECEXP (", stdout);
324       else if (ISDIGIT (path[i]))
325 	fputs ("XEXP (", stdout);
326       else
327 	gcc_unreachable ();
328     }
329 
330   fputs ("pat", stdout);
331 
332   for (i = 0; i < len; i++)
333     {
334       if (ISLOWER (path[i]))
335 	printf (", 0, %d)", path[i] - 'a');
336       else if (ISDIGIT(path[i]))
337 	printf (", %d)", path[i] - '0');
338       else
339 	gcc_unreachable ();
340     }
341 }
342 
343 static void
344 print_header (void)
345 {
346   /* N.B. Code below avoids putting squiggle braces in column 1 inside
347      a string, because this confuses some editors' syntax highlighting
348      engines.  */
349 
350   puts ("\
351 /* Generated automatically by the program `genextract'\n\
352    from the machine description file `md'.  */\n\
353 \n\
354 #include \"config.h\"\n\
355 #include \"system.h\"\n\
356 #include \"coretypes.h\"\n\
357 #include \"tm.h\"\n\
358 #include \"rtl.h\"\n\
359 #include \"insn-config.h\"\n\
360 #include \"recog.h\"\n\
361 #include \"toplev.h\"\n\
362 \n\
363 /* This variable is used as the \"location\" of any missing operand\n\
364    whose numbers are skipped by a given pattern.  */\n\
365 static rtx junk ATTRIBUTE_UNUSED;\n");
366 
367   puts ("\
368 void\n\
369 insn_extract (rtx insn)\n{\n\
370   rtx *ro = recog_data.operand;\n\
371   rtx **ro_loc = recog_data.operand_loc;\n\
372   rtx pat = PATTERN (insn);\n\
373   int i ATTRIBUTE_UNUSED; /* only for peepholes */\n\
374 \n\
375 #ifdef ENABLE_CHECKING\n\
376   memset (ro, 0xab, sizeof (*ro) * MAX_RECOG_OPERANDS);\n\
377   memset (ro_loc, 0xab, sizeof (*ro_loc) * MAX_RECOG_OPERANDS);\n\
378 #endif\n");
379 
380   puts ("\
381   switch (INSN_CODE (insn))\n\
382     {\n\
383     default:\n\
384       /* Control reaches here if insn_extract has been called with an\n\
385          unrecognizable insn (code -1), or an insn whose INSN_CODE\n\
386          corresponds to a DEFINE_EXPAND in the machine description;\n\
387          either way, a bug.  */\n\
388       if (INSN_CODE (insn) < 0)\n\
389         fatal_insn (\"unrecognizable insn:\", insn);\n\
390       else\n\
391         fatal_insn (\"insn with invalid code number:\", insn);\n");
392 }
393 
394 int
395 main (int argc, char **argv)
396 {
397   rtx desc;
398   unsigned int i;
399   struct extraction *p;
400   struct code_ptr *link;
401   const char *name;
402   int insn_code_number;
403   int line_no;
404 
405   progname = "genextract";
406 
407   if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
408     return (FATAL_EXIT_CODE);
409 
410   /* Read the machine description.  */
411 
412   while ((desc = read_md_rtx (&line_no, &insn_code_number)) != NULL)
413     {
414        if (GET_CODE (desc) == DEFINE_INSN)
415 	 gen_insn (desc, insn_code_number);
416 
417       else if (GET_CODE (desc) == DEFINE_PEEPHOLE)
418 	{
419 	  struct code_ptr *link = XNEW (struct code_ptr);
420 
421 	  link->insn_code = insn_code_number;
422 	  link->next = peepholes;
423 	  peepholes = link;
424 	}
425     }
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