/* Generate code from to output assembler insns as recognized from rtl.
- Copyright (C) 1987, 1988, 1992, 1994, 1995, 1997, 1998, 1999, 2000, 2002,
- 2003 Free Software Foundation, Inc.
+ Copyright (C) 1987-2021 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* This program reads the machine description for the compiler target machine
and produces a file containing these things:
- 1. An array of `struct insn_data', which is indexed by insn code number,
+ 1. An array of `struct insn_data_d', which is indexed by insn code number,
which contains:
a. `name' is the name for that pattern. Nameless patterns are
a. `predicate', an int-valued function, is the match_operand predicate
for this operand.
- b. `constraint' is the constraint for this operand. This exists
- only if register constraints appear in match_operand rtx's.
+ b. `constraint' is the constraint for this operand.
c. `address_p' indicates that the operand appears within ADDRESS
- rtx's. This exists only if there are *no* register constraints
- in the match_operand rtx's.
+ rtx's.
d. `mode' is the machine mode that that operand is supposed to have.
MATCH_OPERAND; it is zero for operands that should not be changed during
register elimination such as MATCH_OPERATORs.
+ g. `allows_mem', is true for operands that accept MEM rtxes.
+
The code number of an insn is simply its position in the machine
description; code numbers are assigned sequentially to entries in
the description, starting with code number 0.
#include "tm.h"
#include "rtl.h"
#include "errors.h"
+#include "read-md.h"
#include "gensupport.h"
/* No instruction can have more operands than this. Sorry for this
#define MAX_MAX_OPERANDS 40
+static char general_mem[] = { TARGET_MEM_CONSTRAINT, 0 };
+
static int n_occurrences (int, const char *);
static const char *strip_whitespace (const char *);
-/* insns in the machine description are assigned sequential code numbers
- that are used by insn-recog.c (produced by genrecog) to communicate
- to insn-output.c (produced by this program). */
-
-static int next_code_number;
-
-/* This counts all definitions in the md file,
- for the sake of error messages. */
-
-static int next_index_number;
-
/* This counts all operands used in the md file. The first is null. */
static int next_operand_number = 1;
int index;
const char *predicate;
const char *constraint;
- enum machine_mode mode;
+ machine_mode mode;
unsigned char n_alternatives;
char address_p;
char strict_low;
static struct operand_data null_operand =
{
- 0, 0, "", "", VOIDmode, 0, 0, 0, 0, 0
+ 0, 0, "", "", E_VOIDmode, 0, 0, 0, 0, 0
};
static struct operand_data *odata = &null_operand;
/* Record in this chain all information that we will output,
associated with the code number of the insn. */
-struct data
+class data
{
- struct data *next;
+public:
+ class data *next;
const char *name;
- const char *template;
+ const char *template_code;
+ file_location loc;
int code_number;
- int index_number;
- int lineno;
+ int n_generator_args; /* Number of arguments passed to generator */
int n_operands; /* Number of operands this insn recognizes */
int n_dups; /* Number times match_dup appears in pattern */
int n_alternatives; /* Number of alternatives in each constraint */
};
/* This variable points to the first link in the insn chain. */
+static class data *idata;
+
+/* This variable points to the end of the insn chain. This is where
+ everything relevant from the machien description is appended to. */
+static class data **idata_end;
-static struct data *idata, **idata_end = &idata;
\f
static void output_prologue (void);
static void output_operand_data (void);
static void output_insn_data (void);
static void output_get_insn_name (void);
-static void scan_operands (struct data *, rtx, int, int);
+static void scan_operands (class data *, rtx, int, int);
static int compare_operands (struct operand_data *,
struct operand_data *);
-static void place_operands (struct data *);
-static void process_template (struct data *, const char *);
-static void validate_insn_alternatives (struct data *);
-static void validate_insn_operands (struct data *);
-static void gen_insn (rtx, int);
-static void gen_peephole (rtx, int);
-static void gen_expand (rtx, int);
-static void gen_split (rtx, int);
-static void check_constraint_len (void);
-static int constraint_len (const char *, int);
-\f
-const char *
-get_insn_name (int index)
-{
- static char buf[100];
+static void place_operands (class data *);
+static void process_template (class data *, const char *);
+static void validate_insn_alternatives (class data *);
+static void validate_insn_operands (class data *);
- struct data *i, *last_named = NULL;
- for (i = idata; i ; i = i->next)
- {
- if (i->index_number == index)
- return i->name;
- if (i->name)
- last_named = i;
- }
+class constraint_data
+{
+public:
+ class constraint_data *next_this_letter;
+ file_location loc;
+ unsigned int namelen;
+ char name[1];
+};
- if (last_named)
- sprintf(buf, "%s+%d", last_named->name, index - last_named->index_number);
- else
- sprintf(buf, "insn %d", index);
+/* All machine-independent constraint characters (except digits) that
+ are handled outside the define*_constraint mechanism. */
+static const char indep_constraints[] = ",=+%*?!^$#&g";
- return buf;
-}
+static class constraint_data *
+constraints_by_letter_table[1 << CHAR_BIT];
+static int mdep_constraint_len (const char *, file_location, int);
+static void note_constraint (md_rtx_info *);
+\f
static void
output_prologue (void)
{
printf ("/* Generated automatically by the program `genoutput'\n\
from the machine description file `md'. */\n\n");
+ printf ("#define IN_TARGET_CODE 1\n");
printf ("#include \"config.h\"\n");
printf ("#include \"system.h\"\n");
printf ("#include \"coretypes.h\"\n");
- printf ("#include \"tm.h\"\n");
- printf ("#include \"flags.h\"\n");
- printf ("#include \"ggc.h\"\n");
+ printf ("#include \"backend.h\"\n");
+ printf ("#include \"predict.h\"\n");
+ printf ("#include \"tree.h\"\n");
printf ("#include \"rtl.h\"\n");
+ printf ("#include \"flags.h\"\n");
+ printf ("#include \"alias.h\"\n");
+ printf ("#include \"varasm.h\"\n");
+ printf ("#include \"stor-layout.h\"\n");
+ printf ("#include \"calls.h\"\n");
+ printf ("#include \"insn-config.h\"\n");
+ printf ("#include \"expmed.h\"\n");
+ printf ("#include \"dojump.h\"\n");
+ printf ("#include \"explow.h\"\n");
+ printf ("#include \"memmodel.h\"\n");
+ printf ("#include \"emit-rtl.h\"\n");
+ printf ("#include \"stmt.h\"\n");
printf ("#include \"expr.h\"\n");
printf ("#include \"insn-codes.h\"\n");
printf ("#include \"tm_p.h\"\n");
- printf ("#include \"function.h\"\n");
printf ("#include \"regs.h\"\n");
- printf ("#include \"hard-reg-set.h\"\n");
- printf ("#include \"real.h\"\n");
- printf ("#include \"insn-config.h\"\n\n");
printf ("#include \"conditions.h\"\n");
printf ("#include \"insn-attr.h\"\n\n");
printf ("#include \"recog.h\"\n\n");
- printf ("#include \"toplev.h\"\n");
+ printf ("#include \"diagnostic-core.h\"\n");
printf ("#include \"output.h\"\n");
printf ("#include \"target.h\"\n");
+ printf ("#include \"tm-constrs.h\"\n");
}
static void
for (d = odata; d; d = d->next)
{
+ struct pred_data *pred;
+
printf (" {\n");
printf (" %s,\n",
printf (" \"%s\",\n", d->constraint ? d->constraint : "");
- printf (" %smode,\n", GET_MODE_NAME (d->mode));
+ printf (" E_%smode,\n", GET_MODE_NAME (d->mode));
printf (" %d,\n", d->strict_low);
- printf (" %d\n", d->eliminable);
+ printf (" %d,\n", d->constraint == NULL ? 1 : 0);
+
+ printf (" %d,\n", d->eliminable);
- printf(" },\n");
+ pred = NULL;
+ if (d->predicate)
+ pred = lookup_predicate (d->predicate);
+ printf (" %d\n", pred && pred->codes[MEM]);
+
+ printf (" },\n");
}
- printf("};\n\n\n");
+ printf ("};\n\n\n");
}
static void
output_insn_data (void)
{
- struct data *d;
+ class data *d;
int name_offset = 0;
int next_name_offset;
const char * last_name = 0;
const char * next_name = 0;
- struct data *n;
+ class data *n;
for (n = idata, next_name_offset = 1; n; n = n->next, next_name_offset++)
if (n->name)
break;
}
- printf ("\nconst struct insn_data insn_data[] = \n{\n");
+ printf ("#if GCC_VERSION >= 2007\n__extension__\n#endif\n");
+ printf ("\nconst struct insn_data_d insn_data[] = \n{\n");
for (d = idata; d; d = d->next)
{
+ printf (" /* %s:%d */\n", d->loc.filename, d->loc.lineno);
printf (" {\n");
if (d->name)
switch (d->output_format)
{
case INSN_OUTPUT_FORMAT_NONE:
- printf (" 0,\n");
+ printf ("#if HAVE_DESIGNATED_UNION_INITIALIZERS\n");
+ printf (" { 0 },\n");
+ printf ("#else\n");
+ printf (" { 0, 0, 0 },\n");
+ printf ("#endif\n");
break;
case INSN_OUTPUT_FORMAT_SINGLE:
{
- const char *p = d->template;
+ const char *p = d->template_code;
char prev = 0;
+ printf ("#if HAVE_DESIGNATED_UNION_INITIALIZERS\n");
+ printf (" { .single =\n");
+ printf ("#else\n");
+ printf (" {\n");
+ printf ("#endif\n");
printf (" \"");
while (*p)
{
++p;
}
printf ("\",\n");
+ printf ("#if HAVE_DESIGNATED_UNION_INITIALIZERS\n");
+ printf (" },\n");
+ printf ("#else\n");
+ printf (" 0, 0 },\n");
+ printf ("#endif\n");
}
break;
case INSN_OUTPUT_FORMAT_MULTI:
+ printf ("#if HAVE_DESIGNATED_UNION_INITIALIZERS\n");
+ printf (" { .multi = output_%d },\n", d->code_number);
+ printf ("#else\n");
+ printf (" { 0, output_%d, 0 },\n", d->code_number);
+ printf ("#endif\n");
+ break;
case INSN_OUTPUT_FORMAT_FUNCTION:
- printf (" (const void *) output_%d,\n", d->code_number);
+ printf ("#if HAVE_DESIGNATED_UNION_INITIALIZERS\n");
+ printf (" { .function = output_%d },\n", d->code_number);
+ printf ("#else\n");
+ printf (" { 0, 0, output_%d },\n", d->code_number);
+ printf ("#endif\n");
break;
default:
- abort ();
+ gcc_unreachable ();
}
if (d->name && d->name[0] != '*')
- printf (" (insn_gen_fn) gen_%s,\n", d->name);
+ printf (" { (insn_gen_fn::stored_funcptr) gen_%s },\n", d->name);
else
- printf (" 0,\n");
+ printf (" { 0 },\n");
printf (" &operand_data[%d],\n", d->operand_number);
+ printf (" %d,\n", d->n_generator_args);
printf (" %d,\n", d->n_operands);
printf (" %d,\n", d->n_dups);
printf (" %d,\n", d->n_alternatives);
printf (" %d\n", d->output_format);
- printf(" },\n");
+ printf (" },\n");
}
printf ("};\n\n\n");
}
}
\f
-/* Stores in max_opno the largest operand number present in `part', if
- that is larger than the previous value of max_opno, and the rest of
- the operand data into `d->operand[i]'.
+/* Stores the operand data into `d->operand[i]'.
THIS_ADDRESS_P is nonzero if the containing rtx was an ADDRESS.
THIS_STRICT_LOW is nonzero if the containing rtx was a STRICT_LOW_PART. */
-static int max_opno;
-static int num_dups;
-
static void
-scan_operands (struct data *d, rtx part, int this_address_p,
+scan_operands (class data *d, rtx part, int this_address_p,
int this_strict_low)
{
int i, j;
{
case MATCH_OPERAND:
opno = XINT (part, 0);
- if (opno > max_opno)
- max_opno = opno;
- if (max_opno >= MAX_MAX_OPERANDS)
+ if (opno >= MAX_MAX_OPERANDS)
{
- message_with_line (d->lineno,
- "maximum number of operands exceeded");
- have_error = 1;
+ error_at (d->loc, "maximum number of operands exceeded");
return;
}
if (d->operand[opno].seen)
- {
- message_with_line (d->lineno,
- "repeated operand number %d\n", opno);
- have_error = 1;
- }
+ error_at (d->loc, "repeated operand number %d\n", opno);
d->operand[opno].seen = 1;
d->operand[opno].mode = GET_MODE (part);
case MATCH_SCRATCH:
opno = XINT (part, 0);
- if (opno > max_opno)
- max_opno = opno;
- if (max_opno >= MAX_MAX_OPERANDS)
+ if (opno >= MAX_MAX_OPERANDS)
{
- message_with_line (d->lineno,
- "maximum number of operands exceeded");
- have_error = 1;
+ error_at (d->loc, "maximum number of operands exceeded");
return;
}
if (d->operand[opno].seen)
- {
- message_with_line (d->lineno,
- "repeated operand number %d\n", opno);
- have_error = 1;
- }
+ error_at (d->loc, "repeated operand number %d\n", opno);
d->operand[opno].seen = 1;
d->operand[opno].mode = GET_MODE (part);
case MATCH_OPERATOR:
case MATCH_PARALLEL:
opno = XINT (part, 0);
- if (opno > max_opno)
- max_opno = opno;
- if (max_opno >= MAX_MAX_OPERANDS)
+ if (opno >= MAX_MAX_OPERANDS)
{
- message_with_line (d->lineno,
- "maximum number of operands exceeded");
- have_error = 1;
+ error_at (d->loc, "maximum number of operands exceeded");
return;
}
if (d->operand[opno].seen)
- {
- message_with_line (d->lineno,
- "repeated operand number %d\n", opno);
- have_error = 1;
- }
+ error_at (d->loc, "repeated operand number %d\n", opno);
d->operand[opno].seen = 1;
d->operand[opno].mode = GET_MODE (part);
scan_operands (d, XVECEXP (part, 2, i), 0, 0);
return;
- case MATCH_DUP:
- case MATCH_OP_DUP:
- case MATCH_PAR_DUP:
- ++num_dups;
- break;
-
- case ADDRESS:
- scan_operands (d, XEXP (part, 0), 1, 0);
- return;
-
case STRICT_LOW_PART:
scan_operands (d, XEXP (part, 0), 0, 1);
return;
find a subsequence that is the same, or allocate a new one at the end. */
static void
-place_operands (struct data *d)
+place_operands (class data *d)
{
struct operand_data *od, *od2;
int i;
templates, or C code to generate the assembler code template. */
static void
-process_template (struct data *d, const char *template)
+process_template (class data *d, const char *template_code)
{
const char *cp;
int i;
/* Templates starting with * contain straight code to be run. */
- if (template[0] == '*')
+ if (template_code[0] == '*')
{
- d->template = 0;
+ d->template_code = 0;
d->output_format = INSN_OUTPUT_FORMAT_FUNCTION;
puts ("\nstatic const char *");
- printf ("output_%d (rtx *operands ATTRIBUTE_UNUSED, rtx insn ATTRIBUTE_UNUSED)\n",
+ printf ("output_%d (rtx *operands ATTRIBUTE_UNUSED, rtx_insn *insn ATTRIBUTE_UNUSED)\n",
d->code_number);
puts ("{");
-
- puts (template + 1);
+ rtx_reader_ptr->print_md_ptr_loc (template_code);
+ puts (template_code + 1);
puts ("}");
}
/* If the assembler code template starts with a @ it is a newline-separated
list of assembler code templates, one for each alternative. */
- else if (template[0] == '@')
+ else if (template_code[0] == '@')
{
- d->template = 0;
- d->output_format = INSN_OUTPUT_FORMAT_MULTI;
+ int found_star = 0;
- printf ("\nstatic const char * const output_%d[] = {\n", d->code_number);
+ for (cp = &template_code[1]; *cp; )
+ {
+ while (ISSPACE (*cp))
+ cp++;
+ if (*cp == '*')
+ found_star = 1;
+ while (!IS_VSPACE (*cp) && *cp != '\0')
+ ++cp;
+ }
+ d->template_code = 0;
+ if (found_star)
+ {
+ d->output_format = INSN_OUTPUT_FORMAT_FUNCTION;
+ puts ("\nstatic const char *");
+ printf ("output_%d (rtx *operands ATTRIBUTE_UNUSED, "
+ "rtx_insn *insn ATTRIBUTE_UNUSED)\n", d->code_number);
+ puts ("{");
+ puts (" switch (which_alternative)\n {");
+ }
+ else
+ {
+ d->output_format = INSN_OUTPUT_FORMAT_MULTI;
+ printf ("\nstatic const char * const output_%d[] = {\n",
+ d->code_number);
+ }
- for (i = 0, cp = &template[1]; *cp; )
+ for (i = 0, cp = &template_code[1]; *cp; )
{
+ const char *ep, *sp, *bp;
+
while (ISSPACE (*cp))
cp++;
- printf (" \"");
- while (!IS_VSPACE (*cp) && *cp != '\0')
+ bp = cp;
+ if (found_star)
+ {
+ printf (" case %d:", i);
+ if (*cp == '*')
+ {
+ printf ("\n ");
+ cp++;
+ }
+ else
+ printf (" return \"");
+ }
+ else
+ printf (" \"");
+
+ for (ep = sp = cp; !IS_VSPACE (*ep) && *ep != '\0'; ++ep)
+ if (!ISSPACE (*ep))
+ sp = ep + 1;
+
+ if (sp != ep)
+ message_at (d->loc, "trailing whitespace in output template");
+
+ while (cp < sp)
{
putchar (*cp);
cp++;
}
- printf ("\",\n");
+ if (!found_star)
+ puts ("\",");
+ else if (*bp != '*')
+ puts ("\";");
+ else
+ {
+ /* The usual action will end with a return.
+ If there is neither break or return at the end, this is
+ assumed to be intentional; this allows to have multiple
+ consecutive alternatives share some code. */
+ puts ("");
+ }
i++;
}
if (i == 1)
- message_with_line (d->lineno,
- "'@' is redundant for output template with single alternative");
+ message_at (d->loc, "'@' is redundant for output template with"
+ " single alternative");
if (i != d->n_alternatives)
- {
- message_with_line (d->lineno,
- "wrong number of alternatives in the output template");
- have_error = 1;
- }
+ error_at (d->loc, "wrong number of alternatives in the output"
+ " template");
- printf ("};\n");
+ if (found_star)
+ puts (" default: gcc_unreachable ();\n }\n}");
+ else
+ printf ("};\n");
}
else
{
- d->template = template;
+ d->template_code = template_code;
d->output_format = INSN_OUTPUT_FORMAT_SINGLE;
}
}
/* Check insn D for consistency in number of constraint alternatives. */
static void
-validate_insn_alternatives (struct data *d)
+validate_insn_alternatives (class data *d)
{
int n = 0, start;
char c;
int which_alternative = 0;
int alternative_count_unsure = 0;
+ bool seen_write = false;
for (p = d->operand[start].constraint; (c = *p); p += len)
{
- len = CONSTRAINT_LEN (c, p);
-
- if (len < 1 || (len > 1 && strchr (",#*+=&%!0123456789", c)))
+ if ((c == '%' || c == '=' || c == '+')
+ && p != d->operand[start].constraint)
+ error_at (d->loc, "character '%c' can only be used at the"
+ " beginning of a constraint string", c);
+
+ if (c == '=' || c == '+')
+ seen_write = true;
+
+ /* Earlyclobber operands must always be marked write-only
+ or read/write. */
+ if (!seen_write && c == '&')
+ error_at (d->loc, "earlyclobber operands may not be"
+ " read-only in alternative %d", which_alternative);
+
+ if (ISSPACE (c) || strchr (indep_constraints, c))
+ len = 1;
+ else if (ISDIGIT (c))
{
- message_with_line (d->lineno,
- "invalid length %d for char '%c' in alternative %d of operand %d",
- len, c, which_alternative, start);
- len = 1;
- have_error = 1;
+ const char *q = p;
+ do
+ q++;
+ while (ISDIGIT (*q));
+ len = q - p;
}
+ else
+ len = mdep_constraint_len (p, d->loc, start);
if (c == ',')
{
for (i = 1; i < len; i++)
if (p[i] == '\0')
{
- message_with_line (d->lineno,
- "NUL in alternative %d of operand %d",
- which_alternative, start);
+ error_at (d->loc, "NUL in alternative %d of operand %d",
+ which_alternative, start);
alternative_count_unsure = 1;
break;
}
else if (strchr (",#*", p[i]))
{
- message_with_line (d->lineno,
- "'%c' in alternative %d of operand %d",
- p[i], which_alternative, start);
+ error_at (d->loc, "'%c' in alternative %d of operand %d",
+ p[i], which_alternative, start);
alternative_count_unsure = 1;
}
}
- if (alternative_count_unsure)
- have_error = 1;
- else if (n == 0)
- n = d->operand[start].n_alternatives;
- else if (n != d->operand[start].n_alternatives)
+ if (!alternative_count_unsure)
{
- message_with_line (d->lineno,
- "wrong number of alternatives in operand %d",
- start);
- have_error = 1;
+ if (n == 0)
+ n = d->operand[start].n_alternatives;
+ else if (n != d->operand[start].n_alternatives)
+ error_at (d->loc, "wrong number of alternatives in operand %d",
+ start);
}
}
/* Verify that there are no gaps in operand numbers for INSNs. */
static void
-validate_insn_operands (struct data *d)
+validate_insn_operands (class data *d)
{
int i;
for (i = 0; i < d->n_operands; ++i)
if (d->operand[i].seen == 0)
- {
- message_with_line (d->lineno, "missing operand %d", i);
- have_error = 1;
- }
+ error_at (d->loc, "missing operand %d", i);
+}
+
+static void
+validate_optab_operands (class data *d)
+{
+ if (!d->name || d->name[0] == '\0' || d->name[0] == '*')
+ return;
+
+ /* Miscellaneous tests. */
+ if (strncmp (d->name, "cstore", 6) == 0
+ && d->name[strlen (d->name) - 1] == '4'
+ && d->operand[0].mode == VOIDmode)
+ {
+ message_at (d->loc, "missing mode for operand 0 of cstore");
+ have_error = 1;
+ }
}
\f
/* Look at a define_insn just read. Assign its code number. Record
a hairy output action, output a function for now. */
static void
-gen_insn (rtx insn, int lineno)
+gen_insn (md_rtx_info *info)
{
- struct data *d = (struct data *) xmalloc (sizeof (struct data));
+ struct pattern_stats stats;
+ rtx insn = info->def;
+ data *d = new data;
int i;
- d->code_number = next_code_number;
- d->index_number = next_index_number;
- d->lineno = lineno;
+ d->code_number = info->index;
+ d->loc = info->loc;
if (XSTR (insn, 0)[0])
d->name = XSTR (insn, 0);
else
*idata_end = d;
idata_end = &d->next;
- max_opno = -1;
- num_dups = 0;
memset (d->operand, 0, sizeof (d->operand));
for (i = 0; i < XVECLEN (insn, 1); i++)
scan_operands (d, XVECEXP (insn, 1, i), 0, 0);
- d->n_operands = max_opno + 1;
- d->n_dups = num_dups;
+ get_pattern_stats (&stats, XVEC (insn, 1));
+ d->n_generator_args = stats.num_generator_args;
+ d->n_operands = stats.num_insn_operands;
+ d->n_dups = stats.num_dups;
- check_constraint_len ();
validate_insn_operands (d);
validate_insn_alternatives (d);
+ validate_optab_operands (d);
place_operands (d);
process_template (d, XTMPL (insn, 3));
}
If the insn has a hairy output action, output it now. */
static void
-gen_peephole (rtx peep, int lineno)
+gen_peephole (md_rtx_info *info)
{
- struct data *d = (struct data *) xmalloc (sizeof (struct data));
+ struct pattern_stats stats;
+ data *d = new data;
int i;
- d->code_number = next_code_number;
- d->index_number = next_index_number;
- d->lineno = lineno;
+ d->code_number = info->index;
+ d->loc = info->loc;
d->name = 0;
/* Build up the list in the same order as the insns are seen
*idata_end = d;
idata_end = &d->next;
- max_opno = -1;
- num_dups = 0;
memset (d->operand, 0, sizeof (d->operand));
/* Get the number of operands by scanning all the patterns of the
peephole optimizer. But ignore all the rest of the information
thus obtained. */
+ rtx peep = info->def;
for (i = 0; i < XVECLEN (peep, 0); i++)
scan_operands (d, XVECEXP (peep, 0, i), 0, 0);
- d->n_operands = max_opno + 1;
+ get_pattern_stats (&stats, XVEC (peep, 0));
+ d->n_generator_args = 0;
+ d->n_operands = stats.num_insn_operands;
d->n_dups = 0;
validate_insn_alternatives (d);
only for the purposes of `insn_gen_function'. */
static void
-gen_expand (rtx insn, int lineno)
+gen_expand (md_rtx_info *info)
{
- struct data *d = (struct data *) xmalloc (sizeof (struct data));
+ struct pattern_stats stats;
+ rtx insn = info->def;
+ data *d = new data;
int i;
- d->code_number = next_code_number;
- d->index_number = next_index_number;
- d->lineno = lineno;
+ d->code_number = info->index;
+ d->loc = info->loc;
if (XSTR (insn, 0)[0])
d->name = XSTR (insn, 0);
else
*idata_end = d;
idata_end = &d->next;
- max_opno = -1;
- num_dups = 0;
memset (d->operand, 0, sizeof (d->operand));
/* Scan the operands to get the specified predicates and modes,
for (i = 0; i < XVECLEN (insn, 1); i++)
scan_operands (d, XVECEXP (insn, 1, i), 0, 0);
- d->n_operands = max_opno + 1;
- d->n_dups = num_dups;
- d->template = 0;
+ get_pattern_stats (&stats, XVEC (insn, 1));
+ d->n_generator_args = stats.num_generator_args;
+ d->n_operands = stats.num_insn_operands;
+ d->n_dups = stats.num_dups;
+ d->template_code = 0;
d->output_format = INSN_OUTPUT_FORMAT_NONE;
validate_insn_alternatives (d);
+ validate_optab_operands (d);
place_operands (d);
}
\f
-/* Process a define_split just read. Assign its code number,
- only for reasons of consistency and to simplify genrecog. */
-
static void
-gen_split (rtx split, int lineno)
+init_insn_for_nothing (void)
{
- struct data *d = (struct data *) xmalloc (sizeof (struct data));
- int i;
-
- d->code_number = next_code_number;
- d->index_number = next_index_number;
- d->lineno = lineno;
- d->name = 0;
-
- /* Build up the list in the same order as the insns are seen
- in the machine description. */
- d->next = 0;
- *idata_end = d;
- idata_end = &d->next;
-
- max_opno = -1;
- num_dups = 0;
- memset (d->operand, 0, sizeof (d->operand));
-
- /* Get the number of operands by scanning all the patterns of the
- split patterns. But ignore all the rest of the information thus
- obtained. */
- for (i = 0; i < XVECLEN (split, 0); i++)
- scan_operands (d, XVECEXP (split, 0, i), 0, 0);
-
- d->n_operands = max_opno + 1;
- d->n_dups = 0;
- d->n_alternatives = 0;
- d->template = 0;
- d->output_format = INSN_OUTPUT_FORMAT_NONE;
-
- place_operands (d);
+ idata = XCNEW (class data);
+ new (idata) data ();
+ idata->name = "*placeholder_for_nothing";
+ idata->loc = file_location ("<internal>", 0, 0);
+ idata_end = &idata->next;
}
-extern int main (int, char **);
+extern int main (int, const char **);
int
-main (int argc, char **argv)
+main (int argc, const char **argv)
{
- rtx desc;
-
progname = "genoutput";
- if (argc <= 1)
- fatal ("no input file name");
+ init_insn_for_nothing ();
- if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
+ if (!init_rtx_reader_args (argc, argv))
return (FATAL_EXIT_CODE);
output_prologue ();
- next_code_number = 0;
- next_index_number = 0;
/* Read the machine description. */
- while (1)
- {
- int line_no;
+ md_rtx_info info;
+ while (read_md_rtx (&info))
+ switch (GET_CODE (info.def))
+ {
+ case DEFINE_INSN:
+ gen_insn (&info);
+ break;
- desc = read_md_rtx (&line_no, &next_code_number);
- if (desc == NULL)
+ case DEFINE_PEEPHOLE:
+ gen_peephole (&info);
break;
- if (GET_CODE (desc) == DEFINE_INSN)
- gen_insn (desc, line_no);
- if (GET_CODE (desc) == DEFINE_PEEPHOLE)
- gen_peephole (desc, line_no);
- if (GET_CODE (desc) == DEFINE_EXPAND)
- gen_expand (desc, line_no);
- if (GET_CODE (desc) == DEFINE_SPLIT
- || GET_CODE (desc) == DEFINE_PEEPHOLE2)
- gen_split (desc, line_no);
- next_index_number++;
- }
+ case DEFINE_EXPAND:
+ gen_expand (&info);
+ break;
+
+ case DEFINE_CONSTRAINT:
+ case DEFINE_REGISTER_CONSTRAINT:
+ case DEFINE_ADDRESS_CONSTRAINT:
+ case DEFINE_MEMORY_CONSTRAINT:
+ case DEFINE_SPECIAL_MEMORY_CONSTRAINT:
+ note_constraint (&info);
+ break;
- printf("\n\n");
+ default:
+ break;
+ }
+
+ printf ("\n\n");
output_operand_data ();
output_insn_data ();
output_get_insn_name ();
if (s == 0)
return 0;
- p = q = xmalloc (strlen (s) + 1);
+ p = q = XNEWVEC (char, strlen (s) + 1);
while ((ch = *s++) != '\0')
if (! ISSPACE (ch))
*p++ = ch;
return q;
}
-/* Verify that DEFAULT_CONSTRAINT_LEN is used properly and not
- tampered with. This isn't bullet-proof, but it should catch
- most genuine mistakes. */
+/* Record just enough information about the constraint in *INFO to allow
+ checking of operand constraint strings above, in validate_insn_alternatives.
+ Does not validate most properties of the constraint itself; does enforce
+ no duplicate names, no overlap with MI constraints, and no prefixes. */
static void
-check_constraint_len (void)
+note_constraint (md_rtx_info *info)
{
- const char *p;
- int d;
+ rtx exp = info->def;
+ const char *name = XSTR (exp, 0);
+ class constraint_data **iter, **slot, *new_cdata;
+
+ if (strcmp (name, "TARGET_MEM_CONSTRAINT") == 0)
+ name = general_mem;
+ unsigned int namelen = strlen (name);
+
+ if (strchr (indep_constraints, name[0]))
+ {
+ if (name[1] == '\0')
+ error_at (info->loc, "constraint letter '%s' cannot be "
+ "redefined by the machine description", name);
+ else
+ error_at (info->loc, "constraint name '%s' cannot be defined by "
+ "the machine description, as it begins with '%c'",
+ name, name[0]);
+ return;
+ }
- for (p = ",#*+=&%!1234567890"; *p; p++)
- for (d = -9; d < 9; d++)
- if (constraint_len (p, d) != d)
- abort ();
+ slot = &constraints_by_letter_table[(unsigned int)name[0]];
+ for (iter = slot; *iter; iter = &(*iter)->next_this_letter)
+ {
+ /* This causes slot to end up pointing to the
+ next_this_letter field of the last constraint with a name
+ of equal or greater length than the new constraint; hence
+ the new constraint will be inserted after all previous
+ constraints with names of the same length. */
+ if ((*iter)->namelen >= namelen)
+ slot = iter;
+
+ if (!strcmp ((*iter)->name, name))
+ {
+ error_at (info->loc, "redefinition of constraint '%s'", name);
+ message_at ((*iter)->loc, "previous definition is here");
+ return;
+ }
+ else if (!strncmp ((*iter)->name, name, (*iter)->namelen))
+ {
+ error_at (info->loc, "defining constraint '%s' here", name);
+ message_at ((*iter)->loc, "renders constraint '%s' "
+ "(defined here) a prefix", (*iter)->name);
+ return;
+ }
+ else if (!strncmp ((*iter)->name, name, namelen))
+ {
+ error_at (info->loc, "constraint '%s' is a prefix", name);
+ message_at ((*iter)->loc, "of constraint '%s' "
+ "(defined here)", (*iter)->name);
+ return;
+ }
+ }
+ new_cdata = XNEWVAR (class constraint_data,
+ sizeof (class constraint_data) + namelen);
+ new (new_cdata) constraint_data ();
+ strcpy (CONST_CAST (char *, new_cdata->name), name);
+ new_cdata->namelen = namelen;
+ new_cdata->loc = info->loc;
+ new_cdata->next_this_letter = *slot;
+ *slot = new_cdata;
}
+/* Return the length of the constraint name beginning at position S
+ of an operand constraint string, or issue an error message if there
+ is no such constraint. Does not expect to be called for generic
+ constraints. */
static int
-constraint_len (const char *p, int genoutput_default_constraint_len)
+mdep_constraint_len (const char *s, file_location loc, int opno)
{
- /* Check that we still match defaults.h . First we do a generation-time
- check that fails if the value is not the expected one... */
- if (DEFAULT_CONSTRAINT_LEN (*p, p) != 1)
- abort ();
- /* And now a comile-time check that should give a diagnostic if the
- definition doesn't exactly match. */
-#define DEFAULT_CONSTRAINT_LEN(C,STR) 1
- /* Now re-define DEFAULT_CONSTRAINT_LEN so that we can verify it is
- being used. */
-#undef DEFAULT_CONSTRAINT_LEN
-#define DEFAULT_CONSTRAINT_LEN(C,STR) \
- ((C) != *p || STR != p ? -1 : genoutput_default_constraint_len)
- return CONSTRAINT_LEN (*p, p);
- /* And set it back. */
-#undef DEFAULT_CONSTRAINT_LEN
-#define DEFAULT_CONSTRAINT_LEN(C,STR) 1
+ class constraint_data *p;
+
+ p = constraints_by_letter_table[(unsigned int)s[0]];
+
+ if (p)
+ for (; p; p = p->next_this_letter)
+ if (!strncmp (s, p->name, p->namelen))
+ return p->namelen;
+
+ error_at (loc, "error: undefined machine-specific constraint "
+ "at this point: \"%s\"", s);
+ message_at (loc, "note: in operand %d", opno);
+ return 1; /* safe */
}