OSDN Git Service

gcc/fortran:
[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
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 \f
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 \f
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 }