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
> >

Reply via email to