[gcc r16-6714] tree-optimization/122830 - move VN through aggregate copies

Richard Biener rguenth@gcc.gnu.org
Mon Jan 12 11:40:32 GMT 2026


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

commit r16-6714-g1c7824f0b88ab6e4a471c69c5f903ba6c25cbc18
Author: Richard Biener <rguenther@suse.de>
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


More information about the Gcc-cvs mailing list