#include "hconfig.h"
#include "system.h"
#include "rtl.h"
#include "obstack.h"
#define MAX_MAX_OPERANDS 40
static struct obstack obstack;
struct obstack *rtl_obstack = &obstack;
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
void fatal PVPROTO ((const char *, ...))
ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
void fancy_abort PROTO((void)) ATTRIBUTE_NORETURN;
static void error PVPROTO ((const char *, ...)) ATTRIBUTE_PRINTF_1;
static int n_occurrences PROTO((int, char *));
char **insn_name_ptr = 0;
static int next_code_number;
static int next_index_number;
struct data
{
int code_number;
int index_number;
char *name;
char *template;
int n_operands;
int n_dups;
int n_alternatives;
struct data *next;
char *constraints[MAX_MAX_OPERANDS];
int op_n_alternatives[MAX_MAX_OPERANDS];
char *predicates[MAX_MAX_OPERANDS];
char address_p[MAX_MAX_OPERANDS];
enum machine_mode modes[MAX_MAX_OPERANDS];
char strict_low[MAX_MAX_OPERANDS];
char outfun;
};
struct data *insn_data;
struct data *end_of_insn_data;
int have_constraints;
static int have_error;
static char * name_for_index PROTO((int));
static void output_prologue PROTO((void));
static void output_epilogue PROTO((void));
static void scan_operands PROTO((rtx, int, int));
static void process_template PROTO((struct data *, char *));
static void validate_insn_alternatives PROTO((struct data *));
static void gen_insn PROTO((rtx));
static void gen_peephole PROTO((rtx));
static void gen_expand PROTO((rtx));
static void gen_split PROTO((rtx));
static int n_occurrences PROTO((int, char *));
static char *
name_for_index (index)
int index;
{
static char buf[100];
struct data *i, *last_named = NULL;
for (i = insn_data; i ; i = i->next)
{
if (i->index_number == index)
return i->name;
if (i->name)
last_named = i;
}
if (last_named)
sprintf(buf, "%s+%d", last_named->name, index - last_named->index_number);
else
sprintf(buf, "insn %d", index);
return buf;
}
static void
output_prologue ()
{
printf ("/* Generated automatically by the program `genoutput'\n\
from the machine description file `md'. */\n\n");
printf ("#include \"config.h\"\n");
printf ("#include \"system.h\"\n");
printf ("#include \"flags.h\"\n");
printf ("#include \"rtl.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-flags.h\"\n");
printf ("#include \"insn-attr.h\"\n\n");
printf ("#include \"insn-codes.h\"\n\n");
printf ("#include \"recog.h\"\n\n");
printf ("#include \"output.h\"\n");
}
static void
output_epilogue ()
{
register struct data *d;
printf ("\nconst char * const insn_template[] =\n {\n");
for (d = insn_data; d; d = d->next)
{
if (d->template)
printf (" \"%s\",\n", d->template);
else
printf (" 0,\n");
}
printf (" };\n");
printf ("\nconst char *(*const insn_outfun[])() =\n {\n");
for (d = insn_data; d; d = d->next)
{
if (d->outfun)
printf (" output_%d,\n", d->code_number);
else
printf (" 0,\n");
}
printf (" };\n");
printf ("\nrtx (*const insn_gen_function[]) () =\n {\n");
for (d = insn_data; d; d = d->next)
{
if (d->name && d->name[0] != '*')
printf (" gen_%s,\n", d->name);
else
printf (" 0,\n");
}
printf (" };\n");
printf ("\nconst char *insn_name[] =\n {\n");
{
int offset = 0;
int next;
char * last_name = 0;
char * next_name = 0;
register struct data *n;
for (n = insn_data, next = 1; n; n = n->next, next++)
if (n->name)
{
next_name = n->name;
break;
}
for (d = insn_data; d; d = d->next)
{
if (d->name)
{
printf (" \"%s\",\n", d->name);
offset = 0;
last_name = d->name;
next_name = 0;
for (n = d->next, next = 1; n; n = n->next, next++)
if (n->name)
{
next_name = n->name;
break;
}
}
else
{
offset++;
if (next_name && (last_name == 0 || offset > next / 2))
printf (" \"%s-%d\",\n", next_name, next - offset);
else
printf (" \"%s+%d\",\n", last_name, offset);
}
}
}
printf (" };\n");
printf ("const char **insn_name_ptr = insn_name;\n");
printf ("\nconst int insn_n_operands[] =\n {\n");
for (d = insn_data; d; d = d->next)
printf (" %d,\n", d->n_operands);
printf (" };\n");
printf ("\nconst int insn_n_dups[] =\n {\n");
for (d = insn_data; d; d = d->next)
printf (" %d,\n", d->n_dups);
printf (" };\n");
if (have_constraints)
{
printf ("\nconst char *const insn_operand_constraint[][MAX_RECOG_OPERANDS] =\n {\n");
for (d = insn_data; d; d = d->next)
{
register int i;
printf (" {");
for (i = 0; i < d->n_operands; i++)
{
if (d->constraints[i] == 0)
printf (" \"\",");
else
printf (" \"%s\",", d->constraints[i]);
}
if (d->n_operands == 0)
printf (" 0");
printf (" },\n");
}
printf (" };\n");
}
else
{
printf ("\nconst char insn_operand_address_p[][MAX_RECOG_OPERANDS] =\n {\n");
for (d = insn_data; d; d = d->next)
{
register int i;
printf (" {");
for (i = 0; i < d->n_operands; i++)
printf (" %d,", d->address_p[i]);
if (d->n_operands == 0)
printf (" 0");
printf (" },\n");
}
printf (" };\n");
}
printf ("\nconst enum machine_mode insn_operand_mode[][MAX_RECOG_OPERANDS] =\n {\n");
for (d = insn_data; d; d = d->next)
{
register int i;
printf (" {");
for (i = 0; i < d->n_operands; i++)
printf (" %smode,", GET_MODE_NAME (d->modes[i]));
if (d->n_operands == 0)
printf (" VOIDmode");
printf (" },\n");
}
printf (" };\n");
printf ("\nconst char insn_operand_strict_low[][MAX_RECOG_OPERANDS] =\n {\n");
for (d = insn_data; d; d = d->next)
{
register int i;
printf (" {");
for (i = 0; i < d->n_operands; i++)
printf (" %d,", d->strict_low[i]);
if (d->n_operands == 0)
printf (" 0");
printf (" },\n");
}
printf (" };\n");
{
struct predicate { char *name; struct predicate *next; } *predicates = 0;
struct predicate *p;
int i;
printf ("\n");
for (d = insn_data; d; d = d->next)
for (i = 0; i < d->n_operands; i++)
if (d->predicates[i] && d->predicates[i][0])
{
for (p = predicates; p; p = p->next)
if (! strcmp (p->name, d->predicates[i]))
break;
if (p == 0)
{
printf ("extern int %s ();\n", d->predicates[i]);
p = (struct predicate *) alloca (sizeof (struct predicate));
p->name = d->predicates[i];
p->next = predicates;
predicates = p;
}
}
printf ("\nint (*const insn_operand_predicate[][MAX_RECOG_OPERANDS])() =\n {\n");
for (d = insn_data; d; d = d->next)
{
printf (" {");
for (i = 0; i < d->n_operands; i++)
printf (" %s,", ((d->predicates[i] && d->predicates[i][0])
? d->predicates[i] : "0"));
if (d->n_operands == 0)
printf (" 0");
printf (" },\n");
}
printf (" };\n");
}
printf ("\nconst int insn_n_alternatives[] =\n {\n");
for (d = insn_data; d; d = d->next)
printf (" %d,\n", d->n_alternatives);
printf(" };\n");
}
static int max_opno;
static int num_dups;
static char *constraints[MAX_MAX_OPERANDS];
static int op_n_alternatives[MAX_MAX_OPERANDS];
static const char *predicates[MAX_MAX_OPERANDS];
static char address_p[MAX_MAX_OPERANDS];
static enum machine_mode modes[MAX_MAX_OPERANDS];
static char strict_low[MAX_MAX_OPERANDS];
static char seen[MAX_MAX_OPERANDS];
static void
scan_operands (part, this_address_p, this_strict_low)
rtx part;
int this_address_p;
int this_strict_low;
{
register int i, j;
register char *format_ptr;
int opno;
if (part == 0)
return;
switch (GET_CODE (part))
{
case MATCH_OPERAND:
opno = XINT (part, 0);
if (opno > max_opno)
max_opno = opno;
if (max_opno >= MAX_MAX_OPERANDS)
{
error ("Too many operands (%d) in definition %s.\n",
max_opno + 1, name_for_index (next_index_number));
return;
}
if (seen[opno])
error ("Definition %s specified operand number %d more than once.\n",
name_for_index (next_index_number), opno);
seen[opno] = 1;
modes[opno] = GET_MODE (part);
strict_low[opno] = this_strict_low;
predicates[opno] = XSTR (part, 1);
constraints[opno] = XSTR (part, 2);
if (XSTR (part, 2) != 0 && *XSTR (part, 2) != 0)
{
op_n_alternatives[opno] = n_occurrences (',', XSTR (part, 2)) + 1;
have_constraints = 1;
}
address_p[opno] = this_address_p;
return;
case MATCH_SCRATCH:
opno = XINT (part, 0);
if (opno > max_opno)
max_opno = opno;
if (max_opno >= MAX_MAX_OPERANDS)
{
error ("Too many operands (%d) in definition %s.\n",
max_opno + 1, name_for_index (next_index_number));
return;
}
if (seen[opno])
error ("Definition %s specified operand number %d more than once.\n",
name_for_index (next_index_number), opno);
seen[opno] = 1;
modes[opno] = GET_MODE (part);
strict_low[opno] = 0;
predicates[opno] = "scratch_operand";
constraints[opno] = XSTR (part, 1);
if (XSTR (part, 1) != 0 && *XSTR (part, 1) != 0)
{
op_n_alternatives[opno] = n_occurrences (',', XSTR (part, 1)) + 1;
have_constraints = 1;
}
address_p[opno] = 0;
return;
case MATCH_OPERATOR:
case MATCH_PARALLEL:
opno = XINT (part, 0);
if (opno > max_opno)
max_opno = opno;
if (max_opno >= MAX_MAX_OPERANDS)
{
error ("Too many operands (%d) in definition %s.\n",
max_opno + 1, name_for_index (next_index_number));
return;
}
if (seen[opno])
error ("Definition %s specified operand number %d more than once.\n",
name_for_index (next_index_number), opno);
seen[opno] = 1;
modes[opno] = GET_MODE (part);
strict_low[opno] = 0;
predicates[opno] = XSTR (part, 1);
constraints[opno] = 0;
address_p[opno] = 0;
for (i = 0; i < XVECLEN (part, 2); i++)
scan_operands (XVECEXP (part, 2, i), 0, 0);
return;
case MATCH_DUP:
case MATCH_OP_DUP:
case MATCH_PAR_DUP:
++num_dups;
return;
case ADDRESS:
scan_operands (XEXP (part, 0), 1, 0);
return;
case STRICT_LOW_PART:
scan_operands (XEXP (part, 0), 0, 1);
return;
default:
break;
}
format_ptr = GET_RTX_FORMAT (GET_CODE (part));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++)
switch (*format_ptr++)
{
case 'e':
case 'u':
scan_operands (XEXP (part, i), 0, 0);
break;
case 'E':
if (XVEC (part, i) != NULL)
for (j = 0; j < XVECLEN (part, i); j++)
scan_operands (XVECEXP (part, i, j), 0, 0);
break;
}
}
static void
process_template (d, template)
struct data *d;
char *template;
{
register char *cp;
register int i;
if (template[0] != '*' && template[0] != '@')
{
d->template = template;
d->outfun = 0;
return;
}
d->template = 0;
d->outfun = 1;
printf ("\nstatic const char *\n");
printf ("output_%d (operands, insn)\n", d->code_number);
printf (" rtx *operands ATTRIBUTE_UNUSED;\n");
printf (" rtx insn ATTRIBUTE_UNUSED;\n");
printf ("{\n");
if (template[0] == '@')
{
printf (" static const char *const strings_%d[] = {\n",
d->code_number);
for (i = 0, cp = &template[1]; *cp; )
{
while (*cp == '\n' || *cp == ' ' || *cp== '\t')
cp++;
printf (" \"");
while (*cp != '\n' && *cp != '\0')
{
putchar (*cp);
cp++;
}
printf ("\",\n");
i++;
}
printf (" };\n");
printf (" return strings_%d[which_alternative];\n", d->code_number);
if (i != d->n_alternatives)
fatal ("Insn pattern %d has %d alternatives but %d assembler choices",
d->index_number, d->n_alternatives, i);
}
else
{
cp = &template[1];
while (*cp)
{
putchar (*cp);
cp++;
}
putchar ('\n');
}
printf ("}\n");
}
static void
validate_insn_alternatives (d)
struct data *d;
{
register int n = 0, start;
for (start = 0; start < d->n_operands; start++)
if (d->op_n_alternatives[start] > 0)
{
if (n == 0)
n = d->op_n_alternatives[start];
else if (n != d->op_n_alternatives[start])
error ("wrong number of alternatives in operand %d of insn %s",
start, name_for_index (d->index_number));
}
d->n_alternatives = n;
}
static void
gen_insn (insn)
rtx insn;
{
register struct data *d = (struct data *) xmalloc (sizeof (struct data));
register int i;
d->code_number = next_code_number++;
d->index_number = next_index_number;
if (XSTR (insn, 0)[0])
d->name = XSTR (insn, 0);
else
d->name = 0;
d->next = 0;
if (end_of_insn_data)
end_of_insn_data->next = d;
else
insn_data = d;
end_of_insn_data = d;
max_opno = -1;
num_dups = 0;
memset (constraints, 0, sizeof constraints);
memset (op_n_alternatives, 0, sizeof op_n_alternatives);
memset (predicates, 0, sizeof predicates);
memset (address_p, 0, sizeof address_p);
memset (modes, 0, sizeof modes);
memset (strict_low, 0, sizeof strict_low);
memset (seen, 0, sizeof seen);
for (i = 0; i < XVECLEN (insn, 1); i++)
scan_operands (XVECEXP (insn, 1, i), 0, 0);
d->n_operands = max_opno + 1;
d->n_dups = num_dups;
memcpy (d->constraints, constraints, sizeof constraints);
memcpy (d->op_n_alternatives, op_n_alternatives, sizeof op_n_alternatives);
memcpy (d->predicates, predicates, sizeof predicates);
memcpy (d->address_p, address_p, sizeof address_p);
memcpy (d->modes, modes, sizeof modes);
memcpy (d->strict_low, strict_low, sizeof strict_low);
validate_insn_alternatives (d);
process_template (d, XSTR (insn, 3));
}
static void
gen_peephole (peep)
rtx peep;
{
register struct data *d = (struct data *) xmalloc (sizeof (struct data));
register int i;
d->code_number = next_code_number++;
d->index_number = next_index_number;
d->name = 0;
d->next = 0;
if (end_of_insn_data)
end_of_insn_data->next = d;
else
insn_data = d;
end_of_insn_data = d;
max_opno = -1;
memset (constraints, 0, sizeof constraints);
memset (op_n_alternatives, 0, sizeof op_n_alternatives);
memset (predicates, 0, sizeof predicates);
memset (address_p, 0, sizeof address_p);
memset (modes, 0, sizeof modes);
memset (strict_low, 0, sizeof strict_low);
memset (seen, 0, sizeof seen);
for (i = 0; i < XVECLEN (peep, 0); i++)
scan_operands (XVECEXP (peep, 0, i), 0, 0);
d->n_operands = max_opno + 1;
d->n_dups = 0;
memcpy (d->constraints, constraints, sizeof constraints);
memcpy (d->op_n_alternatives, op_n_alternatives, sizeof op_n_alternatives);
memset (d->predicates, 0, sizeof predicates);
memset (d->address_p, 0, sizeof address_p);
memset (d->modes, 0, sizeof modes);
memset (d->strict_low, 0, sizeof strict_low);
validate_insn_alternatives (d);
process_template (d, XSTR (peep, 2));
}
static void
gen_expand (insn)
rtx insn;
{
register struct data *d = (struct data *) xmalloc (sizeof (struct data));
register int i;
d->code_number = next_code_number++;
d->index_number = next_index_number;
if (XSTR (insn, 0)[0])
d->name = XSTR (insn, 0);
else
d->name = 0;
d->next = 0;
if (end_of_insn_data)
end_of_insn_data->next = d;
else
insn_data = d;
end_of_insn_data = d;
max_opno = -1;
num_dups = 0;
memset (constraints, 0, sizeof constraints);
memset (op_n_alternatives, 0, sizeof op_n_alternatives);
memset (predicates, 0, sizeof predicates);
memset (address_p, 0, sizeof address_p);
memset (modes, 0, sizeof modes);
memset (strict_low, 0, sizeof strict_low);
memset (seen, 0, sizeof seen);
if (XVEC (insn, 1))
for (i = 0; i < XVECLEN (insn, 1); i++)
scan_operands (XVECEXP (insn, 1, i), 0, 0);
d->n_operands = max_opno + 1;
d->n_dups = num_dups;
memcpy (d->constraints, constraints, sizeof constraints);
memcpy (d->op_n_alternatives, op_n_alternatives, sizeof op_n_alternatives);
memcpy (d->predicates, predicates, sizeof predicates);
memcpy (d->address_p, address_p, sizeof address_p);
memcpy (d->modes, modes, sizeof modes);
memcpy (d->strict_low, strict_low, sizeof strict_low);
d->template = 0;
d->outfun = 0;
validate_insn_alternatives (d);
}
static void
gen_split (split)
rtx split;
{
register struct data *d = (struct data *) xmalloc (sizeof (struct data));
register int i;
d->code_number = next_code_number++;
d->index_number = next_index_number;
d->name = 0;
d->next = 0;
if (end_of_insn_data)
end_of_insn_data->next = d;
else
insn_data = d;
end_of_insn_data = d;
max_opno = -1;
num_dups = 0;
memset (constraints, 0, sizeof constraints);
memset (op_n_alternatives, 0, sizeof op_n_alternatives);
memset (predicates, 0, sizeof predicates);
memset (address_p, 0, sizeof address_p);
memset (modes, 0, sizeof modes);
memset (strict_low, 0, sizeof strict_low);
memset (seen, 0, sizeof seen);
for (i = 0; i < XVECLEN (split, 0); i++)
scan_operands (XVECEXP (split, 0, i), 0, 0);
d->n_operands = max_opno + 1;
memset (d->constraints, 0, sizeof constraints);
memset (d->op_n_alternatives, 0, sizeof op_n_alternatives);
memset (d->predicates, 0, sizeof predicates);
memset (d->address_p, 0, sizeof address_p);
memset (d->modes, 0, sizeof modes);
memset (d->strict_low, 0, sizeof strict_low);
d->n_dups = 0;
d->n_alternatives = 0;
d->template = 0;
d->outfun = 0;
}
PTR
xmalloc (size)
size_t size;
{
register PTR val = (PTR) malloc (size);
if (val == 0)
fatal ("virtual memory exhausted");
return val;
}
PTR
xrealloc (old, size)
PTR old;
size_t size;
{
register PTR ptr;
if (old)
ptr = (PTR) realloc (old, size);
else
ptr = (PTR) malloc (size);
if (!ptr)
fatal ("virtual memory exhausted");
return ptr;
}
void
fatal VPROTO ((const char *format, ...))
{
#ifndef ANSI_PROTOTYPES
const char *format;
#endif
va_list ap;
VA_START (ap, format);
#ifndef ANSI_PROTOTYPES
format = va_arg (ap, const char *);
#endif
fprintf (stderr, "genoutput: ");
vfprintf (stderr, format, ap);
va_end (ap);
fprintf (stderr, "\n");
exit (FATAL_EXIT_CODE);
}
void
fancy_abort ()
{
fatal ("Internal gcc abort.");
}
static void
error VPROTO ((const char *format, ...))
{
#ifndef ANSI_PROTOTYPES
const char *format;
#endif
va_list ap;
VA_START (ap, format);
#ifndef ANSI_PROTOTYPES
format = va_arg (ap, const char *);
#endif
fprintf (stderr, "genoutput: ");
vfprintf (stderr, format, ap);
va_end (ap);
fprintf (stderr, "\n");
have_error = 1;
}
int
main (argc, argv)
int argc;
char **argv;
{
rtx desc;
FILE *infile;
register int c;
obstack_init (rtl_obstack);
if (argc <= 1)
fatal ("No input file name.");
infile = fopen (argv[1], "r");
if (infile == 0)
{
perror (argv[1]);
exit (FATAL_EXIT_CODE);
}
init_rtl ();
output_prologue ();
next_code_number = 0;
next_index_number = 0;
have_constraints = 0;
while (1)
{
c = read_skip_spaces (infile);
if (c == EOF)
break;
ungetc (c, infile);
desc = read_rtx (infile);
if (GET_CODE (desc) == DEFINE_INSN)
gen_insn (desc);
if (GET_CODE (desc) == DEFINE_PEEPHOLE)
gen_peephole (desc);
if (GET_CODE (desc) == DEFINE_EXPAND)
gen_expand (desc);
if (GET_CODE (desc) == DEFINE_SPLIT)
gen_split (desc);
next_index_number++;
}
output_epilogue ();
fflush (stdout);
exit (ferror (stdout) != 0 || have_error
? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
return 0;
}
static int
n_occurrences (c, s)
int c;
char *s;
{
int n = 0;
while (*s)
n += (*s++ == c);
return n;
}