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