*** 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, 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
35 /* This structure contains all the information needed to describe one
36    set of extractions methods.  Each method may be used by more than 
37    one pattern if the operands are in the same place.
38
39    The string for each operand describes that path to the operand and
40    contains `0' through `9' when going into an expression and `a' through
41    `z' when going into a vector.  We assume here that only the first operand
42    of an rtl expression is a vector.  genrecog.c makes the same assumption
43    (and uses the same representation) and it is currently true.  */
44
45 struct extraction
46 {
47   int op_count;
48   char *oplocs[MAX_RECOG_OPERANDS];
49   int dup_count;
50   char *duplocs[MAX_DUP_OPERANDS];
51   int dupnums[MAX_DUP_OPERANDS];
52   struct code_ptr *insns;
53   struct extraction *next;
54 };
55
56 /* Holds a single insn code that use an extraction method.  */
57
58 struct code_ptr
59 {
60   int insn_code;
61   struct code_ptr *next;
62 };
63
64 static struct extraction *extractions;
65
66 /* Number instruction patterns handled, starting at 0 for first one.  */
67
68 static int insn_code_number;
69
70 /* Records the large operand number in this insn.  */
71
72 static int op_count;
73
74 /* Records the location of any operands using the string format described
75    above.  */
76
77 static char *oplocs[MAX_RECOG_OPERANDS];
78
79 /* Number the occurrences of MATCH_DUP in each instruction,
80    starting at 0 for the first occurrence.  */
81
82 static int dup_count;
83
84 /* Records the location of any MATCH_DUP operands.  */
85
86 static char *duplocs[MAX_DUP_OPERANDS];
87
88 /* Record the operand number of any MATCH_DUPs.  */
89
90 static int dupnums[MAX_DUP_OPERANDS];
91
92 /* Record the list of insn_codes for peepholes.  */
93
94 static struct code_ptr *peepholes;
95
96 static void walk_rtx ();
97 static void print_path ();
98 char *xmalloc ();
99 char *xrealloc ();
100 static void fatal ();
101 static char *copystr ();
102 static void mybzero ();
103 void fancy_abort ();
104 \f
105 static void
106 gen_insn (insn)
107      rtx insn;
108 {
109   register int i;
110   register struct extraction *p;
111   register struct code_ptr *link;
112
113   op_count = 0;
114   dup_count = 0;
115
116   /* No operands seen so far in this pattern.  */
117   mybzero (oplocs, sizeof oplocs);
118
119   /* Walk the insn's pattern, remembering at all times the path
120      down to the walking point.  */
121
122   if (XVECLEN (insn, 1) == 1)
123     walk_rtx (XVECEXP (insn, 1, 0), "");
124   else
125     for (i = XVECLEN (insn, 1) - 1; i >= 0; i--)
126       {
127         char *path = (char *) alloca (2);
128
129         path[0] = 'a' + i;
130         path[1] = 0;
131
132         walk_rtx (XVECEXP (insn, 1, i), path);
133       }
134
135   link = (struct code_ptr *) xmalloc (sizeof (struct code_ptr));
136   link->insn_code = insn_code_number;
137
138   /* See if we find something that already had this extraction method. */
139
140   for (p = extractions; p; p = p->next)
141     {
142       if (p->op_count != op_count || p->dup_count != dup_count)
143         continue;
144
145       for (i = 0; i < op_count; i++)
146         if (p->oplocs[i] != oplocs[i]
147             && ! (p->oplocs[i] != 0 && oplocs[i] != 0
148                   && ! strcmp (p->oplocs[i], oplocs[i])))
149           break;
150
151       if (i != op_count)
152         continue;
153
154       for (i = 0; i < dup_count; i++)
155         if (p->dupnums[i] != dupnums[i]
156             || strcmp (p->duplocs[i], duplocs[i]))
157           break;
158
159       if (i != dup_count)
160         continue;
161
162       /* This extraction is the same as ours.  Just link us in.  */
163       link->next = p->insns;
164       p->insns = link;
165       return;
166     }
167
168   /* Otherwise, make a new extraction method.  */
169
170   p = (struct extraction *) xmalloc (sizeof (struct extraction));
171   p->op_count = op_count;
172   p->dup_count = dup_count;
173   p->next = extractions;
174   extractions = p;
175   p->insns = link;
176   link->next = 0;
177
178   for (i = 0; i < op_count; i++)
179     p->oplocs[i] = oplocs[i];
180
181   for (i = 0; i < dup_count; i++)
182     p->dupnums[i] = dupnums[i], p->duplocs[i] = duplocs[i];
183 }
184 \f
185 static void
186 walk_rtx (x, path)
187      rtx x;
188      char *path;
189 {
190   register RTX_CODE code;
191   register int i;
192   register int len;
193   register char *fmt;
194   register struct code_ptr *link;
195   int depth = strlen (path);
196   char *newpath;
197
198   if (x == 0)
199     return;
200
201   code = GET_CODE (x);
202
203   switch (code)
204     {
205     case PC:
206     case CC0:
207     case CONST_INT:
208     case SYMBOL_REF:
209       return;
210
211     case MATCH_OPERAND:
212     case MATCH_SCRATCH:
213       oplocs[XINT (x, 0)] = copystr (path);
214       op_count = MAX (op_count, XINT (x, 0) + 1);
215       break;
216
217     case MATCH_DUP:
218     case MATCH_OP_DUP:
219       duplocs[dup_count] = copystr (path);
220       dupnums[dup_count] = XINT (x, 0);
221       dup_count++;
222       break;
223
224     case MATCH_OPERATOR:
225       oplocs[XINT (x, 0)] = copystr (path);
226       op_count = MAX (op_count, XINT (x, 0) + 1);
227
228       newpath = (char *) alloca (depth + 2);
229       strcpy (newpath, path);
230       newpath[depth + 1] = 0;
231
232       for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
233         {
234           newpath[depth] = '0' + i;
235           walk_rtx (XVECEXP (x, 2, i), newpath);
236         }
237       return;
238
239     case MATCH_PARALLEL:
240       oplocs[XINT (x, 0)] = copystr (path);
241       op_count = MAX (op_count, XINT (x, 0) + 1);
242
243       newpath = (char *) alloca (depth + 2);
244       strcpy (newpath, path);
245       newpath[depth + 1] = 0;
246
247       for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
248         {
249           newpath[depth] = 'a' + i;
250           walk_rtx (XVECEXP (x, 2, i), newpath);
251         }
252       return;
253
254     case ADDRESS:
255       walk_rtx (XEXP (x, 0), path);
256       return;
257     }
258
259   newpath = (char *) alloca (depth + 2);
260   strcpy (newpath, path);
261   newpath[depth + 1] = 0;
262
263   fmt = GET_RTX_FORMAT (code);
264   len = GET_RTX_LENGTH (code);
265   for (i = 0; i < len; i++)
266     {
267       if (fmt[i] == 'e' || fmt[i] == 'u')
268         {
269           newpath[depth] = '0' + i;
270           walk_rtx (XEXP (x, i), newpath);
271         }
272       else if (fmt[i] == 'E')
273         {
274           int j;
275           for (j = XVECLEN (x, i) - 1; j >= 0; j--)
276             {
277               newpath[depth] = 'a' + j;
278               walk_rtx (XVECEXP (x, i, j), newpath);
279             }
280         }
281     }
282 }
283
284 /* Given a PATH, representing a path down the instruction's
285    pattern from the root to a certain point, output code to
286    evaluate to the rtx at that point.  */
287
288 static void
289 print_path (path)
290      char *path;
291 {
292   register int len = strlen (path);
293   register int i;
294
295   /* We first write out the operations (XEXP or XVECEXP) in reverse
296      order, then write "insn", then the indices in forward order.  */
297
298   for (i = len - 1; i >=0 ; i--)
299     {
300       if (path[i] >= 'a' && path[i] <= 'z')
301         printf ("XVECEXP (");
302       else if (path[i] >= '0' && path[i] <= '9')
303         printf ("XEXP (");
304       else
305         abort ();
306     }
307   
308   printf ("insn");
309
310   for (i = 0; i < len; i++)
311     {
312       if (path[i] >= 'a' && path[i] <= 'z')
313         printf (", 0, %d)", path[i] - 'a');
314       else if (path[i] >= '0' && path[i] <= '9')
315         printf (", %d)", path[i] - '0');
316       else
317         abort ();
318     }
319 }
320 \f
321 char *
322 xmalloc (size)
323      unsigned size;
324 {
325   register char *val = (char *) malloc (size);
326
327   if (val == 0)
328     fatal ("virtual memory exhausted");
329   return val;
330 }
331
332 char *
333 xrealloc (ptr, size)
334      char *ptr;
335      unsigned size;
336 {
337   char *result = (char *) realloc (ptr, size);
338   if (!result)
339     fatal ("virtual memory exhausted");
340   return result;
341 }
342
343 static void
344 fatal (s, a1, a2)
345      char *s;
346 {
347   fprintf (stderr, "genextract: ");
348   fprintf (stderr, s, a1, a2);
349   fprintf (stderr, "\n");
350   exit (FATAL_EXIT_CODE);
351 }
352
353 /* More 'friendly' abort that prints the line and file.
354    config.h can #define abort fancy_abort if you like that sort of thing.  */
355
356 void
357 fancy_abort ()
358 {
359   fatal ("Internal gcc abort.");
360 }
361
362 static char *
363 copystr (s1)
364      char *s1;
365 {
366   register char *tem;
367
368   if (s1 == 0)
369     return 0;
370
371   tem = (char *) xmalloc (strlen (s1) + 1);
372   strcpy (tem, s1);
373
374   return tem;
375 }
376
377 static void
378 mybzero (b, length)
379      register char *b;
380      register unsigned length;
381 {
382   while (length-- > 0)
383     *b++ = 0;
384 }
385 \f
386 int
387 main (argc, argv)
388      int argc;
389      char **argv;
390 {
391   rtx desc;
392   FILE *infile;
393   extern rtx read_rtx ();
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 ("  int insn_code = INSN_CODE (insn);\n");
440   printf ("  insn = PATTERN (insn);\n");
441   printf ("  switch (insn_code)\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 (insn, 0, 0), ro,\n");
492       printf ("             sizeof (rtx) * XVECLEN (insn, 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 }