OSDN Git Service

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