OSDN Git Service

e5c528bc19e831793a7acfbcb629b8b54515e3d1
[pf3gnuchains/gcc-fork.git] / gcc / genextract.c
1 /* Generate code from machine description to extract operands from insn as rtl.
2    Copyright (C) 1987, 91-93, 97-98, 1999 Free Software Foundation, Inc.
3
4 This file is part of GNU CC.
5
6 GNU CC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU CC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING.  If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20
21
22 #include "hconfig.h"
23 #include "system.h"
24 #include "rtl.h"
25 #include "obstack.h"
26 #include "errors.h"
27 #include "insn-config.h"
28
29 static struct obstack obstack;
30 struct obstack *rtl_obstack = &obstack;
31
32 #define obstack_chunk_alloc xmalloc
33 #define obstack_chunk_free free
34
35 /* Names for patterns.  Need to allow linking with print-rtl.  */
36 char **insn_name_ptr;
37
38 /* This structure contains all the information needed to describe one
39    set of extractions methods.  Each method may be used by more than 
40    one pattern if the operands are in the same place.
41
42    The string for each operand describes that path to the operand and
43    contains `0' through `9' when going into an expression and `a' through
44    `z' when going into a vector.  We assume here that only the first operand
45    of an rtl expression is a vector.  genrecog.c makes the same assumption
46    (and uses the same representation) and it is currently true.  */
47
48 struct extraction
49 {
50   int op_count;
51   char *oplocs[MAX_RECOG_OPERANDS];
52   int dup_count;
53   char *duplocs[MAX_DUP_OPERANDS];
54   int dupnums[MAX_DUP_OPERANDS];
55   struct code_ptr *insns;
56   struct extraction *next;
57 };
58
59 /* Holds a single insn code that use an extraction method.  */
60
61 struct code_ptr
62 {
63   int insn_code;
64   struct code_ptr *next;
65 };
66
67 static struct extraction *extractions;
68
69 /* Number instruction patterns handled, starting at 0 for first one.  */
70
71 static int insn_code_number;
72
73 /* Records the large operand number in this insn.  */
74
75 static int op_count;
76
77 /* Records the location of any operands using the string format described
78    above.  */
79
80 static char *oplocs[MAX_RECOG_OPERANDS];
81
82 /* Number the occurrences of MATCH_DUP in each instruction,
83    starting at 0 for the first occurrence.  */
84
85 static int dup_count;
86
87 /* Records the location of any MATCH_DUP operands.  */
88
89 static char *duplocs[MAX_DUP_OPERANDS];
90
91 /* Record the operand number of any MATCH_DUPs.  */
92
93 static int dupnums[MAX_DUP_OPERANDS];
94
95 /* Record the list of insn_codes for peepholes.  */
96
97 static struct code_ptr *peepholes;
98
99 static void gen_insn PROTO ((rtx));
100 static void walk_rtx PROTO ((rtx, const char *));
101 static void print_path PROTO ((char *));
102
103 static void
104 gen_insn (insn)
105      rtx insn;
106 {
107   register int i;
108   register struct extraction *p;
109   register struct code_ptr *link;
110
111   op_count = 0;
112   dup_count = 0;
113
114   /* No operands seen so far in this pattern.  */
115   memset (oplocs, 0, sizeof oplocs);
116
117   /* Walk the insn's pattern, remembering at all times the path
118      down to the walking point.  */
119
120   if (XVECLEN (insn, 1) == 1)
121     walk_rtx (XVECEXP (insn, 1, 0), "");
122   else
123     for (i = XVECLEN (insn, 1) - 1; i >= 0; i--)
124       {
125         char *path = (char *) alloca (2);
126
127         path[0] = 'a' + i;
128         path[1] = 0;
129
130         walk_rtx (XVECEXP (insn, 1, i), path);
131       }
132
133   link = (struct code_ptr *) xmalloc (sizeof (struct code_ptr));
134   link->insn_code = insn_code_number;
135
136   /* See if we find something that already had this extraction method.  */
137
138   for (p = extractions; p; p = p->next)
139     {
140       if (p->op_count != op_count || p->dup_count != dup_count)
141         continue;
142
143       for (i = 0; i < op_count; i++)
144         if (p->oplocs[i] != oplocs[i]
145             && ! (p->oplocs[i] != 0 && oplocs[i] != 0
146                   && ! strcmp (p->oplocs[i], oplocs[i])))
147           break;
148
149       if (i != op_count)
150         continue;
151
152       for (i = 0; i < dup_count; i++)
153         if (p->dupnums[i] != dupnums[i]
154             || strcmp (p->duplocs[i], duplocs[i]))
155           break;
156
157       if (i != dup_count)
158         continue;
159
160       /* This extraction is the same as ours.  Just link us in.  */
161       link->next = p->insns;
162       p->insns = link;
163       return;
164     }
165
166   /* Otherwise, make a new extraction method.  */
167
168   p = (struct extraction *) xmalloc (sizeof (struct extraction));
169   p->op_count = op_count;
170   p->dup_count = dup_count;
171   p->next = extractions;
172   extractions = p;
173   p->insns = link;
174   link->next = 0;
175
176   for (i = 0; i < op_count; i++)
177     p->oplocs[i] = oplocs[i];
178
179   for (i = 0; i < dup_count; i++)
180     p->dupnums[i] = dupnums[i], p->duplocs[i] = duplocs[i];
181 }
182 \f
183 static void
184 walk_rtx (x, path)
185      rtx x;
186      const char *path;
187 {
188   register RTX_CODE code;
189   register int i;
190   register int len;
191   register const char *fmt;
192   int depth = strlen (path);
193   char *newpath;
194
195   if (x == 0)
196     return;
197
198   code = GET_CODE (x);
199
200   switch (code)
201     {
202     case PC:
203     case CC0:
204     case CONST_INT:
205     case SYMBOL_REF:
206       return;
207
208     case MATCH_OPERAND:
209     case MATCH_SCRATCH:
210       oplocs[XINT (x, 0)] = xstrdup (path);
211       op_count = MAX (op_count, XINT (x, 0) + 1);
212       break;
213
214     case MATCH_DUP:
215     case MATCH_PAR_DUP:
216       duplocs[dup_count] = xstrdup (path);
217       dupnums[dup_count] = XINT (x, 0);
218       dup_count++;
219       break;
220
221     case MATCH_OP_DUP:
222       duplocs[dup_count] = xstrdup (path);
223       dupnums[dup_count] = XINT (x, 0);
224       dup_count++;
225       
226       newpath = (char *) alloca (depth + 2);
227       strcpy (newpath, path);
228       newpath[depth + 1] = 0;
229       
230       for (i = XVECLEN (x, 1) - 1; i >= 0; i--)
231         {
232           newpath[depth] = '0' + i;
233           walk_rtx (XVECEXP (x, 1, i), newpath);
234         }
235       return;
236       
237     case MATCH_OPERATOR:
238       oplocs[XINT (x, 0)] = xstrdup (path);
239       op_count = MAX (op_count, XINT (x, 0) + 1);
240
241       newpath = (char *) alloca (depth + 2);
242       strcpy (newpath, path);
243       newpath[depth + 1] = 0;
244
245       for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
246         {
247           newpath[depth] = '0' + i;
248           walk_rtx (XVECEXP (x, 2, i), newpath);
249         }
250       return;
251
252     case MATCH_PARALLEL:
253       oplocs[XINT (x, 0)] = xstrdup (path);
254       op_count = MAX (op_count, XINT (x, 0) + 1);
255
256       newpath = (char *) alloca (depth + 2);
257       strcpy (newpath, path);
258       newpath[depth + 1] = 0;
259
260       for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
261         {
262           newpath[depth] = 'a' + i;
263           walk_rtx (XVECEXP (x, 2, i), newpath);
264         }
265       return;
266
267     case ADDRESS:
268       walk_rtx (XEXP (x, 0), path);
269       return;
270
271     default:
272       break;
273     }
274
275   newpath = (char *) alloca (depth + 2);
276   strcpy (newpath, path);
277   newpath[depth + 1] = 0;
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           newpath[depth] = '0' + i;
286           walk_rtx (XEXP (x, i), newpath);
287         }
288       else if (fmt[i] == 'E')
289         {
290           int j;
291           for (j = XVECLEN (x, i) - 1; j >= 0; j--)
292             {
293               newpath[depth] = 'a' + j;
294               walk_rtx (XVECEXP (x, i, j), newpath);
295             }
296         }
297     }
298 }
299
300 /* Given a PATH, representing a path down the instruction's
301    pattern from the root to a certain point, output code to
302    evaluate to the rtx at that point.  */
303
304 static void
305 print_path (path)
306      char *path;
307 {
308   register int len = strlen (path);
309   register int i;
310
311   if (len == 0)
312     {
313       /* Don't emit "pat", since we may try to take the address of it,
314          which isn't what is intended.  */
315       printf("PATTERN (insn)");
316       return;
317     }
318
319   /* We first write out the operations (XEXP or XVECEXP) in reverse
320      order, then write "insn", then the indices in forward order.  */
321
322   for (i = len - 1; i >=0 ; i--)
323     {
324       if (ISLOWER(path[i]))
325         printf ("XVECEXP (");
326       else if (ISDIGIT(path[i]))
327         printf ("XEXP (");
328       else
329         abort ();
330     }
331   
332   printf ("pat");
333
334   for (i = 0; i < len; i++)
335     {
336       if (ISLOWER(path[i]))
337         printf (", 0, %d)", path[i] - 'a');
338       else if (ISDIGIT(path[i]))
339         printf (", %d)", path[i] - '0');
340       else
341         abort ();
342     }
343 }
344 \f
345 PTR
346 xmalloc (size)
347   size_t size;
348 {
349   register PTR val = (PTR) malloc (size);
350
351   if (val == 0)
352     fatal ("virtual memory exhausted");
353   return val;
354 }
355
356 PTR
357 xrealloc (old, size)
358   PTR old;
359   size_t size;
360 {
361   register PTR ptr;
362   if (old)
363     ptr = (PTR) realloc (old, size);
364   else
365     ptr = (PTR) malloc (size);
366   if (!ptr)
367     fatal ("virtual memory exhausted");
368   return ptr;
369 }
370
371 char *
372 xstrdup (input)
373   const char *input;
374 {
375   register size_t len = strlen (input) + 1;
376   register char *output = xmalloc (len);
377   memcpy (output, input, len);
378   return output;
379 }
380 \f
381 int
382 main (argc, argv)
383      int argc;
384      char **argv;
385 {
386   rtx desc;
387   FILE *infile;
388   register int c, i;
389   struct extraction *p;
390   struct code_ptr *link;
391
392   progname = "genextract";
393   obstack_init (rtl_obstack);
394
395   if (argc <= 1)
396     fatal ("No input file name.");
397
398   infile = fopen (argv[1], "r");
399   if (infile == 0)
400     {
401       perror (argv[1]);
402       exit (FATAL_EXIT_CODE);
403     }
404
405   /* Assign sequential codes to all entries in the machine description
406      in parallel with the tables in insn-output.c.  */
407
408   insn_code_number = 0;
409
410   printf ("/* Generated automatically by the program `genextract'\n\
411 from the machine description file `md'.  */\n\n");
412
413   printf ("#include \"config.h\"\n");
414   printf ("#include \"system.h\"\n");
415   printf ("#include \"rtl.h\"\n");
416   printf ("#include \"insn-config.h\"\n");
417   printf ("#include \"recog.h\"\n");
418   printf ("#include \"toplev.h\"\n\n");
419
420   /* This variable exists only so it can be the "location"
421      of any missing operand whose numbers are skipped by a given pattern.  */
422   printf ("static rtx junk ATTRIBUTE_UNUSED;\n");
423
424   printf ("void\ninsn_extract (insn)\n");
425   printf ("     rtx insn;\n");
426   printf ("{\n");
427   printf ("  register rtx *ro = recog_operand;\n");
428   printf ("  register rtx **ro_loc = recog_operand_loc;\n");
429   printf ("  rtx pat = PATTERN (insn);\n");
430   printf ("  int i ATTRIBUTE_UNUSED;\n\n");
431   printf ("  memset (ro, 0, sizeof (*ro) * MAX_RECOG_OPERANDS);\n");
432   printf ("  memset (ro_loc, 0, sizeof (*ro_loc) * MAX_RECOG_OPERANDS);\n");
433   printf ("  switch (INSN_CODE (insn))\n");
434   printf ("    {\n");
435   printf ("    case -1:\n");
436   printf ("      fatal_insn_not_found (insn);\n\n");
437
438   /* Read the machine description.  */
439
440   while (1)
441     {
442       c = read_skip_spaces (infile);
443       if (c == EOF)
444         break;
445       ungetc (c, infile);
446
447       desc = read_rtx (infile);
448       if (GET_CODE (desc) == DEFINE_INSN)
449         {
450           gen_insn (desc);
451           ++insn_code_number;
452         }
453
454       else if (GET_CODE (desc) == DEFINE_PEEPHOLE)
455         {
456           struct code_ptr *link
457             = (struct code_ptr *) xmalloc (sizeof (struct code_ptr));
458
459           link->insn_code = insn_code_number;
460           link->next = peepholes;
461           peepholes = link;
462           ++insn_code_number;
463         }
464
465       else if (GET_CODE (desc) == DEFINE_EXPAND
466                || GET_CODE (desc) == DEFINE_PEEPHOLE2
467                || GET_CODE (desc) == DEFINE_SPLIT)
468         ++insn_code_number;
469     }
470
471   /* Write out code to handle peepholes and the insn_codes that it should
472      be called for.  */
473   if (peepholes)
474     {
475       for (link = peepholes; link; link = link->next)
476         printf ("    case %d:\n", link->insn_code);
477
478       /* The vector in the insn says how many operands it has.
479          And all it contains are operands.  In fact, the vector was
480          created just for the sake of this function.  */
481       printf ("      for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n");
482       printf ("          ro[i] = XVECEXP (pat, 0, i);\n");
483       printf ("      break;\n\n");
484     }
485
486   /* Write out all the ways to extract insn operands.  */
487   for (p = extractions; p; p = p->next)
488     {
489       for (link = p->insns; link; link = link->next)
490         printf ("    case %d:\n", link->insn_code);
491
492       for (i = 0; i < p->op_count; i++)
493         {
494           if (p->oplocs[i] == 0)
495             {
496               printf ("      ro[%d] = const0_rtx;\n", i);
497               printf ("      ro_loc[%d] = &junk;\n", i);
498             }
499           else
500             {
501               printf ("      ro[%d] = *(ro_loc[%d] = &", i, i);
502               print_path (p->oplocs[i]);
503               printf (");\n");
504             }
505         }
506
507       for (i = 0; i < p->dup_count; i++)
508         {
509           printf ("      recog_dup_loc[%d] = &", i);
510           print_path (p->duplocs[i]);
511           printf (";\n");
512           printf ("      recog_dup_num[%d] = %d;\n", i, p->dupnums[i]);
513         }
514
515       printf ("      break;\n\n");
516     }
517
518   /* This should never be reached.  Note that we would also reach this abort
519    if we tried to extract something whose INSN_CODE was a DEFINE_EXPAND or
520    DEFINE_SPLIT, but that is correct.  */
521   printf ("    default:\n      abort ();\n");
522
523   printf ("    }\n}\n");
524
525   fflush (stdout);
526   exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
527   /* NOTREACHED */
528   return 0;
529 }