aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Biener <rguenther@suse.de>2025-08-03 12:02:31 +0200
committerRichard Biener <rguenth@gcc.gnu.org>2025-08-04 11:44:42 +0200
commit0d276cd378e7a41b9004577a30b9a8ca16ec6b4c (patch)
treeba6ee2e71466d50ae3b7c3249d15cf2962c90084
parent57a97725a5c493bd8cde0b0c5679099b1a23c795 (diff)
downloadgcc-0d276cd378e7a41b9004577a30b9a8ca16ec6b4c.zip
gcc-0d276cd378e7a41b9004577a30b9a8ca16ec6b4c.tar.gz
gcc-0d276cd378e7a41b9004577a30b9a8ca16ec6b4c.tar.bz2
tree-optimization/121362 - missed FRE through aggregate copy
The following streamlines and generalizes how we find the common base of the lookup ref and a kill ref when looking through aggregate copies. In particular this tries to deal with all variants of punning that happens on the inner MEM_REF after forwarding of address taken components of the common base. PR tree-optimization/121362 * tree-ssa-sccvn.cc (vn_reference_lookup_3): Generalize aggregate copy handling. * gcc.dg/tree-ssa/ssa-fre-105.c: New testcase. * gcc.dg/tree-ssa/ssa-fre-106.c: Likewise.
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-105.c33
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-106.c33
-rw-r--r--gcc/tree-ssa-sccvn.cc108
3 files changed, 153 insertions, 21 deletions
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-105.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-105.c
new file mode 100644
index 0000000..61b93c0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-105.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fno-tree-sra -fdump-tree-fre1-details" } */
+
+struct s1
+{
+ int t, t1;
+};
+
+struct s3
+{
+ struct s1 t;
+};
+
+struct s2
+{
+ struct s3 t;
+};
+
+void f(int, int);
+void l();
+void g(int a, int b, int *p)
+{
+ struct s2 c;
+ {
+ struct s1 tmp = {a,b};
+ struct s3 *t = &c.t;
+ t->t = tmp;
+ }
+ f(c.t.t.t, c.t.t.t1);
+}
+
+/* { dg-final { scan-tree-dump "Replaced c.t.t.t1 with b" "fre1" } } */
+/* { dg-final { scan-tree-dump "Replaced c.t.t.t with a" "fre1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-106.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-106.c
new file mode 100644
index 0000000..6da4201
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-106.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fno-tree-sra -fdump-tree-fre1-details" } */
+
+struct s1
+{
+ int t, t1;
+};
+
+struct s3
+{
+ struct s1 t;
+};
+
+struct s2
+{
+ struct s3 t;
+};
+
+void f(int, int);
+void l();
+void g(int a, int b, int *p)
+{
+ struct s2 c;
+ {
+ struct s1 tmp = {a,b};
+ c.t.t = tmp;
+ }
+ struct s1 *t = &c.t.t;
+ f(t->t, t->t1);
+}
+
+/* { dg-final { scan-tree-dump "Replaced \[^\r\n\]*.t1 with b" "fre1" } } */
+/* { dg-final { scan-tree-dump "Replaced \[^\r\n\]*.t with a" "fre1" } } */
diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc
index 3974c4d..00315d1 100644
--- a/gcc/tree-ssa-sccvn.cc
+++ b/gcc/tree-ssa-sccvn.cc
@@ -3549,8 +3549,95 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
/* Find the common base of ref and the lhs. lhs_ops already
contains valueized operands for the lhs. */
+ poly_int64 extra_off = 0;
i = vr->operands.length () - 1;
j = lhs_ops.length () - 1;
+
+ /* The base should be always equal due to the above check. */
+ if (! vn_reference_op_eq (&vr->operands[i], &lhs_ops[j]))
+ return (void *)-1;
+ i--, j--;
+
+ /* The 2nd component should always exist and be a MEM_REF. */
+ if (!(i >= 0 && j >= 0))
+ ;
+ else if (vn_reference_op_eq (&vr->operands[i], &lhs_ops[j]))
+ i--, j--;
+ else if (vr->operands[i].opcode == MEM_REF
+ && lhs_ops[j].opcode == MEM_REF
+ && known_ne (lhs_ops[j].off, -1)
+ && known_ne (vr->operands[i].off, -1))
+ {
+ bool found = false;
+ /* When we ge a mismatch at a MEM_REF that is not the sole component
+ try finding a match in one of the outer components and continue
+ stripping there. This happens when addresses of components get
+ forwarded into dereferences. */
+ if (j > 0)
+ {
+ int temi = i - 1;
+ extra_off = vr->operands[i].off;
+ while (temi >= 0
+ && known_ne (vr->operands[temi].off, -1))
+ {
+ if (vr->operands[temi].type
+ && lhs_ops[j].type
+ && (TYPE_MAIN_VARIANT (vr->operands[temi].type)
+ == TYPE_MAIN_VARIANT (lhs_ops[j].type)))
+ {
+ i = temi;
+ /* Strip the component that was type matched to
+ the MEM_REF. */
+ extra_off += vr->operands[i].off - lhs_ops[j].off;
+ i--, j--;
+ /* Strip further equal components. */
+ found = true;
+ break;
+ }
+ extra_off += vr->operands[temi].off;
+ temi--;
+ }
+ }
+ if (!found && i > 0)
+ {
+ int temj = j - 1;
+ extra_off = -lhs_ops[j].off;
+ while (temj >= 0
+ && known_ne (lhs_ops[temj].off, -1))
+ {
+ if (vr->operands[i].type
+ && lhs_ops[temj].type
+ && (TYPE_MAIN_VARIANT (vr->operands[i].type)
+ == TYPE_MAIN_VARIANT (lhs_ops[temj].type)))
+ {
+ j = temj;
+ /* Strip the component that was type matched to
+ the MEM_REF. */
+ extra_off += vr->operands[i].off - lhs_ops[j].off;
+ i--, j--;
+ /* Strip further equal components. */
+ found = true;
+ break;
+ }
+ extra_off += -lhs_ops[temj].off;
+ 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)
+ {
+ extra_off = vr->operands[i].off - lhs_ops[j].off;
+ i--, j--;
+ }
+ }
+ else
+ return (void *)-1;
+
+ /* Strip further common components, attempting to consume lhs_ops
+ in full. */
while (j >= 0 && i >= 0
&& vn_reference_op_eq (&vr->operands[i], &lhs_ops[j]))
{
@@ -3558,27 +3645,6 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_,
j--;
}
- /* ??? The innermost op should always be a MEM_REF and we already
- checked that the assignment to the lhs kills vr. Thus for
- aggregate copies using char[] types the vn_reference_op_eq
- may fail when comparing types for compatibility. But we really
- don't care here - further lookups with the rewritten operands
- will simply fail if we messed up types too badly. */
- poly_int64 extra_off = 0;
- if (j == 0 && i >= 0
- && lhs_ops[0].opcode == MEM_REF
- && maybe_ne (lhs_ops[0].off, -1))
- {
- if (known_eq (lhs_ops[0].off, vr->operands[i].off))
- i--, j--;
- else if (vr->operands[i].opcode == MEM_REF
- && maybe_ne (vr->operands[i].off, -1))
- {
- extra_off = vr->operands[i].off - lhs_ops[0].off;
- i--, 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