genoutput.c revision 90075
118334Speter/* Generate code from to output assembler insns as recognized from rtl.
290075Sobrien   Copyright (C) 1987, 1988, 1992, 1994, 1995, 1997, 1998, 1999, 2000
390075Sobrien   Free Software Foundation, Inc.
418334Speter
590075SobrienThis file is part of GCC.
618334Speter
790075SobrienGCC is free software; you can redistribute it and/or modify it under
890075Sobrienthe terms of the GNU General Public License as published by the Free
990075SobrienSoftware Foundation; either version 2, or (at your option) any later
1090075Sobrienversion.
1118334Speter
1290075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1390075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1490075SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1590075Sobrienfor more details.
1618334Speter
1718334SpeterYou should have received a copy of the GNU General Public License
1890075Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
1990075SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA
2090075Sobrien02111-1307, USA.  */
2118334Speter
2218334Speter
2318334Speter/* This program reads the machine description for the compiler target machine
2418334Speter   and produces a file containing these things:
2518334Speter
2690075Sobrien   1. An array of `struct insn_data', which is indexed by insn code number,
2790075Sobrien   which contains:
2818334Speter
2990075Sobrien     a. `name' is the name for that pattern.  Nameless patterns are
3090075Sobrien     given a name.
3118334Speter
3290075Sobrien     b. `output' hold either the output template, an array of output
3390075Sobrien     templates, or an output function.
3418334Speter
3590075Sobrien     c. `genfun' is the function to generate a body for that pattern,
3690075Sobrien     given operands as arguments.
3718334Speter
3890075Sobrien     d. `n_operands' is the number of distinct operands in the pattern
3990075Sobrien     for that insn,
4018334Speter
4190075Sobrien     e. `n_dups' is the number of match_dup's that appear in the insn's
4290075Sobrien     pattern.  This says how many elements of `recog_data.dup_loc' are
4390075Sobrien     significant after an insn has been recognized.
4418334Speter
4590075Sobrien     f. `n_alternatives' is the number of alternatives in the constraints
4690075Sobrien     of each pattern.
4718334Speter
4890075Sobrien     g. `output_format' tells what type of thing `output' is.
4918334Speter
5090075Sobrien     h. `operand' is the base of an array of operand data for the insn.
5118334Speter
5290075Sobrien   2. An array of `struct insn_operand data', used by `operand' above.
5318334Speter
5490075Sobrien     a. `predicate', an int-valued function, is the match_operand predicate
5590075Sobrien     for this operand.
5618334Speter
5790075Sobrien     b. `constraint' is the constraint for this operand.  This exists
5890075Sobrien     only if register constraints appear in match_operand rtx's.
5918334Speter
6090075Sobrien     c. `address_p' indicates that the operand appears within ADDRESS
6190075Sobrien     rtx's.  This exists only if there are *no* register constraints
6290075Sobrien     in the match_operand rtx's.
6318334Speter
6490075Sobrien     d. `mode' is the machine mode that that operand is supposed to have.
6590075Sobrien
6690075Sobrien     e. `strict_low', is nonzero for operands contained in a STRICT_LOW_PART.
6790075Sobrien
6890075Sobrien     f. `eliminable', is nonzero for operands that are matched normally by
6990075Sobrien     MATCH_OPERAND; it is zero for operands that should not be changed during
7090075Sobrien     register elimination such as MATCH_OPERATORs.
7190075Sobrien
7290075Sobrien  The code number of an insn is simply its position in the machine
7390075Sobrien  description; code numbers are assigned sequentially to entries in
7490075Sobrien  the description, starting with code number 0.
7590075Sobrien
7690075Sobrien  Thus, the following entry in the machine description
7790075Sobrien
7818334Speter    (define_insn "clrdf"
7918334Speter      [(set (match_operand:DF 0 "general_operand" "")
8018334Speter	    (const_int 0))]
8118334Speter      ""
8218334Speter      "clrd %0")
8318334Speter
8490075Sobrien  assuming it is the 25th entry present, would cause
8590075Sobrien  insn_data[24].template to be "clrd %0", and
8690075Sobrien  insn_data[24].n_operands to be 1.  */
8718334Speter
8818334Speter#include "hconfig.h"
8950397Sobrien#include "system.h"
9018334Speter#include "rtl.h"
9190075Sobrien#include "errors.h"
9290075Sobrien#include "gensupport.h"
9318334Speter
9490075Sobrien/* No instruction can have more operands than this.  Sorry for this
9590075Sobrien   arbitrary limit, but what machine will have an instruction with
9690075Sobrien   this many operands?  */
9718334Speter
9818334Speter#define MAX_MAX_OPERANDS 40
9918334Speter
10090075Sobrienstatic int n_occurrences		PARAMS ((int, const char *));
10190075Sobrienstatic const char *strip_whitespace	PARAMS ((const char *));
10218334Speter
10318334Speter/* insns in the machine description are assigned sequential code numbers
10418334Speter   that are used by insn-recog.c (produced by genrecog) to communicate
10518334Speter   to insn-output.c (produced by this program).  */
10618334Speter
10718334Speterstatic int next_code_number;
10818334Speter
10918334Speter/* This counts all definitions in the md file,
11018334Speter   for the sake of error messages.  */
11118334Speter
11218334Speterstatic int next_index_number;
11318334Speter
11490075Sobrien/* This counts all operands used in the md file.  The first is null.  */
11590075Sobrien
11690075Sobrienstatic int next_operand_number = 1;
11790075Sobrien
11890075Sobrien/* Record in this chain all information about the operands we will output.  */
11990075Sobrien
12090075Sobrienstruct operand_data
12190075Sobrien{
12290075Sobrien  struct operand_data *next;
12390075Sobrien  int index;
12490075Sobrien  const char *predicate;
12590075Sobrien  const char *constraint;
12690075Sobrien  enum machine_mode mode;
12790075Sobrien  unsigned char n_alternatives;
12890075Sobrien  char address_p;
12990075Sobrien  char strict_low;
13090075Sobrien  char eliminable;
13190075Sobrien  char seen;
13290075Sobrien};
13390075Sobrien
13490075Sobrien/* Begin with a null operand at index 0.  */
13590075Sobrien
13690075Sobrienstatic struct operand_data null_operand =
13790075Sobrien{
13890075Sobrien  0, 0, "", "", VOIDmode, 0, 0, 0, 0, 0
13990075Sobrien};
14090075Sobrien
14190075Sobrienstatic struct operand_data *odata = &null_operand;
14290075Sobrienstatic struct operand_data **odata_end = &null_operand.next;
14390075Sobrien
14490075Sobrien/* Must match the constants in recog.h.  */
14590075Sobrien
14690075Sobrien#define INSN_OUTPUT_FORMAT_NONE         0       /* abort */
14790075Sobrien#define INSN_OUTPUT_FORMAT_SINGLE       1       /* const char * */
14890075Sobrien#define INSN_OUTPUT_FORMAT_MULTI        2       /* const char * const * */
14990075Sobrien#define INSN_OUTPUT_FORMAT_FUNCTION     3       /* const char * (*)(...) */
15090075Sobrien
15118334Speter/* Record in this chain all information that we will output,
15218334Speter   associated with the code number of the insn.  */
15318334Speter
15418334Speterstruct data
15518334Speter{
15690075Sobrien  struct data *next;
15790075Sobrien  const char *name;
15890075Sobrien  const char *template;
15918334Speter  int code_number;
16018334Speter  int index_number;
16190075Sobrien  int lineno;
16218334Speter  int n_operands;		/* Number of operands this insn recognizes */
16318334Speter  int n_dups;			/* Number times match_dup appears in pattern */
16418334Speter  int n_alternatives;		/* Number of alternatives in each constraint */
16590075Sobrien  int operand_number;		/* Operand index in the big array.  */
16690075Sobrien  int output_format;		/* INSN_OUTPUT_FORMAT_*.  */
16790075Sobrien  struct operand_data operand[MAX_MAX_OPERANDS];
16818334Speter};
16918334Speter
17090075Sobrien/* This variable points to the first link in the insn chain.  */
17118334Speter
17290075Sobrienstatic struct data *idata, **idata_end = &idata;
17318334Speter
17490075Sobrienstatic void output_prologue PARAMS ((void));
17590075Sobrienstatic void output_predicate_decls PARAMS ((void));
17690075Sobrienstatic void output_operand_data PARAMS ((void));
17790075Sobrienstatic void output_insn_data PARAMS ((void));
17890075Sobrienstatic void output_get_insn_name PARAMS ((void));
17990075Sobrienstatic void scan_operands PARAMS ((struct data *, rtx, int, int));
18090075Sobrienstatic int compare_operands PARAMS ((struct operand_data *,
18190075Sobrien				   struct operand_data *));
18290075Sobrienstatic void place_operands PARAMS ((struct data *));
18390075Sobrienstatic void process_template PARAMS ((struct data *, const char *));
18490075Sobrienstatic void validate_insn_alternatives PARAMS ((struct data *));
18590075Sobrienstatic void validate_insn_operands PARAMS ((struct data *));
18690075Sobrienstatic void gen_insn PARAMS ((rtx, int));
18790075Sobrienstatic void gen_peephole PARAMS ((rtx, int));
18890075Sobrienstatic void gen_expand PARAMS ((rtx, int));
18990075Sobrienstatic void gen_split PARAMS ((rtx, int));
19050397Sobrien
19190075Sobrienconst char *
19290075Sobrienget_insn_name (index)
19352284Sobrien     int index;
19452284Sobrien{
19552284Sobrien  static char buf[100];
19652284Sobrien
19752284Sobrien  struct data *i, *last_named = NULL;
19890075Sobrien  for (i = idata; i ; i = i->next)
19952284Sobrien    {
20052284Sobrien      if (i->index_number == index)
20152284Sobrien	return i->name;
20252284Sobrien      if (i->name)
20352284Sobrien	last_named = i;
20452284Sobrien    }
20552284Sobrien
20652284Sobrien  if (last_named)
20752284Sobrien    sprintf(buf, "%s+%d", last_named->name, index - last_named->index_number);
20852284Sobrien  else
20952284Sobrien    sprintf(buf, "insn %d", index);
21052284Sobrien
21152284Sobrien  return buf;
21252284Sobrien}
21352284Sobrien
21418334Speterstatic void
21518334Speteroutput_prologue ()
21618334Speter{
21718334Speter  printf ("/* Generated automatically by the program `genoutput'\n\
21890075Sobrien   from the machine description file `md'.  */\n\n");
21918334Speter
22018334Speter  printf ("#include \"config.h\"\n");
22150397Sobrien  printf ("#include \"system.h\"\n");
22250397Sobrien  printf ("#include \"flags.h\"\n");
22390075Sobrien  printf ("#include \"ggc.h\"\n");
22418334Speter  printf ("#include \"rtl.h\"\n");
22590075Sobrien  printf ("#include \"expr.h\"\n");
22690075Sobrien  printf ("#include \"insn-codes.h\"\n");
22790075Sobrien  printf ("#include \"tm_p.h\"\n");
22890075Sobrien  printf ("#include \"function.h\"\n");
22918334Speter  printf ("#include \"regs.h\"\n");
23018334Speter  printf ("#include \"hard-reg-set.h\"\n");
23118334Speter  printf ("#include \"real.h\"\n");
23218334Speter  printf ("#include \"insn-config.h\"\n\n");
23318334Speter  printf ("#include \"conditions.h\"\n");
23418334Speter  printf ("#include \"insn-attr.h\"\n\n");
23518334Speter  printf ("#include \"recog.h\"\n\n");
23690075Sobrien  printf ("#include \"toplev.h\"\n");
23718334Speter  printf ("#include \"output.h\"\n");
23818334Speter}
23918334Speter
24090075Sobrien
24190075Sobrien/* We need to define all predicates used.  Keep a list of those we
24290075Sobrien   have defined so far.  There normally aren't very many predicates
24390075Sobrien   used, so a linked list should be fast enough.  */
24490075Sobrienstruct predicate { const char *name; struct predicate *next; };
24590075Sobrien
24618334Speterstatic void
24790075Sobrienoutput_predicate_decls ()
24818334Speter{
24990075Sobrien  struct predicate *predicates = 0;
25090075Sobrien  struct operand_data *d;
25190075Sobrien  struct predicate *p, *next;
25218334Speter
25390075Sobrien  for (d = odata; d; d = d->next)
25490075Sobrien    if (d->predicate && d->predicate[0])
25590075Sobrien      {
25690075Sobrien	for (p = predicates; p; p = p->next)
25790075Sobrien	  if (strcmp (p->name, d->predicate) == 0)
25890075Sobrien	    break;
25990075Sobrien
26090075Sobrien	if (p == 0)
26190075Sobrien	  {
26290075Sobrien	    printf ("extern int %s PARAMS ((rtx, enum machine_mode));\n",
26390075Sobrien		    d->predicate);
26490075Sobrien	    p = (struct predicate *) xmalloc (sizeof (struct predicate));
26590075Sobrien	    p->name = d->predicate;
26690075Sobrien	    p->next = predicates;
26790075Sobrien	    predicates = p;
26890075Sobrien	  }
26990075Sobrien      }
27090075Sobrien
27190075Sobrien  printf ("\n\n");
27290075Sobrien  for (p = predicates; p; p = next)
27318334Speter    {
27490075Sobrien      next = p->next;
27590075Sobrien      free (p);
27618334Speter    }
27790075Sobrien}
27818334Speter
27990075Sobrienstatic void
28090075Sobrienoutput_operand_data ()
28190075Sobrien{
28290075Sobrien  struct operand_data *d;
28390075Sobrien
28490075Sobrien  printf ("\nstatic const struct insn_operand_data operand_data[] = \n{\n");
28590075Sobrien
28690075Sobrien  for (d = odata; d; d = d->next)
28718334Speter    {
28890075Sobrien      printf ("  {\n");
28918334Speter
29090075Sobrien      printf ("    %s,\n",
29190075Sobrien	      d->predicate && d->predicate[0] ? d->predicate : "0");
29290075Sobrien
29390075Sobrien      printf ("    \"%s\",\n", d->constraint ? d->constraint : "");
29490075Sobrien
29590075Sobrien      printf ("    %smode,\n", GET_MODE_NAME (d->mode));
29690075Sobrien
29790075Sobrien      printf ("    %d,\n", d->strict_low);
29890075Sobrien
29990075Sobrien      printf ("    %d\n", d->eliminable);
30090075Sobrien
30190075Sobrien      printf("  },\n");
30218334Speter    }
30390075Sobrien  printf("};\n\n\n");
30490075Sobrien}
30518334Speter
30690075Sobrienstatic void
30790075Sobrienoutput_insn_data ()
30890075Sobrien{
30990075Sobrien  struct data *d;
31090075Sobrien  int name_offset = 0;
31190075Sobrien  int next_name_offset;
31290075Sobrien  const char * last_name = 0;
31390075Sobrien  const char * next_name = 0;
31490075Sobrien  struct data *n;
31518334Speter
31690075Sobrien  for (n = idata, next_name_offset = 1; n; n = n->next, next_name_offset++)
31790075Sobrien    if (n->name)
31818334Speter      {
31990075Sobrien	next_name = n->name;
32090075Sobrien	break;
32118334Speter      }
32218334Speter
32390075Sobrien  printf ("\nconst struct insn_data insn_data[] = \n{\n");
32418334Speter
32590075Sobrien  for (d = idata; d; d = d->next)
32690075Sobrien    {
32790075Sobrien      printf ("  {\n");
32818334Speter
32990075Sobrien      if (d->name)
33018334Speter	{
33190075Sobrien	  printf ("    \"%s\",\n", d->name);
33290075Sobrien	  name_offset = 0;
33390075Sobrien	  last_name = d->name;
33490075Sobrien	  next_name = 0;
33590075Sobrien	  for (n = d->next, next_name_offset = 1; n;
33690075Sobrien	       n = n->next, next_name_offset++)
33718334Speter	    {
33890075Sobrien	      if (n->name)
33990075Sobrien		{
34090075Sobrien		  next_name = n->name;
34190075Sobrien		  break;
34290075Sobrien		}
34318334Speter	    }
34418334Speter	}
34590075Sobrien      else
34618334Speter	{
34790075Sobrien	  name_offset++;
34890075Sobrien	  if (next_name && (last_name == 0
34990075Sobrien			    || name_offset > next_name_offset / 2))
35090075Sobrien	    printf ("    \"%s-%d\",\n", next_name,
35190075Sobrien		    next_name_offset - name_offset);
35290075Sobrien	  else
35390075Sobrien	    printf ("    \"%s+%d\",\n", last_name, name_offset);
35418334Speter	}
35518334Speter
35690075Sobrien      switch (d->output_format)
35790075Sobrien	{
35890075Sobrien	case INSN_OUTPUT_FORMAT_NONE:
35990075Sobrien	  printf ("    0,\n");
36090075Sobrien	  break;
36190075Sobrien	case INSN_OUTPUT_FORMAT_SINGLE:
36218334Speter	  {
36390075Sobrien	    const char *p = d->template;
36490075Sobrien	    char prev = 0;
36590075Sobrien
36690075Sobrien	    printf ("    \"");
36790075Sobrien	    while (*p)
36818334Speter	      {
36990075Sobrien		if (*p == '\n' && prev != '\\')
37090075Sobrien		  printf ("\\n\\\n");
37190075Sobrien		else
37290075Sobrien		  putchar (*p);
37390075Sobrien		prev = *p;
37490075Sobrien		++p;
37518334Speter	      }
37690075Sobrien	    printf ("\",\n");
37718334Speter	  }
37890075Sobrien	  break;
37990075Sobrien	case INSN_OUTPUT_FORMAT_MULTI:
38090075Sobrien	case INSN_OUTPUT_FORMAT_FUNCTION:
38190075Sobrien	  printf ("    (const PTR) output_%d,\n", d->code_number);
38290075Sobrien	  break;
38390075Sobrien	default:
38490075Sobrien	  abort ();
38590075Sobrien	}
38618334Speter
38790075Sobrien      if (d->name && d->name[0] != '*')
38890075Sobrien	printf ("    (insn_gen_fn) gen_%s,\n", d->name);
38990075Sobrien      else
39090075Sobrien	printf ("    0,\n");
39190075Sobrien
39290075Sobrien      printf ("    &operand_data[%d],\n", d->operand_number);
39390075Sobrien      printf ("    %d,\n", d->n_operands);
39490075Sobrien      printf ("    %d,\n", d->n_dups);
39590075Sobrien      printf ("    %d,\n", d->n_alternatives);
39690075Sobrien      printf ("    %d\n", d->output_format);
39790075Sobrien
39890075Sobrien      printf("  },\n");
39990075Sobrien    }
40090075Sobrien  printf ("};\n\n\n");
40118334Speter}
40290075Sobrien
40390075Sobrienstatic void
40490075Sobrienoutput_get_insn_name ()
40590075Sobrien{
40690075Sobrien  printf ("const char *\n");
40790075Sobrien  printf ("get_insn_name (code)\n");
40890075Sobrien  printf ("     int code;\n");
40990075Sobrien  printf ("{\n");
41090075Sobrien  printf ("  return insn_data[code].name;\n");
41190075Sobrien  printf ("}\n");
41290075Sobrien}
41390075Sobrien
41418334Speter
41590075Sobrien/* Stores in max_opno the largest operand number present in `part', if
41690075Sobrien   that is larger than the previous value of max_opno, and the rest of
41790075Sobrien   the operand data into `d->operand[i]'.
41818334Speter
41918334Speter   THIS_ADDRESS_P is nonzero if the containing rtx was an ADDRESS.
42018334Speter   THIS_STRICT_LOW is nonzero if the containing rtx was a STRICT_LOW_PART.  */
42118334Speter
42218334Speterstatic int max_opno;
42318334Speterstatic int num_dups;
42418334Speter
42518334Speterstatic void
42690075Sobrienscan_operands (d, part, this_address_p, this_strict_low)
42790075Sobrien     struct data *d;
42818334Speter     rtx part;
42918334Speter     int this_address_p;
43018334Speter     int this_strict_low;
43118334Speter{
43290075Sobrien  int i, j;
43390075Sobrien  const char *format_ptr;
43418334Speter  int opno;
43518334Speter
43618334Speter  if (part == 0)
43718334Speter    return;
43818334Speter
43918334Speter  switch (GET_CODE (part))
44018334Speter    {
44118334Speter    case MATCH_OPERAND:
44218334Speter      opno = XINT (part, 0);
44318334Speter      if (opno > max_opno)
44418334Speter	max_opno = opno;
44518334Speter      if (max_opno >= MAX_MAX_OPERANDS)
44618334Speter	{
44790075Sobrien	  message_with_line (d->lineno,
44890075Sobrien			     "maximum number of operands exceeded");
44990075Sobrien	  have_error = 1;
45018334Speter	  return;
45118334Speter	}
45290075Sobrien      if (d->operand[opno].seen)
45318334Speter	{
45490075Sobrien	  message_with_line (d->lineno,
45590075Sobrien			     "repeated operand number %d\n", opno);
45690075Sobrien	  have_error = 1;
45718334Speter	}
45890075Sobrien
45990075Sobrien      d->operand[opno].seen = 1;
46090075Sobrien      d->operand[opno].mode = GET_MODE (part);
46190075Sobrien      d->operand[opno].strict_low = this_strict_low;
46290075Sobrien      d->operand[opno].predicate = XSTR (part, 1);
46390075Sobrien      d->operand[opno].constraint = strip_whitespace (XSTR (part, 2));
46490075Sobrien      d->operand[opno].n_alternatives
46590075Sobrien	= n_occurrences (',', d->operand[opno].constraint) + 1;
46690075Sobrien      d->operand[opno].address_p = this_address_p;
46790075Sobrien      d->operand[opno].eliminable = 1;
46818334Speter      return;
46918334Speter
47018334Speter    case MATCH_SCRATCH:
47118334Speter      opno = XINT (part, 0);
47218334Speter      if (opno > max_opno)
47318334Speter	max_opno = opno;
47418334Speter      if (max_opno >= MAX_MAX_OPERANDS)
47518334Speter	{
47690075Sobrien	  message_with_line (d->lineno,
47790075Sobrien			     "maximum number of operands exceeded");
47890075Sobrien	  have_error = 1;
47918334Speter	  return;
48018334Speter	}
48190075Sobrien      if (d->operand[opno].seen)
48218334Speter	{
48390075Sobrien	  message_with_line (d->lineno,
48490075Sobrien			     "repeated operand number %d\n", opno);
48590075Sobrien	  have_error = 1;
48618334Speter	}
48790075Sobrien
48890075Sobrien      d->operand[opno].seen = 1;
48990075Sobrien      d->operand[opno].mode = GET_MODE (part);
49090075Sobrien      d->operand[opno].strict_low = 0;
49190075Sobrien      d->operand[opno].predicate = "scratch_operand";
49290075Sobrien      d->operand[opno].constraint = strip_whitespace (XSTR (part, 1));
49390075Sobrien      d->operand[opno].n_alternatives
49490075Sobrien	= n_occurrences (',', d->operand[opno].constraint) + 1;
49590075Sobrien      d->operand[opno].address_p = 0;
49690075Sobrien      d->operand[opno].eliminable = 0;
49718334Speter      return;
49818334Speter
49918334Speter    case MATCH_OPERATOR:
50018334Speter    case MATCH_PARALLEL:
50118334Speter      opno = XINT (part, 0);
50218334Speter      if (opno > max_opno)
50318334Speter	max_opno = opno;
50418334Speter      if (max_opno >= MAX_MAX_OPERANDS)
50518334Speter	{
50690075Sobrien	  message_with_line (d->lineno,
50790075Sobrien			     "maximum number of operands exceeded");
50890075Sobrien	  have_error = 1;
50918334Speter	  return;
51018334Speter	}
51190075Sobrien      if (d->operand[opno].seen)
51290075Sobrien	{
51390075Sobrien	  message_with_line (d->lineno,
51490075Sobrien			     "repeated operand number %d\n", opno);
51590075Sobrien	  have_error = 1;
51690075Sobrien	}
51790075Sobrien
51890075Sobrien      d->operand[opno].seen = 1;
51990075Sobrien      d->operand[opno].mode = GET_MODE (part);
52090075Sobrien      d->operand[opno].strict_low = 0;
52190075Sobrien      d->operand[opno].predicate = XSTR (part, 1);
52290075Sobrien      d->operand[opno].constraint = 0;
52390075Sobrien      d->operand[opno].address_p = 0;
52490075Sobrien      d->operand[opno].eliminable = 0;
52518334Speter      for (i = 0; i < XVECLEN (part, 2); i++)
52690075Sobrien	scan_operands (d, XVECEXP (part, 2, i), 0, 0);
52718334Speter      return;
52818334Speter
52918334Speter    case MATCH_DUP:
53018334Speter    case MATCH_OP_DUP:
53118334Speter    case MATCH_PAR_DUP:
53218334Speter      ++num_dups;
53318334Speter      return;
53418334Speter
53518334Speter    case ADDRESS:
53690075Sobrien      scan_operands (d, XEXP (part, 0), 1, 0);
53718334Speter      return;
53818334Speter
53918334Speter    case STRICT_LOW_PART:
54090075Sobrien      scan_operands (d, XEXP (part, 0), 0, 1);
54118334Speter      return;
54250397Sobrien
54350397Sobrien    default:
54450397Sobrien      break;
54518334Speter    }
54618334Speter
54718334Speter  format_ptr = GET_RTX_FORMAT (GET_CODE (part));
54818334Speter
54918334Speter  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++)
55018334Speter    switch (*format_ptr++)
55118334Speter      {
55218334Speter      case 'e':
55350397Sobrien      case 'u':
55490075Sobrien	scan_operands (d, XEXP (part, i), 0, 0);
55518334Speter	break;
55618334Speter      case 'E':
55718334Speter	if (XVEC (part, i) != NULL)
55818334Speter	  for (j = 0; j < XVECLEN (part, i); j++)
55990075Sobrien	    scan_operands (d, XVECEXP (part, i, j), 0, 0);
56018334Speter	break;
56118334Speter      }
56218334Speter}
56390075Sobrien
56490075Sobrien/* Compare two operands for content equality.  */
56590075Sobrien
56690075Sobrienstatic int
56790075Sobriencompare_operands (d0, d1)
56890075Sobrien     struct operand_data *d0, *d1;
56990075Sobrien{
57090075Sobrien  const char *p0, *p1;
57190075Sobrien
57290075Sobrien  p0 = d0->predicate;
57390075Sobrien  if (!p0)
57490075Sobrien    p0 = "";
57590075Sobrien  p1 = d1->predicate;
57690075Sobrien  if (!p1)
57790075Sobrien    p1 = "";
57890075Sobrien  if (strcmp (p0, p1) != 0)
57990075Sobrien    return 0;
58090075Sobrien
58190075Sobrien  p0 = d0->constraint;
58290075Sobrien  if (!p0)
58390075Sobrien    p0 = "";
58490075Sobrien  p1 = d1->constraint;
58590075Sobrien  if (!p1)
58690075Sobrien    p1 = "";
58790075Sobrien  if (strcmp (p0, p1) != 0)
58890075Sobrien    return 0;
58990075Sobrien
59090075Sobrien  if (d0->mode != d1->mode)
59190075Sobrien    return 0;
59290075Sobrien
59390075Sobrien  if (d0->strict_low != d1->strict_low)
59490075Sobrien    return 0;
59590075Sobrien
59690075Sobrien  if (d0->eliminable != d1->eliminable)
59790075Sobrien    return 0;
59890075Sobrien
59990075Sobrien  return 1;
60090075Sobrien}
60190075Sobrien
60290075Sobrien/* Scan the list of operands we've already committed to output and either
60390075Sobrien   find a subsequence that is the same, or allocate a new one at the end.  */
60490075Sobrien
60590075Sobrienstatic void
60690075Sobrienplace_operands (d)
60790075Sobrien     struct data *d;
60890075Sobrien{
60990075Sobrien  struct operand_data *od, *od2;
61090075Sobrien  int i;
61190075Sobrien
61290075Sobrien  if (d->n_operands == 0)
61390075Sobrien    {
61490075Sobrien      d->operand_number = 0;
61590075Sobrien      return;
61690075Sobrien    }
61790075Sobrien
61890075Sobrien  /* Brute force substring search.  */
61990075Sobrien  for (od = odata, i = 0; od; od = od->next, i = 0)
62090075Sobrien    if (compare_operands (od, &d->operand[0]))
62190075Sobrien      {
62290075Sobrien	od2 = od->next;
62390075Sobrien	i = 1;
62490075Sobrien	while (1)
62590075Sobrien	  {
62690075Sobrien	    if (i == d->n_operands)
62790075Sobrien	      goto full_match;
62890075Sobrien	    if (od2 == NULL)
62990075Sobrien	      goto partial_match;
63090075Sobrien	    if (! compare_operands (od2, &d->operand[i]))
63190075Sobrien	      break;
63290075Sobrien	    ++i, od2 = od2->next;
63390075Sobrien	  }
63490075Sobrien      }
63590075Sobrien
63690075Sobrien  /* Either partial match at the end of the list, or no match.  In either
63790075Sobrien     case, we tack on what operands are remaining to the end of the list.  */
63890075Sobrien partial_match:
63990075Sobrien  d->operand_number = next_operand_number - i;
64090075Sobrien  for (; i < d->n_operands; ++i)
64190075Sobrien    {
64290075Sobrien      od2 = &d->operand[i];
64390075Sobrien      *odata_end = od2;
64490075Sobrien      odata_end = &od2->next;
64590075Sobrien      od2->index = next_operand_number++;
64690075Sobrien    }
64790075Sobrien  *odata_end = NULL;
64890075Sobrien  return;
64990075Sobrien
65090075Sobrien full_match:
65190075Sobrien  d->operand_number = od->index;
65290075Sobrien  return;
65390075Sobrien}
65490075Sobrien
65518334Speter
65618334Speter/* Process an assembler template from a define_insn or a define_peephole.
65718334Speter   It is either the assembler code template, a list of assembler code
65818334Speter   templates, or C code to generate the assembler code template.  */
65918334Speter
66018334Speterstatic void
66118334Speterprocess_template (d, template)
66218334Speter    struct data *d;
66390075Sobrien    const char *template;
66418334Speter{
66590075Sobrien  const char *cp;
66690075Sobrien  int i;
66718334Speter
66890075Sobrien  /* Templates starting with * contain straight code to be run.  */
66990075Sobrien  if (template[0] == '*')
67018334Speter    {
67190075Sobrien      d->template = 0;
67290075Sobrien      d->output_format = INSN_OUTPUT_FORMAT_FUNCTION;
67318334Speter
67490075Sobrien      printf ("\nstatic const char *output_%d PARAMS ((rtx *, rtx));\n",
67590075Sobrien	      d->code_number);
67690075Sobrien      puts ("\nstatic const char *");
67790075Sobrien      printf ("output_%d (operands, insn)\n", d->code_number);
67890075Sobrien      puts ("     rtx *operands ATTRIBUTE_UNUSED;");
67990075Sobrien      puts ("     rtx insn ATTRIBUTE_UNUSED;");
68090075Sobrien      puts ("{");
68118334Speter
68290075Sobrien      puts (template + 1);
68390075Sobrien      puts ("}");
68490075Sobrien    }
68518334Speter
68618334Speter  /* If the assembler code template starts with a @ it is a newline-separated
68790075Sobrien     list of assembler code templates, one for each alternative.  */
68890075Sobrien  else if (template[0] == '@')
68918334Speter    {
69090075Sobrien      d->template = 0;
69190075Sobrien      d->output_format = INSN_OUTPUT_FORMAT_MULTI;
69218334Speter
69390075Sobrien      printf ("\nstatic const char * const output_%d[] = {\n", d->code_number);
69418334Speter
69518334Speter      for (i = 0, cp = &template[1]; *cp; )
69618334Speter	{
69718334Speter	  while (*cp == '\n' || *cp == ' ' || *cp== '\t')
69818334Speter	    cp++;
69918334Speter
70090075Sobrien	  printf ("  \"");
70118334Speter	  while (*cp != '\n' && *cp != '\0')
70250397Sobrien	    {
70350397Sobrien	      putchar (*cp);
70450397Sobrien	      cp++;
70550397Sobrien	    }
70618334Speter
70718334Speter	  printf ("\",\n");
70818334Speter	  i++;
70918334Speter	}
71090075Sobrien      if (i == 1)
71190075Sobrien	message_with_line (d->lineno,
71290075Sobrien			   "'@' is redundant for output template with single alternative");
71318334Speter      if (i != d->n_alternatives)
71490075Sobrien	{
71590075Sobrien	  message_with_line (d->lineno,
71690075Sobrien			     "wrong number of alternatives in the output template");
71790075Sobrien	  have_error = 1;
71890075Sobrien	}
71918334Speter
72090075Sobrien      printf ("};\n");
72118334Speter    }
72218334Speter  else
72318334Speter    {
72490075Sobrien      d->template = template;
72590075Sobrien      d->output_format = INSN_OUTPUT_FORMAT_SINGLE;
72618334Speter    }
72718334Speter}
72818334Speter
72918334Speter/* Check insn D for consistency in number of constraint alternatives.  */
73018334Speter
73118334Speterstatic void
73218334Spetervalidate_insn_alternatives (d)
73318334Speter     struct data *d;
73418334Speter{
73590075Sobrien  int n = 0, start;
73690075Sobrien
73790075Sobrien  /* Make sure all the operands have the same number of alternatives
73890075Sobrien     in their constraints.  Let N be that number.  */
73918334Speter  for (start = 0; start < d->n_operands; start++)
74090075Sobrien    if (d->operand[start].n_alternatives > 0)
74118334Speter      {
74218334Speter	if (n == 0)
74390075Sobrien	  n = d->operand[start].n_alternatives;
74490075Sobrien	else if (n != d->operand[start].n_alternatives)
74590075Sobrien	  {
74690075Sobrien	    message_with_line (d->lineno,
74790075Sobrien			       "wrong number of alternatives in operand %d",
74890075Sobrien			       start);
74990075Sobrien	    have_error = 1;
75090075Sobrien	  }
75118334Speter      }
75290075Sobrien
75318334Speter  /* Record the insn's overall number of alternatives.  */
75418334Speter  d->n_alternatives = n;
75518334Speter}
75690075Sobrien
75790075Sobrien/* Verify that there are no gaps in operand numbers for INSNs.  */
75890075Sobrien
75990075Sobrienstatic void
76090075Sobrienvalidate_insn_operands (d)
76190075Sobrien     struct data *d;
76290075Sobrien{
76390075Sobrien  int i;
76490075Sobrien
76590075Sobrien  for (i = 0; i < d->n_operands; ++i)
76690075Sobrien    if (d->operand[i].seen == 0)
76790075Sobrien      {
76890075Sobrien	message_with_line (d->lineno, "missing operand %d", i);
76990075Sobrien	have_error = 1;
77090075Sobrien      }
77190075Sobrien}
77218334Speter
77390075Sobrien/* Look at a define_insn just read.  Assign its code number.  Record
77490075Sobrien   on idata the template and the number of arguments.  If the insn has
77590075Sobrien   a hairy output action, output a function for now.  */
77618334Speter
77718334Speterstatic void
77890075Sobriengen_insn (insn, lineno)
77918334Speter     rtx insn;
78090075Sobrien     int lineno;
78118334Speter{
78290075Sobrien  struct data *d = (struct data *) xmalloc (sizeof (struct data));
78390075Sobrien  int i;
78418334Speter
78590075Sobrien  d->code_number = next_code_number;
78618334Speter  d->index_number = next_index_number;
78790075Sobrien  d->lineno = lineno;
78818334Speter  if (XSTR (insn, 0)[0])
78918334Speter    d->name = XSTR (insn, 0);
79018334Speter  else
79118334Speter    d->name = 0;
79218334Speter
79318334Speter  /* Build up the list in the same order as the insns are seen
79418334Speter     in the machine description.  */
79518334Speter  d->next = 0;
79690075Sobrien  *idata_end = d;
79790075Sobrien  idata_end = &d->next;
79818334Speter
79918334Speter  max_opno = -1;
80018334Speter  num_dups = 0;
80190075Sobrien  memset (d->operand, 0, sizeof (d->operand));
80218334Speter
80318334Speter  for (i = 0; i < XVECLEN (insn, 1); i++)
80490075Sobrien    scan_operands (d, XVECEXP (insn, 1, i), 0, 0);
80518334Speter
80618334Speter  d->n_operands = max_opno + 1;
80718334Speter  d->n_dups = num_dups;
80818334Speter
80990075Sobrien  validate_insn_operands (d);
81018334Speter  validate_insn_alternatives (d);
81190075Sobrien  place_operands (d);
81290075Sobrien  process_template (d, XTMPL (insn, 3));
81318334Speter}
81418334Speter
81518334Speter/* Look at a define_peephole just read.  Assign its code number.
81690075Sobrien   Record on idata the template and the number of arguments.
81718334Speter   If the insn has a hairy output action, output it now.  */
81818334Speter
81918334Speterstatic void
82090075Sobriengen_peephole (peep, lineno)
82118334Speter     rtx peep;
82290075Sobrien     int lineno;
82318334Speter{
82490075Sobrien  struct data *d = (struct data *) xmalloc (sizeof (struct data));
82590075Sobrien  int i;
82618334Speter
82790075Sobrien  d->code_number = next_code_number;
82818334Speter  d->index_number = next_index_number;
82990075Sobrien  d->lineno = lineno;
83018334Speter  d->name = 0;
83118334Speter
83218334Speter  /* Build up the list in the same order as the insns are seen
83318334Speter     in the machine description.  */
83418334Speter  d->next = 0;
83590075Sobrien  *idata_end = d;
83690075Sobrien  idata_end = &d->next;
83718334Speter
83818334Speter  max_opno = -1;
83990075Sobrien  num_dups = 0;
84090075Sobrien  memset (d->operand, 0, sizeof (d->operand));
84118334Speter
84290075Sobrien  /* Get the number of operands by scanning all the patterns of the
84390075Sobrien     peephole optimizer.  But ignore all the rest of the information
84490075Sobrien     thus obtained.  */
84518334Speter  for (i = 0; i < XVECLEN (peep, 0); i++)
84690075Sobrien    scan_operands (d, XVECEXP (peep, 0, i), 0, 0);
84718334Speter
84818334Speter  d->n_operands = max_opno + 1;
84918334Speter  d->n_dups = 0;
85018334Speter
85118334Speter  validate_insn_alternatives (d);
85290075Sobrien  place_operands (d);
85390075Sobrien  process_template (d, XTMPL (peep, 2));
85418334Speter}
85518334Speter
85618334Speter/* Process a define_expand just read.  Assign its code number,
85718334Speter   only for the purposes of `insn_gen_function'.  */
85818334Speter
85918334Speterstatic void
86090075Sobriengen_expand (insn, lineno)
86118334Speter     rtx insn;
86290075Sobrien     int lineno;
86318334Speter{
86490075Sobrien  struct data *d = (struct data *) xmalloc (sizeof (struct data));
86590075Sobrien  int i;
86618334Speter
86790075Sobrien  d->code_number = next_code_number;
86818334Speter  d->index_number = next_index_number;
86990075Sobrien  d->lineno = lineno;
87018334Speter  if (XSTR (insn, 0)[0])
87118334Speter    d->name = XSTR (insn, 0);
87218334Speter  else
87318334Speter    d->name = 0;
87418334Speter
87518334Speter  /* Build up the list in the same order as the insns are seen
87618334Speter     in the machine description.  */
87718334Speter  d->next = 0;
87890075Sobrien  *idata_end = d;
87990075Sobrien  idata_end = &d->next;
88018334Speter
88118334Speter  max_opno = -1;
88218334Speter  num_dups = 0;
88390075Sobrien  memset (d->operand, 0, sizeof (d->operand));
88418334Speter
88518334Speter  /* Scan the operands to get the specified predicates and modes,
88618334Speter     since expand_binop needs to know them.  */
88718334Speter
88818334Speter  if (XVEC (insn, 1))
88918334Speter    for (i = 0; i < XVECLEN (insn, 1); i++)
89090075Sobrien      scan_operands (d, XVECEXP (insn, 1, i), 0, 0);
89118334Speter
89218334Speter  d->n_operands = max_opno + 1;
89318334Speter  d->n_dups = num_dups;
89490075Sobrien  d->template = 0;
89590075Sobrien  d->output_format = INSN_OUTPUT_FORMAT_NONE;
89618334Speter
89718334Speter  validate_insn_alternatives (d);
89890075Sobrien  place_operands (d);
89918334Speter}
90018334Speter
90118334Speter/* Process a define_split just read.  Assign its code number,
90218334Speter   only for reasons of consistency and to simplify genrecog.  */
90318334Speter
90418334Speterstatic void
90590075Sobriengen_split (split, lineno)
90618334Speter     rtx split;
90790075Sobrien     int lineno;
90818334Speter{
90990075Sobrien  struct data *d = (struct data *) xmalloc (sizeof (struct data));
91090075Sobrien  int i;
91118334Speter
91290075Sobrien  d->code_number = next_code_number;
91318334Speter  d->index_number = next_index_number;
91490075Sobrien  d->lineno = lineno;
91518334Speter  d->name = 0;
91618334Speter
91718334Speter  /* Build up the list in the same order as the insns are seen
91818334Speter     in the machine description.  */
91918334Speter  d->next = 0;
92090075Sobrien  *idata_end = d;
92190075Sobrien  idata_end = &d->next;
92218334Speter
92318334Speter  max_opno = -1;
92418334Speter  num_dups = 0;
92590075Sobrien  memset (d->operand, 0, sizeof (d->operand));
92618334Speter
92790075Sobrien  /* Get the number of operands by scanning all the patterns of the
92890075Sobrien     split patterns.  But ignore all the rest of the information thus
92990075Sobrien     obtained.  */
93018334Speter  for (i = 0; i < XVECLEN (split, 0); i++)
93190075Sobrien    scan_operands (d, XVECEXP (split, 0, i), 0, 0);
93218334Speter
93318334Speter  d->n_operands = max_opno + 1;
93418334Speter  d->n_dups = 0;
93518334Speter  d->n_alternatives = 0;
93618334Speter  d->template = 0;
93790075Sobrien  d->output_format = INSN_OUTPUT_FORMAT_NONE;
93818334Speter
93990075Sobrien  place_operands (d);
94018334Speter}
94118334Speter
94290075Sobrienextern int main PARAMS ((int, char **));
94318334Speter
94418334Speterint
94518334Spetermain (argc, argv)
94618334Speter     int argc;
94718334Speter     char **argv;
94818334Speter{
94918334Speter  rtx desc;
95018334Speter
95190075Sobrien  progname = "genoutput";
95218334Speter
95318334Speter  if (argc <= 1)
95490075Sobrien    fatal ("no input file name");
95518334Speter
95690075Sobrien  if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
95790075Sobrien    return (FATAL_EXIT_CODE);
95818334Speter
95918334Speter  output_prologue ();
96018334Speter  next_code_number = 0;
96118334Speter  next_index_number = 0;
96218334Speter
96318334Speter  /* Read the machine description.  */
96418334Speter
96518334Speter  while (1)
96618334Speter    {
96790075Sobrien      int line_no;
96890075Sobrien
96990075Sobrien      desc = read_md_rtx (&line_no, &next_code_number);
97090075Sobrien      if (desc == NULL)
97118334Speter	break;
97218334Speter
97318334Speter      if (GET_CODE (desc) == DEFINE_INSN)
97490075Sobrien	gen_insn (desc, line_no);
97518334Speter      if (GET_CODE (desc) == DEFINE_PEEPHOLE)
97690075Sobrien	gen_peephole (desc, line_no);
97718334Speter      if (GET_CODE (desc) == DEFINE_EXPAND)
97890075Sobrien	gen_expand (desc, line_no);
97990075Sobrien      if (GET_CODE (desc) == DEFINE_SPLIT
98090075Sobrien 	  || GET_CODE (desc) == DEFINE_PEEPHOLE2)
98190075Sobrien	gen_split (desc, line_no);
98218334Speter      next_index_number++;
98318334Speter    }
98418334Speter
98590075Sobrien  printf("\n\n");
98690075Sobrien  output_predicate_decls ();
98790075Sobrien  output_operand_data ();
98890075Sobrien  output_insn_data ();
98990075Sobrien  output_get_insn_name ();
99018334Speter
99118334Speter  fflush (stdout);
99290075Sobrien  return (ferror (stdout) != 0 || have_error
99318334Speter	? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
99418334Speter}
99518334Speter
99690075Sobrien/* Return the number of occurrences of character C in string S or
99790075Sobrien   -1 if S is the null string.  */
99890075Sobrien
99918334Speterstatic int
100018334Spetern_occurrences (c, s)
100118334Speter     int c;
100290075Sobrien     const char *s;
100318334Speter{
100418334Speter  int n = 0;
100590075Sobrien
100690075Sobrien  if (s == 0 || *s == '\0')
100790075Sobrien    return -1;
100890075Sobrien
100918334Speter  while (*s)
101018334Speter    n += (*s++ == c);
101190075Sobrien
101218334Speter  return n;
101318334Speter}
101490075Sobrien
101590075Sobrien/* Remove whitespace in `s' by moving up characters until the end.
101690075Sobrien   Return a new string.  */
101790075Sobrien
101890075Sobrienstatic const char *
101990075Sobrienstrip_whitespace (s)
102090075Sobrien     const char *s;
102190075Sobrien{
102290075Sobrien  char *p, *q;
102390075Sobrien  char ch;
102490075Sobrien
102590075Sobrien  if (s == 0)
102690075Sobrien    return 0;
102790075Sobrien
102890075Sobrien  p = q = xmalloc (strlen (s) + 1);
102990075Sobrien  while ((ch = *s++) != '\0')
103090075Sobrien    if (! ISSPACE (ch))
103190075Sobrien      *p++ = ch;
103290075Sobrien
103390075Sobrien  *p = '\0';
103490075Sobrien  return q;
103590075Sobrien}
1036