https://gcc.gnu.org/g:1c7824f0b88ab6e4a471c69c5f903ba6c25cbc18

commit r16-6714-g1c7824f0b88ab6e4a471c69c5f903ba6c25cbc18
Author: Richard Biener <[email protected]>
Date:   Mon Jan 12 10:04:49 2026 +0100

    tree-optimization/122830 - move VN through aggregate copies
    
    The following generalizes the few hacks we have to more loosely
    allow VN through aggregate copies to a more general (but also
    restrictive) feature to rewrite the lookup to a new base with
    a constant offset.  This should now allow all constant-indexed
    aggregate copies and it does never leave any stray components
    and hoping for the best.
    
    This resolves the diagnostic regression reported in PR122824.
    
            PR tree-optimization/122830
            PR tree-optimization/122824
            * tree-ssa-sccvn.cc (vn_reference_lookup_3): Generalize
            aggregate copy handling when no variable offsets are
            involved.
    
            * gcc.dg/tree-ssa/ssa-fre-112.c: New testcase.
            * g++.dg/warn/Warray-bounds-pr122824.C: Likewise.

Diff:
---
 gcc/testsuite/g++.dg/warn/Warray-bounds-pr122824.C | 15 ++++++++
 gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-112.c        | 27 ++++++++++++++
 gcc/tree-ssa-sccvn.cc                              | 43 +++++++++++++---------
 3 files changed, 67 insertions(+), 18 deletions(-)

diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-pr122824.C 
b/gcc/testsuite/g++.dg/warn/Warray-bounds-pr122824.C
new file mode 100644
index 000000000000..d390856deda9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-pr122824.C
@@ -0,0 +1,15 @@
+// { dg-do compile }
+// { dg-options "-O2 -std=gnu++23 -Warray-bounds" }
+
+#include <format>
+
+template <typename... Args>
+auto foo(std::format_string<Args...> && format, Args &&... args)
+{
+  return std::format(std::move(format), std::forward<Args>(args)...);
+}
+
+int main()
+{
+  auto a = foo("{}", 42);
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-112.c 
b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-112.c
new file mode 100644
index 000000000000..8ab306bf5c26
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-112.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fno-tree-sra -fdump-tree-fre1" } */
+
+struct s1
+{
+  int c;
+};
+struct s2
+{
+  struct s1 l;
+};
+
+void f(int fill)
+{
+  struct s1 D144916, last;
+  int a = fill;
+  D144916.c = a;
+  struct s2 D135323;
+  D135323.l = D144916;
+  struct s1 *s = &D135323.l;
+  const int *sc = &s->c;
+  if (*sc != a)
+    __builtin_abort();
+}
+
+/* We should be able to optimize out the condition guarding the abort.  */
+/* { dg-final { scan-tree-dump-not "abort" "fre1" } } */
diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc
index ed87ffc22862..b152dcb5943f 100644
--- a/gcc/tree-ssa-sccvn.cc
+++ b/gcc/tree-ssa-sccvn.cc
@@ -3664,14 +3664,32 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void 
*data_,
                  temj--;
                }
            }
-         /* When the LHS is already at the outermost level simply
-            adjust for any offset difference.  Further lookups
-            will fail when there's too gross of a type compatibility
-            issue.  */
-         if (!found && j == 0)
+         /* When we cannot find a common base to reconstruct the full
+            reference instead try to reduce the lookup to the new
+            base plus a constant offset.  */
+         if (!found)
            {
-             extra_off = vr->operands[i].off - lhs_ops[j].off;
-             i--, j--;
+             while (j >= 0
+                    && known_ne (lhs_ops[j].off, -1))
+               {
+                 extra_off += -lhs_ops[j].off;
+                 j--;
+               }
+             if (j != -1)
+               return (void *)-1;
+             while (i >= 0
+                    && known_ne (vr->operands[i].off, -1))
+               {
+                 /* Punt if the additional ops contain a storage order
+                    barrier.  */
+                 if (vr->operands[i].opcode == VIEW_CONVERT_EXPR
+                     && vr->operands[i].reverse)
+                   break;
+                 extra_off += vr->operands[i].off;
+                 i--;
+               }
+             if (i != -1)
+               return (void *)-1;
              found = true;
            }
          /* If we did find a match we'd eventually append a MEM_REF
@@ -3691,17 +3709,6 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void 
*data_,
          j--;
        }
 
-      /* When we still didn't manage to strip off all components from
-        lhs_op, opportunistically continue for those we can handle
-        via extra_off.  Note this is an attempt to fixup secondary
-        copies after we hit the !found && j == 0 case above.  */
-      while (j != -1
-            && known_ne (lhs_ops[j].off, -1))
-       {
-         extra_off += -lhs_ops[j].off;
-         j--;
-       }
-
       /* i now points to the first additional op.
         ???  LHS may not be completely contained in VR, one or more
         VIEW_CONVERT_EXPRs could be in its way.  We could at least

Reply via email to