/* Generate code from machine description to recognize rtl as insns.
- Copyright (C) 1987, 1988, 1991 Free Software Foundation, Inc.
+ Copyright (C) 1987, 1988, 1992 Free Software Foundation, Inc.
This file is part of GNU CC.
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 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 */
#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;
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;
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;
&& 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;
}
}
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;
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;
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]);
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)
+ printf (
+#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
+ "XWINT (x%d, 0) == %d && ",
+#else
+ "XWINT (x%d, 0) == %ld && ",
+#endif
+ depth, p->elt_zero_wide);
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);
struct decision_head recog_tree;
struct decision_head split_tree;
FILE *infile;
- extern rtx read_rtx ();
register int c;
obstack_init (rtl_obstack);