On Fri, Jul 10, 2026 at 4:23 AM Andrew Pinski <[email protected]> wrote: > > This adds support to match_simplify_replacement to allowing of the middle-bbs > to have more > than 1 statement in a few cases. If we are replacing the both middle bbs with > a > fully independent sequence we can handle that. If we are replacing with a > sequence > that depends on the first statement of either (or both) blocks, this allows > that. > If the result is defined by part or fully of one of the middle bbs. Then make > the whole bb unconditional. > > Note the middle bbs still need to have statements that can't trap nor have > side effects. And each of the statements need to feed into the next > instruction > and including into the phi. > > This allows removal of the manual matching done in > cond_removal_in_builtin_zero_pattern > as those have been moved to match patterns back in r14-362-gc53237cefbad0c > and r14-414-g078339fc04f5de. > So let's remove it too. > > Bootstrapped and tested on x86_64-linux-gnu.
So what's the limit on the number of stmts to be made unconditionally executed? I think we should, similar to early phiopt, have a white-list of operations we want to allow. You have that for internal function calls, but for example not for other expensive operations. For the actual number of (non-nop-convert(?)) stmts we want a --param I guess, but I'd make it reasonably low and allow only operations like bitwise ops and integer plus/minus/negate? The patch itself looks OK to me apart from the above. Thanks, Richard. > gcc/ChangeLog: > > * tree-ssa-phiopt.cc (gsi_next_nondebug_nonnop_non_predict): New > function. > (enum bbfeeding_info): New enum. > (empty_bb_or_one_feeding_into_p): Rename to ... > (feeding_bb_info): This and support few different other cases. > (auto_flow_sensitive): Increase the vect base size to 4. > (auto_flow_sensitive::auto_flow_sensitive(gimple*)): Split out into > ... > (auto_flow_sensitive::save_stmt): This. > (auto_flow_sensitive::auto_flow_sensitive(basic_block)): New > constructor. > (match_simplify_replacement): Support More than one statement in the > middle BB. > (cond_removal_in_builtin_zero_pattern): Remove. > (pass_phiopt::execute): Don't call > cond_removal_in_builtin_zero_pattern. > > Signed-off-by: Andrew Pinski <[email protected]> > --- > gcc/tree-ssa-phiopt.cc | 602 ++++++++++++++++------------------------- > 1 file changed, 239 insertions(+), 363 deletions(-) > > diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc > index fd173ec01f4..efc818332b3 100644 > --- a/gcc/tree-ssa-phiopt.cc > +++ b/gcc/tree-ssa-phiopt.cc > @@ -861,110 +861,132 @@ gimple_simplify_phiopt (bool early_p, tree type, > gimple *comp_stmt, > return NULL; > } > > -/* empty_bb_or_one_feeding_into_p returns true if bb was empty basic block > - or it has one cheap preparation statement that feeds into the PHI > - statement and it sets STMT to that statement. */ > -static bool > -empty_bb_or_one_feeding_into_p (basic_block bb, > - gimple *phi, > - gimple *&stmt) > +/* Like gsi_next_nondebug but also skips over NOPs and predicats. */ > +static void > +gsi_next_nondebug_nonnop_nonpredict (gimple_stmt_iterator *i) > +{ > + do > + { > + gsi_next_nondebug (i); > + } > + while (!gsi_end_p (*i) > + && (gimple_code (**i) == GIMPLE_PREDICT > + || gimple_code (**i) == GIMPLE_NOP)); > +} > + > +enum bbfeeding_info > +{ > + invalid_bb, > + empty_bb, > + one_stmt_bb, > + feeding_bb > +}; > + > +/* This returns empty_bb if bb was empty basic block. > + or returns one_stmt_bb if it has one cheap preparation statement that > feeds into the PHI > + statement and it sets STMT to that statement. > + Returns feeding_bb if the basic block is not empty but has a sequence of > statements > + feeding into the phi that has no side effects. */ > +static bbfeeding_info > +feeding_bb_info (basic_block bb, > + gimple *phi, > + gimple *&stmt) > { > stmt = nullptr; > gimple *stmt_to_move = nullptr; > tree lhs; > > if (empty_block_p (bb)) > - return true; > + return empty_bb; > > if (!single_pred_p (bb)) > - return false; > + return invalid_bb; > > /* The middle bb cannot have phi nodes as we don't > move those assignments yet. */ > if (!gimple_seq_empty_p (phi_nodes (bb))) > - return false; > + return invalid_bb; > > gimple_stmt_iterator gsi; > > gsi = gsi_start_nondebug_after_labels_bb (bb); > + bool more_than_one = false; > while (!gsi_end_p (gsi)) > { > - gimple *s = gsi_stmt (gsi); > - gsi_next_nondebug (&gsi); > + gimple *s = *gsi; > + gsi_next_nondebug_nonnop_nonpredict (&gsi); > /* Skip over Predict and nop statements. */ > if (gimple_code (s) == GIMPLE_PREDICT > || gimple_code (s) == GIMPLE_NOP) > continue; > /* If there is more one statement return false. */ > if (stmt_to_move) > - return false; > - stmt_to_move = s; > - } > - > - /* The only statement here was a Predict or a nop statement > - so return true. */ > - if (!stmt_to_move) > - return true; > - > - if (gimple_vuse (stmt_to_move)) > - return false; > - > - if (gimple_could_trap_p (stmt_to_move) > - || gimple_has_side_effects (stmt_to_move)) > - return false; > - > - ssa_op_iter it; > - tree use; > - FOR_EACH_SSA_TREE_OPERAND (use, stmt_to_move, it, SSA_OP_USE) > - if (ssa_name_maybe_undef_p (use)) > - return false; > - > - /* Allow assignments but allow some builtin/internal calls. > - As const calls don't match any of the above, yet they could > - still have some side-effects - they could contain > - gimple_could_trap_p statements, like floating point > - exceptions or integer division by zero. See PR70586. > - FIXME: perhaps gimple_has_side_effects or gimple_could_trap_p > - should handle this. > - Allow some known builtin/internal calls that are known not to > - trap: logical functions (e.g. bswap and bit counting). */ > - if (!is_gimple_assign (stmt_to_move)) > - { > - if (!is_gimple_call (stmt_to_move)) > - return false; > - combined_fn cfn = gimple_call_combined_fn (stmt_to_move); > - switch (cfn) > + more_than_one = true; > + if (gimple_vuse (s)) > + return invalid_bb; > + if (gimple_could_trap_p (s) > + || gimple_has_side_effects (s)) > + return invalid_bb; > + ssa_op_iter it; > + tree use; > + FOR_EACH_SSA_TREE_OPERAND (use, s, it, SSA_OP_USE) > + if (ssa_name_maybe_undef_p (use)) > + return invalid_bb; > + > + /* Allow assignments but allow some builtin/internal calls. > + As const calls don't match any of the above, yet they could > + still have some side-effects - they could contain > + gimple_could_trap_p statements, like floating point > + exceptions or integer division by zero. See PR70586. > + FIXME: perhaps gimple_has_side_effects or gimple_could_trap_p > + should handle this. > + Allow some known builtin/internal calls that are known not to > + trap: logical functions (e.g. bswap and bit counting). */ > + if (!is_gimple_assign (s)) > { > - default: > - return false; > - CASE_CFN_BSWAP: > - CASE_CFN_BITREVERSE: > - CASE_CFN_FFS: > - CASE_CFN_PARITY: > - CASE_CFN_POPCOUNT: > - CASE_CFN_CLZ: > - CASE_CFN_CTZ: > - case CFN_BUILT_IN_CLRSB: > - case CFN_BUILT_IN_CLRSBL: > - case CFN_BUILT_IN_CLRSBLL: > - lhs = gimple_call_lhs (stmt_to_move); > - break; > + if (!is_gimple_call (s)) > + return invalid_bb; > + combined_fn cfn = gimple_call_combined_fn (s); > + switch (cfn) > + { > + default: > + return invalid_bb; > + CASE_CFN_BSWAP: > + CASE_CFN_BITREVERSE: > + CASE_CFN_FFS: > + CASE_CFN_PARITY: > + CASE_CFN_POPCOUNT: > + CASE_CFN_CLZ: > + CASE_CFN_CTZ: > + case CFN_BUILT_IN_CLRSB: > + case CFN_BUILT_IN_CLRSBL: > + case CFN_BUILT_IN_CLRSBLL: > + lhs = gimple_call_lhs (s); > + break; > + } > } > - } > - else > - lhs = gimple_assign_lhs (stmt_to_move); > + else > + lhs = gimple_assign_lhs (s); > > - gimple *use_stmt; > - use_operand_p use_p; > + gimple *use_stmt; > + use_operand_p use_p; > > - /* Allow only a statement which feeds into the other stmt. */ > - if (!lhs || TREE_CODE (lhs) != SSA_NAME > - || !single_imm_use (lhs, &use_p, &use_stmt) > - || use_stmt != phi) > - return false; > + /* Allow only a statement which feeds into the next stmt > + or the phi (when last statement). */ > + if (!lhs || TREE_CODE (lhs) != SSA_NAME > + || !single_imm_use (lhs, &use_p, &use_stmt) > + || use_stmt != (gsi_end_p (gsi) ? phi : *gsi )) > + return invalid_bb; > + if (!stmt_to_move) > + stmt_to_move = s; > + } > > + /* The only statement here was a Predict or a nop statement > + so return 1. */ > + if (!stmt_to_move) > + return empty_bb; > stmt = stmt_to_move; > - return true; > + return more_than_one ? feeding_bb : one_stmt_bb; > } > > /* Move STMT to before GSI and insert its defining > @@ -996,14 +1018,17 @@ move_stmt (gimple *stmt, gimple_stmt_iterator *gsi, > auto_bitmap &inserted_exprs) > } > > /* RAII style class to temporarily remove flow sensitive > - from ssa names defined by a gimple statement. */ > + from ssa names defined by a gimple statement or > + a whole Basic block. */ > class auto_flow_sensitive > { > public: > auto_flow_sensitive (gimple *s); > + auto_flow_sensitive (basic_block bb); > ~auto_flow_sensitive (); > private: > - auto_vec<std::pair<tree, flow_sensitive_info_storage>, 2> stack; > + auto_vec<std::pair<tree, flow_sensitive_info_storage>, 4> stack; > + void save_stmt (gimple *s); > }; > > /* Constructor for auto_flow_sensitive. Saves > @@ -1015,6 +1040,15 @@ auto_flow_sensitive::auto_flow_sensitive (gimple *s) > { > if (!s) > return; > + save_stmt (s); > +} > + > +/* Saves off the ssa names' flow sensitive information > + that was defined by gimple statement S and > + resets it to be non-flow based ones. */ > +void > +auto_flow_sensitive::save_stmt (gimple *s) > +{ > ssa_op_iter it; > tree def; > FOR_EACH_SSA_TREE_OPERAND (def, s, it, SSA_OP_DEF) > @@ -1025,6 +1059,21 @@ auto_flow_sensitive::auto_flow_sensitive (gimple *s) > } > } > > +/* Constructor for auto_flow_sensitive. Saves > + off the ssa names' flow sensitive information > + that was defined in the BB and > + resets it to be non-flow based ones. */ > + > +auto_flow_sensitive::auto_flow_sensitive (basic_block bb) > +{ > + if (!bb) > + return; > + gimple_stmt_iterator gsi; > + gsi = gsi_start_nondebug_after_labels_bb (bb); > + for (; !gsi_end_p (gsi); gsi_next_nondebug (&gsi)) > + save_stmt (*gsi); > +} > + > /* Deconstructor, restores the flow sensitive information > for the SSA names that had been saved off. */ > > @@ -1083,14 +1132,20 @@ match_simplify_replacement (basic_block cond_bb, > basic_block middle_bb, > > /* If the basic block only has a cheap preparation statement, > allow it and move it once the transformation is done. */ > - if (!empty_bb_or_one_feeding_into_p (middle_bb, phi, stmt_to_move)) > + bbfeeding_info middle_bb_info = feeding_bb_info (middle_bb, > + phi, stmt_to_move); > + if (middle_bb_info == invalid_bb) > return false; > > + bbfeeding_info middle_bb_alt_info = invalid_bb; > if (threeway_p > - && middle_bb != middle_bb_alt > - && !empty_bb_or_one_feeding_into_p (middle_bb_alt, phi, > - stmt_to_move_alt)) > - return false; > + && middle_bb != middle_bb_alt) > + { > + middle_bb_alt_info = feeding_bb_info (middle_bb_alt, phi, > + stmt_to_move_alt); > + if (middle_bb_alt_info == invalid_bb) > + return false; > + } > > /* Do not make conditional undefs unconditional. */ > if ((TREE_CODE (arg0) == SSA_NAME > @@ -1140,8 +1195,11 @@ match_simplify_replacement (basic_block cond_bb, > basic_block middle_bb, > > tree type = TREE_TYPE (gimple_phi_result (phi)); > { > - auto_flow_sensitive s1(stmt_to_move); > - auto_flow_sensitive s_alt(stmt_to_move_alt); > + auto_flow_sensitive s1(middle_bb); > + basic_block other_bb = nullptr; > + if (middle_bb_alt_info >= one_stmt_bb) > + other_bb = middle_bb_alt; > + auto_flow_sensitive s_alt(other_bb); > > result = gimple_simplify_phiopt (early_p, type, stmt, > arg_true, arg_false, > @@ -1185,7 +1243,8 @@ match_simplify_replacement (basic_block cond_bb, > basic_block middle_bb, > semantics (that's not IEEE max semantics). */ > if (!HONOR_NANS (type) && !HONOR_SIGNED_ZEROS (type)) > return false; > - if (stmt_to_move || stmt_to_move_alt) > + if (middle_bb_info >= one_stmt_bb > + || middle_bb_alt_info >= one_stmt_bb) > return false; > tree_code cmp = gimple_cond_code (stmt); > if (cmp != LT_EXPR && cmp != LE_EXPR > @@ -1207,11 +1266,104 @@ match_simplify_replacement (basic_block cond_bb, > basic_block middle_bb, > statistics_counter_event (cfun, "Non-IEEE FP MIN/MAX PHI replacement", > 1); > } > - if (dump_file && (dump_flags & TDF_FOLDING)) > - fprintf (dump_file, "accepted the phiopt match-simplify.\n"); > > auto_bitmap exprs_maybe_dce; > > + /* One of the middle BBs had more than 1 statement. */ > + if (middle_bb_info == feeding_bb > + || middle_bb_alt_info == feeding_bb) > + { > + gimple_stmt_iterator gsi = gsi_start (seq); > + bool ok = true; > + /* Check to see if any of the new sequence uses the definitions > + from the middle bbs. */ > + for (gsi = gsi_start (seq); !gsi_end_p (gsi); gsi_next (&gsi)) > + { > + gimple *s = *gsi; > + for (unsigned i = 0; i < gimple_num_ops (s); i++) > + { > + tree use = gimple_op (s, i); > + if (!use) > + continue; > + if (TREE_CODE (use) != SSA_NAME) > + continue; > + gimple *us = SSA_NAME_DEF_STMT (use); > + if (!us) > + continue; > + if (us == stmt_to_move || us == stmt_to_move_alt) > + continue; > + basic_block use_bb = gimple_bb (us); > + /* If an operand is defined from the middle bb > + where there was more one statement, reject it. */ > + if ((middle_bb_info == feeding_bb > + && use_bb == middle_bb) > + || (middle_bb_alt_info == feeding_bb > + && use_bb == middle_bb_alt)) > + { > + ok = false; > + break; > + } > + } > + if (!ok) > + break; > + statistics_counter_event (cfun, "unconditionalized one middle bb > phiopt", > + 1); > + } > + if (!ok) > + { > + if (dump_file && (dump_flags & TDF_FOLDING)) > + fprintf (dump_file, "rejected the phiopt match-simplify for > having more stmts.\n"); > + return false; > + } > + // If the result is the one of the arguments or a partial > + // defined in the middle bb, then make those statements unconditional. > + if (TREE_CODE (result) == SSA_NAME > + && (middle_bb_info == feeding_bb > + || middle_bb_alt_info == feeding_bb)) > + { > + gimple *us = SSA_NAME_DEF_STMT (result); > + if (us && ((middle_bb_info == feeding_bb > + && gimple_bb (us) == middle_bb) > + || (middle_bb_alt_info == feeding_bb > + && gimple_bb (us) == middle_bb_alt))) > + { > + gimple_stmt_iterator middle_gsi; > + basic_block use_bb = gimple_bb (us); > + middle_gsi = gsi_start_nondebug_after_labels_bb (use_bb); > + > + // Move the statements one at a time until reach the last > statement > + // or the statement that is referenced from the result. > + while (!gsi_end_p (middle_gsi)) > + { > + // Skip over nop or predicates > + // Also don't move debug statements > + if (gimple_code (*middle_gsi) == GIMPLE_NOP > + || gimple_code (*middle_gsi) == GIMPLE_PREDICT) > + { > + gsi_next_nondebug_nonnop_nonpredict (&middle_gsi); > + continue; > + } > + gsi = gsi_last_bb (cond_bb); > + gimple *s = *middle_gsi; > + move_stmt (s, &gsi, exprs_maybe_dce); > + > + // Reached the last statement that is refenced, > + // all the rest would be DCEd anyways. > + if (s == us) > + break; > + middle_gsi = gsi_start_nondebug_after_labels_bb (use_bb); > + } > + stmt_to_move = nullptr; > + stmt_to_move_alt = nullptr; > + statistics_counter_event (cfun, "unconditionalized one middle > bb phiopt", > + 1); > + } > + } > + } > + > + if (dump_file && (dump_flags & TDF_FOLDING)) > + fprintf (dump_file, "accepted the phiopt match-simplify.\n"); > + > /* Mark the cond statements' lhs/rhs as maybe dce. */ > if (TREE_CODE (gimple_cond_lhs (stmt)) == SSA_NAME > && !SSA_NAME_IS_DEFAULT_DEF (gimple_cond_lhs (stmt))) > @@ -1231,7 +1383,7 @@ match_simplify_replacement (basic_block cond_bb, > basic_block middle_bb, > gsi_insert_seq_before (&gsi, seq, GSI_CONTINUE_LINKING); > } > > - /* If there was a statement to move, move it to right before > + /* If there was one statement to move, move it to right before > the original conditional. */ > move_stmt (stmt_to_move, &gsi, exprs_maybe_dce); > move_stmt (stmt_to_move_alt, &gsi, exprs_maybe_dce); > @@ -2603,276 +2755,6 @@ spaceship_replacement (basic_block cond_bb, > basic_block middle_bb, > return true; > } > > -/* Optimize x ? __builtin_fun (x) : C, where C is __builtin_fun (0). > - Convert > - > - <bb 2> > - if (b_4(D) != 0) > - goto <bb 3> > - else > - goto <bb 4> > - > - <bb 3> > - _2 = (unsigned long) b_4(D); > - _9 = __builtin_popcountl (_2); > - OR > - _9 = __builtin_popcountl (b_4(D)); > - > - <bb 4> > - c_12 = PHI <0(2), _9(3)> > - > - Into > - <bb 2> > - _2 = (unsigned long) b_4(D); > - _9 = __builtin_popcountl (_2); > - OR > - _9 = __builtin_popcountl (b_4(D)); > - > - <bb 4> > - c_12 = PHI <_9(2)> > - > - Similarly for __builtin_clz or __builtin_ctz if > - C?Z_DEFINED_VALUE_AT_ZERO is 2, optab is present and > - instead of 0 above it uses the value from that macro. */ > - > -static bool > -cond_removal_in_builtin_zero_pattern (basic_block cond_bb, > - basic_block middle_bb, > - edge e1, edge e2, gphi *phi, > - tree arg0, tree arg1) > -{ > - gimple_stmt_iterator gsi, gsi_from; > - gimple *call; > - gimple *cast = NULL; > - tree lhs, arg; > - > - /* Check that > - _2 = (unsigned long) b_4(D); > - _9 = __builtin_popcountl (_2); > - OR > - _9 = __builtin_popcountl (b_4(D)); > - are the only stmts in the middle_bb. */ > - > - gsi = gsi_start_nondebug_after_labels_bb (middle_bb); > - if (gsi_end_p (gsi)) > - return false; > - cast = gsi_stmt (gsi); > - gsi_next_nondebug (&gsi); > - if (!gsi_end_p (gsi)) > - { > - call = gsi_stmt (gsi); > - gsi_next_nondebug (&gsi); > - if (!gsi_end_p (gsi)) > - return false; > - } > - else > - { > - call = cast; > - cast = NULL; > - } > - > - /* Check that we have a popcount/clz/ctz builtin. */ > - if (!is_gimple_call (call)) > - return false; > - > - lhs = gimple_get_lhs (call); > - > - if (lhs == NULL_TREE) > - return false; > - > - combined_fn cfn = gimple_call_combined_fn (call); > - if (gimple_call_num_args (call) != 1 > - && (gimple_call_num_args (call) != 2 > - || cfn == CFN_CLZ > - || cfn == CFN_CTZ)) > - return false; > - > - arg = gimple_call_arg (call, 0); > - > - internal_fn ifn = IFN_LAST; > - int val = 0; > - bool any_val = false; > - switch (cfn) > - { > - CASE_CFN_BSWAP: > - CASE_CFN_BITREVERSE: > - CASE_CFN_FFS: > - CASE_CFN_PARITY: > - CASE_CFN_POPCOUNT: > - break; > - CASE_CFN_CLZ: > - if (INTEGRAL_TYPE_P (TREE_TYPE (arg))) > - { > - tree type = TREE_TYPE (arg); > - if (BITINT_TYPE_P (type)) > - { > - if (gimple_call_num_args (call) == 1) > - { > - any_val = true; > - ifn = IFN_CLZ; > - break; > - } > - if (!tree_fits_shwi_p (gimple_call_arg (call, 1))) > - return false; > - HOST_WIDE_INT at_zero = tree_to_shwi (gimple_call_arg (call, > 1)); > - if ((int) at_zero != at_zero) > - return false; > - ifn = IFN_CLZ; > - val = at_zero; > - break; > - } > - if (direct_internal_fn_supported_p (IFN_CLZ, type, > OPTIMIZE_FOR_BOTH) > - && CLZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (type), > - val) == 2) > - { > - ifn = IFN_CLZ; > - break; > - } > - } > - return false; > - CASE_CFN_CTZ: > - if (INTEGRAL_TYPE_P (TREE_TYPE (arg))) > - { > - tree type = TREE_TYPE (arg); > - if (BITINT_TYPE_P (type)) > - { > - if (gimple_call_num_args (call) == 1) > - { > - any_val = true; > - ifn = IFN_CTZ; > - break; > - } > - if (!tree_fits_shwi_p (gimple_call_arg (call, 1))) > - return false; > - HOST_WIDE_INT at_zero = tree_to_shwi (gimple_call_arg (call, > 1)); > - if ((int) at_zero != at_zero) > - return false; > - ifn = IFN_CTZ; > - val = at_zero; > - break; > - } > - if (direct_internal_fn_supported_p (IFN_CTZ, type, > OPTIMIZE_FOR_BOTH) > - && CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (type), > - val) == 2) > - { > - ifn = IFN_CTZ; > - break; > - } > - } > - return false; > - case CFN_BUILT_IN_CLRSB: > - val = TYPE_PRECISION (integer_type_node) - 1; > - break; > - case CFN_BUILT_IN_CLRSBL: > - val = TYPE_PRECISION (long_integer_type_node) - 1; > - break; > - case CFN_BUILT_IN_CLRSBLL: > - val = TYPE_PRECISION (long_long_integer_type_node) - 1; > - break; > - default: > - return false; > - } > - > - if (cast) > - { > - /* We have a cast stmt feeding popcount/clz/ctz builtin. */ > - /* Check that we have a cast prior to that. */ > - if (gimple_code (cast) != GIMPLE_ASSIGN > - || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (cast))) > - return false; > - /* Result of the cast stmt is the argument to the builtin. */ > - if (arg != gimple_assign_lhs (cast)) > - return false; > - arg = gimple_assign_rhs1 (cast); > - } > - > - gcond *cond = dyn_cast <gcond *> (*gsi_last_bb (cond_bb)); > - > - /* Cond_bb has a check for b_4 [!=|==] 0 before calling the > popcount/clz/ctz > - builtin. */ > - if (!cond > - || (gimple_cond_code (cond) != NE_EXPR > - && gimple_cond_code (cond) != EQ_EXPR) > - || !integer_zerop (gimple_cond_rhs (cond)) > - || arg != gimple_cond_lhs (cond)) > - return false; > - > - edge true_edge, false_edge; > - /* We need to know which is the true edge and which is the false > - edge so that we know when to invert the condition below. */ > - extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge); > - > - /* Forward the edges over the middle basic block. */ > - if (true_edge->dest == middle_bb) > - true_edge = EDGE_SUCC (true_edge->dest, 0); > - if (false_edge->dest == middle_bb) > - false_edge = EDGE_SUCC (false_edge->dest, 0); > - > - /* Canonicalize the args with respect to the edges, > - arg0 is from the true edge and arg1 is from the > - false edge. > - That is `cond ? arg0 : arg1`.*/ > - if (true_edge == e1) > - gcc_assert (false_edge == e2); > - else > - { > - gcc_assert (false_edge == e1); > - gcc_assert (true_edge == e2); > - std::swap (arg0, arg1); > - } > - > - /* Canonicalize the args such that we get: > - `arg != 0 ? arg0 : arg1`. So swap arg0/arg1 > - around if cond was an equals. */ > - if (gimple_cond_code (cond) == EQ_EXPR) > - std::swap (arg0, arg1); > - > - /* Check PHI arguments. */ > - if (lhs != arg0 > - || TREE_CODE (arg1) != INTEGER_CST) > - return false; > - if (any_val) > - { > - if (!tree_fits_shwi_p (arg1)) > - return false; > - HOST_WIDE_INT at_zero = tree_to_shwi (arg1); > - if ((int) at_zero != at_zero) > - return false; > - val = at_zero; > - } > - else if (wi::to_wide (arg1) != val) > - return false; > - > - /* And insert the popcount/clz/ctz builtin and cast stmt before the > - cond_bb. */ > - gsi = gsi_last_bb (cond_bb); > - if (cast) > - { > - gsi_from = gsi_for_stmt (cast); > - gsi_move_before (&gsi_from, &gsi); > - reset_flow_sensitive_info (gimple_get_lhs (cast)); > - } > - gsi_from = gsi_for_stmt (call); > - if (ifn == IFN_LAST > - || (gimple_call_internal_p (call) && gimple_call_num_args (call) == 2)) > - gsi_move_before (&gsi_from, &gsi); > - else > - { > - /* For __builtin_c[lt]z* force .C[LT]Z ifn, because only > - the latter is well defined at zero. */ > - call = gimple_build_call_internal (ifn, 2, gimple_call_arg (call, 0), > - build_int_cst (integer_type_node, > val)); > - gimple_call_set_lhs (call, lhs); > - gsi_insert_before (&gsi, call, GSI_SAME_STMT); > - gsi_remove (&gsi_from, true); > - } > - reset_flow_sensitive_info (lhs); > - > - /* Now update the PHI and remove unneeded bbs. */ > - replace_phi_edge_with_variable (cond_bb, e2, phi, lhs); > - return true; > -} > - > /* Auxiliary functions to determine the set of memory accesses which > can't trap because they are preceded by accesses to the same memory > portion. We do that for MEM_REFs, so we only need to track > @@ -4535,12 +4417,6 @@ pass_phiopt::execute (function *) > if (match_simplify_replacement (bb, bb1, bb2, e1, e2, phi, > arg0, arg1, early_p, diamond_p)) > cfgchanged = true; > - else if (!early_p > - && !diamond_p > - && single_pred_p (bb1) > - && cond_removal_in_builtin_zero_pattern (bb, bb1, e1, e2, > - phi, arg0, arg1)) > - cfgchanged = true; > else if (single_pred_p (bb1) > && !diamond_p > && spaceship_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) > -- > 2.43.0 >
