Currently, cselim requires the middle_bb to have only a single statement. This
patch relaxes this restriction if the following pattern is found and also when
it is safe to do the optimization.

SPLIT_BB:
  ...
  STORE = X
  if (cond) goto MIDDLE_BB; else goto JOIN_BB (edge E1)
MIDDLE_BB:
  ...
  STORE = Y;
  ...
  fallthrough (edge E0)
JOIN_BB:
  some more

Bootstrapped and tested on x86_64-linux-gnu and aarch64-linux-gnu.

Changes since v1:
* v2: Revert changes to trailing_store_in_bb and do not call
      trailing_store_in_bb to get split_assign.
      Remove some unnecessary checks in cselim_candidate.
      Pass the result of cselim_candidate which is the candidate store for
      cselim as an argument to cond_store_replacement instead.

        PR tree-optimization/124405

gcc/ChangeLog:

        * tree-ssa-phiopt.cc (cond_store_replacement): Make ASSIGN (the
        candidate store for cselim) an argument of the function instead.
        (cselim_candidate): New.
        (pass_cselim::execute): Call cselim_candidate and pass the result to
        cond_store_replacement.

gcc/testsuite/ChangeLog:

        * gcc.dg/tree-ssa/pr124405.c: New test.

Signed-off-by: Pengxuan Zheng <[email protected]>
---
 gcc/testsuite/gcc.dg/tree-ssa/pr124405.c | 12 +++++
 gcc/tree-ssa-phiopt.cc                   | 68 +++++++++++++++++++++---
 2 files changed, 73 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr124405.c

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr124405.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr124405.c
new file mode 100644
index 00000000000..9ba230d2b56
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr124405.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-cselim-details" } */
+
+void
+f (int *a, int b)
+{
+  *a &= ~3;
+  if (b)
+    *a |= 1;
+}
+
+/* { dg-final { scan-tree-dump-times "Conditional store replacement happened" 
1 "cselim"} } */
diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc
index 324559e6a7d..e55d6efaa2b 100644
--- a/gcc/tree-ssa-phiopt.cc
+++ b/gcc/tree-ssa-phiopt.cc
@@ -2991,16 +2991,16 @@ get_non_trapping (void)
    JOIN_BB:
      some more
 
-   We check that MIDDLE_BB contains only one store, that that store
+   ASSIGN is a store in MIDDLE_BB which is the candidate for cselim.  We check
+   that MIDDLE_BB contains only one store (i.e., ASSIGN), that that store
    doesn't trap (not via NOTRAP, but via checking if an access to the same
-   memory location dominates us, or the store is to a local addressable
-   object) and that the store has a "simple" RHS.  */
+   memory location dominates us, or the store is to a local addressable object)
+   and that the store has a "simple" RHS.  */
 
 static bool
-cond_store_replacement (basic_block middle_bb, basic_block join_bb,
-                       edge e0, edge e1, hash_set<tree> *nontrap)
+cond_store_replacement (basic_block middle_bb, basic_block join_bb, edge e0,
+                       edge e1, gimple *assign, hash_set<tree> *nontrap)
 {
-  gimple *assign = last_and_only_stmt (middle_bb);
   tree lhs, rhs, name, name2;
   gphi *newphi;
   gassign *new_stmt;
@@ -3289,6 +3289,58 @@ trailing_store_in_bb (basic_block bb, tree vdef, gphi 
*vphi, bool onlyonestore)
   return store;
 }
 
+/* Return the candidate store for cselim.  If there is only a single statement
+   in MIDDLE_BB, return that statement.  Otherwise, try to find the following
+   pattern and return the only store in MIDDLE_BB.
+
+   SPLIT_BB:
+     ...
+     STORE = X
+     if (cond) goto MIDDLE_BB; else goto JOIN_BB (edge E1)
+   MIDDLE_BB:
+     ...
+     STORE = Y;
+     ...
+     fallthrough (edge E0)
+   JOIN_BB:
+     some more
+*/
+
+static gimple *
+cselim_candidate (basic_block middle_bb, basic_block join_bb, edge e0, edge e1)
+{
+  gimple *middle_assign = last_and_only_stmt (middle_bb);
+  if (middle_assign)
+    return middle_assign;
+
+  gphi *vphi = get_virtual_phi (join_bb);
+  if (!vphi)
+    return NULL;
+
+  tree middle_vdef = PHI_ARG_DEF_FROM_EDGE (vphi, e0);
+  middle_assign = trailing_store_in_bb (middle_bb, middle_vdef, vphi, true);
+
+  if (!middle_assign || !gimple_assign_single_p (middle_assign)
+      || gimple_has_volatile_ops (middle_assign)
+      || stmt_references_abnormal_ssa_name (middle_assign))
+    return NULL;
+
+  tree split_vdef = PHI_ARG_DEF_FROM_EDGE (vphi, e1);
+  gimple *split_assign = SSA_NAME_DEF_STMT (split_vdef);
+
+  if (!split_assign || !gimple_assign_single_p (split_assign)
+      || gimple_has_volatile_ops (split_assign)
+      || stmt_references_abnormal_ssa_name (split_assign))
+    return NULL;
+
+  if (gimple_vdef (split_assign) != gimple_vuse (middle_assign)
+      || !operand_equal_p (gimple_assign_lhs (middle_assign),
+                          gimple_assign_lhs (split_assign), 0))
+    return NULL;
+
+  return middle_assign;
+}
+
 /* Limited Conditional store replacement.  We already know
    that the recognized pattern looks like so:
 
@@ -4260,7 +4312,9 @@ pass_cselim::execute (function *)
         optimization if the join block has more than two predecessors.  */
       if (EDGE_COUNT (bb2->preds) > 2)
        return;
-      if (cond_store_replacement (bb1, bb2, e1, e2, nontrap))
+
+      gimple *assign = cselim_candidate (bb1, bb2, e1, e2);
+      if (cond_store_replacement (bb1, bb2, e1, e2, assign, nontrap))
        cfgchanged = true;
     };
 
-- 
2.34.1

Reply via email to