https://gcc.gnu.org/g:44b24b62a44e6208d654513cf567dd6900a2fb56

commit r16-2443-g44b24b62a44e6208d654513cf567dd6900a2fb56
Author: Richard Biener <rguent...@suse.de>
Date:   Wed Jul 23 09:40:24 2025 +0200

    tree-optimization/121220 - improve sinking of stores
    
    We currently do only very restricted store sinking into paths
    that have no loads or stores and end in a virtual PHI.  The
    following extends this to sink towards a single virtual
    definition in addition to the case of a PHI, handling skipping
    of unrelated virtual uses.  We later have to prune cases
    that would require virtual PHI insertion and the patch below
    basically restricts this to sinking to noreturn paths for now.
    
            PR tree-optimization/121220
            * tree-ssa-sink.cc (statement_sink_location): For stores
            handle sinking to paths ending in a store.  Skip loads
            that do not use the store.
    
            * gcc.dg/tree-ssa/ssa-sink-23.c: New testcase.

Diff:
---
 gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-23.c | 21 +++++++++
 gcc/tree-ssa-sink.cc                        | 73 +++++++++++++++++++----------
 2 files changed, 70 insertions(+), 24 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-23.c 
b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-23.c
new file mode 100644
index 000000000000..f632dc8b95a4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-23.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-sink1-details" } */
+
+struct S {
+    int* x;
+    int* y;
+};
+
+void __attribute__((noreturn)) bar(const struct S* s);
+
+void foo(int a, int b) {
+    struct S s;
+    s.x = &a;
+    s.y = &b;
+    if (a < b) {
+        bar(&s);
+    }
+}
+
+/* { dg-final { scan-tree-dump "Sinking.*s.y" "sink1" } } */
+/* { dg-final { scan-tree-dump "Sinking.*s.x" "sink1" } } */
diff --git a/gcc/tree-ssa-sink.cc b/gcc/tree-ssa-sink.cc
index 959e0d5c6bea..2244e89fbb7f 100644
--- a/gcc/tree-ssa-sink.cc
+++ b/gcc/tree-ssa-sink.cc
@@ -356,37 +356,54 @@ statement_sink_location (gimple *stmt, basic_block frombb,
 
   use = NULL;
 
-  /* If stmt is a store the one and only use needs to be the VOP
-     merging PHI node.  */
+  /* If stmt is a store the one and only use needs to be a VUSE on
+     the live path.  */
   if (virtual_operand_p (DEF_FROM_PTR (def_p)))
     {
+      tree lhs = gimple_get_lhs (stmt);
+      ao_ref ref;
+      ao_ref_init (&ref, lhs);
       FOR_EACH_IMM_USE_FAST (use_p, imm_iter, DEF_FROM_PTR (def_p))
        {
          gimple *use_stmt = USE_STMT (use_p);
 
          /* A killing definition is not a use.  */
-         if ((gimple_has_lhs (use_stmt)
-              && operand_equal_p (gimple_get_lhs (stmt),
-                                  gimple_get_lhs (use_stmt), 0))
-             || stmt_kills_ref_p (use_stmt, gimple_get_lhs (stmt)))
+         if (gimple_vdef (use_stmt)
+             && ((gimple_has_lhs (use_stmt)
+                  && operand_equal_p (lhs,
+                                      gimple_get_lhs (use_stmt), 0))
+                 || stmt_kills_ref_p (use_stmt, &ref)))
            {
              /* If use_stmt is or might be a nop assignment then USE_STMT
                 acts as a use as well as definition.  */
              if (stmt != use_stmt
-                 && ref_maybe_used_by_stmt_p (use_stmt,
-                                              gimple_get_lhs (stmt)))
-               return false;
+                 && ref_maybe_used_by_stmt_p (use_stmt, &ref))
+               {
+                 if (use && use != use_stmt)
+                   return false;
+                 use = use_stmt;
+               }
              continue;
            }
 
-         if (gimple_code (use_stmt) != GIMPLE_PHI)
-           return false;
-
-         if (use
-             && use != use_stmt)
-           return false;
+         if (is_a <gphi *> (use_stmt)
+             || ref_maybe_used_by_stmt_p (use_stmt, &ref))
+           {
+             if (use && use != use_stmt)
+               return false;
+             use = use_stmt;
+             continue;
+           }
 
-         use = use_stmt;
+         if (gimple_vdef (use_stmt))
+           {
+             if (stmt_may_clobber_ref_p_1 (use_stmt, &ref, false))
+               return false;
+             /* We do not look past VDEFs, so treat them as sink location.  */
+             if (use && use != use_stmt)
+               return false;
+             use = use_stmt;
+           }
        }
       if (!use)
        return false;
@@ -448,18 +465,26 @@ statement_sink_location (gimple *stmt, basic_block frombb,
          break;
        }
       use = USE_STMT (one_use);
+    }
 
-      if (gimple_code (use) != GIMPLE_PHI)
-       {
-         sinkbb = select_best_block (frombb, gimple_bb (use), stmt);
+  if (gimple_code (use) != GIMPLE_PHI)
+    {
+      sinkbb = select_best_block (frombb, gimple_bb (use), stmt);
 
-         if (sinkbb == frombb)
-           return false;
+      if (sinkbb == frombb)
+       return false;
 
-         *togsi = gsi_after_labels (sinkbb);
+      /* The SSA update for sinking of stores cannot insert PHIs, the
+        sink location has to lead to exit without crossing any CFG
+        merge points to paths not dominated by the sink location.  */
+      if (gimple_vdef (stmt)
+         && (!single_succ_p (sinkbb)
+             || single_succ (sinkbb)->index != EXIT_BLOCK))
+       return false;
 
-         return true;
-       }
+      *togsi = gsi_after_labels (sinkbb);
+
+      return true;
     }
 
   sinkbb = find_bb_for_arg (as_a <gphi *> (use), DEF_FROM_PTR (def_p));

Reply via email to