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