Merge from vendor branch READLINE:
[dragonfly.git] / contrib / gcc-3.4 / 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
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         abort ();
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         abort ();
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 (argc <= 1)
358     fatal ("no input file name");
359
360   if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
361     return (FATAL_EXIT_CODE);
362
363   /* Assign sequential codes to all entries in the machine description
364      in parallel with the tables in insn-output.c.  */
365
366   insn_code_number = 0;
367
368   printf ("/* Generated automatically by the program `genextract'\n\
369 from the machine description file `md'.  */\n\n");
370
371   printf ("#include \"config.h\"\n");
372   printf ("#include \"system.h\"\n");
373   printf ("#include \"coretypes.h\"\n");
374   printf ("#include \"tm.h\"\n");
375   printf ("#include \"rtl.h\"\n");
376   printf ("#include \"insn-config.h\"\n");
377   printf ("#include \"recog.h\"\n");
378   printf ("#include \"toplev.h\"\n\n");
379
380   /* This variable exists only so it can be the "location"
381      of any missing operand whose numbers are skipped by a given pattern.  */
382   printf ("static rtx junk ATTRIBUTE_UNUSED;\n");
383
384   printf ("void\ninsn_extract (rtx insn)\n");
385   printf ("{\n");
386   printf ("  rtx *ro = recog_data.operand;\n");
387   printf ("  rtx **ro_loc = recog_data.operand_loc;\n");
388   printf ("  rtx pat = PATTERN (insn);\n");
389   printf ("  int i ATTRIBUTE_UNUSED;\n\n");
390 #ifdef ENABLE_CHECKING
391   printf ("  memset (ro, 0xab, sizeof (*ro) * MAX_RECOG_OPERANDS);\n");
392   printf ("  memset (ro_loc, 0xab, sizeof (*ro_loc) * MAX_RECOG_OPERANDS);\n");
393 #endif
394   printf ("  switch (INSN_CODE (insn))\n");
395   printf ("    {\n");
396   printf ("    case -1:\n");
397   printf ("      fatal_insn_not_found (insn);\n\n");
398
399   /* Read the machine description.  */
400
401   while (1)
402     {
403       int line_no;
404
405       desc = read_md_rtx (&line_no, &insn_code_number);
406       if (desc == NULL)
407         break;
408
409        if (GET_CODE (desc) == DEFINE_INSN)
410         {
411           record_insn_name (insn_code_number, XSTR (desc, 0));
412           gen_insn (desc);
413         }
414
415       else if (GET_CODE (desc) == DEFINE_PEEPHOLE)
416         {
417           struct code_ptr *link = xmalloc (sizeof (struct code_ptr));
418
419           link->insn_code = insn_code_number;
420           link->next = peepholes;
421           peepholes = link;
422         }
423     }
424
425   /* Write out code to handle peepholes and the insn_codes that it should
426      be called for.  */
427   if (peepholes)
428     {
429       for (link = peepholes; link; link = link->next)
430         printf ("    case %d:\n", link->insn_code);
431
432       /* The vector in the insn says how many operands it has.
433          And all it contains are operands.  In fact, the vector was
434          created just for the sake of this function.  We need to set the
435          location of the operands for sake of simplifications after
436          extraction, like eliminating subregs.  */
437       printf ("      for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n");
438       printf ("          ro[i] = *(ro_loc[i] = &XVECEXP (pat, 0, i));\n");
439       printf ("      break;\n\n");
440     }
441
442   /* Write out all the ways to extract insn operands.  */
443   for (p = extractions; p; p = p->next)
444     {
445       for (link = p->insns; link; link = link->next)
446         {
447           i = link->insn_code;
448           name = get_insn_name (i);
449           if (name)
450             printf ("    case %d:  /* %s */\n", i, name);
451           else
452             printf ("    case %d:\n", i);
453         }
454
455       for (i = 0; i < p->op_count; i++)
456         {
457           if (p->oplocs[i] == 0)
458             {
459               printf ("      ro[%d] = const0_rtx;\n", i);
460               printf ("      ro_loc[%d] = &junk;\n", i);
461             }
462           else
463             {
464               printf ("      ro[%d] = *(ro_loc[%d] = &", i, i);
465               print_path (p->oplocs[i]);
466               printf (");\n");
467             }
468         }
469
470       for (i = 0; i < p->dup_count; i++)
471         {
472           printf ("      recog_data.dup_loc[%d] = &", i);
473           print_path (p->duplocs[i]);
474           printf (";\n");
475           printf ("      recog_data.dup_num[%d] = %d;\n", i, p->dupnums[i]);
476         }
477
478       printf ("      break;\n\n");
479     }
480
481   /* This should never be reached.  Note that we would also reach this abort
482    if we tried to extract something whose INSN_CODE was a DEFINE_EXPAND or
483    DEFINE_SPLIT, but that is correct.  */
484   printf ("    default:\n      abort ();\n");
485
486   printf ("    }\n}\n");
487
488   fflush (stdout);
489   return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
490 }
491
492 /* Define this so we can link with print-rtl.o to get debug_rtx function.  */
493 const char *
494 get_insn_name (int code ATTRIBUTE_UNUSED)
495 {
496   if (code < insn_name_ptr_size)
497     return insn_name_ptr[code];
498   else
499     return NULL;
500 }
501
502 static void
503 record_insn_name (int code, const char *name)
504 {
505   static const char *last_real_name = "insn";
506   static int last_real_code = 0;
507   char *new;
508
509   if (insn_name_ptr_size <= code)
510     {
511       int new_size;
512       new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512);
513       insn_name_ptr = xrealloc (insn_name_ptr, sizeof(char *) * new_size);
514       memset (insn_name_ptr + insn_name_ptr_size, 0,
515               sizeof(char *) * (new_size - insn_name_ptr_size));
516       insn_name_ptr_size = new_size;
517     }
518
519   if (!name || name[0] == '\0')
520     {
521       new = xmalloc (strlen (last_real_name) + 10);
522       sprintf (new, "%s+%d", last_real_name, code - last_real_code);
523     }
524   else
525     {
526       last_real_name = new = xstrdup (name);
527       last_real_code = code;
528     }
529
530   insn_name_ptr[code] = new;
531 }