OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / genextract.c
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 \f
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 \f
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 }