118334Speter/* Generate code from machine description to extract operands from insn as rtl.
2169689Skan   Copyright (C) 1987, 1991, 1992, 1993, 1997, 1998, 1999, 2000, 2003,
3169689Skan   2004, 2005
4132718Skan   Free Software Foundation, Inc.
518334Speter
690075SobrienThis file is part of GCC.
718334Speter
890075SobrienGCC is free software; you can redistribute it and/or modify it under
990075Sobrienthe terms of the GNU General Public License as published by the Free
1090075SobrienSoftware Foundation; either version 2, or (at your option) any later
1190075Sobrienversion.
1218334Speter
1390075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1490075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1590075SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1690075Sobrienfor more details.
1718334Speter
1818334SpeterYou should have received a copy of the GNU General Public License
1990075Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
20169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
21169689Skan02110-1301, USA.  */
2218334Speter
2318334Speter
24132718Skan#include "bconfig.h"
2550397Sobrien#include "system.h"
26132718Skan#include "coretypes.h"
27132718Skan#include "tm.h"
2818334Speter#include "rtl.h"
2990075Sobrien#include "errors.h"
3090075Sobrien#include "gensupport.h"
31169689Skan#include "vec.h"
32169689Skan#include "vecprim.h"
3318334Speter
3418334Speter/* This structure contains all the information needed to describe one
35132718Skan   set of extractions methods.  Each method may be used by more than
3618334Speter   one pattern if the operands are in the same place.
3718334Speter
3818334Speter   The string for each operand describes that path to the operand and
3918334Speter   contains `0' through `9' when going into an expression and `a' through
4018334Speter   `z' when going into a vector.  We assume here that only the first operand
4118334Speter   of an rtl expression is a vector.  genrecog.c makes the same assumption
4218334Speter   (and uses the same representation) and it is currently true.  */
4318334Speter
44169689Skantypedef char *locstr;
45169689Skan
4618334Speterstruct extraction
4718334Speter{
48169689Skan  unsigned int op_count;
49169689Skan  unsigned int dup_count;
50169689Skan  locstr *oplocs;
51169689Skan  locstr *duplocs;
52169689Skan  int *dupnums;
5318334Speter  struct code_ptr *insns;
5418334Speter  struct extraction *next;
5518334Speter};
5618334Speter
57169689Skan/* Holds a single insn code that uses an extraction method.  */
5818334Speterstruct code_ptr
5918334Speter{
6018334Speter  int insn_code;
6118334Speter  struct code_ptr *next;
6218334Speter};
6318334Speter
64169689Skan/* All extractions needed for this machine description.  */
6518334Speterstatic struct extraction *extractions;
6618334Speter
67169689Skan/* All insn codes for old-style peepholes.  */
68169689Skanstatic struct code_ptr *peepholes;
6990075Sobrien
70169689Skan/* This structure is used by gen_insn and walk_rtx to accumulate the
71169689Skan   data that will be used to produce an extractions structure.  */
7218334Speter
73169689SkanDEF_VEC_P(locstr);
74169689SkanDEF_VEC_ALLOC_P(locstr,heap);
7518334Speter
76169689Skanstruct accum_extract
77169689Skan{
78169689Skan  VEC(locstr,heap) *oplocs;
79169689Skan  VEC(locstr,heap) *duplocs;
80169689Skan  VEC(int,heap)    *dupnums;
81169689Skan  VEC(char,heap)   *pathstr;
82169689Skan};
8318334Speter
84169689Skan/* Forward declarations.  */
85169689Skanstatic void walk_rtx (rtx, struct accum_extract *);
8618334Speter
8718334Speterstatic void
88169689Skangen_insn (rtx insn, int insn_code_number)
8918334Speter{
9090075Sobrien  int i;
91169689Skan  unsigned int op_count, dup_count, j;
9290075Sobrien  struct extraction *p;
9390075Sobrien  struct code_ptr *link;
94169689Skan  struct accum_extract acc;
9518334Speter
96169689Skan  acc.oplocs  = VEC_alloc (locstr,heap, 10);
97169689Skan  acc.duplocs = VEC_alloc (locstr,heap, 10);
98169689Skan  acc.dupnums = VEC_alloc (int,heap,    10);
99169689Skan  acc.pathstr = VEC_alloc (char,heap,   20);
10018334Speter
10118334Speter  /* Walk the insn's pattern, remembering at all times the path
10218334Speter     down to the walking point.  */
10318334Speter
10418334Speter  if (XVECLEN (insn, 1) == 1)
105169689Skan    walk_rtx (XVECEXP (insn, 1, 0), &acc);
10618334Speter  else
10718334Speter    for (i = XVECLEN (insn, 1) - 1; i >= 0; i--)
10818334Speter      {
109169689Skan	VEC_safe_push (char,heap, acc.pathstr, 'a' + i);
110169689Skan	walk_rtx (XVECEXP (insn, 1, i), &acc);
111169689Skan	VEC_pop (char, acc.pathstr);
11218334Speter      }
11318334Speter
114169689Skan  link = XNEW (struct code_ptr);
11518334Speter  link->insn_code = insn_code_number;
11618334Speter
11750397Sobrien  /* See if we find something that already had this extraction method.  */
11818334Speter
119169689Skan  op_count = VEC_length (locstr, acc.oplocs);
120169689Skan  dup_count = VEC_length (locstr, acc.duplocs);
121169689Skan  gcc_assert (dup_count == VEC_length (int, acc.dupnums));
122169689Skan
12318334Speter  for (p = extractions; p; p = p->next)
12418334Speter    {
12518334Speter      if (p->op_count != op_count || p->dup_count != dup_count)
12618334Speter	continue;
12718334Speter
128169689Skan      for (j = 0; j < op_count; j++)
129169689Skan	{
130169689Skan	  char *a = p->oplocs[j];
131169689Skan	  char *b = VEC_index (locstr, acc.oplocs, j);
132169689Skan	  if (a != b && (!a || !b || strcmp (a, b)))
133169689Skan	    break;
134169689Skan	}
13518334Speter
136169689Skan      if (j != op_count)
13718334Speter	continue;
13818334Speter
139169689Skan      for (j = 0; j < dup_count; j++)
140169689Skan	if (p->dupnums[j] != VEC_index (int, acc.dupnums, j)
141169689Skan	    || strcmp (p->duplocs[j], VEC_index (locstr, acc.duplocs, j)))
14218334Speter	  break;
14318334Speter
144169689Skan      if (j != dup_count)
14518334Speter	continue;
14618334Speter
14718334Speter      /* This extraction is the same as ours.  Just link us in.  */
14818334Speter      link->next = p->insns;
14918334Speter      p->insns = link;
150169689Skan      goto done;
15118334Speter    }
15218334Speter
153169689Skan  /* Otherwise, make a new extraction method.  We stash the arrays
154169689Skan     after the extraction structure in memory.  */
15518334Speter
156169689Skan  p = xmalloc (sizeof (struct extraction)
157169689Skan	       + op_count*sizeof (char *)
158169689Skan	       + dup_count*sizeof (char *)
159169689Skan	       + dup_count*sizeof (int));
16018334Speter  p->op_count = op_count;
16118334Speter  p->dup_count = dup_count;
16218334Speter  p->next = extractions;
16318334Speter  extractions = p;
16418334Speter  p->insns = link;
16518334Speter  link->next = 0;
16618334Speter
167169689Skan  p->oplocs = (char **)((char *)p + sizeof (struct extraction));
168169689Skan  p->duplocs = p->oplocs + op_count;
169169689Skan  p->dupnums = (int *)(p->duplocs + dup_count);
17018334Speter
171169689Skan  memcpy(p->oplocs,  VEC_address(locstr,acc.oplocs),   op_count*sizeof(locstr));
172169689Skan  memcpy(p->duplocs, VEC_address(locstr,acc.duplocs), dup_count*sizeof(locstr));
173169689Skan  memcpy(p->dupnums, VEC_address(int,   acc.dupnums), dup_count*sizeof(int));
174169689Skan
175169689Skan done:
176169689Skan  VEC_free (locstr,heap, acc.oplocs);
177169689Skan  VEC_free (locstr,heap, acc.duplocs);
178169689Skan  VEC_free (int,heap,    acc.dupnums);
179169689Skan  VEC_free (char,heap,   acc.pathstr);
18018334Speter}
18118334Speter
182169689Skan/* Helper subroutine of walk_rtx: given a VEC(locstr), an index, and a
183169689Skan   string, insert the string at the index, which should either already
184169689Skan   exist and be NULL, or not yet exist within the vector.  In the latter
185169689Skan   case the vector is enlarged as appropriate.  */
18618334Speterstatic void
187169689SkanVEC_safe_set_locstr (VEC(locstr,heap) **vp, unsigned int ix, char *str)
18818334Speter{
189169689Skan  if (ix < VEC_length (locstr, *vp))
190169689Skan    {
191169689Skan      gcc_assert (VEC_index (locstr, *vp, ix) == 0);
192169689Skan      VEC_replace (locstr, *vp, ix, str);
193169689Skan    }
194169689Skan  else
195169689Skan    {
196169689Skan      while (ix > VEC_length (locstr, *vp))
197169689Skan	VEC_safe_push (locstr, heap, *vp, 0);
198169689Skan      VEC_safe_push (locstr, heap, *vp, str);
199169689Skan    }
200169689Skan}
201169689Skan
202169689Skan/* Another helper subroutine of walk_rtx: given a VEC(char), convert it
203169689Skan   to a NUL-terminated string in malloc memory.  */
204169689Skanstatic char *
205169689SkanVEC_char_to_string (VEC(char,heap) *v)
206169689Skan{
207169689Skan  size_t n = VEC_length (char, v);
208169689Skan  char *s = XNEWVEC (char, n + 1);
209169689Skan  memcpy (s, VEC_address (char, v), n);
210169689Skan  s[n] = '\0';
211169689Skan  return s;
212169689Skan}
213169689Skan
214169689Skanstatic void
215169689Skanwalk_rtx (rtx x, struct accum_extract *acc)
216169689Skan{
21790075Sobrien  RTX_CODE code;
218169689Skan  int i, len, base;
21990075Sobrien  const char *fmt;
22018334Speter
22118334Speter  if (x == 0)
22218334Speter    return;
22318334Speter
22418334Speter  code = GET_CODE (x);
22518334Speter  switch (code)
22618334Speter    {
22718334Speter    case PC:
22818334Speter    case CC0:
22918334Speter    case CONST_INT:
23018334Speter    case SYMBOL_REF:
23118334Speter      return;
23218334Speter
23318334Speter    case MATCH_OPERAND:
23418334Speter    case MATCH_SCRATCH:
235169689Skan      VEC_safe_set_locstr (&acc->oplocs, XINT (x, 0),
236169689Skan			   VEC_char_to_string (acc->pathstr));
23718334Speter      break;
23818334Speter
239169689Skan    case MATCH_OPERATOR:
240169689Skan    case MATCH_PARALLEL:
241169689Skan      VEC_safe_set_locstr (&acc->oplocs, XINT (x, 0),
242169689Skan			   VEC_char_to_string (acc->pathstr));
243169689Skan
244169689Skan      base = (code == MATCH_OPERATOR ? '0' : 'a');
245169689Skan      for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
246169689Skan	{
247169689Skan	  VEC_safe_push (char,heap, acc->pathstr, base + i);
248169689Skan	  walk_rtx (XVECEXP (x, 2, i), acc);
249169689Skan	  VEC_pop (char, acc->pathstr);
250169689Skan        }
251169689Skan      return;
252169689Skan
25318334Speter    case MATCH_DUP:
25496263Sobrien    case MATCH_PAR_DUP:
25518334Speter    case MATCH_OP_DUP:
256169689Skan      VEC_safe_push (locstr,heap, acc->duplocs,
257169689Skan		     VEC_char_to_string (acc->pathstr));
258169689Skan      VEC_safe_push (int,heap, acc->dupnums, XINT (x, 0));
259132718Skan
260169689Skan      if (code == MATCH_DUP)
261169689Skan	break;
262132718Skan
263169689Skan      base = (code == MATCH_OP_DUP ? '0' : 'a');
26418334Speter      for (i = XVECLEN (x, 1) - 1; i >= 0; i--)
26518334Speter        {
266169689Skan	  VEC_safe_push (char,heap, acc->pathstr, base + i);
267169689Skan	  walk_rtx (XVECEXP (x, 1, i), acc);
268169689Skan	  VEC_pop (char, acc->pathstr);
26918334Speter        }
27018334Speter      return;
271132718Skan
27250397Sobrien    default:
27350397Sobrien      break;
27418334Speter    }
27518334Speter
27618334Speter  fmt = GET_RTX_FORMAT (code);
27718334Speter  len = GET_RTX_LENGTH (code);
27818334Speter  for (i = 0; i < len; i++)
27918334Speter    {
28018334Speter      if (fmt[i] == 'e' || fmt[i] == 'u')
28118334Speter	{
282169689Skan	  VEC_safe_push (char,heap, acc->pathstr, '0' + i);
283169689Skan	  walk_rtx (XEXP (x, i), acc);
284169689Skan	  VEC_pop (char, acc->pathstr);
28518334Speter	}
28618334Speter      else if (fmt[i] == 'E')
28718334Speter	{
28818334Speter	  int j;
28918334Speter	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
29018334Speter	    {
291169689Skan	      VEC_safe_push (char,heap, acc->pathstr, 'a' + j);
292169689Skan	      walk_rtx (XVECEXP (x, i, j), acc);
293169689Skan	      VEC_pop (char, acc->pathstr);
29418334Speter	    }
29518334Speter	}
29618334Speter    }
29718334Speter}
29818334Speter
29918334Speter/* Given a PATH, representing a path down the instruction's
30018334Speter   pattern from the root to a certain point, output code to
30118334Speter   evaluate to the rtx at that point.  */
30218334Speter
30318334Speterstatic void
304132718Skanprint_path (const char *path)
30518334Speter{
30690075Sobrien  int len = strlen (path);
30790075Sobrien  int i;
30818334Speter
30950397Sobrien  if (len == 0)
31050397Sobrien    {
31150397Sobrien      /* Don't emit "pat", since we may try to take the address of it,
31250397Sobrien	 which isn't what is intended.  */
313169689Skan      fputs ("PATTERN (insn)", stdout);
31450397Sobrien      return;
31550397Sobrien    }
31650397Sobrien
31718334Speter  /* We first write out the operations (XEXP or XVECEXP) in reverse
318169689Skan     order, then write "pat", then the indices in forward order.  */
31918334Speter
320132718Skan  for (i = len - 1; i >= 0 ; i--)
32118334Speter    {
322169689Skan      if (ISLOWER (path[i]))
323169689Skan	fputs ("XVECEXP (", stdout);
324169689Skan      else if (ISDIGIT (path[i]))
325169689Skan	fputs ("XEXP (", stdout);
32618334Speter      else
327169689Skan	gcc_unreachable ();
32818334Speter    }
329132718Skan
330169689Skan  fputs ("pat", stdout);
33118334Speter
33218334Speter  for (i = 0; i < len; i++)
33318334Speter    {
334169689Skan      if (ISLOWER (path[i]))
33518334Speter	printf (", 0, %d)", path[i] - 'a');
33690075Sobrien      else if (ISDIGIT(path[i]))
33718334Speter	printf (", %d)", path[i] - '0');
33818334Speter      else
339169689Skan	gcc_unreachable ();
34018334Speter    }
34118334Speter}
34218334Speter
343169689Skanstatic void
344169689Skanprint_header (void)
345169689Skan{
346169689Skan  /* N.B. Code below avoids putting squiggle braces in column 1 inside
347169689Skan     a string, because this confuses some editors' syntax highlighting
348169689Skan     engines.  */
34918334Speter
350169689Skan  puts ("\
351169689Skan/* Generated automatically by the program `genextract'\n\
352169689Skan   from the machine description file `md'.  */\n\
353169689Skan\n\
354169689Skan#include \"config.h\"\n\
355169689Skan#include \"system.h\"\n\
356169689Skan#include \"coretypes.h\"\n\
357169689Skan#include \"tm.h\"\n\
358169689Skan#include \"rtl.h\"\n\
359169689Skan#include \"insn-config.h\"\n\
360169689Skan#include \"recog.h\"\n\
361169689Skan#include \"toplev.h\"\n\
362169689Skan\n\
363169689Skan/* This variable is used as the \"location\" of any missing operand\n\
364169689Skan   whose numbers are skipped by a given pattern.  */\n\
365169689Skanstatic rtx junk ATTRIBUTE_UNUSED;\n");
366169689Skan
367169689Skan  puts ("\
368169689Skanvoid\n\
369169689Skaninsn_extract (rtx insn)\n{\n\
370169689Skan  rtx *ro = recog_data.operand;\n\
371169689Skan  rtx **ro_loc = recog_data.operand_loc;\n\
372169689Skan  rtx pat = PATTERN (insn);\n\
373169689Skan  int i ATTRIBUTE_UNUSED; /* only for peepholes */\n\
374169689Skan\n\
375169689Skan#ifdef ENABLE_CHECKING\n\
376169689Skan  memset (ro, 0xab, sizeof (*ro) * MAX_RECOG_OPERANDS);\n\
377169689Skan  memset (ro_loc, 0xab, sizeof (*ro_loc) * MAX_RECOG_OPERANDS);\n\
378169689Skan#endif\n");
379169689Skan
380169689Skan  puts ("\
381169689Skan  switch (INSN_CODE (insn))\n\
382169689Skan    {\n\
383169689Skan    default:\n\
384169689Skan      /* Control reaches here if insn_extract has been called with an\n\
385169689Skan         unrecognizable insn (code -1), or an insn whose INSN_CODE\n\
386169689Skan         corresponds to a DEFINE_EXPAND in the machine description;\n\
387169689Skan         either way, a bug.  */\n\
388169689Skan      if (INSN_CODE (insn) < 0)\n\
389169689Skan        fatal_insn (\"unrecognizable insn:\", insn);\n\
390169689Skan      else\n\
391169689Skan        fatal_insn (\"insn with invalid code number:\", insn);\n");
392169689Skan}
393169689Skan
39418334Speterint
395132718Skanmain (int argc, char **argv)
39618334Speter{
39718334Speter  rtx desc;
398169689Skan  unsigned int i;
39918334Speter  struct extraction *p;
40018334Speter  struct code_ptr *link;
40190075Sobrien  const char *name;
402169689Skan  int insn_code_number;
403169689Skan  int line_no;
40418334Speter
40590075Sobrien  progname = "genextract";
40618334Speter
40790075Sobrien  if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
40890075Sobrien    return (FATAL_EXIT_CODE);
40918334Speter
41018334Speter  /* Read the machine description.  */
41118334Speter
412169689Skan  while ((desc = read_md_rtx (&line_no, &insn_code_number)) != NULL)
41318334Speter    {
41490075Sobrien       if (GET_CODE (desc) == DEFINE_INSN)
415169689Skan	 gen_insn (desc, insn_code_number);
41618334Speter
41718334Speter      else if (GET_CODE (desc) == DEFINE_PEEPHOLE)
41818334Speter	{
419169689Skan	  struct code_ptr *link = XNEW (struct code_ptr);
42018334Speter
42118334Speter	  link->insn_code = insn_code_number;
42218334Speter	  link->next = peepholes;
42318334Speter	  peepholes = link;
42418334Speter	}
42518334Speter    }
42618334Speter
427169689Skan  print_header ();
428169689Skan
42918334Speter  /* Write out code to handle peepholes and the insn_codes that it should
43018334Speter     be called for.  */
43118334Speter  if (peepholes)
43218334Speter    {
43318334Speter      for (link = peepholes; link; link = link->next)
43418334Speter	printf ("    case %d:\n", link->insn_code);
43518334Speter
43618334Speter      /* The vector in the insn says how many operands it has.
43718334Speter	 And all it contains are operands.  In fact, the vector was
43890075Sobrien	 created just for the sake of this function.  We need to set the
43990075Sobrien	 location of the operands for sake of simplifications after
44090075Sobrien	 extraction, like eliminating subregs.  */
441169689Skan      puts ("      for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n"
442169689Skan	    "          ro[i] = *(ro_loc[i] = &XVECEXP (pat, 0, i));\n"
443169689Skan	    "      break;\n");
44418334Speter    }
44518334Speter
44618334Speter  /* Write out all the ways to extract insn operands.  */
44718334Speter  for (p = extractions; p; p = p->next)
44818334Speter    {
44918334Speter      for (link = p->insns; link; link = link->next)
45090075Sobrien	{
45190075Sobrien	  i = link->insn_code;
45290075Sobrien	  name = get_insn_name (i);
45390075Sobrien	  if (name)
45490075Sobrien	    printf ("    case %d:  /* %s */\n", i, name);
45590075Sobrien	  else
45690075Sobrien	    printf ("    case %d:\n", i);
45790075Sobrien	}
458132718Skan
45918334Speter      for (i = 0; i < p->op_count; i++)
46018334Speter	{
46118334Speter	  if (p->oplocs[i] == 0)
46218334Speter	    {
46318334Speter	      printf ("      ro[%d] = const0_rtx;\n", i);
46418334Speter	      printf ("      ro_loc[%d] = &junk;\n", i);
46518334Speter	    }
46618334Speter	  else
46718334Speter	    {
46818334Speter	      printf ("      ro[%d] = *(ro_loc[%d] = &", i, i);
46918334Speter	      print_path (p->oplocs[i]);
470169689Skan	      puts (");");
47118334Speter	    }
47218334Speter	}
47318334Speter
47418334Speter      for (i = 0; i < p->dup_count; i++)
47518334Speter	{
47690075Sobrien	  printf ("      recog_data.dup_loc[%d] = &", i);
47718334Speter	  print_path (p->duplocs[i]);
478169689Skan	  puts (";");
47990075Sobrien	  printf ("      recog_data.dup_num[%d] = %d;\n", i, p->dupnums[i]);
48018334Speter	}
48118334Speter
482169689Skan      puts ("      break;\n");
48318334Speter    }
48418334Speter
485169689Skan  puts ("    }\n}");
48618334Speter  fflush (stdout);
48790075Sobrien  return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
48818334Speter}
489