OSDN Git Service

* extend.texi (-fthis-is-variable): Undocument.
[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, 1993, 1997, 1998,
3    1999, 2000 Free Software Foundation, Inc.
4
5 This file is part of GNU CC.
6
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING.  If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22
23 #include "hconfig.h"
24 #include "system.h"
25 #include "rtl.h"
26 #include "obstack.h"
27 #include "errors.h"
28 #include "insn-config.h"
29
30 static struct obstack obstack;
31 struct obstack *rtl_obstack = &obstack;
32
33 #define obstack_chunk_alloc xmalloc
34 #define obstack_chunk_free free
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 /* Holds an array of names indexed by insn_code_number.  */
68 static char **insn_name_ptr = 0;
69 static int insn_name_ptr_size = 0;
70
71 /* Number instruction patterns handled, starting at 0 for first one.  */
72
73 static int insn_code_number;
74
75 /* Records the large operand number in this insn.  */
76
77 static int op_count;
78
79 /* Records the location of any operands using the string format described
80    above.  */
81
82 static char *oplocs[MAX_RECOG_OPERANDS];
83
84 /* Number the occurrences of MATCH_DUP in each instruction,
85    starting at 0 for the first occurrence.  */
86
87 static int dup_count;
88
89 /* Records the location of any MATCH_DUP operands.  */
90
91 static char *duplocs[MAX_DUP_OPERANDS];
92
93 /* Record the operand number of any MATCH_DUPs.  */
94
95 static int dupnums[MAX_DUP_OPERANDS];
96
97 /* Record the list of insn_codes for peepholes.  */
98
99 static struct code_ptr *peepholes;
100
101 static void gen_insn PARAMS ((rtx));
102 static void walk_rtx PARAMS ((rtx, const char *));
103 static void print_path PARAMS ((const char *));
104 static void record_insn_name PARAMS ((int, const char *));
105
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   memset (oplocs, 0, 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      const char *path;
190 {
191   register RTX_CODE code;
192   register int i;
193   register int len;
194   register const char *fmt;
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)] = xstrdup (path);
214       op_count = MAX (op_count, XINT (x, 0) + 1);
215       break;
216
217     case MATCH_DUP:
218     case MATCH_PAR_DUP:
219       duplocs[dup_count] = xstrdup (path);
220       dupnums[dup_count] = XINT (x, 0);
221       dup_count++;
222       break;
223
224     case MATCH_OP_DUP:
225       duplocs[dup_count] = xstrdup (path);
226       dupnums[dup_count] = XINT (x, 0);
227       dup_count++;
228       
229       newpath = (char *) alloca (depth + 2);
230       strcpy (newpath, path);
231       newpath[depth + 1] = 0;
232       
233       for (i = XVECLEN (x, 1) - 1; i >= 0; i--)
234         {
235           newpath[depth] = '0' + i;
236           walk_rtx (XVECEXP (x, 1, i), newpath);
237         }
238       return;
239       
240     case MATCH_OPERATOR:
241       oplocs[XINT (x, 0)] = xstrdup (path);
242       op_count = MAX (op_count, XINT (x, 0) + 1);
243
244       newpath = (char *) alloca (depth + 2);
245       strcpy (newpath, path);
246       newpath[depth + 1] = 0;
247
248       for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
249         {
250           newpath[depth] = '0' + i;
251           walk_rtx (XVECEXP (x, 2, i), newpath);
252         }
253       return;
254
255     case MATCH_PARALLEL:
256       oplocs[XINT (x, 0)] = xstrdup (path);
257       op_count = MAX (op_count, XINT (x, 0) + 1);
258
259       newpath = (char *) alloca (depth + 2);
260       strcpy (newpath, path);
261       newpath[depth + 1] = 0;
262
263       for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
264         {
265           newpath[depth] = 'a' + i;
266           walk_rtx (XVECEXP (x, 2, i), newpath);
267         }
268       return;
269
270     case ADDRESS:
271       walk_rtx (XEXP (x, 0), path);
272       return;
273
274     default:
275       break;
276     }
277
278   newpath = (char *) alloca (depth + 2);
279   strcpy (newpath, path);
280   newpath[depth + 1] = 0;
281
282   fmt = GET_RTX_FORMAT (code);
283   len = GET_RTX_LENGTH (code);
284   for (i = 0; i < len; i++)
285     {
286       if (fmt[i] == 'e' || fmt[i] == 'u')
287         {
288           newpath[depth] = '0' + i;
289           walk_rtx (XEXP (x, i), newpath);
290         }
291       else if (fmt[i] == 'E')
292         {
293           int j;
294           for (j = XVECLEN (x, i) - 1; j >= 0; j--)
295             {
296               newpath[depth] = 'a' + j;
297               walk_rtx (XVECEXP (x, i, j), newpath);
298             }
299         }
300     }
301 }
302
303 /* Given a PATH, representing a path down the instruction's
304    pattern from the root to a certain point, output code to
305    evaluate to the rtx at that point.  */
306
307 static void
308 print_path (path)
309      const char *path;
310 {
311   register int len = strlen (path);
312   register int i;
313
314   if (len == 0)
315     {
316       /* Don't emit "pat", since we may try to take the address of it,
317          which isn't what is intended.  */
318       printf("PATTERN (insn)");
319       return;
320     }
321
322   /* We first write out the operations (XEXP or XVECEXP) in reverse
323      order, then write "insn", then the indices in forward order.  */
324
325   for (i = len - 1; i >=0 ; i--)
326     {
327       if (ISLOWER(path[i]))
328         printf ("XVECEXP (");
329       else if (ISDIGIT(path[i]))
330         printf ("XEXP (");
331       else
332         abort ();
333     }
334   
335   printf ("pat");
336
337   for (i = 0; i < len; i++)
338     {
339       if (ISLOWER(path[i]))
340         printf (", 0, %d)", path[i] - 'a');
341       else if (ISDIGIT(path[i]))
342         printf (", %d)", path[i] - '0');
343       else
344         abort ();
345     }
346 }
347 \f
348 PTR
349 xmalloc (size)
350   size_t size;
351 {
352   register PTR val = (PTR) malloc (size);
353
354   if (val == 0)
355     fatal ("virtual memory exhausted");
356   return val;
357 }
358
359 PTR
360 xrealloc (old, size)
361   PTR old;
362   size_t size;
363 {
364   register PTR ptr;
365   if (old)
366     ptr = (PTR) realloc (old, size);
367   else
368     ptr = (PTR) malloc (size);
369   if (!ptr)
370     fatal ("virtual memory exhausted");
371   return ptr;
372 }
373
374 char *
375 xstrdup (input)
376   const char *input;
377 {
378   register size_t len = strlen (input) + 1;
379   register char *output = xmalloc (len);
380   memcpy (output, input, len);
381   return output;
382 }
383 \f
384 extern int main PARAMS ((int, char **));
385
386 int
387 main (argc, argv)
388      int argc;
389      char **argv;
390 {
391   rtx desc;
392   FILE *infile;
393   int c, i;
394   struct extraction *p;
395   struct code_ptr *link;
396   const char *name;
397
398   progname = "genextract";
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       return (FATAL_EXIT_CODE);
409     }
410   read_rtx_filename = argv[1];
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 \"system.h\"\n");
422   printf ("#include \"rtl.h\"\n");
423   printf ("#include \"insn-config.h\"\n");
424   printf ("#include \"recog.h\"\n");
425   printf ("#include \"toplev.h\"\n\n");
426
427   /* This variable exists only so it can be the "location"
428      of any missing operand whose numbers are skipped by a given pattern.  */
429   printf ("static rtx junk ATTRIBUTE_UNUSED;\n");
430
431   printf ("void\ninsn_extract (insn)\n");
432   printf ("     rtx insn;\n");
433   printf ("{\n");
434   printf ("  register rtx *ro = recog_data.operand;\n");
435   printf ("  register rtx **ro_loc = recog_data.operand_loc;\n");
436   printf ("  rtx pat = PATTERN (insn);\n");
437   printf ("  int i ATTRIBUTE_UNUSED;\n\n");
438   printf ("  memset (ro, 0, sizeof (*ro) * MAX_RECOG_OPERANDS);\n");
439   printf ("  memset (ro_loc, 0, sizeof (*ro_loc) * MAX_RECOG_OPERANDS);\n");
440   printf ("  switch (INSN_CODE (insn))\n");
441   printf ("    {\n");
442   printf ("    case -1:\n");
443   printf ("      fatal_insn_not_found (insn);\n\n");
444
445   /* Read the machine description.  */
446
447   while (1)
448     {
449       c = read_skip_spaces (infile);
450       if (c == EOF)
451         break;
452       ungetc (c, infile);
453
454       desc = read_rtx (infile);
455       if (GET_CODE (desc) == DEFINE_INSN)
456         {
457           record_insn_name (insn_code_number, XSTR (desc, 0));
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_PEEPHOLE2
475                || GET_CODE (desc) == DEFINE_SPLIT)
476         ++insn_code_number;
477     }
478
479   /* Write out code to handle peepholes and the insn_codes that it should
480      be called for.  */
481   if (peepholes)
482     {
483       for (link = peepholes; link; link = link->next)
484         printf ("    case %d:\n", link->insn_code);
485
486       /* The vector in the insn says how many operands it has.
487          And all it contains are operands.  In fact, the vector was
488          created just for the sake of this function.  */
489       printf ("      for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n");
490       printf ("          ro[i] = XVECEXP (pat, 0, i);\n");
491       printf ("      break;\n\n");
492     }
493
494   /* Write out all the ways to extract insn operands.  */
495   for (p = extractions; p; p = p->next)
496     {
497       for (link = p->insns; link; link = link->next)
498         {
499           i = link->insn_code;
500           name = get_insn_name (i);
501           if (name)
502             printf ("    case %d:  /* %s */\n", i, name);
503           else
504             printf ("    case %d:\n", i);
505         }
506       
507       for (i = 0; i < p->op_count; i++)
508         {
509           if (p->oplocs[i] == 0)
510             {
511               printf ("      ro[%d] = const0_rtx;\n", i);
512               printf ("      ro_loc[%d] = &junk;\n", i);
513             }
514           else
515             {
516               printf ("      ro[%d] = *(ro_loc[%d] = &", i, i);
517               print_path (p->oplocs[i]);
518               printf (");\n");
519             }
520         }
521
522       for (i = 0; i < p->dup_count; i++)
523         {
524           printf ("      recog_data.dup_loc[%d] = &", i);
525           print_path (p->duplocs[i]);
526           printf (";\n");
527           printf ("      recog_data.dup_num[%d] = %d;\n", i, p->dupnums[i]);
528         }
529
530       printf ("      break;\n\n");
531     }
532
533   /* This should never be reached.  Note that we would also reach this abort
534    if we tried to extract something whose INSN_CODE was a DEFINE_EXPAND or
535    DEFINE_SPLIT, but that is correct.  */
536   printf ("    default:\n      abort ();\n");
537
538   printf ("    }\n}\n");
539
540   fflush (stdout);
541   return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
542 }
543
544 /* Define this so we can link with print-rtl.o to get debug_rtx function.  */
545 const char *
546 get_insn_name (code)
547      int code ATTRIBUTE_UNUSED;
548 {
549   if (code < insn_name_ptr_size)
550     return insn_name_ptr[code];
551   else
552     return NULL;
553 }
554
555 static void
556 record_insn_name (code, name)
557      int code;
558      const char *name;
559 {
560   static const char *last_real_name = "insn";
561   static int last_real_code = 0;
562   char *new;
563
564   if (insn_name_ptr_size <= code)
565     {
566       int new_size;
567       new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512);
568       insn_name_ptr =
569         (char **) xrealloc (insn_name_ptr, sizeof(char *) * new_size);
570       memset (insn_name_ptr + insn_name_ptr_size, 0, 
571               sizeof(char *) * (new_size - insn_name_ptr_size));
572       insn_name_ptr_size = new_size;
573     }
574
575   if (!name || name[0] == '\0')
576     {
577       new = xmalloc (strlen (last_real_name) + 10);
578       sprintf (new, "%s+%d", last_real_name, code - last_real_code);
579     }
580   else
581     {
582       last_real_name = new = xstrdup (name);
583       last_real_code = code;
584     }
585   
586   insn_name_ptr[code] = new;
587 }