At the moment, define_cond_exec allows only a single substitution pattern. That is rather limiting if the target needs to clobber a scratch register in order to compute the required condition. The attached patch allows to add clobber patterns after the main pattern, and also adds support for MATCH_SCRATCH in alter_predicate_for_insn.
This makes most sense together with the previous patch for MATCH_DUP support, although the latter can also be used stand-alone, so have posted and tested these patches separately. Bootstrapped on x86_64-pc-linux-gnu.
2020-12-12 Joern Rennecke <joern.renne...@embecosm.com> Fix define_cond_exec flaw of not accepting clobbers. * gensupport.c (alter_predicate_for_insn): Handle MATCH_SCRATCH. (process_one_cond_exec): Allow extra patterns for clobbers. diff --git a/gcc/gensupport.c b/gcc/gensupport.c index e1ca06dbc1e..b472dc115b5 100644 --- a/gcc/gensupport.c +++ b/gcc/gensupport.c @@ -1198,8 +1198,11 @@ alter_predicate_for_insn (rtx pattern, int alt, int max_op, switch (code) { case MATCH_OPERAND: + case MATCH_SCRATCH: { - const char *c = XSTR (pattern, 2); + const char **altstr_loc + = &XSTR (pattern, code == MATCH_SCRATCH ? 1 : 2); + const char *c = *altstr_loc; if (n_alternatives (c) != 1) { @@ -1216,19 +1219,22 @@ alter_predicate_for_insn (rtx pattern, int alt, int max_op, char *new_c = XNEWVEC (char, len); memcpy (new_c, c, c_len); + char *wp = new_c + c_len; + if (*c == '=') + c++, c_len--; for (i = 1; i < alt; ++i) { - new_c[i * (c_len + 1) - 1] = ','; - memcpy (&new_c[i * (c_len + 1)], c, c_len); + *wp++ = ','; + memcpy (wp, c, c_len); + wp += c_len; } - new_c[len - 1] = '\0'; - XSTR (pattern, 2) = new_c; + *wp = '\0'; + *altstr_loc = new_c; } } /* Fall through. */ case MATCH_OPERATOR: - case MATCH_SCRATCH: case MATCH_PARALLEL: XINT (pattern, 0) += max_op; break; @@ -1754,13 +1760,18 @@ process_one_cond_exec (class queue_elem *ce_elem) collect_insn_data (insn_elem->data, &alternatives, &max_operand); max_operand += 1; - if (XVECLEN (ce_elem->data, 0) != 1) + for (i = XVECLEN (ce_elem->data, 0) - 1; i > 0; i--) { - error_at (ce_elem->loc, "too many patterns in predicate"); - return; + rtx part = XVECEXP (ce_elem->data, 0, i); + if (GET_CODE (part) != CLOBBER) + { + error_at (ce_elem->loc, "too many patterns in predicate"); + return; + } } pred = copy_rtx (XVECEXP (ce_elem->data, 0, 0)); + int n_clobbers = XVECLEN (ce_elem->data, 0) - 1; pred = alter_predicate_for_insn (pred, alternatives, max_operand, ce_elem->loc); if (pred == NULL) @@ -1774,8 +1785,15 @@ process_one_cond_exec (class queue_elem *ce_elem) pattern = rtx_alloc (COND_EXEC); XEXP (pattern, 0) = pred; XEXP (pattern, 1) = add_implicit_parallel (XVEC (insn, 1)); - XVEC (insn, 1) = rtvec_alloc (1); + XVEC (insn, 1) = rtvec_alloc (1 + n_clobbers); XVECEXP (insn, 1, 0) = pattern; + for (int i = n_clobbers; i > 0; i--) + { + rtx clobber = copy_rtx (XVECEXP (ce_elem->data, 0, i)); + clobber = alter_predicate_for_insn (clobber, alternatives, + max_operand, ce_elem->loc); + XVECEXP (insn, 1, i) = clobber; + } if (XVEC (ce_elem->data, 3) != NULL) {