On Sat, Nov 2, 2024 at 12:20 PM Alexandre Oliva <ol...@adacore.com> wrote: > > > It became apparent that conditions could be combined that had deep SSA > dependency trees, that might thus require moving lots of statements. > Set a hard upper bound for now, hopefully to be replaced by a > dynamically computed bound, based on probabilities and costs. > > Also reset flow sensitive info and avoid introducing undefined > behavior when moving stmts from under guarding conditions. > > Finally, rework the preexisting reset of flow sensitive info and > avoidance of undefined behavior to be done when needed on all affected > inner blocks: reset flow info whenever enclosing conditions change, > and avoid undefined behavior whenever enclosing conditions become > laxer. > > Regstrapped on x86_64-linux-gnu. Ok to install?
OK. Thanks, Richard. > > for gcc/ChangeLog > > * tree-ssa-ifcombine.cc > (ifcombine_rewrite_to_defined_overflow): New. > (ifcombine_replace_cond): Reject conds that would require > moving too many stmts. Reset flow sensitive info and avoid > undefined behavior in moved stmts. Reset flow sensitive info > in all inner blocks when the outer condition changes, and > avoid undefined behavior whenever the outer condition becomes > laxer, adapted and moved from... > (pass_tree_ifcombine::execute): ... here. > --- > gcc/tree-ssa-ifcombine.cc | 114 > +++++++++++++++++++++++++++++++++++---------- > 1 file changed, 89 insertions(+), 25 deletions(-) > > diff --git a/gcc/tree-ssa-ifcombine.cc b/gcc/tree-ssa-ifcombine.cc > index ac4811e42e082..ae1b039335a85 100644 > --- a/gcc/tree-ssa-ifcombine.cc > +++ b/gcc/tree-ssa-ifcombine.cc > @@ -508,6 +508,25 @@ ifcombine_mark_ssa_name_walk (tree *t, int *, void > *data_) > return NULL; > } > > +/* Rewrite a stmt, that presumably used to be guarded by conditions that > could > + avoid undefined overflow, into one that has well-defined overflow, so that > + it won't invoke undefined behavior once the guarding conditions change. > */ > + > +static inline void > +ifcombine_rewrite_to_defined_overflow (gimple_stmt_iterator gsi) > +{ > + gassign *ass = dyn_cast <gassign *> (gsi_stmt (gsi)); > + if (!ass) > + return; > + tree lhs = gimple_assign_lhs (ass); > + if ((INTEGRAL_TYPE_P (TREE_TYPE (lhs)) > + || POINTER_TYPE_P (TREE_TYPE (lhs))) > + && arith_code_with_undefined_signed_overflow > + (gimple_assign_rhs_code (ass))) > + rewrite_to_defined_overflow (&gsi); > +} > + > + > /* 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 > @@ -518,6 +537,7 @@ ifcombine_replace_cond (gcond *inner_cond, bool inner_inv, > gcond *outer_cond, bool outer_inv, > tree cond, bool must_canon, tree cond2) > { > + bool split_single_cond = false; > /* 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. */ > @@ -527,11 +547,13 @@ ifcombine_replace_cond (gcond *inner_cond, bool > inner_inv, > { > cond2 = TREE_OPERAND (cond, 1); > cond = TREE_OPERAND (cond, 0); > + split_single_cond = true; > } > > bool outer_p = cond2 || (single_pred (gimple_bb (inner_cond)) > != gimple_bb (outer_cond)); > bool result_inv = outer_p ? outer_inv : inner_inv; > + bool strictening_outer_cond = !split_single_cond && outer_p; > > if (result_inv) > cond = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (cond), cond); > @@ -558,9 +580,11 @@ ifcombine_replace_cond (gcond *inner_cond, bool > inner_inv, > > if (!bitmap_empty_p (used)) > { > + const int max_stmts = 6; > + auto_vec<gimple *, max_stmts> stmts; > + > /* 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)) > { > @@ -582,11 +606,14 @@ ifcombine_replace_cond (gcond *inner_cond, bool > inner_inv, > if (!move) > continue; > > + if (stmts.length () < max_stmts) > + stmts.quick_push (stmt); > + else > + return false; > + > /* 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 > @@ -609,22 +636,59 @@ ifcombine_replace_cond (gcond *inner_cond, bool > inner_inv, > continue; > } > > + if (stmts.length () < max_stmts) > + stmts.quick_push (phi); > + else > + return false; > + > /* 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); > + } > + } > > + /* ??? Test whether it makes sense to move STMTS. */ > + > + /* Move the STMTS that need moving. From this point on, we're > + committing to the attempted ifcombine. */ > + gimple_stmt_iterator gsins = gsi_for_stmt (outer_cond); > + unsigned i; > + gimple *stmt; > + FOR_EACH_VEC_ELT (stmts, i, stmt) > + { > + if (gphi *phi = dyn_cast <gphi *> (stmt)) > + { > + tree def = gimple_phi_result (phi); > tree use = gimple_phi_arg_def (phi, 0); > location_t loc = gimple_phi_arg_location (phi, 0); > > + gphi_iterator gsi = gsi_for_phi (phi); > 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); > } > + else > + { > + gimple_stmt_iterator gsitr = gsi_for_stmt (stmt); > + gsi_move_before (&gsitr, &gsins, GSI_NEW_STMT); > + } > + } > + > + for (; gsi_stmt (gsins) != outer_cond; gsi_next (&gsins)) > + { > + /* Clear range info from all defs we've moved from under > + conditions. */ > + tree t; > + ssa_op_iter it; > + FOR_EACH_SSA_TREE_OPERAND (t, gsi_stmt (gsins), it, > SSA_OP_DEF) > + reset_flow_sensitive_info (t); > + /* Avoid introducing undefined overflows while at that. */ > + ifcombine_rewrite_to_defined_overflow (gsins); > } > } > } > @@ -684,6 +748,27 @@ ifcombine_replace_cond (gcond *inner_cond, bool > inner_inv, > update_stmt (outer_cond); > } > > + /* We're changing conditions that guard inner blocks, so reset flow > sensitive > + info and avoid introducing undefined behavior. */ > + for (basic_block bb = gimple_bb (inner_cond), end = gimple_bb (outer_cond); > + bb != end; bb = single_pred (bb)) > + { > + /* Clear range info from all stmts in BB which is now guarded by > + different conditionals. */ > + reset_flow_sensitive_info_in_bb (gimple_bb (inner_cond)); > + > + /* We only need to worry about introducing undefined behavior if we've > + relaxed the outer condition. */ > + if (strictening_outer_cond) > + continue; > + > + /* Avoid introducing undefined behavior as we move stmts that used to > be > + guarded by OUTER_COND. */ > + for (gimple_stmt_iterator gsi = gsi_start_bb (gimple_bb (inner_cond)); > + !gsi_end_p (gsi); gsi_next (&gsi)) > + ifcombine_rewrite_to_defined_overflow (gsi); > + } > + > update_profile_after_ifcombine (gimple_bb (inner_cond), > gimple_bb (outer_cond)); > > @@ -1184,28 +1269,7 @@ pass_tree_ifcombine::execute (function *fun) > > if (safe_is_a <gcond *> (*gsi_last_bb (bb))) > if (tree_ssa_ifcombine_bb (bb)) > - { > - /* Clear range info from all stmts in BB which is now executed > - conditional on a always true/false condition. ??? When we > - combine noncontiguous blocks, do we need to adjust the > - intervening blocks as well? If we leave outer conditions > - nonconstant, do we still need to modify them? */ > - reset_flow_sensitive_info_in_bb (bb); > - for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p > (gsi); > - gsi_next (&gsi)) > - { > - gassign *ass = dyn_cast <gassign *> (gsi_stmt (gsi)); > - if (!ass) > - continue; > - tree lhs = gimple_assign_lhs (ass); > - if ((INTEGRAL_TYPE_P (TREE_TYPE (lhs)) > - || POINTER_TYPE_P (TREE_TYPE (lhs))) > - && arith_code_with_undefined_signed_overflow > - (gimple_assign_rhs_code (ass))) > - rewrite_to_defined_overflow (&gsi); > - } > - cfg_changed |= true; > - } > + cfg_changed |= true; > } > > free (bbs); > > -- > Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/ > Free Software Activist GNU Toolchain Engineer > More tolerance and less prejudice are key for inclusion and diversity > Excluding neuro-others for not behaving ""normal"" is *not* inclusive