]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
tree-optimization/121740 - handle aggregate zeroing as skipped may-def
authorRichard Biener <rguenther@suse.de>
Wed, 3 Sep 2025 10:54:58 +0000 (12:54 +0200)
committerRichard Biener <rguenth@gcc.gnu.org>
Thu, 4 Sep 2025 08:03:32 +0000 (10:03 +0200)
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.

gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-104.c
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-110.c [new file with mode: 0644]
gcc/tree-ssa-sccvn.cc

index 52756bb7e40dbaf2dc9c19b62ce0901e5415bd45..8c9df702d228d7a943430eb0c51abab8fa6c2183 100644 (file)
@@ -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 (file)
index 0000000..10e391d
--- /dev/null
@@ -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" } } */
index 3884f0fca7e5962bdad1b9c3abd613038235e1b4..3212063ad743cb96e3c7b395f1483de7038e1152 100644 (file)
@@ -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))