OSDN Git Service

Include hconfig.h, not config.h.
[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 "hconfig.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     case MATCH_PAR_DUP:
221       duplocs[dup_count] = copystr (path);
222       dupnums[dup_count] = XINT (x, 0);
223       dup_count++;
224       break;
225
226     case MATCH_OPERATOR:
227       oplocs[XINT (x, 0)] = copystr (path);
228       op_count = MAX (op_count, XINT (x, 0) + 1);
229
230       newpath = (char *) alloca (depth + 2);
231       strcpy (newpath, path);
232       newpath[depth + 1] = 0;
233
234       for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
235         {
236           newpath[depth] = '0' + i;
237           walk_rtx (XVECEXP (x, 2, i), newpath);
238         }
239       return;
240
241     case MATCH_PARALLEL:
242       oplocs[XINT (x, 0)] = copystr (path);
243       op_count = MAX (op_count, XINT (x, 0) + 1);
244
245       newpath = (char *) alloca (depth + 2);
246       strcpy (newpath, path);
247       newpath[depth + 1] = 0;
248
249       for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
250         {
251           newpath[depth] = 'a' + i;
252           walk_rtx (XVECEXP (x, 2, i), newpath);
253         }
254       return;
255
256     case ADDRESS:
257       walk_rtx (XEXP (x, 0), path);
258       return;
259     }
260
261   newpath = (char *) alloca (depth + 2);
262   strcpy (newpath, path);
263   newpath[depth + 1] = 0;
264
265   fmt = GET_RTX_FORMAT (code);
266   len = GET_RTX_LENGTH (code);
267   for (i = 0; i < len; i++)
268     {
269       if (fmt[i] == 'e' || fmt[i] == 'u')
270         {
271           newpath[depth] = '0' + i;
272           walk_rtx (XEXP (x, i), newpath);
273         }
274       else if (fmt[i] == 'E')
275         {
276           int j;
277           for (j = XVECLEN (x, i) - 1; j >= 0; j--)
278             {
279               newpath[depth] = 'a' + j;
280               walk_rtx (XVECEXP (x, i, j), newpath);
281             }
282         }
283     }
284 }
285
286 /* Given a PATH, representing a path down the instruction's
287    pattern from the root to a certain point, output code to
288    evaluate to the rtx at that point.  */
289
290 static void
291 print_path (path)
292      char *path;
293 {
294   register int len = strlen (path);
295   register int i;
296
297   /* We first write out the operations (XEXP or XVECEXP) in reverse
298      order, then write "insn", then the indices in forward order.  */
299
300   for (i = len - 1; i >=0 ; i--)
301     {
302       if (path[i] >= 'a' && path[i] <= 'z')
303         printf ("XVECEXP (");
304       else if (path[i] >= '0' && path[i] <= '9')
305         printf ("XEXP (");
306       else
307         abort ();
308     }
309   
310   printf ("pat");
311
312   for (i = 0; i < len; i++)
313     {
314       if (path[i] >= 'a' && path[i] <= 'z')
315         printf (", 0, %d)", path[i] - 'a');
316       else if (path[i] >= '0' && path[i] <= '9')
317         printf (", %d)", path[i] - '0');
318       else
319         abort ();
320     }
321 }
322 \f
323 char *
324 xmalloc (size)
325      unsigned size;
326 {
327   register char *val = (char *) malloc (size);
328
329   if (val == 0)
330     fatal ("virtual memory exhausted");
331   return val;
332 }
333
334 char *
335 xrealloc (ptr, size)
336      char *ptr;
337      unsigned size;
338 {
339   char *result = (char *) realloc (ptr, size);
340   if (!result)
341     fatal ("virtual memory exhausted");
342   return result;
343 }
344
345 static void
346 fatal (s, a1, a2)
347      char *s;
348 {
349   fprintf (stderr, "genextract: ");
350   fprintf (stderr, s, a1, a2);
351   fprintf (stderr, "\n");
352   exit (FATAL_EXIT_CODE);
353 }
354
355 /* More 'friendly' abort that prints the line and file.
356    config.h can #define abort fancy_abort if you like that sort of thing.  */
357
358 void
359 fancy_abort ()
360 {
361   fatal ("Internal gcc abort.");
362 }
363
364 static char *
365 copystr (s1)
366      char *s1;
367 {
368   register char *tem;
369
370   if (s1 == 0)
371     return 0;
372
373   tem = (char *) xmalloc (strlen (s1) + 1);
374   strcpy (tem, s1);
375
376   return tem;
377 }
378
379 static void
380 mybzero (b, length)
381      register char *b;
382      register unsigned length;
383 {
384   while (length-- > 0)
385     *b++ = 0;
386 }
387 \f
388 int
389 main (argc, argv)
390      int argc;
391      char **argv;
392 {
393   rtx desc;
394   FILE *infile;
395   register int c, i;
396   struct extraction *p;
397   struct code_ptr *link;
398
399   obstack_init (rtl_obstack);
400
401   if (argc <= 1)
402     fatal ("No input file name.");
403
404   infile = fopen (argv[1], "r");
405   if (infile == 0)
406     {
407       perror (argv[1]);
408       exit (FATAL_EXIT_CODE);
409     }
410
411   init_rtl ();
412
413   /* Assign sequential codes to all entries in the machine description
414      in parallel with the tables in insn-output.c.  */
415
416   insn_code_number = 0;
417
418   printf ("/* Generated automatically by the program `genextract'\n\
419 from the machine description file `md'.  */\n\n");
420
421   printf ("#include \"config.h\"\n");
422   printf ("#include \"rtl.h\"\n\n");
423
424   /* This variable exists only so it can be the "location"
425      of any missing operand whose numbers are skipped by a given pattern.  */
426   printf ("static rtx junk;\n");
427
428   printf ("extern rtx recog_operand[];\n");
429   printf ("extern rtx *recog_operand_loc[];\n");
430   printf ("extern rtx *recog_dup_loc[];\n");
431   printf ("extern char recog_dup_num[];\n");
432   printf ("extern\n#ifdef __GNUC__\nvolatile\n#endif\n");
433   printf ("void fatal_insn_not_found ();\n\n");
434
435   printf ("void\ninsn_extract (insn)\n");
436   printf ("     rtx insn;\n");
437   printf ("{\n");
438   printf ("  register rtx *ro = recog_operand;\n");
439   printf ("  register rtx **ro_loc = recog_operand_loc;\n");
440   printf ("  rtx pat = PATTERN (insn);\n");
441   printf ("  switch (INSN_CODE (insn))\n");
442   printf ("    {\n");
443   printf ("    case -1:\n");
444   printf ("      fatal_insn_not_found (insn);\n\n");
445
446   /* Read the machine description.  */
447
448   while (1)
449     {
450       c = read_skip_spaces (infile);
451       if (c == EOF)
452         break;
453       ungetc (c, infile);
454
455       desc = read_rtx (infile);
456       if (GET_CODE (desc) == DEFINE_INSN)
457         {
458           gen_insn (desc);
459           ++insn_code_number;
460         }
461
462       else if (GET_CODE (desc) == DEFINE_PEEPHOLE)
463         {
464           struct code_ptr *link
465             = (struct code_ptr *) xmalloc (sizeof (struct code_ptr));
466
467           link->insn_code = insn_code_number;
468           link->next = peepholes;
469           peepholes = link;
470           ++insn_code_number;
471         }
472
473       else if (GET_CODE (desc) == DEFINE_EXPAND
474                || GET_CODE (desc) == DEFINE_SPLIT)
475         ++insn_code_number;
476     }
477
478   /* Write out code to handle peepholes and the insn_codes that it should
479      be called for.  */
480   if (peepholes)
481     {
482       for (link = peepholes; link; link = link->next)
483         printf ("    case %d:\n", link->insn_code);
484
485       /* The vector in the insn says how many operands it has.
486          And all it contains are operands.  In fact, the vector was
487          created just for the sake of this function.  */
488       printf ("#if __GNUC__ > 1 && !defined (bcopy)\n");
489       printf ("#define bcopy(FROM,TO,COUNT) __builtin_memcpy(TO,FROM,COUNT)\n");
490       printf ("#endif\n");
491       printf ("      bcopy (&XVECEXP (pat, 0, 0), ro,\n");
492       printf ("             sizeof (rtx) * XVECLEN (pat, 0));\n");
493       printf ("      break;\n\n");
494     }
495
496   /* Write out all the ways to extract insn operands.  */
497   for (p = extractions; p; p = p->next)
498     {
499       for (link = p->insns; link; link = link->next)
500         printf ("    case %d:\n", link->insn_code);
501
502       for (i = 0; i < p->op_count; i++)
503         {
504           if (p->oplocs[i] == 0)
505             {
506               printf ("      ro[%d] = const0_rtx;\n", i);
507               printf ("      ro_loc[%d] = &junk;\n", i, i);
508             }
509           else
510             {
511               printf ("      ro[%d] = *(ro_loc[%d] = &", i, i);
512               print_path (p->oplocs[i]);
513               printf (");\n");
514             }
515         }
516
517       for (i = 0; i < p->dup_count; i++)
518         {
519           printf ("      recog_dup_loc[%d] = &", i);
520           print_path (p->duplocs[i]);
521           printf (";\n");
522           printf ("      recog_dup_num[%d] = %d;\n", i, p->dupnums[i]);
523         }
524
525       printf ("      break;\n\n");
526     }
527
528   /* This should never be reached.  Note that we would also reach this abort
529    if we tried to extract something whose INSN_CODE was a DEFINE_EXPAND or
530    DEFINE_SPLIT, but that is correct.  */
531   printf ("    default:\n      abort ();\n");
532
533   printf ("    }\n}\n");
534
535   fflush (stdout);
536   exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
537   /* NOTREACHED */
538   return 0;
539 }