https://gcc.gnu.org/g:80b11a66973e6e5a33d0bd43ab2a97df5b7accd9

commit r12-11200-g80b11a66973e6e5a33d0bd43ab2a97df5b7accd9
Author: Richard Earnshaw <rearn...@arm.com>
Date:   Thu Mar 20 14:42:59 2025 +0000

    opcodes: fix wrong code in expand_binop_directly [PR117811]
    
    If expand_binop_directly fails to add a REG_EQUAL note it tries to
    unwind and restart.  But it can unwind too far if expand_binop changed
    some of the operands before calling it.  We don't need to unwind that
    far anyway since we should end up taking exactly the same route next
    time, just without a target rtx.
    
    To fix this we remove LAST from the argument list and let the callers
    (all in expand_binop) do their own unwinding if the call fails.
    Instead we unwind just as far as the entry to expand_binop_directly
    and recurse within this function instead of all the way back up.
    
    gcc/ChangeLog:
    
            PR middle-end/117811
            * optabs.cc (expand_binop_directly): Remove LAST as an argument,
            instead record the last insn on entry.  Only delete insns if
            we need to restart and restart by calling ourself, not expand_binop.
            (expand_binop): Update callers to expand_binop_directly.  If it
            fails to expand the operation, delete back to LAST.
    
    gcc/testsuite:
    
            PR middle-end/117811
            * gcc.dg/torture/pr117811.c: New test.
    
    (cherry picked from commit 7679b826840c58343d72d05922355b646db4bdcc)

Diff:
---
 gcc/optabs.cc                           | 24 ++++++++++++------------
 gcc/testsuite/gcc.dg/torture/pr117811.c | 27 +++++++++++++++++++++++++++
 2 files changed, 39 insertions(+), 12 deletions(-)

diff --git a/gcc/optabs.cc b/gcc/optabs.cc
index 3d8fa3abdfea..1de349719b74 100644
--- a/gcc/optabs.cc
+++ b/gcc/optabs.cc
@@ -1353,8 +1353,7 @@ avoid_expensive_constant (machine_mode mode, optab 
binoptab,
 static rtx
 expand_binop_directly (enum insn_code icode, machine_mode mode, optab binoptab,
                       rtx op0, rtx op1,
-                      rtx target, int unsignedp, enum optab_methods methods,
-                      rtx_insn *last)
+                      rtx target, int unsignedp, enum optab_methods methods)
 {
   machine_mode xmode0 = insn_data[(int) icode].operand[1].mode;
   machine_mode xmode1 = insn_data[(int) icode].operand[2].mode;
@@ -1364,6 +1363,7 @@ expand_binop_directly (enum insn_code icode, machine_mode 
mode, optab binoptab,
   rtx_insn *pat;
   rtx xop0 = op0, xop1 = op1;
   bool canonicalize_op1 = false;
+  rtx_insn *last = get_last_insn ();
 
   /* If it is a commutative operator and the modes would match
      if we would swap the operands, we can save the conversions.  */
@@ -1428,10 +1428,7 @@ expand_binop_directly (enum insn_code icode, 
machine_mode mode, optab binoptab,
       tmp_mode = insn_data[(int) icode].operand[0].mode;
       if (VECTOR_MODE_P (mode)
          && maybe_ne (GET_MODE_NUNITS (tmp_mode), 2 * GET_MODE_NUNITS (mode)))
-       {
-         delete_insns_since (last);
-         return NULL_RTX;
-       }
+       return NULL_RTX;
     }
   else
     tmp_mode = mode;
@@ -1451,14 +1448,14 @@ expand_binop_directly (enum insn_code icode, 
machine_mode mode, optab binoptab,
                               ops[1].value, ops[2].value, mode0))
        {
          delete_insns_since (last);
-         return expand_binop (mode, binoptab, op0, op1, NULL_RTX,
-                              unsignedp, methods);
+         return expand_binop_directly (icode, mode, binoptab, op0, op1,
+                                       NULL_RTX, unsignedp, methods);
        }
 
       emit_insn (pat);
       return ops[0].value;
     }
-  delete_insns_since (last);
+
   return NULL_RTX;
 }
 
@@ -1527,9 +1524,10 @@ expand_binop (machine_mode mode, optab binoptab, rtx 
op0, rtx op1,
       if (icode != CODE_FOR_nothing)
        {
          temp = expand_binop_directly (icode, mode, binoptab, op0, op1,
-                                       target, unsignedp, methods, last);
+                                       target, unsignedp, methods);
          if (temp)
            return temp;
+         delete_insns_since (last);
        }
     }
 
@@ -1555,9 +1553,10 @@ expand_binop (machine_mode mode, optab binoptab, rtx 
op0, rtx op1,
                               NULL_RTX, unsignedp, OPTAB_DIRECT);
 
       temp = expand_binop_directly (icode, int_mode, otheroptab, op0, newop1,
-                                   target, unsignedp, methods, last);
+                                   target, unsignedp, methods);
       if (temp)
        return temp;
+      delete_insns_since (last);
     }
 
   /* If this is a multiply, see if we can do a widening operation that
@@ -1621,9 +1620,10 @@ expand_binop (machine_mode mode, optab binoptab, rtx 
op0, rtx op1,
          if (vop1)
            {
              temp = expand_binop_directly (icode, mode, otheroptab, op0, vop1,
-                                           target, unsignedp, methods, last);
+                                           target, unsignedp, methods);
              if (temp)
                return temp;
+             delete_insns_since (last);
            }
        }
     }
diff --git a/gcc/testsuite/gcc.dg/torture/pr117811.c 
b/gcc/testsuite/gcc.dg/torture/pr117811.c
new file mode 100644
index 000000000000..13d7e1347807
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr117811.c
@@ -0,0 +1,27 @@
+/* { dg-do run } */
+
+#include <string.h>
+
+typedef int v4 __attribute__((vector_size (4 * sizeof (int))));
+
+void __attribute__((noclone,noinline)) do_shift (v4 *vec, int shift)
+{
+  v4 t = *vec;
+
+  if (shift > 0)
+  {
+    t = t >> shift;
+  }
+
+  *vec = t;
+}
+
+int main ()
+{
+  v4 vec =  {0x1000000, 0x2000, 0x300, 0x40};
+  v4 vec2 = {0x100000,  0x200,  0x30,  0x4};
+  do_shift (&vec, 4);
+  if (memcmp (&vec, &vec2, sizeof (v4)) != 0)
+    __builtin_abort ();
+  return 0;
+}

Reply via email to