https://gcc.gnu.org/g:95afbe4c7633459b59d434550888decc41b4d44f
commit r16-3561-g95afbe4c7633459b59d434550888decc41b4d44f Author: Richard Biener <rguent...@suse.de> Date: Wed Sep 3 12:54:58 2025 +0200 tree-optimization/121740 - handle aggregate zeroing as skipped may-def The following makes value-numbering handle a situation like D.58046 = {}; SR.83_44->i = {}; pretmp_41 = MEM[(struct _Optional_payload_base &)&D.58046 + 8]._M_engaged; where the intermediate may-def SR.83_44->i = {} prevents CSE of the load to zero. The problem is two-fold here, one is that the code skipping may-defs does not handle zeroing via a CTOR, the other is that (partial) must-defs can be better handled by later code as otherwise we may not find an appropriate definition to CSE to. I've noticed we fail to guard against storage-order issues, so fixed that on the fly. PR tree-optimization/121740 * tree-ssa-sccvn.cc (vn_reference_lookup_3): Allow skipping may-defs from CTORs. Do not skip may-defs with storage-order issues or (partial) must-defs. * gcc.dg/tree-ssa/ssa-fre-104.c: Un-XFAIL. * gcc.dg/tree-ssa/ssa-fre-110.c: New testcase. Diff: --- gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-104.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-110.c | 15 +++++++++++++ gcc/tree-ssa-sccvn.cc | 33 +++++++++++++++++++++++++++-- 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-104.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-104.c index 52756bb7e40d..8c9df702d228 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-104.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-104.c @@ -21,4 +21,4 @@ int main() { *c = &d; } -/* { dg-final { scan-tree-dump-not "foo" "fre1" { xfail *-*-* } } } */ +/* { dg-final { scan-tree-dump-not "foo" "fre1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-110.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-110.c new file mode 100644 index 000000000000..10e391d25def --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-110.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-fre1-details" } */ + +struct A { int x; int y; }; +struct B { struct A a; int k; }; + +int foo (struct A *a, struct B *b) +{ + *a = (struct A){}; + *b = (struct B){}; + return a->x; +} + +/* { dg-final { scan-tree-dump "Skipping possible redundant definition" "fre1" } } */ +/* { dg-final { scan-tree-dump "return 0;" "fre1" } } */ diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc index 3884f0fca7e5..3212063ad743 100644 --- a/gcc/tree-ssa-sccvn.cc +++ b/gcc/tree-ssa-sccvn.cc @@ -2810,8 +2810,11 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_, possible clobber. In this case we can ignore the clobber and return the found value. */ if (!gimple_has_volatile_ops (def_stmt) - && is_gimple_reg_type (TREE_TYPE (lhs)) - && types_compatible_p (TREE_TYPE (lhs), vr->type) + && ((is_gimple_reg_type (TREE_TYPE (lhs)) + && types_compatible_p (TREE_TYPE (lhs), vr->type) + && !storage_order_barrier_p (lhs) + && !reverse_storage_order_for_component_p (lhs)) + || TREE_CODE (gimple_assign_rhs1 (def_stmt)) == CONSTRUCTOR) && (ref->ref || data->orig_ref.ref) && !data->mask && data->partial_defs.is_empty () @@ -2820,7 +2823,19 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_, ref->size) && multiple_p (get_object_alignment (lhs), ref->size)) { + HOST_WIDE_INT offset2i, size2i; + poly_int64 offset = ref->offset; + poly_int64 maxsize = ref->max_size; + + gcc_assert (lhs_ref_ok); + tree base2 = ao_ref_base (&lhs_ref); + poly_int64 offset2 = lhs_ref.offset; + poly_int64 size2 = lhs_ref.size; + poly_int64 maxsize2 = lhs_ref.max_size; + tree rhs = gimple_assign_rhs1 (def_stmt); + if (TREE_CODE (rhs) == CONSTRUCTOR) + rhs = integer_zero_node; /* ??? We may not compare to ahead values which might be from a different loop iteration but only to loop invariants. Use CONSTANT_CLASS_P (unvalueized!) as conservative approximation. @@ -2831,6 +2846,20 @@ vn_reference_lookup_3 (ao_ref *ref, tree vuse, void *data_, if (data->same_val && !operand_equal_p (data->same_val, rhs)) ; + /* When this is a (partial) must-def, leave it to handling + below in case we are interested in the value. */ + else if (!(*disambiguate_only > TR_TRANSLATE) + && base2 + && known_eq (maxsize2, size2) + && adjust_offsets_for_equal_base_address (base, &offset, + base2, &offset2) + && offset2.is_constant (&offset2i) + && size2.is_constant (&size2i) + && maxsize.is_constant (&maxsizei) + && offset.is_constant (&offseti) + && ranges_known_overlap_p (offseti, maxsizei, offset2i, + size2i)) + ; else if (CONSTANT_CLASS_P (rhs)) { if (dump_file && (dump_flags & TDF_DETAILS))