struct decision_test *next;
/* These types are roughly in the order in which we'd like to test them. */
- enum decision_type {
- DT_mode, DT_code, DT_veclen,
- DT_elt_zero_int, DT_elt_one_int, DT_elt_zero_wide,
- DT_dup, DT_pred, DT_c_test,
- DT_accept_op, DT_accept_insn
- } type;
+ enum decision_type
+ {
+ DT_mode, DT_code, DT_veclen,
+ DT_elt_zero_int, DT_elt_one_int, DT_elt_zero_wide, DT_elt_zero_wide_safe,
+ DT_veclen_ge, DT_dup, DT_pred, DT_c_test,
+ DT_accept_op, DT_accept_insn
+ } type;
union
{
LABEL_REF, SUBREG, REG, MEM}}
};
-#define NUM_KNOWN_PREDS (sizeof preds / sizeof preds[0])
+#define NUM_KNOWN_PREDS ARRAY_SIZE (preds)
static const char * special_mode_pred_table[] = {
#ifdef SPECIAL_MODE_PREDICATES
"pmode_register_operand"
};
-#define NUM_SPECIAL_MODE_PREDS \
- (sizeof (special_mode_pred_table) / sizeof (special_mode_pred_table[0]))
+#define NUM_SPECIAL_MODE_PREDS ARRAY_SIZE (special_mode_pred_table)
static struct decision *new_decision
PARAMS ((const char *, struct decision_head *));
PARAMS ((enum decision_type, struct decision_test ***));
static rtx find_operand
PARAMS ((rtx, int));
+static rtx find_matching_operand
+ PARAMS ((rtx, int));
static void validate_pattern
- PARAMS ((rtx, rtx, rtx));
+ PARAMS ((rtx, rtx, rtx, int));
static struct decision *add_to_sequence
PARAMS ((rtx, struct decision_head *, const char *, enum routine_type, int));
return r;
break;
+ case 'V':
+ if (! XVEC (pattern, i))
+ break;
+ /* FALLTHRU */
+
case 'E':
for (j = 0; j < XVECLEN (pattern, i); j++)
if ((r = find_operand (XVECEXP (pattern, i, j), n)) != NULL_RTX)
return NULL;
}
+/* Search for and return operand M, such that it has a matching
+ constraint for operand N. */
+
+static rtx
+find_matching_operand (pattern, n)
+ rtx pattern;
+ int n;
+{
+ const char *fmt;
+ RTX_CODE code;
+ int i, j, len;
+ rtx r;
+
+ code = GET_CODE (pattern);
+ if (code == MATCH_OPERAND
+ && (XSTR (pattern, 2)[0] == '0' + n
+ || (XSTR (pattern, 2)[0] == '%'
+ && XSTR (pattern, 2)[1] == '0' + n)))
+ return pattern;
+
+ fmt = GET_RTX_FORMAT (code);
+ len = GET_RTX_LENGTH (code);
+ for (i = 0; i < len; i++)
+ {
+ switch (fmt[i])
+ {
+ case 'e': case 'u':
+ if ((r = find_matching_operand (XEXP (pattern, i), n)))
+ return r;
+ break;
+
+ case 'V':
+ if (! XVEC (pattern, i))
+ break;
+ /* FALLTHRU */
+
+ case 'E':
+ for (j = 0; j < XVECLEN (pattern, i); j++)
+ if ((r = find_matching_operand (XVECEXP (pattern, i, j), n)))
+ return r;
+ break;
+
+ case 'i': case 'w': case '0': case 's':
+ break;
+
+ default:
+ abort ();
+ }
+ }
+
+ return NULL;
+}
+
+
/* Check for various errors in patterns. SET is nonnull for a destination,
- and is the complete set pattern. */
+ and is the complete set pattern. SET_CODE is '=' for normal sets, and
+ '+' within a context that requires in-out constraints. */
static void
-validate_pattern (pattern, insn, set)
+validate_pattern (pattern, insn, set, set_code)
rtx pattern;
rtx insn;
rtx set;
+ int set_code;
{
const char *fmt;
RTX_CODE code;
}
/* A MATCH_OPERAND that is a SET should have an output reload. */
- if (set
- && code == MATCH_OPERAND
- && XSTR (pattern, 2)[0] != '\0'
- && XSTR (pattern, 2)[0] != '='
- && XSTR (pattern, 2)[0] != '+')
+ if (set && code == MATCH_OPERAND
+ && XSTR (pattern, 2)[0] != '\0')
{
- message_with_line (pattern_lineno,
- "operand %d missing output reload",
- XINT (pattern, 0));
- error_count++;
+ if (set_code == '+')
+ {
+ if (XSTR (pattern, 2)[0] == '+')
+ ;
+ /* If we've only got an output reload for this operand,
+ we'd better have a matching input operand. */
+ else if (XSTR (pattern, 2)[0] == '='
+ && find_matching_operand (insn, XINT (pattern, 0)))
+ ;
+ else
+ {
+ message_with_line (pattern_lineno,
+ "operand %d missing in-out reload",
+ XINT (pattern, 0));
+ error_count++;
+ }
+ }
+ else if (XSTR (pattern, 2)[0] != '='
+ && XSTR (pattern, 2)[0] != '+')
+ {
+ message_with_line (pattern_lineno,
+ "operand %d missing output reload",
+ XINT (pattern, 0));
+ error_count++;
+ }
}
/* Allowing non-lvalues in destinations -- particularly CONST_INT --
}
if (dest != SET_DEST (pattern))
- validate_pattern (dest, insn, pattern);
- validate_pattern (SET_DEST (pattern), insn, pattern);
- validate_pattern (SET_SRC (pattern), insn, NULL_RTX);
+ validate_pattern (dest, insn, pattern, '=');
+ validate_pattern (SET_DEST (pattern), insn, pattern, '=');
+ validate_pattern (SET_SRC (pattern), insn, NULL_RTX, 0);
return;
}
case CLOBBER:
- validate_pattern (SET_DEST (pattern), insn, pattern);
+ validate_pattern (SET_DEST (pattern), insn, pattern, '=');
+ return;
+
+ case ZERO_EXTRACT:
+ validate_pattern (XEXP (pattern, 0), insn, set, set ? '+' : 0);
+ validate_pattern (XEXP (pattern, 1), insn, NULL_RTX, 0);
+ validate_pattern (XEXP (pattern, 2), insn, NULL_RTX, 0);
+ return;
+
+ case STRICT_LOW_PART:
+ validate_pattern (XEXP (pattern, 0), insn, set, set ? '+' : 0);
return;
case LABEL_REF:
switch (fmt[i])
{
case 'e': case 'u':
- validate_pattern (XEXP (pattern, i), insn, NULL_RTX);
+ validate_pattern (XEXP (pattern, i), insn, NULL_RTX, 0);
break;
case 'E':
for (j = 0; j < XVECLEN (pattern, i); j++)
- validate_pattern (XVECEXP (pattern, i, j), insn, NULL_RTX);
+ validate_pattern (XVECEXP (pattern, i, j), insn, NULL_RTX, 0);
break;
case 'i': case 'w': case '0': case 's':
if (depth > max_depth)
max_depth = depth;
- subpos = (char *) alloca (depth + 2);
+ subpos = (char *) xmalloc (depth + 2);
strcpy (subpos, position);
subpos[depth + 1] = 0;
last, subpos, insn_type, 0);
last = &sub->success;
}
- return sub;
+ goto ret;
}
/* Else nothing special. */
break;
+ case MATCH_PARALLEL:
+ /* The explicit patterns within a match_parallel enforce a minimum
+ length on the vector. The match_parallel predicate may allow
+ for more elements. We do need to check for this minimum here
+ or the code generated to match the internals may reference data
+ beyond the end of the vector. */
+ test = new_decision_test (DT_veclen_ge, &place);
+ test->u.veclen = XVECLEN (pattern, 2);
+ /* FALLTHRU */
+
case MATCH_OPERAND:
case MATCH_SCRATCH:
case MATCH_OPERATOR:
- case MATCH_PARALLEL:
case MATCH_INSN:
{
const char *pred_name;
code = UNKNOWN;
}
- /* We know exactly what const_int_operand matches -- any CONST_INT. */
- if (strcmp ("const_int_operand", pred_name) == 0)
- {
- code = CONST_INT;
- mode = VOIDmode;
- }
- else if (pred_name[0] != 0)
+ if (pred_name[0] != 0)
{
test = new_decision_test (DT_pred, &place);
test->u.pred.name = pred_name;
test->u.pred.mode = mode;
- /* See if we know about this predicate and save its number. If
- we do, and it only accepts one code, note that fact. The
- predicate `const_int_operand' only tests for a CONST_INT, so
- if we do so we can avoid calling it at all.
+ /* See if we know about this predicate and save its number.
+ If we do, and it only accepts one code, note that fact.
- 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 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 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 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. */
for (i = 0; i < NUM_KNOWN_PREDS; i++)
if (! strcmp (preds[i].name, pred_name))
}
else if (fmt[i] == 'w')
{
+ /* If this value actually fits in an int, we can use a switch
+ statement here, so indicate that. */
+ enum decision_type type
+ = ((int) XWINT (pattern, i) == XWINT (pattern, i))
+ ? DT_elt_zero_wide_safe : DT_elt_zero_wide;
+
if (i != 0)
abort ();
- test = new_decision_test (DT_elt_zero_wide, &place);
+ test = new_decision_test (type, &place);
test->u.intval = XWINT (pattern, i);
}
else if (fmt[i] == 'E')
if (this->tests == NULL)
abort ();
+ ret:
+ free (subpos);
return sub;
}
\f
case DT_elt_zero_int:
case DT_elt_one_int:
case DT_elt_zero_wide:
+ case DT_elt_zero_wide_safe:
return d1->u.intval == d2->u.intval;
default:
}
}
+ /* Tests vs veclen may be known when strict equality is involved. */
+ if (d1->type == DT_veclen && d2->type == DT_veclen_ge)
+ return d1->u.veclen >= d2->u.veclen;
+ if (d1->type == DT_veclen_ge && d2->type == DT_veclen)
+ return d2->u.veclen >= d1->u.veclen;
+
return -1;
}
p1 = d1, d1 = d2, d2 = p1;
if (d1->success.first == 0)
- return 0;
+ return 1;
for (p1 = d1->success.first; p1; p1 = p1->next)
if (maybe_both_true (p1, d2, 0))
return 1;
return strcmp (d1->u.c_test, d2->u.c_test) == 0;
case DT_veclen:
+ case DT_veclen_ge:
return d1->u.veclen == d2->u.veclen;
case DT_dup:
case DT_elt_zero_int:
case DT_elt_one_int:
case DT_elt_zero_wide:
+ case DT_elt_zero_wide_safe:
return d1->u.intval == d2->u.intval;
case DT_accept_op:
return 0;
/* Check that their subnodes are at the same position, as any one set
- of sibling decisions must be at the same position. */
+ of sibling decisions must be at the same position. Allowing this
+ requires complications to find_afterward and when change_state is
+ invoked. */
if (d1->success.first
&& d2->success.first
&& strcmp (d1->success.first->position, d2->success.first->position))
how expensive/important the test is. Given that the tests
are also ordered within the list, examining the first is
sufficient. */
- if (add->tests->type < old->tests->type)
+ if ((int) add->tests->type < (int) old->tests->type)
insert_before = old;
}
&& type != DT_veclen
&& type != DT_elt_zero_int
&& type != DT_elt_one_int
- && type != DT_elt_zero_wide)
+ && type != DT_elt_zero_wide_safe)
continue;
/* If we'd been performing more than one test, create a new node
{
struct decision *p = start;
enum decision_type type = p->tests->type;
+ struct decision *needs_label = NULL;
/* If we have two or more nodes in sequence that test the same one
thing, we may be able to use a switch statement. */
if (!p->next
|| p->tests->next
|| p->next->tests->type != type
- || p->next->tests->next)
+ || p->next->tests->next
+ || nodes_identical_1 (p->tests, p->next->tests))
return p;
/* DT_code is special in that we can do interesting things with
code = p->tests->u.code;
do
{
+ if (p != start && p->need_label && needs_label == NULL)
+ needs_label = p;
+
printf (" case ");
print_code (code);
printf (":\n goto L%d;\n", p->success.first->number);
we don't actually write the test here, as it gets kinda messy.
It is trivial to leave this to later by telling our caller that
we only processed the CODE tests. */
- ret = p;
+ if (needs_label != NULL)
+ ret = needs_label;
+ else
+ ret = p;
while (p && p->tests->type == DT_pred
&& p->tests->u.pred.index >= 0)
|| type == DT_veclen
|| type == DT_elt_zero_int
|| type == DT_elt_one_int
- || type == DT_elt_zero_wide)
+ || type == DT_elt_zero_wide_safe)
{
printf (" switch (");
switch (type)
case DT_elt_one_int:
printf ("XINT (x%d, 1)", depth);
break;
- case DT_elt_zero_wide:
+ case DT_elt_zero_wide_safe:
/* Convert result of XWINT to int for portability since some C
compilers won't do it and some will. */
printf ("(int) XWINT (x%d, 0)", depth);
do
{
+ /* Merge trees will not unify identical nodes if their
+ sub-nodes are at different levels. Thus we must check
+ for duplicate cases. */
+ struct decision *q;
+ for (q = start; q != p; q = q->next)
+ if (nodes_identical_1 (p->tests, q->tests))
+ goto case_done;
+
+ if (p != start && p->need_label && needs_label == NULL)
+ needs_label = p;
+
printf (" case ");
switch (type)
{
case DT_elt_zero_int:
case DT_elt_one_int:
case DT_elt_zero_wide:
+ case DT_elt_zero_wide_safe:
printf (HOST_WIDE_INT_PRINT_DEC, p->tests->u.intval);
break;
default:
p = p->next;
}
while (p && p->tests->type == type && !p->tests->next);
-
+
+ case_done:
printf (" default:\n break;\n }\n");
- return p;
+ return needs_label != NULL ? needs_label : p;
}
else
{
break;
case DT_elt_zero_wide:
+ case DT_elt_zero_wide_safe:
printf ("XWINT (x%d, 0) == ", depth);
printf (HOST_WIDE_INT_PRINT_DEC, p->u.intval);
break;
+ case DT_veclen_ge:
+ printf ("XVECLEN (x%d, 0) >= %d", depth, p->u.veclen);
+ break;
+
case DT_dup:
printf ("rtx_equal_p (x%d, operands[%d])", depth, p->u.dup);
break;
printf (" %s tem ATTRIBUTE_UNUSED;\n", IS_SPLIT (type) ? "rtx" : "int");
+ if (!subfunction)
+ printf (" recog_data.insn = NULL_RTX;\n");
+
if (head->first)
write_tree (head, "", type, 1);
else
#include \"flags.h\"\n\
#include \"hard-reg-set.h\"\n\
#include \"resource.h\"\n\
+#include \"toplev.h\"\n\
\n");
puts ("\n\
PUT_MODE (x, VOIDmode);
}
- validate_pattern (x, insn, NULL_RTX);
+ validate_pattern (x, insn, NULL_RTX, 0);
memset(&head, 0, sizeof(head));
last = add_to_sequence (x, &head, "", type, 1);
fprintf (stderr, "elt0_w=");
fprintf (stderr, HOST_WIDE_INT_PRINT_DEC, test->u.intval);
break;
+ case DT_elt_zero_wide_safe:
+ fprintf (stderr, "elt0_ws=");
+ fprintf (stderr, HOST_WIDE_INT_PRINT_DEC, test->u.intval);
+ break;
+ case DT_veclen_ge:
+ fprintf (stderr, "veclen>=%d", test->u.veclen);
+ break;
case DT_dup:
fprintf (stderr, "dup=%d", test->u.dup);
break;