OSDN Git Service

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