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)
        {

Reply via email to