OSDN Git Service

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