OSDN Git Service

* g++.dg/pch/pch.exp: Make testcase names longer.
[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 GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING.  If not, write to the Free
19 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.  */
21
22
23 #include "bconfig.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tm.h"
27 #include "rtl.h"
28 #include "errors.h"
29 #include "insn-config.h"
30 #include "gensupport.h"
31
32
33 /* This structure contains all the information needed to describe one
34    set of extractions methods.  Each method may be used by more than 
35    one pattern if the operands are in the same place.
36
37    The string for each operand describes that path to the operand and
38    contains `0' through `9' when going into an expression and `a' through
39    `z' when going into a vector.  We assume here that only the first operand
40    of an rtl expression is a vector.  genrecog.c makes the same assumption
41    (and uses the same representation) and it is currently true.  */
42
43 struct extraction
44 {
45   int op_count;
46   char *oplocs[MAX_RECOG_OPERANDS];
47   int dup_count;
48   char *duplocs[MAX_DUP_OPERANDS];
49   int dupnums[MAX_DUP_OPERANDS];
50   struct code_ptr *insns;
51   struct extraction *next;
52 };
53
54 /* Holds a single insn code that use an extraction method.  */
55
56 struct code_ptr
57 {
58   int insn_code;
59   struct code_ptr *next;
60 };
61
62 static struct extraction *extractions;
63
64 /* Holds an array of names indexed by insn_code_number.  */
65 static char **insn_name_ptr = 0;
66 static int insn_name_ptr_size = 0;
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 PARAMS ((rtx));
99 static void walk_rtx PARAMS ((rtx, const char *));
100 static void print_path PARAMS ((const char *));
101 static void record_insn_name PARAMS ((int, const char *));
102
103 static void
104 gen_insn (insn)
105      rtx insn;
106 {
107   int i;
108   struct extraction *p;
109   struct code_ptr *link;
110
111   op_count = 0;
112   dup_count = 0;
113
114   /* No operands seen so far in this pattern.  */
115   memset (oplocs, 0, sizeof oplocs);
116
117   /* Walk the insn's pattern, remembering at all times the path
118      down to the walking point.  */
119
120   if (XVECLEN (insn, 1) == 1)
121     walk_rtx (XVECEXP (insn, 1, 0), "");
122   else
123     for (i = XVECLEN (insn, 1) - 1; i >= 0; i--)
124       {
125         char path[2];
126
127         path[0] = 'a' + i;
128         path[1] = 0;
129
130         walk_rtx (XVECEXP (insn, 1, i), path);
131       }
132
133   link = (struct code_ptr *) xmalloc (sizeof (struct code_ptr));
134   link->insn_code = insn_code_number;
135
136   /* See if we find something that already had this extraction method.  */
137
138   for (p = extractions; p; p = p->next)
139     {
140       if (p->op_count != op_count || p->dup_count != dup_count)
141         continue;
142
143       for (i = 0; i < op_count; i++)
144         if (p->oplocs[i] != oplocs[i]
145             && ! (p->oplocs[i] != 0 && oplocs[i] != 0
146                   && ! strcmp (p->oplocs[i], oplocs[i])))
147           break;
148
149       if (i != op_count)
150         continue;
151
152       for (i = 0; i < dup_count; i++)
153         if (p->dupnums[i] != dupnums[i]
154             || strcmp (p->duplocs[i], duplocs[i]))
155           break;
156
157       if (i != dup_count)
158         continue;
159
160       /* This extraction is the same as ours.  Just link us in.  */
161       link->next = p->insns;
162       p->insns = link;
163       return;
164     }
165
166   /* Otherwise, make a new extraction method.  */
167
168   p = (struct extraction *) xmalloc (sizeof (struct extraction));
169   p->op_count = op_count;
170   p->dup_count = dup_count;
171   p->next = extractions;
172   extractions = p;
173   p->insns = link;
174   link->next = 0;
175
176   for (i = 0; i < op_count; i++)
177     p->oplocs[i] = oplocs[i];
178
179   for (i = 0; i < dup_count; i++)
180     p->dupnums[i] = dupnums[i], p->duplocs[i] = duplocs[i];
181 }
182 \f
183 static void
184 walk_rtx (x, path)
185      rtx x;
186      const char *path;
187 {
188   RTX_CODE code;
189   int i;
190   int len;
191   const char *fmt;
192   int depth = strlen (path);
193   char *newpath;
194
195   if (x == 0)
196     return;
197
198   code = GET_CODE (x);
199
200   switch (code)
201     {
202     case PC:
203     case CC0:
204     case CONST_INT:
205     case SYMBOL_REF:
206       return;
207
208     case MATCH_OPERAND:
209     case MATCH_SCRATCH:
210       oplocs[XINT (x, 0)] = xstrdup (path);
211       op_count = MAX (op_count, XINT (x, 0) + 1);
212       break;
213
214     case MATCH_DUP:
215       duplocs[dup_count] = xstrdup (path);
216       dupnums[dup_count] = XINT (x, 0);
217       dup_count++;
218       break;
219
220     case MATCH_PAR_DUP:
221     case MATCH_OP_DUP:
222       duplocs[dup_count] = xstrdup (path);
223       dupnums[dup_count] = XINT (x, 0);
224       dup_count++;
225       
226       newpath = (char *) xmalloc (depth + 2);
227       strcpy (newpath, path);
228       newpath[depth + 1] = 0;
229       
230       for (i = XVECLEN (x, 1) - 1; i >= 0; i--)
231         {
232           newpath[depth] = (code == MATCH_OP_DUP ? '0' : 'a') + i;
233           walk_rtx (XVECEXP (x, 1, i), newpath);
234         }
235       free (newpath);
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 *) xmalloc (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       free (newpath);
252       return;
253
254     case MATCH_PARALLEL:
255       oplocs[XINT (x, 0)] = xstrdup (path);
256       op_count = MAX (op_count, XINT (x, 0) + 1);
257
258       newpath = (char *) xmalloc (depth + 2);
259       strcpy (newpath, path);
260       newpath[depth + 1] = 0;
261
262       for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
263         {
264           newpath[depth] = 'a' + i;
265           walk_rtx (XVECEXP (x, 2, i), newpath);
266         }
267       free (newpath);
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 *) xmalloc (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   free (newpath);
302 }
303
304 /* Given a PATH, representing a path down the instruction's
305    pattern from the root to a certain point, output code to
306    evaluate to the rtx at that point.  */
307
308 static void
309 print_path (path)
310      const char *path;
311 {
312   int len = strlen (path);
313   int i;
314
315   if (len == 0)
316     {
317       /* Don't emit "pat", since we may try to take the address of it,
318          which isn't what is intended.  */
319       printf("PATTERN (insn)");
320       return;
321     }
322
323   /* We first write out the operations (XEXP or XVECEXP) in reverse
324      order, then write "insn", then the indices in forward order.  */
325
326   for (i = len - 1; i >= 0 ; i--)
327     {
328       if (ISLOWER(path[i]))
329         printf ("XVECEXP (");
330       else if (ISDIGIT(path[i]))
331         printf ("XEXP (");
332       else
333         abort ();
334     }
335   
336   printf ("pat");
337
338   for (i = 0; i < len; i++)
339     {
340       if (ISLOWER(path[i]))
341         printf (", 0, %d)", path[i] - 'a');
342       else if (ISDIGIT(path[i]))
343         printf (", %d)", path[i] - '0');
344       else
345         abort ();
346     }
347 }
348 \f
349 extern int main PARAMS ((int, char **));
350
351 int
352 main (argc, argv)
353      int argc;
354      char **argv;
355 {
356   rtx desc;
357   int i;
358   struct extraction *p;
359   struct code_ptr *link;
360   const char *name;
361
362   progname = "genextract";
363
364   if (argc <= 1)
365     fatal ("no input file name");
366
367   if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
368     return (FATAL_EXIT_CODE);
369
370   /* Assign sequential codes to all entries in the machine description
371      in parallel with the tables in insn-output.c.  */
372
373   insn_code_number = 0;
374
375   printf ("/* Generated automatically by the program `genextract'\n\
376 from the machine description file `md'.  */\n\n");
377
378   printf ("#include \"config.h\"\n");
379   printf ("#include \"system.h\"\n");
380   printf ("#include \"coretypes.h\"\n");
381   printf ("#include \"tm.h\"\n");
382   printf ("#include \"rtl.h\"\n");
383   printf ("#include \"insn-config.h\"\n");
384   printf ("#include \"recog.h\"\n");
385   printf ("#include \"toplev.h\"\n\n");
386
387   /* This variable exists only so it can be the "location"
388      of any missing operand whose numbers are skipped by a given pattern.  */
389   printf ("static rtx junk ATTRIBUTE_UNUSED;\n");
390
391   printf ("void\ninsn_extract (insn)\n");
392   printf ("     rtx insn;\n");
393   printf ("{\n");
394   printf ("  rtx *ro = recog_data.operand;\n");
395   printf ("  rtx **ro_loc = recog_data.operand_loc;\n");
396   printf ("  rtx pat = PATTERN (insn);\n");
397   printf ("  int i ATTRIBUTE_UNUSED;\n\n");
398   printf ("  memset (ro, 0, sizeof (*ro) * MAX_RECOG_OPERANDS);\n");
399   printf ("  memset (ro_loc, 0, sizeof (*ro_loc) * MAX_RECOG_OPERANDS);\n");
400   printf ("  switch (INSN_CODE (insn))\n");
401   printf ("    {\n");
402   printf ("    case -1:\n");
403   printf ("      fatal_insn_not_found (insn);\n\n");
404
405   /* Read the machine description.  */
406
407   while (1)
408     {
409       int line_no;
410
411       desc = read_md_rtx (&line_no, &insn_code_number);
412       if (desc == NULL)
413         break;
414
415        if (GET_CODE (desc) == DEFINE_INSN)
416         {
417           record_insn_name (insn_code_number, XSTR (desc, 0));
418           gen_insn (desc);
419         }
420
421       else if (GET_CODE (desc) == DEFINE_PEEPHOLE)
422         {
423           struct code_ptr *link
424             = (struct code_ptr *) xmalloc (sizeof (struct code_ptr));
425
426           link->insn_code = insn_code_number;
427           link->next = peepholes;
428           peepholes = link;
429         }
430     }
431
432   /* Write out code to handle peepholes and the insn_codes that it should
433      be called for.  */
434   if (peepholes)
435     {
436       for (link = peepholes; link; link = link->next)
437         printf ("    case %d:\n", link->insn_code);
438
439       /* The vector in the insn says how many operands it has.
440          And all it contains are operands.  In fact, the vector was
441          created just for the sake of this function.  We need to set the
442          location of the operands for sake of simplifications after
443          extraction, like eliminating subregs.  */
444       printf ("      for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n");
445       printf ("          ro[i] = *(ro_loc[i] = &XVECEXP (pat, 0, i));\n");
446       printf ("      break;\n\n");
447     }
448
449   /* Write out all the ways to extract insn operands.  */
450   for (p = extractions; p; p = p->next)
451     {
452       for (link = p->insns; link; link = link->next)
453         {
454           i = link->insn_code;
455           name = get_insn_name (i);
456           if (name)
457             printf ("    case %d:  /* %s */\n", i, name);
458           else
459             printf ("    case %d:\n", i);
460         }
461       
462       for (i = 0; i < p->op_count; i++)
463         {
464           if (p->oplocs[i] == 0)
465             {
466               printf ("      ro[%d] = const0_rtx;\n", i);
467               printf ("      ro_loc[%d] = &junk;\n", i);
468             }
469           else
470             {
471               printf ("      ro[%d] = *(ro_loc[%d] = &", i, i);
472               print_path (p->oplocs[i]);
473               printf (");\n");
474             }
475         }
476
477       for (i = 0; i < p->dup_count; i++)
478         {
479           printf ("      recog_data.dup_loc[%d] = &", i);
480           print_path (p->duplocs[i]);
481           printf (";\n");
482           printf ("      recog_data.dup_num[%d] = %d;\n", i, p->dupnums[i]);
483         }
484
485       printf ("      break;\n\n");
486     }
487
488   /* This should never be reached.  Note that we would also reach this abort
489    if we tried to extract something whose INSN_CODE was a DEFINE_EXPAND or
490    DEFINE_SPLIT, but that is correct.  */
491   printf ("    default:\n      abort ();\n");
492
493   printf ("    }\n}\n");
494
495   fflush (stdout);
496   return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
497 }
498
499 /* Define this so we can link with print-rtl.o to get debug_rtx function.  */
500 const char *
501 get_insn_name (code)
502      int code ATTRIBUTE_UNUSED;
503 {
504   if (code < insn_name_ptr_size)
505     return insn_name_ptr[code];
506   else
507     return NULL;
508 }
509
510 static void
511 record_insn_name (code, name)
512      int code;
513      const char *name;
514 {
515   static const char *last_real_name = "insn";
516   static int last_real_code = 0;
517   char *new;
518
519   if (insn_name_ptr_size <= code)
520     {
521       int new_size;
522       new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512);
523       insn_name_ptr =
524         (char **) xrealloc (insn_name_ptr, sizeof(char *) * new_size);
525       memset (insn_name_ptr + insn_name_ptr_size, 0, 
526               sizeof(char *) * (new_size - insn_name_ptr_size));
527       insn_name_ptr_size = new_size;
528     }
529
530   if (!name || name[0] == '\0')
531     {
532       new = xmalloc (strlen (last_real_name) + 10);
533       sprintf (new, "%s+%d", last_real_name, code - last_real_code);
534     }
535   else
536     {
537       last_real_name = new = xstrdup (name);
538       last_real_code = code;
539     }
540   
541   insn_name_ptr[code] = new;
542 }