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_veclen_ge, DT_dup, DT_pred, DT_c_test,
DT_accept_op, DT_accept_insn
} type;
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, int));
static struct decision *add_to_sequence
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. SET_CODE is '=' for normal sets, and
'+' within a context that requires in-out constraints. */
}
/* A MATCH_OPERAND that is a SET should have an output reload. */
- if (set && code == MATCH_OPERAND)
+ if (set && code == MATCH_OPERAND
+ && XSTR (pattern, 2)[0] != '\0')
{
- if (set_code == '+'
- && XSTR (pattern, 2)[0] != '\0'
- && XSTR (pattern, 2)[0] != '+')
+ if (set_code == '+')
{
- message_with_line (pattern_lineno,
- "operand %d missing in-out reload",
- XINT (pattern, 0));
- error_count++;
+ 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] != '\0'
- && XSTR (pattern, 2)[0] != '='
+ else if (XSTR (pattern, 2)[0] != '='
&& XSTR (pattern, 2)[0] != '+')
{
message_with_line (pattern_lineno,
case STRICT_LOW_PART:
validate_pattern (XEXP (pattern, 0), insn, set, set ? '+' : 0);
- validate_pattern (XEXP (pattern, 1), insn, NULL, 0);
return;
case LABEL_REF:
/* 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;
}
}
+ /* 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:
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))
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
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;
p = p->next;
}
while (p && p->tests->type == type && !p->tests->next);
-
+
+ case_done:
printf (" default:\n break;\n }\n");
return needs_label != NULL ? needs_label : p;
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;
fprintf (stderr, "elt0_w=");
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;