Commit 4bbf910e by Richard Henderson Committed by Richard Henderson

recog.h (INSN_OUTPUT_FORMAT_*): New.

        * recog.h (INSN_OUTPUT_FORMAT_*): New.
        (struct insn_data): Merge `template' and `outfun' into `output'.
        Add `output_format'.
        * genoutput.c (INSN_OUTPUT_FORMAT_*): New.
        (struct data): Remove `outfun'; add `output_format'.
        (name_for_index): Remove declaration.
        (output_insn_data): Handle output formats.
        (process_template): Emit the bare array for @.
        (gen_expand, gen_split): Set output_format to NONE.
        * output.h (get_insn_template): Declare.
        * final.c (get_insn_template): New.
        (final_scan_insn): Use it.
        * toplev.c (compile_file): Likewise.

        * c4x/c4x.c (c4x_process_after_reload): Likewise.
        * i860/i860.c (output_delayed_branch): Likewise.
        (output_delay_insn): Likewise.

From-SVN: r29389
parent c452dcde
Mon Sep 13 21:06:01 1999 Richard Henderson <rth@cygnus.com>
* recog.h (INSN_OUTPUT_FORMAT_*): New.
(struct insn_data): Merge `template' and `outfun' into `output'.
Add `output_format'.
* genoutput.c (INSN_OUTPUT_FORMAT_*): New.
(struct data): Remove `outfun'; add `output_format'.
(name_for_index): Remove declaration.
(output_insn_data): Handle output formats.
(process_template): Emit the bare array for @.
(gen_expand, gen_split): Set output_format to NONE.
* output.h (get_insn_template): Declare.
* final.c (get_insn_template): New.
(final_scan_insn): Use it.
* toplev.c (compile_file): Likewise.
* c4x/c4x.c (c4x_process_after_reload): Likewise.
* i860/i860.c (output_delayed_branch): Likewise.
(output_delay_insn): Likewise.
1999-09-13 Alexandre Oliva <oliva@lsd.ic.unicamp.br> 1999-09-13 Alexandre Oliva <oliva@lsd.ic.unicamp.br>
* rtl.c (obstack_alloc_rtx): Removed. * rtl.c (obstack_alloc_rtx): Removed.
......
...@@ -2196,7 +2196,7 @@ c4x_process_after_reload (first) ...@@ -2196,7 +2196,7 @@ c4x_process_after_reload (first)
{ {
const char *template; const char *template;
template = insn_data[insn_code_number].template; template = get_insn_template (insn_code_number, insn);
if (template && template[0] == '#' && template[1] == '\0') if (template && template[0] == '#' && template[1] == '\0')
{ {
rtx new = try_split (PATTERN(insn), insn, 0); rtx new = try_split (PATTERN(insn), insn, 0);
......
...@@ -1456,10 +1456,7 @@ output_delayed_branch (template, operands, insn) ...@@ -1456,10 +1456,7 @@ output_delayed_branch (template, operands, insn)
if (! constrain_operands (1)) if (! constrain_operands (1))
fatal_insn_not_found (delay_insn); fatal_insn_not_found (delay_insn);
template = insn_data[insn_code_number].template; template = get_insn_template (insn_code_number, delay_insn);
if (template == 0)
template = ((*insn_data[insn_code_number].outfun)
(recog_data.operand, delay_insn));
output_asm_insn (template, recog_data.operand); output_asm_insn (template, recog_data.operand);
} }
CC_STATUS_INIT; CC_STATUS_INIT;
...@@ -1513,10 +1510,7 @@ output_delay_insn (delay_insn) ...@@ -1513,10 +1510,7 @@ output_delay_insn (delay_insn)
/* Now get the template for what this insn would /* Now get the template for what this insn would
have been, without the branch. */ have been, without the branch. */
template = insn_data[insn_code_number].template; template = get_insn_template (insn_code_number, delay_insn);
if (template == 0)
template = ((*insn_data[insn_code_number].outfun)
(recog_data.operand, delay_insn));
output_asm_insn (template, recog_data.operand); output_asm_insn (template, recog_data.operand);
return ""; return "";
} }
......
...@@ -2034,6 +2034,27 @@ final (first, file, optimize, prescan) ...@@ -2034,6 +2034,27 @@ final (first, file, optimize, prescan)
free_insn_eh_region (); free_insn_eh_region ();
} }
const char *
get_insn_template (code, insn)
int code;
rtx insn;
{
const void *output = insn_data[code].output;
switch (insn_data[code].output_format)
{
case INSN_OUTPUT_FORMAT_SINGLE:
return (const char *) output;
case INSN_OUTPUT_FORMAT_MULTI:
return ((const char * const *) output)[which_alternative];
case INSN_OUTPUT_FORMAT_FUNCTION:
if (insn == NULL)
abort ();
return (* (insn_output_fn) output) (recog_data.operand, insn);
default:
abort ();
}
}
/* The final scan for one insn, INSN. /* The final scan for one insn, INSN.
Args are same as in `final', except that INSN Args are same as in `final', except that INSN
is the insn being scanned. is the insn being scanned.
...@@ -2895,25 +2916,18 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes) ...@@ -2895,25 +2916,18 @@ final_scan_insn (insn, file, optimize, prescan, nopeepholes)
dwarf2out_frame_debug (insn); dwarf2out_frame_debug (insn);
#endif #endif
/* If the proper template needs to be chosen by some C code, /* Find the proper template for this insn. */
run that code and get the real template. */ template = get_insn_template (insn_code_number, insn);
template = insn_data[insn_code_number].template; /* If the C code returns 0, it means that it is a jump insn
which follows a deleted test insn, and that test insn
needs to be reinserted. */
if (template == 0) if (template == 0)
{ {
template = ((*insn_data[insn_code_number].outfun) if (prev_nonnote_insn (insn) != last_ignored_compare)
(recog_data.operand, insn)); abort ();
new_block = 0;
/* If the C code returns 0, it means that it is a jump insn return prev_nonnote_insn (insn);
which follows a deleted test insn, and that test insn
needs to be reinserted. */
if (template == 0)
{
if (prev_nonnote_insn (insn) != last_ignored_compare)
abort ();
new_block = 0;
return prev_nonnote_insn (insn);
}
} }
/* If the template is the string "#", it means that this insn must /* If the template is the string "#", it means that this insn must
......
...@@ -29,27 +29,24 @@ Boston, MA 02111-1307, USA. */ ...@@ -29,27 +29,24 @@ Boston, MA 02111-1307, USA. */
a. `name' is the name for that pattern. Nameless patterns are a. `name' is the name for that pattern. Nameless patterns are
given a name. given a name.
b. `template' is the template for output of that insn, b. `output' hold either the output template, an array of output
templates, or an output function.
c. `outfun' is the function that returns a template to use for output of
that insn. This is used only in the cases where the template is not c. `genfun' is the function to generate a body for that pattern,
constant. These cases are specified by a * or @ at the beginning of the
template string in the machine description. They are identified for the
sake of other parts of the compiler by a zero element in `template'.
d. `genfun' is the function to generate a body for that pattern,
given operands as arguments. given operands as arguments.
e. `n_operands' is the number of distinct operands in the pattern d. `n_operands' is the number of distinct operands in the pattern
for that insn, for that insn,
f. `n_dups' is the number of match_dup's that appear in the insn's e. `n_dups' is the number of match_dup's that appear in the insn's
pattern. This says how many elements of `recog_data.dup_loc' are pattern. This says how many elements of `recog_data.dup_loc' are
significant after an insn has been recognized. significant after an insn has been recognized.
g. `n_alternatives' is the number of alternatives in the constraints f. `n_alternatives' is the number of alternatives in the constraints
of each pattern. of each pattern.
g. `output_format' tells what type of thing `output' is.
h. `operand' is the base of an array of operand data for the insn. h. `operand' is the base of an array of operand data for the insn.
2. An array of `struct insn_operand data', used by `operand' above. 2. An array of `struct insn_operand data', used by `operand' above.
...@@ -144,6 +141,13 @@ static struct operand_data null_operand = ...@@ -144,6 +141,13 @@ static struct operand_data null_operand =
static struct operand_data *odata = &null_operand; static struct operand_data *odata = &null_operand;
static struct operand_data **odata_end = &null_operand.next; static struct operand_data **odata_end = &null_operand.next;
/* Must match the constants in recog.h. */
#define INSN_OUTPUT_FORMAT_NONE 0 /* abort */
#define INSN_OUTPUT_FORMAT_SINGLE 1 /* const char * */
#define INSN_OUTPUT_FORMAT_MULTI 2 /* const char * const * */
#define INSN_OUTPUT_FORMAT_FUNCTION 3 /* const char * (*)(...) */
/* Record in this chain all information that we will output, /* Record in this chain all information that we will output,
associated with the code number of the insn. */ associated with the code number of the insn. */
...@@ -151,14 +155,14 @@ struct data ...@@ -151,14 +155,14 @@ struct data
{ {
struct data *next; struct data *next;
char *name; char *name;
char *template; /* string such as "movl %1,%0" */ char *template;
int code_number; int code_number;
int index_number; int index_number;
int n_operands; /* Number of operands this insn recognizes */ int n_operands; /* Number of operands this insn recognizes */
int n_dups; /* Number times match_dup appears in pattern */ int n_dups; /* Number times match_dup appears in pattern */
int n_alternatives; /* Number of alternatives in each constraint */ int n_alternatives; /* Number of alternatives in each constraint */
char outfun; /* Nonzero means this has an output function */
int operand_number; /* Operand index in the big array. */ int operand_number; /* Operand index in the big array. */
int output_format; /* INSN_OUTPUT_FORMAT_*. */
struct operand_data operand[MAX_MAX_OPERANDS]; struct operand_data operand[MAX_MAX_OPERANDS];
}; };
...@@ -172,7 +176,6 @@ static struct data *idata, **idata_end = &idata; ...@@ -172,7 +176,6 @@ static struct data *idata, **idata_end = &idata;
static int have_constraints; static int have_constraints;
static char * name_for_index PROTO((int));
static void output_prologue PROTO((void)); static void output_prologue PROTO((void));
static void output_predicate_decls PROTO((void)); static void output_predicate_decls PROTO((void));
static void output_operand_data PROTO((void)); static void output_operand_data PROTO((void));
...@@ -353,15 +356,21 @@ output_insn_data () ...@@ -353,15 +356,21 @@ output_insn_data ()
printf (" \"%s+%d\",\n", last_name, name_offset); printf (" \"%s+%d\",\n", last_name, name_offset);
} }
if (d->template) switch (d->output_format)
printf (" \"%s\",\n", d->template); {
else case INSN_OUTPUT_FORMAT_NONE:
printf (" 0,\n"); printf (" 0,\n");
break;
if (d->outfun) case INSN_OUTPUT_FORMAT_SINGLE:
printf (" output_%d,\n", d->code_number); printf (" \"%s\",\n", d->template);
else break;
printf (" 0,\n"); case INSN_OUTPUT_FORMAT_MULTI:
case INSN_OUTPUT_FORMAT_FUNCTION:
printf (" output_%d,\n", d->code_number);
break;
default:
abort ();
}
if (d->name && d->name[0] != '*') if (d->name && d->name[0] != '*')
printf (" gen_%s,\n", d->name); printf (" gen_%s,\n", d->name);
...@@ -371,7 +380,8 @@ output_insn_data () ...@@ -371,7 +380,8 @@ output_insn_data ()
printf (" &operand_data[%d],\n", d->operand_number); printf (" &operand_data[%d],\n", d->operand_number);
printf (" %d,\n", d->n_operands); printf (" %d,\n", d->n_operands);
printf (" %d,\n", d->n_dups); printf (" %d,\n", d->n_dups);
printf (" %d\n", d->n_alternatives); printf (" %d,\n", d->n_alternatives);
printf (" %d\n", d->output_format);
printf(" },\n"); printf(" },\n");
} }
...@@ -637,44 +647,39 @@ process_template (d, template) ...@@ -637,44 +647,39 @@ process_template (d, template)
register char *cp; register char *cp;
register int i; register int i;
/* We need to consider only the instructions whose assembler code template /* Templates starting with * contain straight code to be run. */
starts with a * or @. These are the ones where C code is run to decide if (template[0] == '*')
on a template to use. So for all others just return now. */
if (template[0] != '*' && template[0] != '@')
{ {
d->template = template; d->template = 0;
d->outfun = 0; d->output_format = INSN_OUTPUT_FORMAT_FUNCTION;
return;
}
d->template = 0; printf ("\nstatic const char *output_%d PROTO ((rtx *, rtx));\n",
d->outfun = 1; d->code_number);
puts ("\nstatic const char *");
printf ("\nstatic const char *output_%d PROTO ((rtx *, rtx));\n", printf ("output_%d (operands, insn)\n", d->code_number);
d->code_number); puts (" rtx *operands ATTRIBUTE_UNUSED;");
printf ("\nstatic const char *\n"); puts (" rtx insn ATTRIBUTE_UNUSED;");
printf ("output_%d (operands, insn)\n", d->code_number); puts ("{");
printf (" rtx *operands ATTRIBUTE_UNUSED;\n");
printf (" rtx insn ATTRIBUTE_UNUSED;\n"); puts (template + 1);
printf ("{\n"); puts ("}");
}
/* If the assembler code template starts with a @ it is a newline-separated /* If the assembler code template starts with a @ it is a newline-separated
list of assembler code templates, one for each alternative. So produce list of assembler code templates, one for each alternative. */
a routine to select the correct one. */ else if (template[0] == '@')
if (template[0] == '@')
{ {
d->template = 0;
d->output_format = INSN_OUTPUT_FORMAT_MULTI;
printf (" static const char *const strings_%d[] = {\n", printf ("\nstatic const char * const output_%d[] = {\n", d->code_number);
d->code_number);
for (i = 0, cp = &template[1]; *cp; ) for (i = 0, cp = &template[1]; *cp; )
{ {
while (*cp == '\n' || *cp == ' ' || *cp== '\t') while (*cp == '\n' || *cp == ' ' || *cp== '\t')
cp++; cp++;
printf (" \""); printf (" \"");
while (*cp != '\n' && *cp != '\0') while (*cp != '\n' && *cp != '\0')
{ {
putchar (*cp); putchar (*cp);
...@@ -685,29 +690,13 @@ process_template (d, template) ...@@ -685,29 +690,13 @@ process_template (d, template)
i++; i++;
} }
printf (" };\n"); 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 else
{ {
/* The following is done in a funny way to get around problems in d->template = template;
VAX-11 "C" on VMS. It is the equivalent of: d->output_format = INSN_OUTPUT_FORMAT_SINGLE;
printf ("%s\n", &template[1])); */
cp = &template[1];
while (*cp)
{
putchar (*cp);
cp++;
}
putchar ('\n');
} }
printf ("}\n");
} }
/* Check insn D for consistency in number of constraint alternatives. */ /* Check insn D for consistency in number of constraint alternatives. */
...@@ -849,7 +838,7 @@ gen_expand (insn) ...@@ -849,7 +838,7 @@ gen_expand (insn)
d->n_operands = max_opno + 1; d->n_operands = max_opno + 1;
d->n_dups = num_dups; d->n_dups = num_dups;
d->template = 0; d->template = 0;
d->outfun = 0; d->output_format = INSN_OUTPUT_FORMAT_NONE;
validate_insn_alternatives (d); validate_insn_alternatives (d);
place_operands (d); place_operands (d);
...@@ -889,7 +878,7 @@ gen_split (split) ...@@ -889,7 +878,7 @@ gen_split (split)
d->n_dups = 0; d->n_dups = 0;
d->n_alternatives = 0; d->n_alternatives = 0;
d->template = 0; d->template = 0;
d->outfun = 0; d->output_format = INSN_OUTPUT_FORMAT_NONE;
place_operands (d); place_operands (d);
} }
......
...@@ -123,6 +123,9 @@ extern int only_leaf_regs_used PROTO((void)); ...@@ -123,6 +123,9 @@ extern int only_leaf_regs_used PROTO((void));
available in leaf functions. */ available in leaf functions. */
extern void leaf_renumber_regs_insn PROTO((rtx)); extern void leaf_renumber_regs_insn PROTO((rtx));
/* Locate the proper template for the given insn-code. */
extern const char *get_insn_template PROTO((int, rtx));
/* Functions in flow.c */ /* Functions in flow.c */
extern void allocate_for_life_analysis PROTO((void)); extern void allocate_for_life_analysis PROTO((void));
extern int regno_uninitialized PROTO((int)); extern int regno_uninitialized PROTO((int));
......
...@@ -211,17 +211,24 @@ struct insn_operand_data ...@@ -211,17 +211,24 @@ struct insn_operand_data
char strict_low; char strict_low;
}; };
/* Legal values for insn_data.output_format. Indicate what type of data
is stored in insn_data.output. */
#define INSN_OUTPUT_FORMAT_NONE 0 /* abort */
#define INSN_OUTPUT_FORMAT_SINGLE 1 /* const char * */
#define INSN_OUTPUT_FORMAT_MULTI 2 /* const char * const * */
#define INSN_OUTPUT_FORMAT_FUNCTION 3 /* const char * (*)(...) */
struct insn_data struct insn_data
{ {
const char *name; const char *name;
const char *template; const PTR output;
insn_output_fn outfun;
insn_gen_fn genfun; insn_gen_fn genfun;
const struct insn_operand_data *operand; const struct insn_operand_data *operand;
unsigned char n_operands; unsigned char n_operands;
unsigned char n_dups; unsigned char n_dups;
unsigned char n_alternatives; unsigned char n_alternatives;
unsigned char output_format;
}; };
extern const struct insn_data insn_data[]; extern const struct insn_data insn_data[];
...@@ -3172,7 +3172,7 @@ compile_file (name) ...@@ -3172,7 +3172,7 @@ compile_file (name)
/* It's best if we can write a nop here since some /* It's best if we can write a nop here since some
assemblers don't tolerate zeros in the text section. */ assemblers don't tolerate zeros in the text section. */
if (insn_data[CODE_FOR_nop].template != 0) if (insn_data[CODE_FOR_nop].template != 0)
output_asm_insn (insn_data[CODE_FOR_nop].template, NULL_PTR); output_asm_insn (get_insn_template (CODE_FOR_nop, NULL), NULL_PTR);
else else
assemble_zeros (UNITS_PER_WORD); assemble_zeros (UNITS_PER_WORD);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment