genextract.c revision 50397
1/* Generate code from machine description to extract operands from insn as rtl.
2   Copyright (C) 1987, 91, 92, 93, 97, 1998 Free Software Foundation, Inc.
3
4This file is part of GNU CC.
5
6GNU CC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU CC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU CC; see the file COPYING.  If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA.  */
20
21
22#include "hconfig.h"
23#ifdef __STDC__
24#include <stdarg.h>
25#else
26#include <varargs.h>
27#endif
28#include "system.h"
29#include "rtl.h"
30#include "obstack.h"
31#include "insn-config.h"
32
33static struct obstack obstack;
34struct obstack *rtl_obstack = &obstack;
35
36#define obstack_chunk_alloc xmalloc
37#define obstack_chunk_free free
38
39/* Names for patterns.  Need to allow linking with print-rtl.  */
40char **insn_name_ptr;
41
42/* This structure contains all the information needed to describe one
43   set of extractions methods.  Each method may be used by more than
44   one pattern if the operands are in the same place.
45
46   The string for each operand describes that path to the operand and
47   contains `0' through `9' when going into an expression and `a' through
48   `z' when going into a vector.  We assume here that only the first operand
49   of an rtl expression is a vector.  genrecog.c makes the same assumption
50   (and uses the same representation) and it is currently true.  */
51
52struct extraction
53{
54  int op_count;
55  char *oplocs[MAX_RECOG_OPERANDS];
56  int dup_count;
57  char *duplocs[MAX_DUP_OPERANDS];
58  int dupnums[MAX_DUP_OPERANDS];
59  struct code_ptr *insns;
60  struct extraction *next;
61};
62
63/* Holds a single insn code that use an extraction method.  */
64
65struct code_ptr
66{
67  int insn_code;
68  struct code_ptr *next;
69};
70
71static struct extraction *extractions;
72
73/* Number instruction patterns handled, starting at 0 for first one.  */
74
75static int insn_code_number;
76
77/* Records the large operand number in this insn.  */
78
79static int op_count;
80
81/* Records the location of any operands using the string format described
82   above.  */
83
84static char *oplocs[MAX_RECOG_OPERANDS];
85
86/* Number the occurrences of MATCH_DUP in each instruction,
87   starting at 0 for the first occurrence.  */
88
89static int dup_count;
90
91/* Records the location of any MATCH_DUP operands.  */
92
93static char *duplocs[MAX_DUP_OPERANDS];
94
95/* Record the operand number of any MATCH_DUPs.  */
96
97static int dupnums[MAX_DUP_OPERANDS];
98
99/* Record the list of insn_codes for peepholes.  */
100
101static struct code_ptr *peepholes;
102
103static void gen_insn PROTO ((rtx));
104static void walk_rtx PROTO ((rtx, char *));
105static void print_path PROTO ((char *));
106char *xmalloc PROTO ((unsigned));
107char *xrealloc PROTO ((char *, unsigned));
108static void fatal PVPROTO ((char *, ...)) ATTRIBUTE_PRINTF_1;
109static char *copystr PROTO ((char *));
110static void mybzero ();
111void fancy_abort PROTO ((void));
112
113static void
114gen_insn (insn)
115     rtx insn;
116{
117  register int i;
118  register struct extraction *p;
119  register struct code_ptr *link;
120
121  op_count = 0;
122  dup_count = 0;
123
124  /* No operands seen so far in this pattern.  */
125  mybzero (oplocs, sizeof oplocs);
126
127  /* Walk the insn's pattern, remembering at all times the path
128     down to the walking point.  */
129
130  if (XVECLEN (insn, 1) == 1)
131    walk_rtx (XVECEXP (insn, 1, 0), "");
132  else
133    for (i = XVECLEN (insn, 1) - 1; i >= 0; i--)
134      {
135	char *path = (char *) alloca (2);
136
137	path[0] = 'a' + i;
138	path[1] = 0;
139
140	walk_rtx (XVECEXP (insn, 1, i), path);
141      }
142
143  link = (struct code_ptr *) xmalloc (sizeof (struct code_ptr));
144  link->insn_code = insn_code_number;
145
146  /* See if we find something that already had this extraction method.  */
147
148  for (p = extractions; p; p = p->next)
149    {
150      if (p->op_count != op_count || p->dup_count != dup_count)
151	continue;
152
153      for (i = 0; i < op_count; i++)
154	if (p->oplocs[i] != oplocs[i]
155	    && ! (p->oplocs[i] != 0 && oplocs[i] != 0
156		  && ! strcmp (p->oplocs[i], oplocs[i])))
157	  break;
158
159      if (i != op_count)
160	continue;
161
162      for (i = 0; i < dup_count; i++)
163	if (p->dupnums[i] != dupnums[i]
164	    || strcmp (p->duplocs[i], duplocs[i]))
165	  break;
166
167      if (i != dup_count)
168	continue;
169
170      /* This extraction is the same as ours.  Just link us in.  */
171      link->next = p->insns;
172      p->insns = link;
173      return;
174    }
175
176  /* Otherwise, make a new extraction method.  */
177
178  p = (struct extraction *) xmalloc (sizeof (struct extraction));
179  p->op_count = op_count;
180  p->dup_count = dup_count;
181  p->next = extractions;
182  extractions = p;
183  p->insns = link;
184  link->next = 0;
185
186  for (i = 0; i < op_count; i++)
187    p->oplocs[i] = oplocs[i];
188
189  for (i = 0; i < dup_count; i++)
190    p->dupnums[i] = dupnums[i], p->duplocs[i] = duplocs[i];
191}
192
193static void
194walk_rtx (x, path)
195     rtx x;
196     char *path;
197{
198  register RTX_CODE code;
199  register int i;
200  register int len;
201  register char *fmt;
202  int depth = strlen (path);
203  char *newpath;
204
205  if (x == 0)
206    return;
207
208  code = GET_CODE (x);
209
210  switch (code)
211    {
212    case PC:
213    case CC0:
214    case CONST_INT:
215    case SYMBOL_REF:
216      return;
217
218    case MATCH_OPERAND:
219    case MATCH_SCRATCH:
220      oplocs[XINT (x, 0)] = copystr (path);
221      op_count = MAX (op_count, XINT (x, 0) + 1);
222      break;
223
224    case MATCH_DUP:
225    case MATCH_PAR_DUP:
226      duplocs[dup_count] = copystr (path);
227      dupnums[dup_count] = XINT (x, 0);
228      dup_count++;
229      break;
230
231    case MATCH_OP_DUP:
232      duplocs[dup_count] = copystr (path);
233      dupnums[dup_count] = XINT (x, 0);
234      dup_count++;
235
236      newpath = (char *) alloca (depth + 2);
237      strcpy (newpath, path);
238      newpath[depth + 1] = 0;
239
240      for (i = XVECLEN (x, 1) - 1; i >= 0; i--)
241        {
242	  newpath[depth] = '0' + i;
243	  walk_rtx (XVECEXP (x, 1, i), newpath);
244        }
245      return;
246
247    case MATCH_OPERATOR:
248      oplocs[XINT (x, 0)] = copystr (path);
249      op_count = MAX (op_count, XINT (x, 0) + 1);
250
251      newpath = (char *) alloca (depth + 2);
252      strcpy (newpath, path);
253      newpath[depth + 1] = 0;
254
255      for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
256	{
257	  newpath[depth] = '0' + i;
258	  walk_rtx (XVECEXP (x, 2, i), newpath);
259	}
260      return;
261
262    case MATCH_PARALLEL:
263      oplocs[XINT (x, 0)] = copystr (path);
264      op_count = MAX (op_count, XINT (x, 0) + 1);
265
266      newpath = (char *) alloca (depth + 2);
267      strcpy (newpath, path);
268      newpath[depth + 1] = 0;
269
270      for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
271	{
272	  newpath[depth] = 'a' + i;
273	  walk_rtx (XVECEXP (x, 2, i), newpath);
274	}
275      return;
276
277    case ADDRESS:
278      walk_rtx (XEXP (x, 0), path);
279      return;
280
281    default:
282      break;
283    }
284
285  newpath = (char *) alloca (depth + 2);
286  strcpy (newpath, path);
287  newpath[depth + 1] = 0;
288
289  fmt = GET_RTX_FORMAT (code);
290  len = GET_RTX_LENGTH (code);
291  for (i = 0; i < len; i++)
292    {
293      if (fmt[i] == 'e' || fmt[i] == 'u')
294	{
295	  newpath[depth] = '0' + i;
296	  walk_rtx (XEXP (x, i), newpath);
297	}
298      else if (fmt[i] == 'E')
299	{
300	  int j;
301	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
302	    {
303	      newpath[depth] = 'a' + j;
304	      walk_rtx (XVECEXP (x, i, j), newpath);
305	    }
306	}
307    }
308}
309
310/* Given a PATH, representing a path down the instruction's
311   pattern from the root to a certain point, output code to
312   evaluate to the rtx at that point.  */
313
314static void
315print_path (path)
316     char *path;
317{
318  register int len = strlen (path);
319  register int i;
320
321  if (len == 0)
322    {
323      /* Don't emit "pat", since we may try to take the address of it,
324	 which isn't what is intended.  */
325      printf("PATTERN (insn)");
326      return;
327    }
328
329  /* We first write out the operations (XEXP or XVECEXP) in reverse
330     order, then write "insn", then the indices in forward order.  */
331
332  for (i = len - 1; i >=0 ; i--)
333    {
334      if (path[i] >= 'a' && path[i] <= 'z')
335	printf ("XVECEXP (");
336      else if (path[i] >= '0' && path[i] <= '9')
337	printf ("XEXP (");
338      else
339	abort ();
340    }
341
342  printf ("pat");
343
344  for (i = 0; i < len; i++)
345    {
346      if (path[i] >= 'a' && path[i] <= 'z')
347	printf (", 0, %d)", path[i] - 'a');
348      else if (path[i] >= '0' && path[i] <= '9')
349	printf (", %d)", path[i] - '0');
350      else
351	abort ();
352    }
353}
354
355char *
356xmalloc (size)
357     unsigned size;
358{
359  register char *val = (char *) malloc (size);
360
361  if (val == 0)
362    fatal ("virtual memory exhausted");
363  return val;
364}
365
366char *
367xrealloc (ptr, size)
368     char *ptr;
369     unsigned size;
370{
371  char *result = (char *) realloc (ptr, size);
372  if (!result)
373    fatal ("virtual memory exhausted");
374  return result;
375}
376
377static void
378fatal VPROTO ((char *format, ...))
379{
380#ifndef __STDC__
381  char *format;
382#endif
383  va_list ap;
384
385  VA_START (ap, format);
386
387#ifndef __STDC__
388  format = va_arg (ap, char *);
389#endif
390
391  fprintf (stderr, "genextract: ");
392  vfprintf (stderr, format, ap);
393  va_end (ap);
394  fprintf (stderr, "\n");
395  exit (FATAL_EXIT_CODE);
396}
397
398/* More 'friendly' abort that prints the line and file.
399   config.h can #define abort fancy_abort if you like that sort of thing.  */
400
401void
402fancy_abort ()
403{
404  fatal ("Internal gcc abort.");
405}
406
407static char *
408copystr (s1)
409     char *s1;
410{
411  register char *tem;
412
413  if (s1 == 0)
414    return 0;
415
416  tem = (char *) xmalloc (strlen (s1) + 1);
417  strcpy (tem, s1);
418
419  return tem;
420}
421
422static void
423mybzero (b, length)
424     register char *b;
425     register unsigned length;
426{
427  while (length-- > 0)
428    *b++ = 0;
429}
430
431int
432main (argc, argv)
433     int argc;
434     char **argv;
435{
436  rtx desc;
437  FILE *infile;
438  register int c, i;
439  struct extraction *p;
440  struct code_ptr *link;
441
442  obstack_init (rtl_obstack);
443
444  if (argc <= 1)
445    fatal ("No input file name.");
446
447  infile = fopen (argv[1], "r");
448  if (infile == 0)
449    {
450      perror (argv[1]);
451      exit (FATAL_EXIT_CODE);
452    }
453
454  init_rtl ();
455
456  /* Assign sequential codes to all entries in the machine description
457     in parallel with the tables in insn-output.c.  */
458
459  insn_code_number = 0;
460
461  printf ("/* Generated automatically by the program `genextract'\n\
462from the machine description file `md'.  */\n\n");
463
464  printf ("#include \"config.h\"\n");
465  printf ("#include \"system.h\"\n");
466  printf ("#include \"rtl.h\"\n\n");
467
468  /* This variable exists only so it can be the "location"
469     of any missing operand whose numbers are skipped by a given pattern.  */
470  printf ("static rtx junk ATTRIBUTE_UNUSED;\n");
471
472  printf ("extern rtx recog_operand[];\n");
473  printf ("extern rtx *recog_operand_loc[];\n");
474  printf ("extern rtx *recog_dup_loc[];\n");
475  printf ("extern char recog_dup_num[];\n");
476
477  printf ("void\ninsn_extract (insn)\n");
478  printf ("     rtx insn;\n");
479  printf ("{\n");
480  printf ("  register rtx *ro = recog_operand;\n");
481  printf ("  register rtx **ro_loc = recog_operand_loc;\n");
482  printf ("  rtx pat = PATTERN (insn);\n");
483  printf ("  int i ATTRIBUTE_UNUSED;\n\n");
484  printf ("  switch (INSN_CODE (insn))\n");
485  printf ("    {\n");
486  printf ("    case -1:\n");
487  printf ("      fatal_insn_not_found (insn);\n\n");
488
489  /* Read the machine description.  */
490
491  while (1)
492    {
493      c = read_skip_spaces (infile);
494      if (c == EOF)
495	break;
496      ungetc (c, infile);
497
498      desc = read_rtx (infile);
499      if (GET_CODE (desc) == DEFINE_INSN)
500	{
501	  gen_insn (desc);
502	  ++insn_code_number;
503	}
504
505      else if (GET_CODE (desc) == DEFINE_PEEPHOLE)
506	{
507	  struct code_ptr *link
508	    = (struct code_ptr *) xmalloc (sizeof (struct code_ptr));
509
510	  link->insn_code = insn_code_number;
511	  link->next = peepholes;
512	  peepholes = link;
513	  ++insn_code_number;
514	}
515
516      else if (GET_CODE (desc) == DEFINE_EXPAND
517	       || GET_CODE (desc) == DEFINE_SPLIT)
518	++insn_code_number;
519    }
520
521  /* Write out code to handle peepholes and the insn_codes that it should
522     be called for.  */
523  if (peepholes)
524    {
525      for (link = peepholes; link; link = link->next)
526	printf ("    case %d:\n", link->insn_code);
527
528      /* The vector in the insn says how many operands it has.
529	 And all it contains are operands.  In fact, the vector was
530	 created just for the sake of this function.  */
531      printf ("      for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n");
532      printf ("          ro[i] = XVECEXP (pat, 0, i);\n");
533      printf ("      break;\n\n");
534    }
535
536  /* Write out all the ways to extract insn operands.  */
537  for (p = extractions; p; p = p->next)
538    {
539      for (link = p->insns; link; link = link->next)
540	printf ("    case %d:\n", link->insn_code);
541
542      for (i = 0; i < p->op_count; i++)
543	{
544	  if (p->oplocs[i] == 0)
545	    {
546	      printf ("      ro[%d] = const0_rtx;\n", i);
547	      printf ("      ro_loc[%d] = &junk;\n", i);
548	    }
549	  else
550	    {
551	      printf ("      ro[%d] = *(ro_loc[%d] = &", i, i);
552	      print_path (p->oplocs[i]);
553	      printf (");\n");
554	    }
555	}
556
557      for (i = 0; i < p->dup_count; i++)
558	{
559	  printf ("      recog_dup_loc[%d] = &", i);
560	  print_path (p->duplocs[i]);
561	  printf (";\n");
562	  printf ("      recog_dup_num[%d] = %d;\n", i, p->dupnums[i]);
563	}
564
565      printf ("      break;\n\n");
566    }
567
568  /* This should never be reached.  Note that we would also reach this abort
569   if we tried to extract something whose INSN_CODE was a DEFINE_EXPAND or
570   DEFINE_SPLIT, but that is correct.  */
571  printf ("    default:\n      abort ();\n");
572
573  printf ("    }\n}\n");
574
575  fflush (stdout);
576  exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
577  /* NOTREACHED */
578  return 0;
579}
580