OSDN Git Service

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