/* Generate code from machine description to recognize rtl as insns.
- Copyright (C) 1987, 1988, 1992 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"
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, 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
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;
}
}
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
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 definitions\n", next_index);
exit (FATAL_EXIT_CODE);