OSDN Git Service

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