*** empty log message ***
[platform/upstream/gcc.git] / gcc / genextract.c
1 /* Generate code from machine description to extract operands from insn as rtl.
2    Copyright (C) 1987, 1991 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
26 static struct obstack obstack;
27 struct obstack *rtl_obstack = &obstack;
28
29 #define obstack_chunk_alloc xmalloc
30 #define obstack_chunk_free free
31
32 extern void free ();
33
34 /* Number instruction patterns handled, starting at 0 for first one.  */
35
36 static int insn_code_number;
37
38 /* Number the occurrences of MATCH_DUP in each instruction,
39    starting at 0 for the first occurrence.  */
40
41 static int dup_count;
42
43 /* Record which operand numbers have been seen in the current pattern.
44    This table is made longer as needed.  */
45
46 static char *operand_seen;
47
48 /* Current allocated length of operand_seen.  */
49
50 static int operand_seen_length;
51
52 /* Have we got any peephole patterns yet?  */
53
54 static int peephole_seen;
55
56 /* While tree-walking an instruction pattern, we keep a chain
57    of these `struct link's to record how to get down to the
58    current position.  In each one, POS is the operand number,
59    and if the operand is a vector VEC is the element number.
60    VEC is -1 if the operand is not a vector.  */
61
62 struct link
63 {
64   struct link *next;
65   int pos;
66   int vecelt;
67 };
68
69 static void walk_rtx ();
70 static void print_path ();
71 char *xmalloc ();
72 char *xrealloc ();
73 static void fatal ();
74 static void mybzero ();
75 void fancy_abort ();
76 \f
77 static void
78 gen_insn (insn)
79      rtx insn;
80 {
81   register int i;
82
83   dup_count = 0;
84
85   /* No operands seen so far in this pattern.  */
86   mybzero (operand_seen, operand_seen_length);
87
88   printf ("    case %d:\n", insn_code_number);
89
90   /* Walk the insn's pattern, remembering at all times the path
91      down to the walking point.  */
92
93   if (XVECLEN (insn, 1) == 1)
94     walk_rtx (XVECEXP (insn, 1, 0), 0);
95   else
96     for (i = XVECLEN (insn, 1) - 1; i >= 0; i--)
97       {
98         struct link link;
99         link.next = 0;
100         link.pos = 0;
101         link.vecelt = i;
102         walk_rtx (XVECEXP (insn, 1, i), &link);
103       }
104
105   /* If the operand numbers used in the pattern are not consecutive,
106      don't leave an operand uninitialized.  */
107   for (i = operand_seen_length - 1; i >= 0; i--)
108     if (operand_seen[i])
109       break;
110   for (; i >= 0; i--)
111     if (!operand_seen[i])
112       {
113         printf ("      ro[%d] = const0_rtx;\n", i);
114         printf ("      ro_loc[%d] = &junk;\n", i);
115       }
116   printf ("      break;\n");
117 }
118 \f
119 /* Record that we have seen an operand with number OPNO in this pattern.  */
120
121 static void
122 mark_operand_seen (opno)
123      int opno;
124 {
125   if (opno >= operand_seen_length)
126     {
127       operand_seen_length *= 2;
128       operand_seen = (char *) xrealloc (operand_seen, operand_seen_length);
129     }
130
131   operand_seen[opno] = 1;
132 }
133
134 static void
135 walk_rtx (x, path)
136      rtx x;
137      struct link *path;
138 {
139   register RTX_CODE code;
140   register int i;
141   register int len;
142   register char *fmt;
143   struct link link;
144
145   if (x == 0)
146     return;
147
148   code = GET_CODE (x);
149
150   switch (code)
151     {
152     case PC:
153     case CC0:
154     case CONST_INT:
155     case SYMBOL_REF:
156       return;
157
158     case MATCH_OPERAND:
159     case MATCH_SCRATCH:
160       mark_operand_seen (XINT (x, 0));
161       printf ("      ro[%d] = *(ro_loc[%d] = &",
162               XINT (x, 0), XINT (x, 0));
163       print_path (path);
164       printf (");\n");
165       break;
166
167     case MATCH_DUP:
168     case MATCH_OP_DUP:
169       printf ("      recog_dup_loc[%d] = &", dup_count);
170       print_path (path);
171       printf (";\n");
172       printf ("      recog_dup_num[%d] = %d;\n", dup_count, XINT (x, 0));
173       dup_count++;
174       break;
175
176     case MATCH_OPERATOR:
177       mark_operand_seen (XINT (x, 0));
178       printf ("      ro[%d] = *(ro_loc[%d]\n        = &",
179               XINT (x, 0), XINT (x, 0));
180       print_path (path);
181       printf (");\n");
182       link.next = path;
183       link.vecelt = -1;
184       for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
185         {
186           link.pos = i;
187           walk_rtx (XVECEXP (x, 2, i), &link);
188         }
189       return;
190
191     case MATCH_PARALLEL:
192       mark_operand_seen (XINT (x, 0));
193       printf ("      ro[%d] = *(ro_loc[%d]\n        = &",
194               XINT (x, 0), XINT (x, 0));
195       print_path (path);
196       printf (");\n");
197       link.next = path;
198       link.pos = 0;
199       for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
200         {
201           link.vecelt = i;
202           walk_rtx (XVECEXP (x, 2, i), &link);
203         }
204       return;
205
206     case ADDRESS:
207       walk_rtx (XEXP (x, 0), path);
208       return;
209     }
210
211   link.next = path;
212   link.vecelt = -1;
213   fmt = GET_RTX_FORMAT (code);
214   len = GET_RTX_LENGTH (code);
215   for (i = 0; i < len; i++)
216     {
217       link.pos = i;
218       if (fmt[i] == 'e' || fmt[i] == 'u')
219         {
220           walk_rtx (XEXP (x, i), &link);
221         }
222       else if (fmt[i] == 'E')
223         {
224           int j;
225           for (j = XVECLEN (x, i) - 1; j >= 0; j--)
226             {
227               link.vecelt = j;
228               walk_rtx (XVECEXP (x, i, j), &link);
229             }
230         }
231     }
232 }
233
234 /* Given a PATH, representing a path down the instruction's
235    pattern from the root to a certain point, output code to
236    evaluate to the rtx at that point.  */
237
238 static void
239 print_path (path)
240      struct link *path;
241 {
242   if (path == 0)
243     printf ("insn");
244   else if (path->vecelt >= 0)
245     {
246       printf ("XVECEXP (");
247       print_path (path->next);
248       printf (", %d, %d)", path->pos, path->vecelt);
249     }
250   else
251     {
252       printf ("XEXP (");
253       print_path (path->next);
254       printf (", %d)", path->pos);
255     }
256 }
257 \f
258 char *
259 xmalloc (size)
260      unsigned size;
261 {
262   register char *val = (char *) malloc (size);
263
264   if (val == 0)
265     fatal ("virtual memory exhausted");
266   return val;
267 }
268
269 char *
270 xrealloc (ptr, size)
271      char *ptr;
272      unsigned size;
273 {
274   char *result = (char *) realloc (ptr, size);
275   if (!result)
276     fatal ("virtual memory exhausted");
277   return result;
278 }
279
280 static void
281 fatal (s, a1, a2)
282      char *s;
283 {
284   fprintf (stderr, "genextract: ");
285   fprintf (stderr, s, a1, a2);
286   fprintf (stderr, "\n");
287   exit (FATAL_EXIT_CODE);
288 }
289
290 /* More 'friendly' abort that prints the line and file.
291    config.h can #define abort fancy_abort if you like that sort of thing.  */
292
293 void
294 fancy_abort ()
295 {
296   fatal ("Internal gcc abort.");
297 }
298
299 static void
300 mybzero (b, length)
301      register char *b;
302      register unsigned length;
303 {
304   while (length-- > 0)
305     *b++ = 0;
306 }
307 \f
308 int
309 main (argc, argv)
310      int argc;
311      char **argv;
312 {
313   rtx desc;
314   FILE *infile;
315   extern rtx read_rtx ();
316   register int c, i;
317
318   obstack_init (rtl_obstack);
319
320   if (argc <= 1)
321     fatal ("No input file name.");
322
323   infile = fopen (argv[1], "r");
324   if (infile == 0)
325     {
326       perror (argv[1]);
327       exit (FATAL_EXIT_CODE);
328     }
329
330   init_rtl ();
331
332   /* Assign sequential codes to all entries in the machine description
333      in parallel with the tables in insn-output.c.  */
334
335   insn_code_number = 0;
336
337   operand_seen_length = 40;
338   operand_seen = (char *) xmalloc (40);
339
340   printf ("/* Generated automatically by the program `genextract'\n\
341 from the machine description file `md'.  */\n\n");
342
343   printf ("#include \"config.h\"\n");
344   printf ("#include \"rtl.h\"\n\n");
345
346   /* This variable exists only so it can be the "location"
347      of any missing operand whose numbers are skipped by a given pattern.  */
348   printf ("static rtx junk;\n");
349   printf ("extern rtx recog_operand[];\n");
350   printf ("extern rtx *recog_operand_loc[];\n");
351   printf ("extern rtx *recog_dup_loc[];\n");
352   printf ("extern char recog_dup_num[];\n");
353   printf ("extern\n#ifdef __GNUC__\nvolatile\n#endif\n");
354   printf ("void fatal_insn_not_found ();\n\n");
355
356   printf ("void\ninsn_extract (insn)\n");
357   printf ("     rtx insn;\n");
358   printf ("{\n");
359   printf ("  register rtx *ro = recog_operand;\n");
360   printf ("  register rtx **ro_loc = recog_operand_loc;\n");
361   printf ("  int insn_code = INSN_CODE (insn);\n");
362   printf ("  if (insn_code == -1) fatal_insn_not_found (insn);\n");
363   printf ("  insn = PATTERN (insn);\n");
364   printf ("  switch (insn_code)\n");
365   printf ("    {\n");
366
367   /* Read the machine description.  */
368
369   while (1)
370     {
371       c = read_skip_spaces (infile);
372       if (c == EOF)
373         break;
374       ungetc (c, infile);
375
376       desc = read_rtx (infile);
377       if (GET_CODE (desc) == DEFINE_INSN)
378         {
379           gen_insn (desc);
380           ++insn_code_number;
381         }
382       if (GET_CODE (desc) == DEFINE_PEEPHOLE)
383         {
384           printf ("    case %d: goto peephole;\n", insn_code_number);
385           ++insn_code_number;
386           ++peephole_seen;
387         }
388       if (GET_CODE (desc) == DEFINE_EXPAND || GET_CODE (desc) == DEFINE_SPLIT)
389         {
390           printf ("    case %d: break;\n", insn_code_number);
391           ++insn_code_number;
392         }
393     }
394
395   /* This should never be reached.  */
396   printf ("\n    default:\n      abort ();\n");
397
398   if (peephole_seen)
399     {
400       /* The vector in the insn says how many operands it has.
401          And all it contains are operands.  In fact, the vector was
402          created just for the sake of this function.  */
403       printf ("    peephole:\n");
404       printf ("#if __GNUC__ > 1 && !defined (bcopy)\n");
405       printf ("#define bcopy(FROM,TO,COUNT) __builtin_memcpy(TO,FROM,COUNT)\n");
406       printf ("#endif\n");
407       printf ("      bcopy (&XVECEXP (insn, 0, 0), ro,\n");
408       printf ("             sizeof (rtx) * XVECLEN (insn, 0));\n");
409       printf ("      break;\n");
410     }
411
412   printf ("    }\n}\n");
413
414   fflush (stdout);
415   exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
416   /* NOTREACHED */
417   return 0;
418 }