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   2004, 2005
4   Free Software Foundation, Inc.
5
6This file is part of GCC.
7
8GCC is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
10Software Foundation; either version 2, or (at your option) any later
11version.
12
13GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16for more details.
17
18You should have received a copy of the GNU General Public License
19along with GCC; see the file COPYING.  If not, write to the Free
20Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
2102110-1301, USA.  */
22
23
24#include "bconfig.h"
25#include "system.h"
26#include "coretypes.h"
27#include "tm.h"
28#include "rtl.h"
29#include "errors.h"
30#include "insn-config.h"
31#include "gensupport.h"
32
33
34/* This structure contains all the information needed to describe one
35   set of extractions methods.  Each method may be used by more than
36   one pattern if the operands are in the same place.
37
38   The string for each operand describes that path to the operand and
39   contains `0' through `9' when going into an expression and `a' through
40   `z' when going into a vector.  We assume here that only the first operand
41   of an rtl expression is a vector.  genrecog.c makes the same assumption
42   (and uses the same representation) and it is currently true.  */
43
44struct extraction
45{
46  int op_count;
47  char *oplocs[MAX_RECOG_OPERANDS];
48  int dup_count;
49  char *duplocs[MAX_DUP_OPERANDS];
50  int dupnums[MAX_DUP_OPERANDS];
51  struct code_ptr *insns;
52  struct extraction *next;
53};
54
55/* Holds a single insn code that use an extraction method.  */
56
57struct code_ptr
58{
59  int insn_code;
60  struct code_ptr *next;
61};
62
63static struct extraction *extractions;
64
65/* Holds an array of names indexed by insn_code_number.  */
66static char **insn_name_ptr = 0;
67static int insn_name_ptr_size = 0;
68
69/* Number instruction patterns handled, starting at 0 for first one.  */
70
71static int insn_code_number;
72
73/* Records the large operand number in this insn.  */
74
75static int op_count;
76
77/* Records the location of any operands using the string format described
78   above.  */
79
80static char *oplocs[MAX_RECOG_OPERANDS];
81
82/* Number the occurrences of MATCH_DUP in each instruction,
83   starting at 0 for the first occurrence.  */
84
85static int dup_count;
86
87/* Records the location of any MATCH_DUP operands.  */
88
89static char *duplocs[MAX_DUP_OPERANDS];
90
91/* Record the operand number of any MATCH_DUPs.  */
92
93static int dupnums[MAX_DUP_OPERANDS];
94
95/* Record the list of insn_codes for peepholes.  */
96
97static struct code_ptr *peepholes;
98
99static void gen_insn (rtx);
100static void walk_rtx (rtx, const char *);
101static void print_path (const char *);
102static void record_insn_name (int, const char *);
103
104static void
105gen_insn (rtx insn)
106{
107  int i;
108  struct extraction *p;
109  struct code_ptr *link;
110
111  op_count = 0;
112  dup_count = 0;
113
114  /* No operands seen so far in this pattern.  */
115  memset (oplocs, 0, sizeof oplocs);
116
117  /* Walk the insn's pattern, remembering at all times the path
118     down to the walking point.  */
119
120  if (XVECLEN (insn, 1) == 1)
121    walk_rtx (XVECEXP (insn, 1, 0), "");
122  else
123    for (i = XVECLEN (insn, 1) - 1; i >= 0; i--)
124      {
125	char path[2];
126
127	path[0] = 'a' + i;
128	path[1] = 0;
129
130	walk_rtx (XVECEXP (insn, 1, i), path);
131      }
132
133  link = xmalloc (sizeof (struct code_ptr));
134  link->insn_code = insn_code_number;
135
136  /* See if we find something that already had this extraction method.  */
137
138  for (p = extractions; p; p = p->next)
139    {
140      if (p->op_count != op_count || p->dup_count != dup_count)
141	continue;
142
143      for (i = 0; i < op_count; i++)
144	if (p->oplocs[i] != oplocs[i]
145	    && ! (p->oplocs[i] != 0 && oplocs[i] != 0
146		  && ! strcmp (p->oplocs[i], oplocs[i])))
147	  break;
148
149      if (i != op_count)
150	continue;
151
152      for (i = 0; i < dup_count; i++)
153	if (p->dupnums[i] != dupnums[i]
154	    || strcmp (p->duplocs[i], duplocs[i]))
155	  break;
156
157      if (i != dup_count)
158	continue;
159
160      /* This extraction is the same as ours.  Just link us in.  */
161      link->next = p->insns;
162      p->insns = link;
163      return;
164    }
165
166  /* Otherwise, make a new extraction method.  */
167
168  p = xmalloc (sizeof (struct extraction));
169  p->op_count = op_count;
170  p->dup_count = dup_count;
171  p->next = extractions;
172  extractions = p;
173  p->insns = link;
174  link->next = 0;
175
176  for (i = 0; i < op_count; i++)
177    p->oplocs[i] = oplocs[i];
178
179  for (i = 0; i < dup_count; i++)
180    p->dupnums[i] = dupnums[i], p->duplocs[i] = duplocs[i];
181}
182
183static void
184walk_rtx (rtx x, 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 = 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 = 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 = 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 = 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
306static void
307print_path (const char *path)
308{
309  int len = strlen (path);
310  int i;
311
312  if (len == 0)
313    {
314      /* Don't emit "pat", since we may try to take the address of it,
315	 which isn't what is intended.  */
316      printf("PATTERN (insn)");
317      return;
318    }
319
320  /* We first write out the operations (XEXP or XVECEXP) in reverse
321     order, then write "insn", then the indices in forward order.  */
322
323  for (i = len - 1; i >= 0 ; i--)
324    {
325      if (ISLOWER(path[i]))
326	printf ("XVECEXP (");
327      else if (ISDIGIT(path[i]))
328	printf ("XEXP (");
329      else
330	gcc_unreachable ();
331    }
332
333  printf ("pat");
334
335  for (i = 0; i < len; i++)
336    {
337      if (ISLOWER(path[i]))
338	printf (", 0, %d)", path[i] - 'a');
339      else if (ISDIGIT(path[i]))
340	printf (", %d)", path[i] - '0');
341      else
342	gcc_unreachable ();
343    }
344}
345
346
347int
348main (int argc, char **argv)
349{
350  rtx desc;
351  int i;
352  struct extraction *p;
353  struct code_ptr *link;
354  const char *name;
355
356  progname = "genextract";
357
358  if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
359    return (FATAL_EXIT_CODE);
360
361  /* Assign sequential codes to all entries in the machine description
362     in parallel with the tables in insn-output.c.  */
363
364  insn_code_number = 0;
365
366  printf ("/* Generated automatically by the program `genextract'\n\
367from the machine description file `md'.  */\n\n");
368
369  printf ("#include \"config.h\"\n");
370  printf ("#include \"system.h\"\n");
371  printf ("#include \"coretypes.h\"\n");
372  printf ("#include \"tm.h\"\n");
373  printf ("#include \"rtl.h\"\n");
374  printf ("#include \"insn-config.h\"\n");
375  printf ("#include \"recog.h\"\n");
376  printf ("#include \"toplev.h\"\n\n");
377
378  /* This variable exists only so it can be the "location"
379     of any missing operand whose numbers are skipped by a given pattern.  */
380  printf ("static rtx junk ATTRIBUTE_UNUSED;\n");
381
382  printf ("void\ninsn_extract (rtx insn)\n");
383  printf ("{\n");
384  printf ("  rtx *ro = recog_data.operand;\n");
385  printf ("  rtx **ro_loc = recog_data.operand_loc;\n");
386  printf ("  rtx pat = PATTERN (insn);\n");
387  printf ("  int i ATTRIBUTE_UNUSED;\n\n");
388#ifdef ENABLE_CHECKING
389  printf ("  memset (ro, 0xab, sizeof (*ro) * MAX_RECOG_OPERANDS);\n");
390  printf ("  memset (ro_loc, 0xab, sizeof (*ro_loc) * MAX_RECOG_OPERANDS);\n");
391#endif
392  printf ("  switch (INSN_CODE (insn))\n");
393  printf ("    {\n");
394  printf ("    case -1:\n");
395  printf ("      fatal_insn_not_found (insn);\n\n");
396
397  /* Read the machine description.  */
398
399  while (1)
400    {
401      int line_no;
402
403      desc = read_md_rtx (&line_no, &insn_code_number);
404      if (desc == NULL)
405	break;
406
407       if (GET_CODE (desc) == DEFINE_INSN)
408	{
409	  record_insn_name (insn_code_number, XSTR (desc, 0));
410	  gen_insn (desc);
411	}
412
413      else if (GET_CODE (desc) == DEFINE_PEEPHOLE)
414	{
415	  struct code_ptr *link = xmalloc (sizeof (struct code_ptr));
416
417	  link->insn_code = insn_code_number;
418	  link->next = peepholes;
419	  peepholes = link;
420	}
421    }
422
423  /* Write out code to handle peepholes and the insn_codes that it should
424     be called for.  */
425  if (peepholes)
426    {
427      for (link = peepholes; link; link = link->next)
428	printf ("    case %d:\n", link->insn_code);
429
430      /* The vector in the insn says how many operands it has.
431	 And all it contains are operands.  In fact, the vector was
432	 created just for the sake of this function.  We need to set the
433	 location of the operands for sake of simplifications after
434	 extraction, like eliminating subregs.  */
435      printf ("      for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n");
436      printf ("          ro[i] = *(ro_loc[i] = &XVECEXP (pat, 0, i));\n");
437      printf ("      break;\n\n");
438    }
439
440  /* Write out all the ways to extract insn operands.  */
441  for (p = extractions; p; p = p->next)
442    {
443      for (link = p->insns; link; link = link->next)
444	{
445	  i = link->insn_code;
446	  name = get_insn_name (i);
447	  if (name)
448	    printf ("    case %d:  /* %s */\n", i, name);
449	  else
450	    printf ("    case %d:\n", i);
451	}
452
453      for (i = 0; i < p->op_count; i++)
454	{
455	  if (p->oplocs[i] == 0)
456	    {
457	      printf ("      ro[%d] = const0_rtx;\n", i);
458	      printf ("      ro_loc[%d] = &junk;\n", i);
459	    }
460	  else
461	    {
462	      printf ("      ro[%d] = *(ro_loc[%d] = &", i, i);
463	      print_path (p->oplocs[i]);
464	      printf (");\n");
465	    }
466	}
467
468      for (i = 0; i < p->dup_count; i++)
469	{
470	  printf ("      recog_data.dup_loc[%d] = &", i);
471	  print_path (p->duplocs[i]);
472	  printf (";\n");
473	  printf ("      recog_data.dup_num[%d] = %d;\n", i, p->dupnums[i]);
474	}
475
476      printf ("      break;\n\n");
477    }
478
479  /* This should never be reached.  Note that we would also reach here
480     if we tried to extract something whose INSN_CODE was a
481     DEFINE_EXPAND or DEFINE_SPLIT, but that is correct.  */
482  printf ("    default:\n      gcc_unreachable ();\n");
483
484  printf ("    }\n}\n");
485
486  fflush (stdout);
487  return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
488}
489
490/* Define this so we can link with print-rtl.o to get debug_rtx function.  */
491const char *
492get_insn_name (int code ATTRIBUTE_UNUSED)
493{
494  if (code < insn_name_ptr_size)
495    return insn_name_ptr[code];
496  else
497    return NULL;
498}
499
500static void
501record_insn_name (int code, const char *name)
502{
503  static const char *last_real_name = "insn";
504  static int last_real_code = 0;
505  char *new;
506
507  if (insn_name_ptr_size <= code)
508    {
509      int new_size;
510      new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512);
511      insn_name_ptr = xrealloc (insn_name_ptr, sizeof(char *) * new_size);
512      memset (insn_name_ptr + insn_name_ptr_size, 0,
513	      sizeof(char *) * (new_size - insn_name_ptr_size));
514      insn_name_ptr_size = new_size;
515    }
516
517  if (!name || name[0] == '\0')
518    {
519      new = xmalloc (strlen (last_real_name) + 10);
520      sprintf (new, "%s+%d", last_real_name, code - last_real_code);
521    }
522  else
523    {
524      last_real_name = new = xstrdup (name);
525      last_real_code = code;
526    }
527
528  insn_name_ptr[code] = new;
529}
530