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