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;
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;
if (this->tests == NULL)
abort ();
+ ret:
+ free (subpos);
return sub;
}
\f
}
}
+ /* 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;
}
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))
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;
}
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
|| type == DT_elt_one_int
|| type == DT_elt_zero_wide)
{
+ /* The argument is casted to int. In case HOST_WIDE_INT is more exact,
+ we can't safely construct switch statement over it. */
+ if (type == DT_elt_zero_wide && HOST_BITS_PER_WIDE_INT > sizeof (int) * CHAR_BIT)
+ return p;
printf (" switch (");
switch (type)
{
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;
#include \"flags.h\"\n\
#include \"hard-reg-set.h\"\n\
#include \"resource.h\"\n\
+#include \"toplev.h\"\n\
\n");
puts ("\n\
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;