https://gcc.gnu.org/g:f73379f550d19f779d46a98e507aaa1d328876a5

commit r15-11328-gf73379f550d19f779d46a98e507aaa1d328876a5
Author: Alex Coplan <[email protected]>
Date:   Thu Jun 18 15:05:07 2026 +0100

    aarch64: Fix unsharing in svset_impl::fold [PR125818]
    
    svset_impl::fold lowers svset intrinsics into a copy of the entire tuple
    and then a subsequent update of the given tuple member to the new vector
    value, e.g.:
    
      D.14149 = svset2_f32 (a, 0, v);
    
    gets lowered into:
    
      D.14149 = a;
      D.14149.__val[0] = v;
    
    .  Because both stmts use the lhs of the original call stmt, the code
    unshares the expressions.  As svset_impl::fold notes:
    
        /* [...]
           The fold routines expect the replacement statement to have the
           same lhs as the original call, so return the copy statement
           rather than the field update.  */
    
    ultimately gsi_replace asserts that:
    
      gimple_get_lhs (orig_stmt) == gimple_get_lhs (stmt)
    
    i.e. requiring pointer equality, but the copy stmt we build is:
    
      gassign *copy = gimple_build_assign (unshare_expr (f.lhs), rhs_tuple);
    
    and notably the unshare_expr means that the pointer equality test above
    fails.  For VAR_DECLs (as above) it happens to work, since those aren't
    unshared.  mostly_copy_tree_r (called from unshare_expr) has:
    
      /* Stop at types, decls, constants like copy_tree_r.  */
      else if (TREE_CODE_CLASS (code) == tcc_type
               || TREE_CODE_CLASS (code) == tcc_declaration
               || TREE_CODE_CLASS (code) == tcc_constant)
        *walk_subtrees = 0;
    
    but for MEM_EXPRs (as with the tescase in the PR) we *do* actually
    unshare them, and thus trip the assert in gsi_replace (or since
    r17-1237-g4fb2541debcca1, ICE in completely_unused, but the root cause
    is the same).
    
    We want the stmt returned from svset_impl::fold (copy) to have a
    pointer-identical lhs as the original stmt, so this patch just changes
    which use of f.lhs is unshared.  We keep copy's use as per the original
    stmt, and unshare the use in the update stmt instead.
    
    gcc/ChangeLog:
    
            PR target/125818
            * config/aarch64/aarch64-sve-builtins-base.cc (svset_impl::fold): 
Fix
            unsharing to ensure the returned stmt has the exact same lhs as the
            original.
    
    gcc/testsuite/ChangeLog:
    
            PR target/125818
            * gcc.target/aarch64/torture/pr125818.c: New test.
    
    (cherry picked from commit f6aac7ffab9f80d55b58beafc87da3379a70672a)

Diff:
---
 gcc/config/aarch64/aarch64-sve-builtins-base.cc     | 4 ++--
 gcc/testsuite/gcc.target/aarch64/torture/pr125818.c | 6 ++++++
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/gcc/config/aarch64/aarch64-sve-builtins-base.cc 
b/gcc/config/aarch64/aarch64-sve-builtins-base.cc
index 6eef545dd3f6..7e6c25d0a7c3 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins-base.cc
+++ b/gcc/config/aarch64/aarch64-sve-builtins-base.cc
@@ -2937,12 +2937,12 @@ public:
        The fold routines expect the replacement statement to have the
        same lhs as the original call, so return the copy statement
        rather than the field update.  */
-    gassign *copy = gimple_build_assign (unshare_expr (f.lhs), rhs_tuple);
+    gassign *copy = gimple_build_assign (f.lhs, rhs_tuple);
 
     /* Get a reference to the individual vector.  */
     tree field = tuple_type_field (TREE_TYPE (f.lhs));
     tree lhs_array = build3 (COMPONENT_REF, TREE_TYPE (field),
-                            f.lhs, field, NULL_TREE);
+                            unshare_expr (f.lhs), field, NULL_TREE);
     tree lhs_vector = build4 (ARRAY_REF, TREE_TYPE (rhs_vector),
                              lhs_array, index, NULL_TREE, NULL_TREE);
     gassign *update = gimple_build_assign (lhs_vector, rhs_vector);
diff --git a/gcc/testsuite/gcc.target/aarch64/torture/pr125818.c 
b/gcc/testsuite/gcc.target/aarch64/torture/pr125818.c
new file mode 100644
index 000000000000..875092000df6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/torture/pr125818.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=armv8.2-a+sve" } */
+#include <arm_sve.h>
+void f(svfloat32x2_t *tp, const svfloat32x2_t *tuple, const svfloat32_t *vp) {
+  *tp = svset2_f32(*tuple, 0, *vp);
+}

Reply via email to