OSDN Git Service

2004-09-22 Frank Ch. Eigler <fche@redhat.com>
[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, 1999, 2000, 2003, 2004
3    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 (rtx);
99 static void walk_rtx (rtx, const char *);
100 static void print_path (const char *);
101 static void record_insn_name (int, const char *);
102
103 static void
104 gen_insn (rtx insn)
105 {
106   int i;
107   struct extraction *p;
108   struct code_ptr *link;
109
110   op_count = 0;
111   dup_count = 0;
112
113   /* No operands seen so far in this pattern.  */
114   memset (oplocs, 0, sizeof oplocs);
115
116   /* Walk the insn's pattern, remembering at all times the path
117      down to the walking point.  */
118
119   if (XVECLEN (insn, 1) == 1)
120     walk_rtx (XVECEXP (insn, 1, 0), "");
121   else
122     for (i = XVECLEN (insn, 1) - 1; i >= 0; i--)
123       {
124         char path[2];
125
126         path[0] = 'a' + i;
127         path[1] = 0;
128
129         walk_rtx (XVECEXP (insn, 1, i), path);
130       }
131
132   link = xmalloc (sizeof (struct code_ptr));
133   link->insn_code = insn_code_number;
134
135   /* See if we find something that already had this extraction method.  */
136
137   for (p = extractions; p; p = p->next)
138     {
139       if (p->op_count != op_count || p->dup_count != dup_count)
140         continue;
141
142       for (i = 0; i < op_count; i++)
143         if (p->oplocs[i] != oplocs[i]
144             && ! (p->oplocs[i] != 0 && oplocs[i] != 0
145                   && ! strcmp (p->oplocs[i], oplocs[i])))
146           break;
147
148       if (i != op_count)
149         continue;
150
151       for (i = 0; i < dup_count; i++)
152         if (p->dupnums[i] != dupnums[i]
153             || strcmp (p->duplocs[i], duplocs[i]))
154           break;
155
156       if (i != dup_count)
157         continue;
158
159       /* This extraction is the same as ours.  Just link us in.  */
160       link->next = p->insns;
161       p->insns = link;
162       return;
163     }
164
165   /* Otherwise, make a new extraction method.  */
166
167   p = xmalloc (sizeof (struct extraction));
168   p->op_count = op_count;
169   p->dup_count = dup_count;
170   p->next = extractions;
171   extractions = p;
172   p->insns = link;
173   link->next = 0;
174
175   for (i = 0; i < op_count; i++)
176     p->oplocs[i] = oplocs[i];
177
178   for (i = 0; i < dup_count; i++)
179     p->dupnums[i] = dupnums[i], p->duplocs[i] = duplocs[i];
180 }
181 \f
182 static void
183 walk_rtx (rtx x, const char *path)
184 {
185   RTX_CODE code;
186   int i;
187   int len;
188   const char *fmt;
189   int depth = strlen (path);
190   char *newpath;
191
192   if (x == 0)
193     return;
194
195   code = GET_CODE (x);
196
197   switch (code)
198     {
199     case PC:
200     case CC0:
201     case CONST_INT:
202     case SYMBOL_REF:
203       return;
204
205     case MATCH_OPERAND:
206     case MATCH_SCRATCH:
207       oplocs[XINT (x, 0)] = xstrdup (path);
208       op_count = MAX (op_count, XINT (x, 0) + 1);
209       break;
210
211     case MATCH_DUP:
212       duplocs[dup_count] = xstrdup (path);
213       dupnums[dup_count] = XINT (x, 0);
214       dup_count++;
215       break;
216
217     case MATCH_PAR_DUP:
218     case MATCH_OP_DUP:
219       duplocs[dup_count] = xstrdup (path);
220       dupnums[dup_count] = XINT (x, 0);
221       dup_count++;
222
223       newpath = xmalloc (depth + 2);
224       strcpy (newpath, path);
225       newpath[depth + 1] = 0;
226
227       for (i = XVECLEN (x, 1) - 1; i >= 0; i--)
228         {
229           newpath[depth] = (code == MATCH_OP_DUP ? '0' : 'a') + i;
230           walk_rtx (XVECEXP (x, 1, i), newpath);
231         }
232       free (newpath);
233       return;
234
235     case MATCH_OPERATOR:
236       oplocs[XINT (x, 0)] = xstrdup (path);
237       op_count = MAX (op_count, XINT (x, 0) + 1);
238
239       newpath = xmalloc (depth + 2);
240       strcpy (newpath, path);
241       newpath[depth + 1] = 0;
242
243       for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
244         {
245           newpath[depth] = '0' + i;
246           walk_rtx (XVECEXP (x, 2, i), newpath);
247         }
248       free (newpath);
249       return;
250
251     case MATCH_PARALLEL:
252       oplocs[XINT (x, 0)] = xstrdup (path);
253       op_count = MAX (op_count, XINT (x, 0) + 1);
254
255       newpath = xmalloc (depth + 2);
256       strcpy (newpath, path);
257       newpath[depth + 1] = 0;
258
259       for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
260         {
261           newpath[depth] = 'a' + i;
262           walk_rtx (XVECEXP (x, 2, i), newpath);
263         }
264       free (newpath);
265       return;
266
267     case ADDRESS:
268       walk_rtx (XEXP (x, 0), path);
269       return;
270
271     default:
272       break;
273     }
274
275   newpath = xmalloc (depth + 2);
276   strcpy (newpath, path);
277   newpath[depth + 1] = 0;
278
279   fmt = GET_RTX_FORMAT (code);
280   len = GET_RTX_LENGTH (code);
281   for (i = 0; i < len; i++)
282     {
283       if (fmt[i] == 'e' || fmt[i] == 'u')
284         {
285           newpath[depth] = '0' + i;
286           walk_rtx (XEXP (x, i), newpath);
287         }
288       else if (fmt[i] == 'E')
289         {
290           int j;
291           for (j = XVECLEN (x, i) - 1; j >= 0; j--)
292             {
293               newpath[depth] = 'a' + j;
294               walk_rtx (XVECEXP (x, i, j), newpath);
295             }
296         }
297     }
298   free (newpath);
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 (const char *path)
307 {
308   int len = strlen (path);
309   int i;
310
311   if (len == 0)
312     {
313       /* Don't emit "pat", since we may try to take the address of it,
314          which isn't what is intended.  */
315       printf("PATTERN (insn)");
316       return;
317     }
318
319   /* We first write out the operations (XEXP or XVECEXP) in reverse
320      order, then write "insn", then the indices in forward order.  */
321
322   for (i = len - 1; i >= 0 ; i--)
323     {
324       if (ISLOWER(path[i]))
325         printf ("XVECEXP (");
326       else if (ISDIGIT(path[i]))
327         printf ("XEXP (");
328       else
329         gcc_unreachable ();
330     }
331
332   printf ("pat");
333
334   for (i = 0; i < len; i++)
335     {
336       if (ISLOWER(path[i]))
337         printf (", 0, %d)", path[i] - 'a');
338       else if (ISDIGIT(path[i]))
339         printf (", %d)", path[i] - '0');
340       else
341         gcc_unreachable ();
342     }
343 }
344 \f
345
346 int
347 main (int argc, char **argv)
348 {
349   rtx desc;
350   int i;
351   struct extraction *p;
352   struct code_ptr *link;
353   const char *name;
354
355   progname = "genextract";
356
357   if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
358     return (FATAL_EXIT_CODE);
359
360   /* Assign sequential codes to all entries in the machine description
361      in parallel with the tables in insn-output.c.  */
362
363   insn_code_number = 0;
364
365   printf ("/* Generated automatically by the program `genextract'\n\
366 from the machine description file `md'.  */\n\n");
367
368   printf ("#include \"config.h\"\n");
369   printf ("#include \"system.h\"\n");
370   printf ("#include \"coretypes.h\"\n");
371   printf ("#include \"tm.h\"\n");
372   printf ("#include \"rtl.h\"\n");
373   printf ("#include \"insn-config.h\"\n");
374   printf ("#include \"recog.h\"\n");
375   printf ("#include \"toplev.h\"\n\n");
376
377   /* This variable exists only so it can be the "location"
378      of any missing operand whose numbers are skipped by a given pattern.  */
379   printf ("static rtx junk ATTRIBUTE_UNUSED;\n");
380
381   printf ("void\ninsn_extract (rtx insn)\n");
382   printf ("{\n");
383   printf ("  rtx *ro = recog_data.operand;\n");
384   printf ("  rtx **ro_loc = recog_data.operand_loc;\n");
385   printf ("  rtx pat = PATTERN (insn);\n");
386   printf ("  int i ATTRIBUTE_UNUSED;\n\n");
387 #ifdef ENABLE_CHECKING
388   printf ("  memset (ro, 0xab, sizeof (*ro) * MAX_RECOG_OPERANDS);\n");
389   printf ("  memset (ro_loc, 0xab, sizeof (*ro_loc) * MAX_RECOG_OPERANDS);\n");
390 #endif
391   printf ("  switch (INSN_CODE (insn))\n");
392   printf ("    {\n");
393   printf ("    case -1:\n");
394   printf ("      fatal_insn_not_found (insn);\n\n");
395
396   /* Read the machine description.  */
397
398   while (1)
399     {
400       int line_no;
401
402       desc = read_md_rtx (&line_no, &insn_code_number);
403       if (desc == NULL)
404         break;
405
406        if (GET_CODE (desc) == DEFINE_INSN)
407         {
408           record_insn_name (insn_code_number, XSTR (desc, 0));
409           gen_insn (desc);
410         }
411
412       else if (GET_CODE (desc) == DEFINE_PEEPHOLE)
413         {
414           struct code_ptr *link = xmalloc (sizeof (struct code_ptr));
415
416           link->insn_code = insn_code_number;
417           link->next = peepholes;
418           peepholes = link;
419         }
420     }
421
422   /* Write out code to handle peepholes and the insn_codes that it should
423      be called for.  */
424   if (peepholes)
425     {
426       for (link = peepholes; link; link = link->next)
427         printf ("    case %d:\n", link->insn_code);
428
429       /* The vector in the insn says how many operands it has.
430          And all it contains are operands.  In fact, the vector was
431          created just for the sake of this function.  We need to set the
432          location of the operands for sake of simplifications after
433          extraction, like eliminating subregs.  */
434       printf ("      for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n");
435       printf ("          ro[i] = *(ro_loc[i] = &XVECEXP (pat, 0, i));\n");
436       printf ("      break;\n\n");
437     }
438
439   /* Write out all the ways to extract insn operands.  */
440   for (p = extractions; p; p = p->next)
441     {
442       for (link = p->insns; link; link = link->next)
443         {
444           i = link->insn_code;
445           name = get_insn_name (i);
446           if (name)
447             printf ("    case %d:  /* %s */\n", i, name);
448           else
449             printf ("    case %d:\n", i);
450         }
451
452       for (i = 0; i < p->op_count; i++)
453         {
454           if (p->oplocs[i] == 0)
455             {
456               printf ("      ro[%d] = const0_rtx;\n", i);
457               printf ("      ro_loc[%d] = &junk;\n", i);
458             }
459           else
460             {
461               printf ("      ro[%d] = *(ro_loc[%d] = &", i, i);
462               print_path (p->oplocs[i]);
463               printf (");\n");
464             }
465         }
466
467       for (i = 0; i < p->dup_count; i++)
468         {
469           printf ("      recog_data.dup_loc[%d] = &", i);
470           print_path (p->duplocs[i]);
471           printf (";\n");
472           printf ("      recog_data.dup_num[%d] = %d;\n", i, p->dupnums[i]);
473         }
474
475       printf ("      break;\n\n");
476     }
477
478   /* This should never be reached.  Note that we would also reach this abort
479    if we tried to extract something whose INSN_CODE was a DEFINE_EXPAND or
480    DEFINE_SPLIT, but that is correct.  */
481   printf ("    default:\n      gcc_unreachable ();\n");
482
483   printf ("    }\n}\n");
484
485   fflush (stdout);
486   return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
487 }
488
489 /* Define this so we can link with print-rtl.o to get debug_rtx function.  */
490 const char *
491 get_insn_name (int code ATTRIBUTE_UNUSED)
492 {
493   if (code < insn_name_ptr_size)
494     return insn_name_ptr[code];
495   else
496     return NULL;
497 }
498
499 static void
500 record_insn_name (int code, const char *name)
501 {
502   static const char *last_real_name = "insn";
503   static int last_real_code = 0;
504   char *new;
505
506   if (insn_name_ptr_size <= code)
507     {
508       int new_size;
509       new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512);
510       insn_name_ptr = xrealloc (insn_name_ptr, sizeof(char *) * new_size);
511       memset (insn_name_ptr + insn_name_ptr_size, 0,
512               sizeof(char *) * (new_size - insn_name_ptr_size));
513       insn_name_ptr_size = new_size;
514     }
515
516   if (!name || name[0] == '\0')
517     {
518       new = xmalloc (strlen (last_real_name) + 10);
519       sprintf (new, "%s+%d", last_real_name, code - last_real_code);
520     }
521   else
522     {
523       last_real_name = new = xstrdup (name);
524       last_real_code = code;
525     }
526
527   insn_name_ptr[code] = new;
528 }