/* Generate code from machine description to recognize rtl as insns.
- Copyright (C) 1987-1991 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92, 93, 94, 1995 Free Software Foundation, Inc.
This file is part of GNU CC.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
/* This program is used to produce insn-recog.c, which contains
it returns the split rtl in a SEQUENCE. */
#include <stdio.h>
-#include "config.h"
+#include "hconfig.h"
#include "rtl.h"
#include "obstack.h"
#define obstack_chunk_free free
extern void free ();
+extern rtx read_rtx ();
/* Data structure for a listhead of decision trees. The alternatives
to a node are kept in a doublely-linked list so we can easily add nodes
int test_elt_zero_int; /* Nonzero if should test XINT (rtl, 0) */
int elt_zero_int; /* Required value for XINT (rtl, 0) */
int test_elt_one_int; /* Nonzero if should test XINT (rtl, 1) */
- int elt_one_int; /* Required value for XINT (rtl, 2) */
+ int elt_one_int; /* Required value for XINT (rtl, 1) */
+ int test_elt_zero_wide; /* Nonzero if should test XWINT (rtl, 0) */
+ HOST_WIDE_INT elt_zero_wide; /* Required value for XWINT (rtl, 0) */
char *tests; /* If nonzero predicate to call */
int pred; /* `preds' index of predicate or -1 */
char *c_test; /* Additional test to perform */
static int next_insn_code;
/* Similar, but counts all expressions in the MD file; used for
- error messages. */
+ error messages. */
static int next_index;
{"push_operand", {MEM}},
{"memory_operand", {SUBREG, MEM}},
{"indirect_operand", {SUBREG, MEM}},
- {"comparison_operation", {EQ, NE, LE, LT, GE, LT, LEU, LTU, GEU, GTU}},
+ {"comparison_operator", {EQ, NE, LE, LT, GE, GT, LEU, LTU, GEU, GTU}},
{"mode_independent_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
LABEL_REF, SUBREG, REG, MEM}}};
#define NUM_KNOWN_PREDS (sizeof preds / sizeof preds[0])
-static int try_merge_1 ();
-static int no_same_mode ();
-static int same_codes ();
-static int same_modes ();
-char *xmalloc ();
-static struct decision *add_to_sequence ();
-static struct decision_head merge_trees ();
-static struct decision *try_merge_2 ();
-static void write_subroutine ();
-static void print_code ();
-static void clear_codes ();
-static void clear_modes ();
-static void change_state ();
-static void write_tree ();
-static char *copystr ();
-static char *concat ();
-static void fatal ();
-void fancy_abort ();
-static void mybzero ();
-static void mybcopy ();
+static struct decision_head make_insn_sequence PROTO((rtx, enum routine_type));
+static struct decision *add_to_sequence PROTO((rtx, struct decision_head *,
+ char *));
+static int not_both_true PROTO((struct decision *, struct decision *,
+ int));
+static int position_merit PROTO((struct decision *, enum machine_mode,
+ enum rtx_code));
+static struct decision_head merge_trees PROTO((struct decision_head,
+ struct decision_head));
+static int break_out_subroutines PROTO((struct decision_head,
+ enum routine_type, int));
+static void write_subroutine PROTO((struct decision *, enum routine_type));
+static void write_tree_1 PROTO((struct decision *, char *,
+ struct decision *, enum routine_type));
+static void print_code PROTO((enum rtx_code));
+static int same_codes PROTO((struct decision *, enum rtx_code));
+static void clear_codes PROTO((struct decision *));
+static int same_modes PROTO((struct decision *, enum machine_mode));
+static void clear_modes PROTO((struct decision *));
+static void write_tree PROTO((struct decision *, char *,
+ struct decision *, int,
+ enum routine_type));
+static void change_state PROTO((char *, char *, int));
+static char *copystr PROTO((char *));
+static void mybzero PROTO((char *, unsigned));
+static void mybcopy PROTO((char *, char *, unsigned));
+static char *concat PROTO((char *, char *));
+static void fatal PROTO((char *));
+char *xrealloc PROTO((char *, unsigned));
+char *xmalloc PROTO((unsigned));
+void fancy_abort PROTO((void));
\f
/* Construct and return a sequence of decisions
that will recognize INSN.
new->veclen = 0;
new->test_elt_zero_int = 0;
new->test_elt_one_int = 0;
+ new->test_elt_zero_wide = 0;
new->elt_zero_int = 0;
new->elt_one_int = 0;
+ new->elt_zero_wide = 0;
new->tests = 0;
new->pred = -1;
new->c_test = 0;
Finally, if we know that the predicate does not allow CONST_INT, we
know that the only way the predicate can match is if the modes match
- (here we use the kluge of relying on the fact that "address_operand"
+ (here we use the kludge of relying on the fact that "address_operand"
accepts CONST_INT; otherwise, it would have to be a special case),
so we can test the mode (but we need not). This fact should
considerably simplify the generated code. */
if (new->tests)
- for (i = 0; i < NUM_KNOWN_PREDS; i++)
- if (! strcmp (preds[i].name, new->tests))
- {
- int j;
- int allows_const_int = 0;
+ {
+ for (i = 0; i < NUM_KNOWN_PREDS; i++)
+ if (! strcmp (preds[i].name, new->tests))
+ {
+ int j;
+ int allows_const_int = 0;
- new->pred = i;
+ new->pred = i;
- if (preds[i].codes[1] == 0 && new->code == UNKNOWN)
- {
- new->code = preds[i].codes[0];
- if (! strcmp ("const_int_operand", new->tests))
- new->tests = 0, new->pred = -1;
- }
+ if (preds[i].codes[1] == 0 && new->code == UNKNOWN)
+ {
+ new->code = preds[i].codes[0];
+ if (! strcmp ("const_int_operand", new->tests))
+ new->tests = 0, new->pred = -1;
+ }
- for (j = 0; j < NUM_RTX_CODE && preds[i].codes[j] != 0; j++)
- if (preds[i].codes[j] == CONST_INT)
- allows_const_int = 1;
+ for (j = 0; j < NUM_RTX_CODE && preds[i].codes[j] != 0; j++)
+ if (preds[i].codes[j] == CONST_INT)
+ allows_const_int = 1;
- if (! allows_const_int)
- new->enforce_mode = new->ignore_mode= 1;
+ if (! allows_const_int)
+ new->enforce_mode = new->ignore_mode= 1;
- break;
- }
+ break;
+ }
+
+#ifdef PREDICATE_CODES
+ /* If the port has a list of the predicates it uses but omits
+ one, warn. */
+ if (i == NUM_KNOWN_PREDS)
+ fprintf (stderr, "Warning: `%s' not in PREDICATE_CODES\n",
+ new->tests);
+#endif
+ }
if (code == MATCH_OPERATOR || code == MATCH_PARALLEL)
{
new = add_to_sequence (XVECEXP (pattern, 2, i),
&new->success, newpos);
}
-
- this->success.first->enforce_mode = 0;
}
return new;
new = add_to_sequence (XVECEXP (pattern, 1, i),
&new->success, newpos);
}
- this->success.first->enforce_mode = 0;
return new;
case MATCH_DUP:
+ case MATCH_PAR_DUP:
new->dupno = XINT (pattern, 0);
new->code = UNKNOWN;
new->enforce_mode = 0;
if (GET_CODE (XEXP (pattern, 0)) == CC0)
break;
- /* ... fall through ... */
+ /* ... fall through ... */
case COMPARE:
/* Enforce the mode on the first operand to avoid ambiguous insns. */
this->test_elt_one_int = 1;
this->elt_one_int = XINT (pattern, i);
}
+ else if (fmt[i] == 'w' && i == 0)
+ {
+ this->test_elt_zero_wide = 1;
+ this->elt_zero_wide = XWINT (pattern, i);
+ }
else if (fmt[i] == 'E')
{
register int j;
struct decision *p1, *p2;
/* If they are both to test modes and the modes are different, they aren't
- both true. Similarly for codes, integer elements, and vector lengths. */
+ both true. Similarly for codes, integer elements, and vector lengths. */
if ((d1->enforce_mode && d2->enforce_mode
&& d1->mode != VOIDmode && d2->mode != VOIDmode && d1->mode != d2->mode)
&& d1->elt_zero_int != d2->elt_zero_int)
|| (d1->test_elt_one_int && d2->test_elt_one_int
&& d1->elt_one_int != d2->elt_one_int)
+ || (d1->test_elt_zero_wide && d2->test_elt_zero_wide
+ && d1->elt_zero_wide != d2->elt_zero_wide)
|| (d1->veclen && d2->veclen && d1->veclen != d2->veclen))
return 1;
for D1's predicate. */
if (d2->code != UNKNOWN)
{
- for (i = 0; i < NUM_RTX_CODE && preds[d1->pred].codes[i]; i++)
+ for (i = 0; i < NUM_RTX_CODE && preds[d1->pred].codes[i] != 0; i++)
if (preds[d1->pred].codes[i] == d2->code)
break;
else if (d2->pred >= 0)
{
- for (i = 0; i < NUM_RTX_CODE && preds[d1->pred].codes[i]; i++)
+ for (i = 0; i < NUM_RTX_CODE && preds[d1->pred].codes[i] != 0; i++)
{
for (j = 0; j < NUM_RTX_CODE; j++)
if (preds[d2->pred].codes[j] == 0
We would like to list nodes testing for specific codes before those
that test predicates to avoid unnecessary function calls. Similarly,
- tests for specific modes should preceed nodes that allow any mode.
+ tests for specific modes should precede nodes that allow any mode.
This function returns the merit (with 0 being the best) of inserting
a test involving the specified MODE and CODE after node P. If P is
position_merit (p, mode, code)
struct decision *p;
enum machine_mode mode;
- RTX_CODE code;
+ enum rtx_code code;
{
enum machine_mode p_mode;
would cause an infinite recursion. */
if (old->tests == 0 && old->test_elt_zero_int == 0
&& old->test_elt_one_int == 0 && old->veclen == 0
+ && old->test_elt_zero_wide == 0
&& old->dupno == -1 && old->mode == VOIDmode
&& old->code == UNKNOWN
&& (old->c_test != 0 || add->c_test != 0))
|| (old->pred >= 0 && old->pred == add->pred)
|| (old->tests && add->tests
&& !strcmp (old->tests, add->tests)))
- && old->test_elt_zero_int == add->test_elt_zero_int
- && old->elt_zero_int == add->elt_zero_int
- && old->test_elt_one_int == add->test_elt_one_int
- && old->elt_one_int == add->elt_one_int
- && old->veclen == add->veclen
- && old->dupno == add->dupno
- && old->opno == add->opno
- && old->code == add->code
- && old->enforce_mode == add->enforce_mode
- && old->mode == add->mode)
+ && old->test_elt_zero_int == add->test_elt_zero_int
+ && old->elt_zero_int == add->elt_zero_int
+ && old->test_elt_one_int == add->test_elt_one_int
+ && old->elt_one_int == add->elt_one_int
+ && old->test_elt_zero_wide == add->test_elt_zero_wide
+ && old->elt_zero_wide == add->elt_zero_wide
+ && old->veclen == add->veclen
+ && old->dupno == add->dupno
+ && old->opno == add->opno
+ && old->code == add->code
+ && old->enforce_mode == add->enforce_mode
+ && old->mode == add->mode)
{
/* If the additional test is not the same, split both nodes
into nodes that just contain all things tested before the
struct decision *split
= (struct decision *) xmalloc (sizeof (struct decision));
- mybcopy (old, split, sizeof (struct decision));
+ mybcopy ((char *) old, (char *) split,
+ sizeof (struct decision));
old->success.first = old->success.last = split;
old->c_test = 0;
split->veclen = 0;
split->test_elt_zero_int = 0;
split->test_elt_one_int = 0;
+ split->test_elt_zero_wide = 0;
split->tests = 0;
split->pred = -1;
+ split->dupno = -1;
}
if (add->insn_code_number >= 0 || add->opno >= 0)
struct decision *split
= (struct decision *) xmalloc (sizeof (struct decision));
- mybcopy (add, split, sizeof (struct decision));
+ mybcopy ((char *) add, (char *) split,
+ sizeof (struct decision));
add->success.first = add->success.last = split;
add->c_test = 0;
split->veclen = 0;
split->test_elt_zero_int = 0;
split->test_elt_one_int = 0;
+ split->test_elt_zero_wide = 0;
split->tests = 0;
split->pred = -1;
+ split->dupno = -1;
}
}
- old->success = merge_trees (old->success, add->success);
if (old->insn_code_number >= 0 && add->insn_code_number >= 0)
- fatal ("Two actions at one point in tree");
+ {
+ /* If one node is for a normal insn and the second is
+ for the base insn with clobbers stripped off, the
+ second node should be ignored. */
+
+ if (old->num_clobbers_to_add == 0
+ && add->num_clobbers_to_add > 0)
+ /* Nothing to do here. */
+ ;
+ else if (old->num_clobbers_to_add > 0
+ && add->num_clobbers_to_add == 0)
+ {
+ /* In this case, replace OLD with ADD. */
+ old->insn_code_number = add->insn_code_number;
+ old->num_clobbers_to_add = 0;
+ }
+ else
+ fatal ("Two actions at one point in tree");
+ }
+
if (old->insn_code_number == -1)
old->insn_code_number = add->insn_code_number;
+ old->success = merge_trees (old->success, add->success);
add = 0;
break;
}
if (best_position == 0)
abort ();
- if (old == 0 && position_merit (0, add_mode, add->code) < best_merit)
+ if (old == 0
+ && position_merit (NULL_PTR, add_mode, add->code) < best_merit)
{
add->prev = 0;
add->next = oldh.first;
int initial;
{
int size = 0;
- struct decision *node, *sub;
+ struct decision *sub;
for (sub = head.first; sub; sub = sub->next)
size += 1 + break_out_subroutines (sub->success, type, 0);
printf ("x%d;\n", max_depth);
printf (" %s tem;\n", type == SPLIT ? "rtx" : "int");
- write_tree (tree, "", 0, 1, type);
+ write_tree (tree, "", NULL_PTR, 1, type);
printf (" ret0: return %d;\n}\n\n", type == SPLIT ? 0 : -1);
}
\f
of the same mode, we also group tests with the same code, followed by a
group that does not test a code.
- Occasionally, we cannot arbitarily reorder the tests so that multiple
+ Occasionally, we cannot arbitrarily reorder the tests so that multiple
sequence of groups as described above are present.
We generate two nested switch statements, the outer statement for
resulting function. We do check for when every test is the same mode
or code. */
-void
+static void
write_tree_1 (tree, prevpos, afterward, type)
struct decision *tree;
char *prevpos;
seen any of the codes that are valid for the predicate, we
can write a series of "case" statement, one for each possible
code. Since we are already in a switch, these redundant tests
- are very cheap and will reduce the number of predicate called. */
+ are very cheap and will reduce the number of predicate called. */
if (p->pred >= 0)
{
- for (i = 0; i < NUM_RTX_CODE && preds[p->pred].codes[i]; i++)
+ for (i = 0; i < NUM_RTX_CODE && preds[p->pred].codes[i] != 0; i++)
if (codemap[(int) preds[p->pred].codes[i]])
break;
if (code == MATCH_OPERAND)
{
- for (i = 0; i < NUM_RTX_CODE && preds[p->pred].codes[i]; i++)
+ for (i = 0; i < NUM_RTX_CODE && preds[p->pred].codes[i] != 0; i++)
{
printf ("%scase ", indents[indent - 2]);
print_code (preds[p->pred].codes[i]);
}
/* Now that most mode and code tests have been done, we can write out
- a label for an inner node, if we haven't already. */
+ a label for an inner node, if we haven't already. */
if (p->label_needed)
printf ("%sL%d:\n", indents[indent - 2], p->number);
if ((mode != switch_mode && ! p->ignore_mode)
|| (p->code != switch_code && p->code != UNKNOWN && ! p->ignore_code)
- || p->test_elt_zero_int || p->test_elt_one_int || p->veclen
+ || p->test_elt_zero_int || p->test_elt_one_int
+ || p->test_elt_zero_wide || p->veclen
|| p->dupno >= 0 || p->tests || p->num_clobbers_to_add)
{
printf ("%sif (", indents[indent]);
printf ("XINT (x%d, 0) == %d && ", depth, p->elt_zero_int);
if (p->test_elt_one_int)
printf ("XINT (x%d, 1) == %d && ", depth, p->elt_one_int);
+ if (p->test_elt_zero_wide)
+ {
+ /* Set offset to 1 iff the number might get propagated to
+ unsigned long by ANSI C rules, else 0.
+ Prospective hosts are required to have at least 32 bit
+ ints, and integer constants in machine descriptions
+ must fit in 32 bit, thus it suffices to check only
+ for 1 << 31 . */
+ HOST_WIDE_INT offset = p->elt_zero_wide == -2147483647 - 1;
+ printf (
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+ "XWINT (x%d, 0) == %d%s && ",
+#else
+ "XWINT (x%d, 0) == %ld%s && ",
+#endif
+ depth, p->elt_zero_wide + offset, offset ? "-1" : "");
+ }
if (p->veclen)
printf ("XVECLEN (x%d, 0) == %d && ", depth, p->veclen);
if (p->dupno >= 0)
static void
print_code (code)
- RTX_CODE code;
+ enum rtx_code code;
{
register char *p1;
for (p1 = GET_RTX_NAME (code); *p1; p1++)
static int
same_codes (p, code)
register struct decision *p;
- register RTX_CODE code;
+ register enum rtx_code code;
{
for (; p; p = p->next)
if (p->code != code)
{
printf (" tem = %s_%d (x0, insn%s);\n",
name_prefix, tree->subroutine_number, call_suffix);
- printf (" if (tem >= 0) return tem;\n");
+ if (type == SPLIT)
+ printf (" if (tem != 0) return tem;\n");
+ else
+ printf (" if (tem >= 0) return tem;\n");
change_state (tree->position, afterward->position, 2);
printf (" goto L%d;\n", afterward->number);
}
}
static void
-fatal (s, a1, a2)
+fatal (s)
char *s;
{
fprintf (stderr, "genrecog: ");
- fprintf (stderr, s, a1, a2);
+ fprintf (stderr, s);
fprintf (stderr, "\n");
- fprintf (stderr, "after %d instruction definitions\n", next_index);
+ fprintf (stderr, "after %d definitions\n", next_index);
exit (FATAL_EXIT_CODE);
}
struct decision_head recog_tree;
struct decision_head split_tree;
FILE *infile;
- extern rtx read_rtx ();
register int c;
obstack_init (rtl_obstack);