On Tue, May 25, 2021 at 7:12 AM Richard Biener via Gcc-patches <gcc-patches@gcc.gnu.org> wrote: > > On Mon, May 24, 2021 at 4:09 AM apinski--- via Gcc-patches > <gcc-patches@gcc.gnu.org> wrote: > > > > From: Andrew Pinski <apin...@marvell.com> > > > > To simplify PHI-OPT and future improvements to it in most > > (but not all) cases, using match-and-simplify simplifies how > > much code is needed to be added. > > > > This depends on the following two patches: > > https://gcc.gnu.org/pipermail/gcc-patches/2021-May/571033.html > > https://gcc.gnu.org/pipermail/gcc-patches/2021-May/571054.html > > As this patch removes those parts from phiopt. > > > > Note I will be looking to move two_value_replacement and > > value_replacement to match-and-simplify next. > > > > Note also there is one latent bug found while working > > on this: https://gcc.gnu.org/PR100733 . > > > > OK? Bootstrapped and tested on x86_64-linux-gnu with no regressions and > > all languages. > > > > Thanks, > > Andrew Pinski > > > > gcc/ChangeLog: > > > > * tree-ssa-phiopt.c: Include explow.h. > > Fix up comment before the pass struction. > > (conditional_replacement): Remove function. > > (xor_replacement): Remove function. > > (match_simplify_replacement): New function. > > (tree_ssa_phiopt_worker): Don't call conditional_replacement > > or xor_replacement. Call match_simplify_replacement > > if everything else fails to happen. > > (block_with_single_simple_statement): New function. > > > > gcc/testsuite/ChangeLog: > > > > * gcc.dg/tree-ssa/pr96928-1.c: Fix testcase for now that ~ > > happens on the outside of the bit_xor. > > --- > > gcc/testsuite/gcc.dg/tree-ssa/pr96928-1.c | 4 +- > > gcc/tree-ssa-phiopt.c | 478 ++++++++++------------ > > 2 files changed, 229 insertions(+), 253 deletions(-) > > > > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr96928-1.c > > b/gcc/testsuite/gcc.dg/tree-ssa/pr96928-1.c > > index a2770e5e896..2e86620da11 100644 > > --- a/gcc/testsuite/gcc.dg/tree-ssa/pr96928-1.c > > +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr96928-1.c > > @@ -1,9 +1,9 @@ > > /* PR tree-optimization/96928 */ > > /* { dg-do compile } */ > > -/* { dg-options "-O2 -fdump-tree-phiopt2" } */ > > +/* { dg-options "-O2 -fdump-tree-phiopt2 -fdump-tree-optimized" } */ > > /* { dg-final { scan-tree-dump-times " = a_\[0-9]*\\\(D\\\) >> " 5 > > "phiopt2" } } */ > > /* { dg-final { scan-tree-dump-times " = ~c_\[0-9]*\\\(D\\\);" 1 "phiopt2" > > } } */ > > -/* { dg-final { scan-tree-dump-times " = ~" 1 "phiopt2" } } */ > > +/* { dg-final { scan-tree-dump-times " = ~" 1 "optimized" } } */ > > /* { dg-final { scan-tree-dump-times " = \[abc_0-9\\\(\\\)D]* \\\^ " 5 > > "phiopt2" } } */ > > /* { dg-final { scan-tree-dump-not "a < 0" "phiopt2" } } */ > > > > diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c > > index f133659a781..f7c82cf192f 100644 > > --- a/gcc/tree-ssa-phiopt.c > > +++ b/gcc/tree-ssa-phiopt.c > > @@ -48,12 +48,11 @@ along with GCC; see the file COPYING3. If not see > > #include "tree-eh.h" > > #include "gimple-fold.h" > > #include "internal-fn.h" > > +#include "explow.h" /* For promote_mode. */ > > > > static unsigned int tree_ssa_phiopt_worker (bool, bool, bool); > > static bool two_value_replacement (basic_block, basic_block, edge, gphi *, > > tree, tree); > > -static bool conditional_replacement (basic_block, basic_block, > > - edge, edge, gphi *, tree, tree); > > static gphi *factor_out_conditional_conversion (edge, edge, gphi *, tree, > > tree, > > gimple *); > > static int value_replacement (basic_block, basic_block, > > @@ -62,8 +61,6 @@ static bool minmax_replacement (basic_block, basic_block, > > edge, edge, gphi *, tree, tree); > > static bool abs_replacement (basic_block, basic_block, > > edge, edge, gphi *, tree, tree); > > -static bool xor_replacement (basic_block, basic_block, > > - edge, edge, gphi *, tree, tree); > > static bool spaceship_replacement (basic_block, basic_block, > > edge, edge, gphi *, tree, tree); > > static bool cond_removal_in_popcount_clz_ctz_pattern (basic_block, > > basic_block, > > @@ -71,6 +68,8 @@ static bool cond_removal_in_popcount_clz_ctz_pattern > > (basic_block, basic_block, > > tree, tree); > > static bool cond_store_replacement (basic_block, basic_block, edge, edge, > > hash_set<tree> *); > > +static bool match_simplify_replacement (basic_block, basic_block, > > + edge, edge, gimple_seq, bool, bool); > > static bool cond_if_else_store_replacement (basic_block, basic_block, > > basic_block); > > static hash_set<tree> * get_non_trapping (); > > static void replace_phi_edge_with_variable (basic_block, edge, gphi *, > > tree); > > @@ -319,7 +318,7 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool > > do_hoist_loads, bool early_p) > > > > phi = single_non_singleton_phi_for_edges (phis, e1, e2); > > if (!phi) > > - continue; > > + goto try_match_simplify; > > > > arg0 = gimple_phi_arg_def (phi, e1->dest_idx); > > arg1 = gimple_phi_arg_def (phi, e2->dest_idx); > > @@ -345,14 +344,9 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool > > do_hoist_loads, bool early_p) > > /* Do the replacement of conditional if it can be done. */ > > if (!early_p && two_value_replacement (bb, bb1, e2, phi, arg0, > > arg1)) > > cfgchanged = true; > > - else if (!early_p > > - && conditional_replacement (bb, bb1, e1, e2, phi, > > - arg0, arg1)) > > - cfgchanged = true; > > else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) > > cfgchanged = true; > > - else if (!early_p > > - && xor_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) > > + else if (abs_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) > > cfgchanged = true; > > else if (!early_p > > && cond_removal_in_popcount_clz_ctz_pattern (bb, bb1, e1, > > @@ -363,7 +357,14 @@ tree_ssa_phiopt_worker (bool do_store_elim, bool > > do_hoist_loads, bool early_p) > > cfgchanged = true; > > else if (spaceship_replacement (bb, bb1, e1, e2, phi, arg0, arg1)) > > cfgchanged = true; > > + else > > + goto try_match_simplify; > > } > > + continue; > > +try_match_simplify: > > + if (match_simplify_replacement (bb, bb1, e1, e2, phi_nodes (bb2), > > + early_p, /*late_p = */false)) > > + cfgchanged = true; > > Can we do this in steps please? First only handle > single_non_singleton_phi_for_edges, > thus a plain else if (!early_p && ...) in the above chain? In particular ...
Yes I agree. These are the steps I am going to take to begin with: * match and simplify with an empty basic block, to be able to remove conditional_replacement * add support for non-empty basic block, to be able to remove xor_replacement * and then see if the non-single_non_singleton_phi_for_edges case is still needed. * and then add the conditional move support I should have the first patch done by tomorrow; just finish writing it, it is much shorter. Thanks, Andrew Pinski > > > } > > > > free (bb_order); > > @@ -775,142 +776,6 @@ two_value_replacement (basic_block cond_bb, > > basic_block middle_bb, > > return true; > > } > > > > -/* The function conditional_replacement does the main work of doing the > > - conditional replacement. Return true if the replacement is done. > > - Otherwise return false. > > - BB is the basic block where the replacement is going to be done on. > > ARG0 > > - is argument 0 from PHI. Likewise for ARG1. */ > > - > > -static bool > > -conditional_replacement (basic_block cond_bb, basic_block middle_bb, > > - edge e0, edge e1, gphi *phi, > > - tree arg0, tree arg1) > > -{ > > - tree result; > > - gimple *stmt; > > - gassign *new_stmt; > > - tree cond; > > - gimple_stmt_iterator gsi; > > - edge true_edge, false_edge; > > - tree new_var, new_var2; > > - bool neg = false; > > - int shift = 0; > > - tree nonzero_arg; > > - > > - /* FIXME: Gimplification of complex type is too hard for now. */ > > - /* We aren't prepared to handle vectors either (and it is a question > > - if it would be worthwhile anyway). */ > > - if (!(INTEGRAL_TYPE_P (TREE_TYPE (arg0)) > > - || POINTER_TYPE_P (TREE_TYPE (arg0))) > > - || !(INTEGRAL_TYPE_P (TREE_TYPE (arg1)) > > - || POINTER_TYPE_P (TREE_TYPE (arg1)))) > > - return false; > > - > > - /* The PHI arguments have the constants 0 and 1, or 0 and -1 or > > - 0 and (1 << cst), then convert it to the conditional. */ > > - if (integer_zerop (arg0)) > > - nonzero_arg = arg1; > > - else if (integer_zerop (arg1)) > > - nonzero_arg = arg0; > > - else > > - return false; > > - if (integer_pow2p (nonzero_arg)) > > - { > > - shift = tree_log2 (nonzero_arg); > > - if (shift && POINTER_TYPE_P (TREE_TYPE (nonzero_arg))) > > - return false; > > - } > > - else if (integer_all_onesp (nonzero_arg)) > > - neg = true; > > - else > > - return false; > > - > > - if (!empty_block_p (middle_bb)) > > - return false; > > - > > - /* At this point we know we have a GIMPLE_COND with two successors. > > - One successor is BB, the other successor is an empty block which > > - falls through into BB. > > - > > - There is a single PHI node at the join point (BB) and its arguments > > - are constants (0, 1) or (0, -1) or (0, (1 << shift)). > > - > > - So, given the condition COND, and the two PHI arguments, we can > > - rewrite this PHI into non-branching code: > > - > > - dest = (COND) or dest = COND' or dest = (COND) << shift > > - > > - We use the condition as-is if the argument associated with the > > - true edge has the value one or the argument associated with the > > - false edge as the value zero. Note that those conditions are not > > - the same since only one of the outgoing edges from the GIMPLE_COND > > - will directly reach BB and thus be associated with an argument. */ > > - > > - stmt = last_stmt (cond_bb); > > - result = PHI_RESULT (phi); > > - > > - /* To handle special cases like floating point comparison, it is easier > > and > > - less error-prone to build a tree and gimplify it on the fly though it > > is > > - less efficient. */ > > - cond = fold_build2_loc (gimple_location (stmt), > > - gimple_cond_code (stmt), boolean_type_node, > > - gimple_cond_lhs (stmt), gimple_cond_rhs (stmt)); > > - > > - /* 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); > > - if ((e0 == true_edge && integer_zerop (arg0)) > > - || (e0 == false_edge && !integer_zerop (arg0)) > > - || (e1 == true_edge && integer_zerop (arg1)) > > - || (e1 == false_edge && !integer_zerop (arg1))) > > - cond = fold_build1_loc (gimple_location (stmt), > > - TRUTH_NOT_EXPR, TREE_TYPE (cond), cond); > > - > > - if (neg) > > - { > > - cond = fold_convert_loc (gimple_location (stmt), > > - TREE_TYPE (result), cond); > > - cond = fold_build1_loc (gimple_location (stmt), > > - NEGATE_EXPR, TREE_TYPE (cond), cond); > > - } > > - else if (shift) > > - { > > - cond = fold_convert_loc (gimple_location (stmt), > > - TREE_TYPE (result), cond); > > - cond = fold_build2_loc (gimple_location (stmt), > > - LSHIFT_EXPR, TREE_TYPE (cond), cond, > > - build_int_cst (integer_type_node, shift)); > > - } > > - > > - /* Insert our new statements at the end of conditional block before the > > - COND_STMT. */ > > - gsi = gsi_for_stmt (stmt); > > - new_var = force_gimple_operand_gsi (&gsi, cond, true, NULL, true, > > - GSI_SAME_STMT); > > - > > - if (!useless_type_conversion_p (TREE_TYPE (result), TREE_TYPE (new_var))) > > - { > > - location_t locus_0, locus_1; > > - > > - new_var2 = make_ssa_name (TREE_TYPE (result)); > > - new_stmt = gimple_build_assign (new_var2, CONVERT_EXPR, new_var); > > - gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT); > > - new_var = new_var2; > > - > > - /* Set the locus to the first argument, unless is doesn't have one. > > */ > > - locus_0 = gimple_phi_arg_location (phi, 0); > > - locus_1 = gimple_phi_arg_location (phi, 1); > > - if (locus_0 == UNKNOWN_LOCATION) > > - locus_0 = locus_1; > > - gimple_set_location (new_stmt, locus_0); > > - } > > - > > - replace_phi_edge_with_variable (cond_bb, e1, phi, new_var); > > - > > - /* Note that we optimized this PHI. */ > > - return true; > > -} > > - > > /* Update *ARG which is defined in STMT so that it contains the > > computed value if that seems profitable. Return true if the > > statement is made dead by that rewriting. */ > > @@ -1413,6 +1278,219 @@ value_replacement (basic_block cond_bb, basic_block > > middle_bb, > > return 0; > > } > > > > +/* Return true if basic block BB has no statements or > > + a statement (that has no side effects) with one cheap > > + preparation statement. Const/pure functions can only be the last > > + statmenent. */ > > +static bool > > +block_with_single_simple_statement (basic_block bb, gimple **stmt) > > +{ > > + /* BB must have no executable statements. */ > > + gimple *stmt1; > > + gimple_stmt_iterator gsi = gsi_after_labels (bb); > > + *stmt = NULL; > > + if (phi_nodes (bb)) > > + return false; > > + if (gsi_end_p (gsi)) > > + return true; > > + if (is_gimple_debug (gsi_stmt (gsi))) > > + gsi_next_nondebug (&gsi); > > + if (gsi_end_p (gsi)) > > + return true; > > + stmt1 = gsi_stmt (gsi); > > + gsi_next_nondebug (&gsi); > > + if (!gsi_end_p (gsi)) > > + return false; > > + if (gimple_could_trap_p (stmt1)) > > + return false; > > + if (gimple_has_side_effects (stmt1)) > > + return false; > > + *stmt = stmt1; > > + if (is_gimple_assign (stmt1) > > + && TREE_CODE (gimple_assign_lhs (stmt1)) == SSA_NAME) > > + return true; > > + if (is_gimple_call (stmt1) > > + && gimple_inexpensive_call_p (as_a <gcall *> (stmt1))) > > + return true; > > + return false; > > +} > > + > > +/* The function match_simplify_replacement does the main work of using the > > + match and simplify infastructure to do the replacement. Return true > > if the replacement is done. Otherwise return false. > > + BB is the basic block where the replacement is going to be done on. > > ARG0 > > + is argument 0 from the PHI. Likewise for ARG1. */ > > + > > +static bool > > +match_simplify_replacement (basic_block cond_bb, basic_block middle_bb, > > + edge e0, edge e1, gimple_seq phis, bool early_p, > > + bool late_p) > > +{ > > + gimple *stmt; > > + edge true_edge, false_edge; > > + tree cond; > > + tree type; > > + gimple_stmt_iterator gsi; > > + int reverse = false; > > + gimple *stmt_to_move; > > + gimple_seq seq = NULL; > > + bool allhappened = true; > > + bool happened_once = false; > > + auto_vec<std::pair<gimple *,tree>, 4> changedphis; > > + > > + if (!block_with_single_simple_statement (middle_bb, &stmt_to_move)) > > It feels like we must have two or three "similar" copies of such function > around > already ...? > > > + return false; > > + > > + /* If there is a statement to move and is early, then don't do. */ > > + if (early_p && stmt_to_move) > > + return false; > > + > > + stmt = last_stmt (cond_bb); > > + > > + /* We need to know which is the true edge and which is the false > > + edge so that we know if have abs or negative abs. */ > > + extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge); > > + if (e1 == true_edge || e0 == false_edge) > > + reverse = true; > > + > > + /* Don't use fold_build2 here as that might create (bool)a instead of > > just > > + "a != 0". */ > > + cond = build2_loc (gimple_location (stmt), gimple_cond_code (stmt), > > + boolean_type_node, gimple_cond_lhs (stmt), > > + gimple_cond_rhs (stmt)); > > + > > + for (gsi = gsi_start (phis); !gsi_end_p (gsi); gsi_next (&gsi)) > > + { > > + gimple *p = gsi_stmt (gsi); > > + tree conditional; > > + tree arg0, arg1; > > + gimple_seq seq1 = NULL; > > + bool happened = false; > > + > > + /* If the PHI arguments are equal then we can skip this PHI. */ > > + arg0 = gimple_phi_arg_def (p, e0->dest_idx); > > + arg1 = gimple_phi_arg_def (p, e1->dest_idx); > > + > > + /* Skip the equal case as it will be optimize to the same thing. */ > > + if (operand_equal_for_phi_arg_p (arg0, arg1)) > > + continue; > > + > > + if (reverse) > > + std::swap (arg0, arg1); > > + > > + type = TREE_TYPE (gimple_phi_result (p)); > > + > > + conditional = gimple_simplify (COND_EXPR, type, > > + unshare_expr (cond), > > + arg0, arg1, > > + &seq1, NULL); > > + > > + /* If we did not simplify, then emit a COND_EXPR if we can. */ > > ... this is now general (late) if-conversion on GIMPLE which should be done > separately. In particular when dealing with multiple PHIs it needs some > better cost modeling IMHO. > > What's the reason you want to push it with this general change? > > So I'd like to have an initially simpler approach of just replacing some of > the > handling by match.pd patterns after which we could see to handle multiple PHIs > in general - even the other matchers could benefit from that (but I see some > refactoring necessary to have a analysis and a transform stage, maybe just > an added bool to the functions...). > > Thanks for working on this, > Richard. > > > + if (!conditional) > > + { > > + gimple *stmt; > > + > > + /* Only emit a COND_EXPR if this is the late PHI-OPT. */ > > + if (!late_p) > > + { > > + /* Note some transformations can happen even without having > > + extra staments. */ > > + allhappened = false; > > + continue; > > + } > > + > > + if (!can_conditionally_move_p (TYPE_MODE (TREE_TYPE (PHI_RESULT > > (p))))) > > + { > > + tree type = TREE_TYPE (PHI_RESULT (p)); > > + enum machine_mode mode = TYPE_MODE (type); > > + int unsignedp = TYPE_UNSIGNED (type); > > + mode = promote_mode (type, mode, &unsignedp); > > + if (!can_conditionally_move_p (mode)) > > + { > > + allhappened = false; > > + continue; > > + } > > + } > > + /* Manually create the final assignment so the aliasing info > > + for the ssa name will be up todate. */ > > + conditional = duplicate_ssa_name (PHI_RESULT (p), NULL); > > + stmt = gimple_build_assign (conditional, COND_EXPR, > > + unshare_expr (cond), arg0, arg1); > > + gimple_seq_add_stmt_without_update (&seq1, stmt); > > + } > > + /* If the simplification can be done without any extra statement, > > + do this transformation all the time. > > + For an example a == 0 ? 0 : a -> a . > > + This requires there to be no statement to be moved as: > > + a == 0 ? 0 : (t = a * b) will be replaced with just t and then > > + later on the statement might not be moved. */ > > + if (!seq1 && !stmt_to_move) > > + { > > + /* Set both of the edges of the PHI node to be the result. */ > > + SET_USE (PHI_ARG_DEF_PTR (p, e1->dest_idx), conditional); > > + SET_USE (PHI_ARG_DEF_PTR (p, e0->dest_idx), conditional); > > + happened = true; > > + } > > + else if (early_p || !allhappened) > > + { > > + happened = false; > > + allhappened = false; > > + } > > + else > > + { > > + gimple_seq_add_seq_without_update (&seq, seq1); > > + changedphis.safe_push (std::make_pair (p, conditional)); > > + happened = true; > > + } > > + > > + if (happened && dump_file && (dump_flags & TDF_DETAILS)) > > + { > > + if (!seq1 && !stmt_to_move) > > + fprintf (dump_file, "Committed: "); > > + fprintf (dump_file, "PHI "); > > + print_generic_expr (dump_file, gimple_phi_result (p)); > > + fprintf (dump_file, > > + " trying change to straight line code for COND_EXPR in > > block %d: COND_EXPR: ", > > + cond_bb->index); > > + print_generic_expr (dump_file, cond); > > + fprintf (dump_file, "PHI elements to: "); > > + print_generic_expr (dump_file, conditional); > > + fprintf (dump_file, "\n"); > > + } > > + happened_once |= happened; > > + } > > + > > + if (!happened_once || !allhappened) > > + return false; > > + > > + if (dump_file && (dump_flags & TDF_DETAILS)) > > + fprintf (dump_file, "commited the above changes.\n"); > > + > > + for(auto phi_to_change : changedphis) > > + { > > + gimple *phi = phi_to_change.first; > > + tree conditional = phi_to_change.second; > > + /* Set both of the edges of the PHI node to be the result. */ > > + SET_USE (PHI_ARG_DEF_PTR (phi, e1->dest_idx), conditional); > > + SET_USE (PHI_ARG_DEF_PTR (phi, e0->dest_idx), conditional); > > + } > > + > > + gsi = gsi_for_stmt (stmt); > > + if (stmt_to_move) > > + { > > + if (dump_file && (dump_flags & TDF_DETAILS)) > > + { > > + fprintf (dump_file, "statement un-sinked:\n"); > > + print_gimple_stmt (dump_file, stmt_to_move, 0, > > + TDF_VOPS|TDF_MEMSYMS); > > + } > > + gimple_stmt_iterator gsi1 = gsi_for_stmt (stmt_to_move); > > + gsi_move_before (&gsi1, &gsi); > > + } > > + > > + gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT); > > + return true; > > +} > > + > > /* The function minmax_replacement does the main work of doing the minmax > > replacement. Return true if the replacement is done. Otherwise return > > false. > > @@ -2649,108 +2727,6 @@ abs_replacement (basic_block cond_bb, basic_block > > middle_bb, > > return true; > > } > > > > -/* Optimize x < 0 ? ~y : y into (x >> (prec-1)) ^ y. */ > > - > > -static bool > > -xor_replacement (basic_block cond_bb, basic_block middle_bb, > > - edge e0 ATTRIBUTE_UNUSED, edge e1, > > - gphi *phi, tree arg0, tree arg1) > > -{ > > - if (!INTEGRAL_TYPE_P (TREE_TYPE (arg1))) > > - return false; > > - > > - /* OTHER_BLOCK must have only one executable statement which must have > > the > > - form arg0 = ~arg1 or arg1 = ~arg0. */ > > - > > - gimple *assign = last_and_only_stmt (middle_bb); > > - /* If we did not find the proper one's complement assignment, then we > > cannot > > - optimize. */ > > - if (assign == NULL) > > - return false; > > - > > - /* If we got here, then we have found the only executable statement > > - in OTHER_BLOCK. If it is anything other than arg = ~arg1 or > > - arg1 = ~arg0, then we cannot optimize. */ > > - if (!is_gimple_assign (assign)) > > - return false; > > - > > - if (gimple_assign_rhs_code (assign) != BIT_NOT_EXPR) > > - return false; > > - > > - tree lhs = gimple_assign_lhs (assign); > > - tree rhs = gimple_assign_rhs1 (assign); > > - > > - /* The assignment has to be arg0 = -arg1 or arg1 = -arg0. */ > > - if (!(lhs == arg0 && rhs == arg1) && !(lhs == arg1 && rhs == arg0)) > > - return false; > > - > > - gimple *cond = last_stmt (cond_bb); > > - tree result = PHI_RESULT (phi); > > - > > - /* Only relationals comparing arg[01] against zero are interesting. */ > > - enum tree_code cond_code = gimple_cond_code (cond); > > - if (cond_code != LT_EXPR && cond_code != GE_EXPR) > > - return false; > > - > > - /* Make sure the conditional is x OP 0. */ > > - tree clhs = gimple_cond_lhs (cond); > > - if (TREE_CODE (clhs) != SSA_NAME > > - || !INTEGRAL_TYPE_P (TREE_TYPE (clhs)) > > - || TYPE_UNSIGNED (TREE_TYPE (clhs)) > > - || TYPE_PRECISION (TREE_TYPE (clhs)) != TYPE_PRECISION (TREE_TYPE > > (arg1)) > > - || !integer_zerop (gimple_cond_rhs (cond))) > > - return false; > > - > > - /* We need to know which is the true edge and which is the false > > - edge so that we know if have xor or inverted xor. */ > > - edge true_edge, false_edge; > > - extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge); > > - > > - /* For GE_EXPR, if the true edge goes to OTHER_BLOCK, then we > > - will need to invert the result. Similarly for LT_EXPR if > > - the false edge goes to OTHER_BLOCK. */ > > - edge e; > > - if (cond_code == GE_EXPR) > > - e = true_edge; > > - else > > - e = false_edge; > > - > > - bool invert = e->dest == middle_bb; > > - > > - result = duplicate_ssa_name (result, NULL); > > - > > - gimple_stmt_iterator gsi = gsi_last_bb (cond_bb); > > - > > - int prec = TYPE_PRECISION (TREE_TYPE (clhs)); > > - gimple *new_stmt > > - = gimple_build_assign (make_ssa_name (TREE_TYPE (clhs)), RSHIFT_EXPR, > > clhs, > > - build_int_cst (integer_type_node, prec - 1)); > > - gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT); > > - > > - if (!useless_type_conversion_p (TREE_TYPE (result), TREE_TYPE (clhs))) > > - { > > - new_stmt = gimple_build_assign (make_ssa_name (TREE_TYPE (result)), > > - NOP_EXPR, gimple_assign_lhs > > (new_stmt)); > > - gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT); > > - } > > - lhs = gimple_assign_lhs (new_stmt); > > - > > - if (invert) > > - { > > - new_stmt = gimple_build_assign (make_ssa_name (TREE_TYPE (result)), > > - BIT_NOT_EXPR, rhs); > > - gsi_insert_before (&gsi, new_stmt, GSI_SAME_STMT); > > - rhs = gimple_assign_lhs (new_stmt); > > - } > > - > > - new_stmt = gimple_build_assign (result, BIT_XOR_EXPR, lhs, rhs); > > - gsi_insert_before (&gsi, new_stmt, GSI_NEW_STMT); > > - > > - replace_phi_edge_with_variable (cond_bb, e1, phi, result); > > - > > - /* Note that we optimized this PHI. */ > > - 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 > > @@ -3618,8 +3594,8 @@ gate_hoist_loads (void) > > Conditional Replacement > > ----------------------- > > > > - This transformation, implemented in conditional_replacement, > > - replaces > > + This transformation, using the match and simplify infastructure and > > implemented in > > + match_simplify_replacement, replaces > > > > bb0: > > if (cond) goto bb2; else goto bb1; > > -- > > 2.17.1 > >