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