https://gcc.gnu.org/g:11bf09a22577a9ed775a3a47a70afe5ee063d072
commit 11bf09a22577a9ed775a3a47a70afe5ee063d072 Author: Alexandre Oliva <ol...@gnu.org> Date: Thu Oct 24 05:25:30 2024 -0300 introduce ifcombine_replace_cond Diff: --- gcc/tree-ssa-ifcombine.cc | 187 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 183 insertions(+), 4 deletions(-) diff --git a/gcc/tree-ssa-ifcombine.cc b/gcc/tree-ssa-ifcombine.cc index d9595132512f..6be5d969de88 100644 --- a/gcc/tree-ssa-ifcombine.cc +++ b/gcc/tree-ssa-ifcombine.cc @@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-ssa.h" #include "attribs.h" #include "asan.h" +#include "bitmap.h" #ifndef LOGICAL_OP_NON_SHORT_CIRCUIT #define LOGICAL_OP_NON_SHORT_CIRCUIT \ @@ -445,16 +446,72 @@ update_profile_after_ifcombine (basic_block inner_cond_bb, } } -/* Replace the conditions in INNER_COND with COND. - Replace OUTER_COND with a constant. */ +/* Set NAME's bit in USED if OUTER dominates it. */ + +static void +ifcombine_mark_ssa_name (bitmap used, tree name, basic_block outer) +{ + if (SSA_NAME_IS_DEFAULT_DEF (name)) + return; + + gimple *def = SSA_NAME_DEF_STMT (name); + basic_block bb = gimple_bb (def); + if (!dominated_by_p (CDI_DOMINATORS, bb, outer)) + return; + + bitmap_set_bit (used, SSA_NAME_VERSION (name)); +} + +/* Data structure passed to ifcombine_mark_ssa_name. */ +struct ifcombine_mark_ssa_name_t +{ + /* SSA_NAMEs that have been referenced. */ + bitmap used; + /* Dominating block of DEFs that might need moving. */ + basic_block outer; +}; + +/* Mark in DATA->used any SSA_NAMEs used in *t. */ + +static tree +ifcombine_mark_ssa_name_walk (tree *t, int *, void *data_) +{ + ifcombine_mark_ssa_name_t *data = (ifcombine_mark_ssa_name_t *)data_; + + if (*t && TREE_CODE (*t) == SSA_NAME) + ifcombine_mark_ssa_name (data->used, *t, data->outer); + + return NULL; +} + +/* Replace the conditions in INNER_COND and OUTER_COND with COND and COND2. + COND and COND2 are computed for insertion at INNER_COND, with OUTER_COND + replaced with a constant, but if there are intervening blocks, it's best to + adjust COND for insertion at OUTER_COND, placing COND2 at INNER_COND. */ static tree ifcombine_replace_cond (gcond *inner_cond, bool inner_inv, gcond *outer_cond, bool outer_inv, - tree cond, bool must_canon, tree) + tree cond, bool must_canon, tree cond2) { tree ret = cond; - bool result_inv = inner_inv; + if (cond2) + ret = fold_build2 (TRUTH_AND_EXPR, TREE_TYPE (ret), ret, cond2); + + /* Split cond into cond2 if they're contiguous. ??? We might be able to + handle ORIF as well, inverting both conditions, but it's not clear that + this would be enough, and it never comes up. */ + if (!cond2 + && TREE_CODE (cond) == TRUTH_ANDIF_EXPR + && single_pred (gimple_bb (inner_cond)) == gimple_bb (outer_cond)) + { + cond2 = TREE_OPERAND (cond, 1); + cond = TREE_OPERAND (cond, 0); + } + + bool outer_p = cond2 || (single_pred (gimple_bb (inner_cond)) + != gimple_bb (outer_cond)); + bool result_inv = outer_p ? outer_inv : inner_inv; if (result_inv) cond = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (cond), cond); @@ -464,6 +521,128 @@ ifcombine_replace_cond (gcond *inner_cond, bool inner_inv, else if (must_canon) return NULL_TREE; + if (outer_p) + { + { + auto_bitmap used; + basic_block outer_bb = gimple_bb (outer_cond); + + /* Mark SSA DEFs that are referenced by cond and may thus need to be + moved to outer. */ + { + ifcombine_mark_ssa_name_t data = { used, outer_bb }; + walk_tree (&cond, ifcombine_mark_ssa_name_walk, &data, NULL); + } + + if (!bitmap_empty_p (used)) + { + /* Iterate up from inner_cond, moving DEFs identified as used by + cond, and marking USEs in the DEFs for moving as well. */ + gimple_stmt_iterator gsins = gsi_for_stmt (outer_cond); + for (basic_block bb = gimple_bb (inner_cond); + bb != outer_bb; bb = single_pred (bb)) + { + for (gimple_stmt_iterator gsitr = gsi_last_bb (bb); + !gsi_end_p (gsitr); gsi_prev (&gsitr)) + { + gimple *stmt = gsi_stmt (gsitr); + bool move = false; + tree t; + ssa_op_iter it; + + FOR_EACH_SSA_TREE_OPERAND (t, stmt, it, SSA_OP_DEF) + if (bitmap_bit_p (used, SSA_NAME_VERSION (t))) + { + move = true; + break; + } + + if (!move) + continue; + + /* Mark uses in STMT before moving it. */ + FOR_EACH_SSA_TREE_OPERAND (t, stmt, it, SSA_OP_USE) + ifcombine_mark_ssa_name (used, t, outer_bb); + + gsi_move_before (&gsitr, &gsins, GSI_NEW_STMT); + } + + /* Surprisingly, there may be PHI nodes in single-predecessor + bocks, as in pr50682.C. Fortunately, since they can't + involve back edges, there won't be references to parallel + nodes that we'd have to pay special attention to to keep + them parallel. We can't move the PHI nodes, but we can turn + them into assignments. */ + for (gphi_iterator gsi = gsi_start_phis (bb); + !gsi_end_p (gsi);) + { + gphi *phi = gsi.phi (); + + gcc_assert (gimple_phi_num_args (phi) == 1); + tree def = gimple_phi_result (phi); + + if (!bitmap_bit_p (used, SSA_NAME_VERSION (def))) + { + gsi_next (&gsi); + continue; + } + + /* Mark uses in STMT before moving it. */ + use_operand_p use_p; + ssa_op_iter it; + FOR_EACH_PHI_ARG (use_p, phi, it, SSA_OP_USE) + ifcombine_mark_ssa_name (used, USE_FROM_PTR (use_p), + outer_bb); + + tree use = gimple_phi_arg_def (phi, 0); + location_t loc = gimple_phi_arg_location (phi, 0); + + remove_phi_node (&gsi, false); + + gassign *a = gimple_build_assign (def, use); + gimple_set_location (a, loc); + gsi_insert_before (&gsins, a, GSI_NEW_STMT); + } + } + } + } + + if (!is_gimple_condexpr_for_cond (cond)) + { + gimple_stmt_iterator gsi = gsi_for_stmt (outer_cond); + cond = force_gimple_operand_gsi_1 (&gsi, cond, + is_gimple_condexpr_for_cond, + NULL, true, GSI_SAME_STMT); + } + + /* Leave CFG optimization to cfg_cleanup. */ + gimple_cond_set_condition_from_tree (outer_cond, cond); + update_stmt (outer_cond); + + if (cond2) + { + if (inner_inv) + cond2 = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (cond2), cond2); + + if (tree tcanon = canonicalize_cond_expr_cond (cond2)) + cond2 = tcanon; + if (!is_gimple_condexpr_for_cond (cond2)) + { + gimple_stmt_iterator gsi = gsi_for_stmt (inner_cond); + cond2 = force_gimple_operand_gsi_1 (&gsi, cond2, + is_gimple_condexpr_for_cond, + NULL, true, GSI_SAME_STMT); + } + gimple_cond_set_condition_from_tree (inner_cond, cond2); + } + else + gimple_cond_set_condition_from_tree (inner_cond, + inner_inv + ? boolean_false_node + : boolean_true_node); + update_stmt (inner_cond); + } + else { if (!is_gimple_condexpr_for_cond (cond)) {