diff mbox series

[2/2] phiopt: Move the common code between pass_phiopt and pass_cselim into a seperate function

Message ID 20240910034036.1984338-2-quic_apinski@quicinc.com
State New
Headers show
Series [1/2] phiopt: Use gimple_phi_result rather than PHI_RESULT [PR116643] | expand

Commit Message

Andrew Pinski Sept. 10, 2024, 3:40 a.m. UTC
When r14-303-gb9fedabe381cce was done, it was missed that some of the common parts could
be done in a template and a lambda could be used. This patch implements that. This new
function can be used later on to implement a simple ifcvt pass.

gcc/ChangeLog:

	* tree-ssa-phiopt.cc (execute_over_cond_phis): New template function,
	moved the common parts from pass_phiopt::execute/pass_cselim::execute.
	(pass_phiopt::execute): Move the functon specific parts of the loop
	into an lamdba.
	(pass_cselim::execute): Likewise.

Signed-off-by: Andrew Pinski <quic_apinski@quicinc.com>
---
 gcc/tree-ssa-phiopt.cc | 253 ++++++++++++++++-------------------------
 1 file changed, 100 insertions(+), 153 deletions(-)

Comments

Richard Biener Sept. 10, 2024, 5:01 a.m. UTC | #1
> Am 10.09.2024 um 05:41 schrieb Andrew Pinski <quic_apinski@quicinc.com>:
> 
> When r14-303-gb9fedabe381cce was done, it was missed that some of the common parts could
> be done in a template and a lambda could be used. This patch implements that. This new
> function can be used later on to implement a simple ifcvt pass.

Ok


> gcc/ChangeLog:
> 
>    * tree-ssa-phiopt.cc (execute_over_cond_phis): New template function,
>    moved the common parts from pass_phiopt::execute/pass_cselim::execute.
>    (pass_phiopt::execute): Move the functon specific parts of the loop
>    into an lamdba.
>    (pass_cselim::execute): Likewise.
> 
> Signed-off-by: Andrew Pinski <quic_apinski@quicinc.com>
> ---
> gcc/tree-ssa-phiopt.cc | 253 ++++++++++++++++-------------------------
> 1 file changed, 100 insertions(+), 153 deletions(-)
> 
> diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc
> index bd8ede06a98..5710bc32e61 100644
> --- a/gcc/tree-ssa-phiopt.cc
> +++ b/gcc/tree-ssa-phiopt.cc
> @@ -3933,6 +3933,83 @@ gate_hoist_loads (void)
>      && HAVE_conditional_move);
> }
> 
> +template <class func_type>
> +static void
> +execute_over_cond_phis (func_type func)
> +{
> +  unsigned n, i;
> +  basic_block *bb_order;
> +  basic_block bb;
> +  /* Search every basic block for COND_EXPR we may be able to optimize.
> +
> +     We walk the blocks in order that guarantees that a block with
> +     a single predecessor is processed before the predecessor.
> +     This ensures that we collapse inner ifs before visiting the
> +     outer ones, and also that we do not try to visit a removed
> +     block.  */
> +  bb_order = single_pred_before_succ_order ();
> +  n = n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS;
> +
> +  for (i = 0; i < n; i++)
> +    {
> +      basic_block bb1, bb2;
> +      edge e1, e2;
> +      bool diamond_p = false;
> +
> +      bb = bb_order[i];
> +
> +      /* Check to see if the last statement is a GIMPLE_COND.  */
> +      gcond *cond_stmt = safe_dyn_cast <gcond *> (*gsi_last_bb (bb));
> +      if (!cond_stmt)
> +    continue;
> +
> +      e1 = EDGE_SUCC (bb, 0);
> +      bb1 = e1->dest;
> +      e2 = EDGE_SUCC (bb, 1);
> +      bb2 = e2->dest;
> +
> +      /* We cannot do the optimization on abnormal edges.  */
> +      if ((e1->flags & EDGE_ABNORMAL) != 0
> +      || (e2->flags & EDGE_ABNORMAL) != 0)
> +    continue;
> +
> +      /* If either bb1's succ or bb2 or bb2's succ is non NULL.  */
> +      if (EDGE_COUNT (bb1->succs) == 0
> +      || EDGE_COUNT (bb2->succs) == 0)
> +    continue;
> +
> +      /* Find the bb which is the fall through to the other.  */
> +      if (EDGE_SUCC (bb1, 0)->dest == bb2)
> +    ;
> +      else if (EDGE_SUCC (bb2, 0)->dest == bb1)
> +    {
> +      std::swap (bb1, bb2);
> +      std::swap (e1, e2);
> +    }
> +      else if (EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest
> +           && single_succ_p (bb2))
> +    {
> +      diamond_p = true;
> +      e2 = EDGE_SUCC (bb2, 0);
> +      /* Make sure bb2 is just a fall through. */
> +      if ((e2->flags & EDGE_FALLTHRU) == 0)
> +        continue;
> +    }
> +      else
> +    continue;
> +
> +      e1 = EDGE_SUCC (bb1, 0);
> +
> +      /* Make sure that bb1 is just a fall through.  */
> +      if (!single_succ_p (bb1)
> +      || (e1->flags & EDGE_FALLTHRU) == 0)
> +    continue;
> +
> +      func (bb, bb1, bb2, e1, e2, diamond_p, cond_stmt);
> +    }
> +  free (bb_order);
> +}
> +
> /* This pass tries to replaces an if-then-else block with an
>    assignment.  We have different kinds of transformations.
>    Some of these transformations are also performed by the ifcvt
> @@ -4156,88 +4233,22 @@ unsigned int
> pass_phiopt::execute (function *)
> {
>   bool do_hoist_loads = !early_p ? gate_hoist_loads () : false;
> -  basic_block bb;
> -  basic_block *bb_order;
> -  unsigned n, i;
>   bool cfgchanged = false;
> 
>   calculate_dominance_info (CDI_DOMINATORS);
>   mark_ssa_maybe_undefs ();
> 
> -  /* Search every basic block for COND_EXPR we may be able to optimize.
> -
> -     We walk the blocks in order that guarantees that a block with
> -     a single predecessor is processed before the predecessor.
> -     This ensures that we collapse inner ifs before visiting the
> -     outer ones, and also that we do not try to visit a removed
> -     block.  */
> -  bb_order = single_pred_before_succ_order ();
> -  n = n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS;
> -
> -  for (i = 0; i < n; i++)
> +  auto phiopt_exec = [&] (basic_block bb, basic_block bb1,
> +              basic_block bb2, edge e1, edge e2,
> +              bool diamond_p, gcond *cond_stmt)
>     {
> -      gphi *phi;
> -      basic_block bb1, bb2;
> -      edge e1, e2;
> -      tree arg0, arg1;
> -      bool diamond_p = false;
> -
> -      bb = bb_order[i];
> -
> -      /* Check to see if the last statement is a GIMPLE_COND.  */
> -      gcond *cond_stmt = safe_dyn_cast <gcond *> (*gsi_last_bb (bb));
> -      if (!cond_stmt)
> -    continue;
> -
> -      e1 = EDGE_SUCC (bb, 0);
> -      bb1 = e1->dest;
> -      e2 = EDGE_SUCC (bb, 1);
> -      bb2 = e2->dest;
> -
> -      /* We cannot do the optimization on abnormal edges.  */
> -      if ((e1->flags & EDGE_ABNORMAL) != 0
> -      || (e2->flags & EDGE_ABNORMAL) != 0)
> -    continue;
> -
> -      /* If either bb1's succ or bb2 or bb2's succ is non NULL.  */
> -      if (EDGE_COUNT (bb1->succs) == 0
> -      || EDGE_COUNT (bb2->succs) == 0)
> -    continue;
> -
> -      /* Find the bb which is the fall through to the other.  */
> -      if (EDGE_SUCC (bb1, 0)->dest == bb2)
> -    ;
> -      else if (EDGE_SUCC (bb2, 0)->dest == bb1)
> -    {
> -      std::swap (bb1, bb2);
> -      std::swap (e1, e2);
> -    }
> -      else if (EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest
> -           && single_succ_p (bb2))
> -    {
> -      diamond_p = true;
> -      e2 = EDGE_SUCC (bb2, 0);
> -      /* Make sure bb2 is just a fall through. */
> -      if ((e2->flags & EDGE_FALLTHRU) == 0)
> -        continue;
> -    }
> -      else
> -    continue;
> -
> -      e1 = EDGE_SUCC (bb1, 0);
> -
> -      /* Make sure that bb1 is just a fall through.  */
> -      if (!single_succ_p (bb1)
> -      || (e1->flags & EDGE_FALLTHRU) == 0)
> -    continue;
> -
>       if (diamond_p)
>    {
>      basic_block bb3 = e1->dest;
> 
>      if (!single_pred_p (bb1)
>          || !single_pred_p (bb2))
> -        continue;
> +        return;
> 
>      if (do_hoist_loads
>          && !FLOAT_TYPE_P (TREE_TYPE (gimple_cond_lhs (cond_stmt)))
> @@ -4262,9 +4273,9 @@ pass_phiopt::execute (function *)
>       if (!early_p && !diamond_p)
>    for (gsi = gsi_start (phis); !gsi_end_p (gsi); gsi_next (&gsi))
>      {
> -        phi = as_a <gphi *> (gsi_stmt (gsi));
> -        arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
> -        arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
> +        gphi *phi = as_a <gphi *> (gsi_stmt (gsi));
> +        tree arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
> +        tree arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
>        if (value_replacement (bb, bb1, e1, e2, phi, arg0, arg1) == 2)
>          {
>        candorest = false;
> @@ -4274,14 +4285,14 @@ pass_phiopt::execute (function *)
>      }
> 
>       if (!candorest)
> -    continue;
> +    return;
> 
> -      phi = single_non_singleton_phi_for_edges (phis, e1, e2);
> +      gphi *phi = single_non_singleton_phi_for_edges (phis, e1, e2);
>       if (!phi)
> -    continue;
> +    return;
> 
> -      arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
> -      arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
> +      tree arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
> +      tree arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
> 
>       /* Something is wrong if we cannot find the arguments in the PHI
>      node.  */
> @@ -4323,9 +4334,9 @@ pass_phiopt::execute (function *)
>           && !diamond_p
>           && spaceship_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
>    cfgchanged = true;
> -    }
> +    };
> 
> -  free (bb_order);
> +  execute_over_cond_phis (phiopt_exec);
> 
>   if (cfgchanged)
>     return TODO_cleanup_cfg;
> @@ -4412,9 +4423,6 @@ make_pass_cselim (gcc::context *ctxt)
> unsigned int
> pass_cselim::execute (function *)
> {
> -  basic_block bb;
> -  basic_block *bb_order;
> -  unsigned n, i;
>   bool cfgchanged = false;
>   hash_set<tree> *nontrap = 0;
>   unsigned todo = 0;
> @@ -4430,71 +4438,10 @@ pass_cselim::execute (function *)
>   /* Calculate the set of non-trapping memory accesses.  */
>   nontrap = get_non_trapping ();
> 
> -  /* Search every basic block for COND_EXPR we may be able to optimize.
> -
> -     We walk the blocks in order that guarantees that a block with
> -     a single predecessor is processed before the predecessor.
> -     This ensures that we collapse inner ifs before visiting the
> -     outer ones, and also that we do not try to visit a removed
> -     block.  */
> -  bb_order = single_pred_before_succ_order ();
> -  n = n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS;
> -
> -  for (i = 0; i < n; i++)
> +  auto cselim_exec = [&] (basic_block bb, basic_block bb1,
> +              basic_block bb2, edge e1, edge e2,
> +              bool diamond_p, gcond *)
>     {
> -      basic_block bb1, bb2;
> -      edge e1, e2;
> -      bool diamond_p = false;
> -
> -      bb = bb_order[i];
> -
> -      /* Check to see if the last statement is a GIMPLE_COND.  */
> -      gcond *cond_stmt = safe_dyn_cast <gcond *> (*gsi_last_bb (bb));
> -      if (!cond_stmt)
> -    continue;
> -
> -      e1 = EDGE_SUCC (bb, 0);
> -      bb1 = e1->dest;
> -      e2 = EDGE_SUCC (bb, 1);
> -      bb2 = e2->dest;
> -
> -      /* We cannot do the optimization on abnormal edges.  */
> -      if ((e1->flags & EDGE_ABNORMAL) != 0
> -      || (e2->flags & EDGE_ABNORMAL) != 0)
> -    continue;
> -
> -      /* If either bb1's succ or bb2 or bb2's succ is non NULL.  */
> -      if (EDGE_COUNT (bb1->succs) == 0
> -      || EDGE_COUNT (bb2->succs) == 0)
> -    continue;
> -
> -      /* Find the bb which is the fall through to the other.  */
> -      if (EDGE_SUCC (bb1, 0)->dest == bb2)
> -    ;
> -      else if (EDGE_SUCC (bb2, 0)->dest == bb1)
> -    {
> -      std::swap (bb1, bb2);
> -      std::swap (e1, e2);
> -    }
> -      else if (EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest
> -           && single_succ_p (bb2))
> -    {
> -      diamond_p = true;
> -      e2 = EDGE_SUCC (bb2, 0);
> -      /* Make sure bb2 is just a fall through. */
> -      if ((e2->flags & EDGE_FALLTHRU) == 0)
> -        continue;
> -    }
> -      else
> -    continue;
> -
> -      e1 = EDGE_SUCC (bb1, 0);
> -
> -      /* Make sure that bb1 is just a fall through.  */
> -      if (!single_succ_p (bb1)
> -      || (e1->flags & EDGE_FALLTHRU) == 0)
> -    continue;
> -
>       if (diamond_p)
>    {
>      basic_block bb3 = e1->dest;
> @@ -4504,28 +4451,28 @@ pass_cselim::execute (function *)
>         if always since we are sinking rather than
>         hoisting. */
>      if (EDGE_COUNT (bb3->preds) != 2)
> -        continue;
> +        return;
>      if (cond_if_else_store_replacement (bb1, bb2, bb3))
>        cfgchanged = true;
> -      continue;
> +      return;
>    }
> 
>       /* Also make sure that bb1 only have one predecessor and that it
>     is bb.  */
>       if (!single_pred_p (bb1)
>      || single_pred (bb1) != bb)
> -    continue;
> +    return;
> 
>       /* bb1 is the middle block, bb2 the join block, bb the split block,
>     e1 the fallthrough edge from bb1 to bb2.  We can't do the
>     optimization if the join block has more than two predecessors.  */
>       if (EDGE_COUNT (bb2->preds) > 2)
> -    continue;
> +    return;
>       if (cond_store_replacement (bb1, bb2, e1, e2, nontrap))
>    cfgchanged = true;
> -    }
> +    };
> 
> -  free (bb_order);
> +  execute_over_cond_phis (cselim_exec);
> 
>   delete nontrap;
>   /* If the CFG has changed, we should cleanup the CFG.  */
> --
> 2.43.0
>
Richard Biener Sept. 10, 2024, 5:03 a.m. UTC | #2
> Am 10.09.2024 um 05:41 schrieb Andrew Pinski <quic_apinski@quicinc.com>:
> 
> When r14-303-gb9fedabe381cce was done, it was missed that some of the common parts could
> be done in a template and a lambda could be used. This patch implements that. This new
> function can be used later on to implement a simple ifcvt pass.

Ok

> gcc/ChangeLog:
> 
>    * tree-ssa-phiopt.cc (execute_over_cond_phis): New template function,
>    moved the common parts from pass_phiopt::execute/pass_cselim::execute.
>    (pass_phiopt::execute): Move the functon specific parts of the loop
>    into an lamdba.
>    (pass_cselim::execute): Likewise.
> 
> Signed-off-by: Andrew Pinski <quic_apinski@quicinc.com>
> ---
> gcc/tree-ssa-phiopt.cc | 253 ++++++++++++++++-------------------------
> 1 file changed, 100 insertions(+), 153 deletions(-)
> 
> diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc
> index bd8ede06a98..5710bc32e61 100644
> --- a/gcc/tree-ssa-phiopt.cc
> +++ b/gcc/tree-ssa-phiopt.cc
> @@ -3933,6 +3933,83 @@ gate_hoist_loads (void)
>      && HAVE_conditional_move);
> }
> 
> +template <class func_type>
> +static void
> +execute_over_cond_phis (func_type func)
> +{
> +  unsigned n, i;
> +  basic_block *bb_order;
> +  basic_block bb;
> +  /* Search every basic block for COND_EXPR we may be able to optimize.
> +
> +     We walk the blocks in order that guarantees that a block with
> +     a single predecessor is processed before the predecessor.
> +     This ensures that we collapse inner ifs before visiting the
> +     outer ones, and also that we do not try to visit a removed
> +     block.  */
> +  bb_order = single_pred_before_succ_order ();
> +  n = n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS;
> +
> +  for (i = 0; i < n; i++)
> +    {
> +      basic_block bb1, bb2;
> +      edge e1, e2;
> +      bool diamond_p = false;
> +
> +      bb = bb_order[i];
> +
> +      /* Check to see if the last statement is a GIMPLE_COND.  */
> +      gcond *cond_stmt = safe_dyn_cast <gcond *> (*gsi_last_bb (bb));
> +      if (!cond_stmt)
> +    continue;
> +
> +      e1 = EDGE_SUCC (bb, 0);
> +      bb1 = e1->dest;
> +      e2 = EDGE_SUCC (bb, 1);
> +      bb2 = e2->dest;
> +
> +      /* We cannot do the optimization on abnormal edges.  */
> +      if ((e1->flags & EDGE_ABNORMAL) != 0
> +      || (e2->flags & EDGE_ABNORMAL) != 0)
> +    continue;
> +
> +      /* If either bb1's succ or bb2 or bb2's succ is non NULL.  */
> +      if (EDGE_COUNT (bb1->succs) == 0
> +      || EDGE_COUNT (bb2->succs) == 0)
> +    continue;
> +
> +      /* Find the bb which is the fall through to the other.  */
> +      if (EDGE_SUCC (bb1, 0)->dest == bb2)
> +    ;
> +      else if (EDGE_SUCC (bb2, 0)->dest == bb1)
> +    {
> +      std::swap (bb1, bb2);
> +      std::swap (e1, e2);
> +    }
> +      else if (EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest
> +           && single_succ_p (bb2))
> +    {
> +      diamond_p = true;
> +      e2 = EDGE_SUCC (bb2, 0);
> +      /* Make sure bb2 is just a fall through. */
> +      if ((e2->flags & EDGE_FALLTHRU) == 0)
> +        continue;
> +    }
> +      else
> +    continue;
> +
> +      e1 = EDGE_SUCC (bb1, 0);
> +
> +      /* Make sure that bb1 is just a fall through.  */
> +      if (!single_succ_p (bb1)
> +      || (e1->flags & EDGE_FALLTHRU) == 0)
> +    continue;
> +
> +      func (bb, bb1, bb2, e1, e2, diamond_p, cond_stmt);
> +    }
> +  free (bb_order);
> +}
> +
> /* This pass tries to replaces an if-then-else block with an
>    assignment.  We have different kinds of transformations.
>    Some of these transformations are also performed by the ifcvt
> @@ -4156,88 +4233,22 @@ unsigned int
> pass_phiopt::execute (function *)
> {
>   bool do_hoist_loads = !early_p ? gate_hoist_loads () : false;
> -  basic_block bb;
> -  basic_block *bb_order;
> -  unsigned n, i;
>   bool cfgchanged = false;
> 
>   calculate_dominance_info (CDI_DOMINATORS);
>   mark_ssa_maybe_undefs ();
> 
> -  /* Search every basic block for COND_EXPR we may be able to optimize.
> -
> -     We walk the blocks in order that guarantees that a block with
> -     a single predecessor is processed before the predecessor.
> -     This ensures that we collapse inner ifs before visiting the
> -     outer ones, and also that we do not try to visit a removed
> -     block.  */
> -  bb_order = single_pred_before_succ_order ();
> -  n = n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS;
> -
> -  for (i = 0; i < n; i++)
> +  auto phiopt_exec = [&] (basic_block bb, basic_block bb1,
> +              basic_block bb2, edge e1, edge e2,
> +              bool diamond_p, gcond *cond_stmt)
>     {
> -      gphi *phi;
> -      basic_block bb1, bb2;
> -      edge e1, e2;
> -      tree arg0, arg1;
> -      bool diamond_p = false;
> -
> -      bb = bb_order[i];
> -
> -      /* Check to see if the last statement is a GIMPLE_COND.  */
> -      gcond *cond_stmt = safe_dyn_cast <gcond *> (*gsi_last_bb (bb));
> -      if (!cond_stmt)
> -    continue;
> -
> -      e1 = EDGE_SUCC (bb, 0);
> -      bb1 = e1->dest;
> -      e2 = EDGE_SUCC (bb, 1);
> -      bb2 = e2->dest;
> -
> -      /* We cannot do the optimization on abnormal edges.  */
> -      if ((e1->flags & EDGE_ABNORMAL) != 0
> -      || (e2->flags & EDGE_ABNORMAL) != 0)
> -    continue;
> -
> -      /* If either bb1's succ or bb2 or bb2's succ is non NULL.  */
> -      if (EDGE_COUNT (bb1->succs) == 0
> -      || EDGE_COUNT (bb2->succs) == 0)
> -    continue;
> -
> -      /* Find the bb which is the fall through to the other.  */
> -      if (EDGE_SUCC (bb1, 0)->dest == bb2)
> -    ;
> -      else if (EDGE_SUCC (bb2, 0)->dest == bb1)
> -    {
> -      std::swap (bb1, bb2);
> -      std::swap (e1, e2);
> -    }
> -      else if (EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest
> -           && single_succ_p (bb2))
> -    {
> -      diamond_p = true;
> -      e2 = EDGE_SUCC (bb2, 0);
> -      /* Make sure bb2 is just a fall through. */
> -      if ((e2->flags & EDGE_FALLTHRU) == 0)
> -        continue;
> -    }
> -      else
> -    continue;
> -
> -      e1 = EDGE_SUCC (bb1, 0);
> -
> -      /* Make sure that bb1 is just a fall through.  */
> -      if (!single_succ_p (bb1)
> -      || (e1->flags & EDGE_FALLTHRU) == 0)
> -    continue;
> -
>       if (diamond_p)
>    {
>      basic_block bb3 = e1->dest;
> 
>      if (!single_pred_p (bb1)
>          || !single_pred_p (bb2))
> -        continue;
> +        return;
> 
>      if (do_hoist_loads
>          && !FLOAT_TYPE_P (TREE_TYPE (gimple_cond_lhs (cond_stmt)))
> @@ -4262,9 +4273,9 @@ pass_phiopt::execute (function *)
>       if (!early_p && !diamond_p)
>    for (gsi = gsi_start (phis); !gsi_end_p (gsi); gsi_next (&gsi))
>      {
> -        phi = as_a <gphi *> (gsi_stmt (gsi));
> -        arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
> -        arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
> +        gphi *phi = as_a <gphi *> (gsi_stmt (gsi));
> +        tree arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
> +        tree arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
>        if (value_replacement (bb, bb1, e1, e2, phi, arg0, arg1) == 2)
>          {
>        candorest = false;
> @@ -4274,14 +4285,14 @@ pass_phiopt::execute (function *)
>      }
> 
>       if (!candorest)
> -    continue;
> +    return;
> 
> -      phi = single_non_singleton_phi_for_edges (phis, e1, e2);
> +      gphi *phi = single_non_singleton_phi_for_edges (phis, e1, e2);
>       if (!phi)
> -    continue;
> +    return;
> 
> -      arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
> -      arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
> +      tree arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
> +      tree arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
> 
>       /* Something is wrong if we cannot find the arguments in the PHI
>      node.  */
> @@ -4323,9 +4334,9 @@ pass_phiopt::execute (function *)
>           && !diamond_p
>           && spaceship_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
>    cfgchanged = true;
> -    }
> +    };
> 
> -  free (bb_order);
> +  execute_over_cond_phis (phiopt_exec);
> 
>   if (cfgchanged)
>     return TODO_cleanup_cfg;
> @@ -4412,9 +4423,6 @@ make_pass_cselim (gcc::context *ctxt)
> unsigned int
> pass_cselim::execute (function *)
> {
> -  basic_block bb;
> -  basic_block *bb_order;
> -  unsigned n, i;
>   bool cfgchanged = false;
>   hash_set<tree> *nontrap = 0;
>   unsigned todo = 0;
> @@ -4430,71 +4438,10 @@ pass_cselim::execute (function *)
>   /* Calculate the set of non-trapping memory accesses.  */
>   nontrap = get_non_trapping ();
> 
> -  /* Search every basic block for COND_EXPR we may be able to optimize.
> -
> -     We walk the blocks in order that guarantees that a block with
> -     a single predecessor is processed before the predecessor.
> -     This ensures that we collapse inner ifs before visiting the
> -     outer ones, and also that we do not try to visit a removed
> -     block.  */
> -  bb_order = single_pred_before_succ_order ();
> -  n = n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS;
> -
> -  for (i = 0; i < n; i++)
> +  auto cselim_exec = [&] (basic_block bb, basic_block bb1,
> +              basic_block bb2, edge e1, edge e2,
> +              bool diamond_p, gcond *)
>     {
> -      basic_block bb1, bb2;
> -      edge e1, e2;
> -      bool diamond_p = false;
> -
> -      bb = bb_order[i];
> -
> -      /* Check to see if the last statement is a GIMPLE_COND.  */
> -      gcond *cond_stmt = safe_dyn_cast <gcond *> (*gsi_last_bb (bb));
> -      if (!cond_stmt)
> -    continue;
> -
> -      e1 = EDGE_SUCC (bb, 0);
> -      bb1 = e1->dest;
> -      e2 = EDGE_SUCC (bb, 1);
> -      bb2 = e2->dest;
> -
> -      /* We cannot do the optimization on abnormal edges.  */
> -      if ((e1->flags & EDGE_ABNORMAL) != 0
> -      || (e2->flags & EDGE_ABNORMAL) != 0)
> -    continue;
> -
> -      /* If either bb1's succ or bb2 or bb2's succ is non NULL.  */
> -      if (EDGE_COUNT (bb1->succs) == 0
> -      || EDGE_COUNT (bb2->succs) == 0)
> -    continue;
> -
> -      /* Find the bb which is the fall through to the other.  */
> -      if (EDGE_SUCC (bb1, 0)->dest == bb2)
> -    ;
> -      else if (EDGE_SUCC (bb2, 0)->dest == bb1)
> -    {
> -      std::swap (bb1, bb2);
> -      std::swap (e1, e2);
> -    }
> -      else if (EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest
> -           && single_succ_p (bb2))
> -    {
> -      diamond_p = true;
> -      e2 = EDGE_SUCC (bb2, 0);
> -      /* Make sure bb2 is just a fall through. */
> -      if ((e2->flags & EDGE_FALLTHRU) == 0)
> -        continue;
> -    }
> -      else
> -    continue;
> -
> -      e1 = EDGE_SUCC (bb1, 0);
> -
> -      /* Make sure that bb1 is just a fall through.  */
> -      if (!single_succ_p (bb1)
> -      || (e1->flags & EDGE_FALLTHRU) == 0)
> -    continue;
> -
>       if (diamond_p)
>    {
>      basic_block bb3 = e1->dest;
> @@ -4504,28 +4451,28 @@ pass_cselim::execute (function *)
>         if always since we are sinking rather than
>         hoisting. */
>      if (EDGE_COUNT (bb3->preds) != 2)
> -        continue;
> +        return;
>      if (cond_if_else_store_replacement (bb1, bb2, bb3))
>        cfgchanged = true;
> -      continue;
> +      return;
>    }
> 
>       /* Also make sure that bb1 only have one predecessor and that it
>     is bb.  */
>       if (!single_pred_p (bb1)
>      || single_pred (bb1) != bb)
> -    continue;
> +    return;
> 
>       /* bb1 is the middle block, bb2 the join block, bb the split block,
>     e1 the fallthrough edge from bb1 to bb2.  We can't do the
>     optimization if the join block has more than two predecessors.  */
>       if (EDGE_COUNT (bb2->preds) > 2)
> -    continue;
> +    return;
>       if (cond_store_replacement (bb1, bb2, e1, e2, nontrap))
>    cfgchanged = true;
> -    }
> +    };
> 
> -  free (bb_order);
> +  execute_over_cond_phis (cselim_exec);
> 
>   delete nontrap;
>   /* If the CFG has changed, we should cleanup the CFG.  */
> --
> 2.43.0
>
diff mbox series

Patch

diff --git a/gcc/tree-ssa-phiopt.cc b/gcc/tree-ssa-phiopt.cc
index bd8ede06a98..5710bc32e61 100644
--- a/gcc/tree-ssa-phiopt.cc
+++ b/gcc/tree-ssa-phiopt.cc
@@ -3933,6 +3933,83 @@  gate_hoist_loads (void)
 	  && HAVE_conditional_move);
 }
 
+template <class func_type>
+static void
+execute_over_cond_phis (func_type func)
+{
+  unsigned n, i;
+  basic_block *bb_order;
+  basic_block bb;
+  /* Search every basic block for COND_EXPR we may be able to optimize.
+
+     We walk the blocks in order that guarantees that a block with
+     a single predecessor is processed before the predecessor.
+     This ensures that we collapse inner ifs before visiting the
+     outer ones, and also that we do not try to visit a removed
+     block.  */
+  bb_order = single_pred_before_succ_order ();
+  n = n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS;
+
+  for (i = 0; i < n; i++)
+    {
+      basic_block bb1, bb2;
+      edge e1, e2;
+      bool diamond_p = false;
+
+      bb = bb_order[i];
+
+      /* Check to see if the last statement is a GIMPLE_COND.  */
+      gcond *cond_stmt = safe_dyn_cast <gcond *> (*gsi_last_bb (bb));
+      if (!cond_stmt)
+	continue;
+
+      e1 = EDGE_SUCC (bb, 0);
+      bb1 = e1->dest;
+      e2 = EDGE_SUCC (bb, 1);
+      bb2 = e2->dest;
+
+      /* We cannot do the optimization on abnormal edges.  */
+      if ((e1->flags & EDGE_ABNORMAL) != 0
+	  || (e2->flags & EDGE_ABNORMAL) != 0)
+	continue;
+
+      /* If either bb1's succ or bb2 or bb2's succ is non NULL.  */
+      if (EDGE_COUNT (bb1->succs) == 0
+	  || EDGE_COUNT (bb2->succs) == 0)
+	continue;
+
+      /* Find the bb which is the fall through to the other.  */
+      if (EDGE_SUCC (bb1, 0)->dest == bb2)
+	;
+      else if (EDGE_SUCC (bb2, 0)->dest == bb1)
+	{
+	  std::swap (bb1, bb2);
+	  std::swap (e1, e2);
+	}
+      else if (EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest
+	       && single_succ_p (bb2))
+	{
+	  diamond_p = true;
+	  e2 = EDGE_SUCC (bb2, 0);
+	  /* Make sure bb2 is just a fall through. */
+	  if ((e2->flags & EDGE_FALLTHRU) == 0)
+	    continue;
+	}
+      else
+	continue;
+
+      e1 = EDGE_SUCC (bb1, 0);
+
+      /* Make sure that bb1 is just a fall through.  */
+      if (!single_succ_p (bb1)
+	  || (e1->flags & EDGE_FALLTHRU) == 0)
+	continue;
+
+      func (bb, bb1, bb2, e1, e2, diamond_p, cond_stmt);
+    }
+  free (bb_order);
+}
+
 /* This pass tries to replaces an if-then-else block with an
    assignment.  We have different kinds of transformations.
    Some of these transformations are also performed by the ifcvt
@@ -4156,88 +4233,22 @@  unsigned int
 pass_phiopt::execute (function *)
 {
   bool do_hoist_loads = !early_p ? gate_hoist_loads () : false;
-  basic_block bb;
-  basic_block *bb_order;
-  unsigned n, i;
   bool cfgchanged = false;
 
   calculate_dominance_info (CDI_DOMINATORS);
   mark_ssa_maybe_undefs ();
 
-  /* Search every basic block for COND_EXPR we may be able to optimize.
-
-     We walk the blocks in order that guarantees that a block with
-     a single predecessor is processed before the predecessor.
-     This ensures that we collapse inner ifs before visiting the
-     outer ones, and also that we do not try to visit a removed
-     block.  */
-  bb_order = single_pred_before_succ_order ();
-  n = n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS;
-
-  for (i = 0; i < n; i++)
+  auto phiopt_exec = [&] (basic_block bb, basic_block bb1,
+			  basic_block bb2, edge e1, edge e2,
+			  bool diamond_p, gcond *cond_stmt)
     {
-      gphi *phi;
-      basic_block bb1, bb2;
-      edge e1, e2;
-      tree arg0, arg1;
-      bool diamond_p = false;
-
-      bb = bb_order[i];
-
-      /* Check to see if the last statement is a GIMPLE_COND.  */
-      gcond *cond_stmt = safe_dyn_cast <gcond *> (*gsi_last_bb (bb));
-      if (!cond_stmt)
-	continue;
-
-      e1 = EDGE_SUCC (bb, 0);
-      bb1 = e1->dest;
-      e2 = EDGE_SUCC (bb, 1);
-      bb2 = e2->dest;
-
-      /* We cannot do the optimization on abnormal edges.  */
-      if ((e1->flags & EDGE_ABNORMAL) != 0
-	  || (e2->flags & EDGE_ABNORMAL) != 0)
-	continue;
-
-      /* If either bb1's succ or bb2 or bb2's succ is non NULL.  */
-      if (EDGE_COUNT (bb1->succs) == 0
-	  || EDGE_COUNT (bb2->succs) == 0)
-	continue;
-
-      /* Find the bb which is the fall through to the other.  */
-      if (EDGE_SUCC (bb1, 0)->dest == bb2)
-	;
-      else if (EDGE_SUCC (bb2, 0)->dest == bb1)
-	{
-	  std::swap (bb1, bb2);
-	  std::swap (e1, e2);
-	}
-      else if (EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest
-	       && single_succ_p (bb2))
-	{
-	  diamond_p = true;
-	  e2 = EDGE_SUCC (bb2, 0);
-	  /* Make sure bb2 is just a fall through. */
-	  if ((e2->flags & EDGE_FALLTHRU) == 0)
-	    continue;
-	}
-      else
-	continue;
-
-      e1 = EDGE_SUCC (bb1, 0);
-
-      /* Make sure that bb1 is just a fall through.  */
-      if (!single_succ_p (bb1)
-	  || (e1->flags & EDGE_FALLTHRU) == 0)
-	continue;
-
       if (diamond_p)
 	{
 	  basic_block bb3 = e1->dest;
 
 	  if (!single_pred_p (bb1)
 	      || !single_pred_p (bb2))
-	    continue;
+	    return;
 
 	  if (do_hoist_loads
 	      && !FLOAT_TYPE_P (TREE_TYPE (gimple_cond_lhs (cond_stmt)))
@@ -4262,9 +4273,9 @@  pass_phiopt::execute (function *)
       if (!early_p && !diamond_p)
 	for (gsi = gsi_start (phis); !gsi_end_p (gsi); gsi_next (&gsi))
 	  {
-	    phi = as_a <gphi *> (gsi_stmt (gsi));
-	    arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
-	    arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
+	    gphi *phi = as_a <gphi *> (gsi_stmt (gsi));
+	    tree arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
+	    tree arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
 	    if (value_replacement (bb, bb1, e1, e2, phi, arg0, arg1) == 2)
 	      {
 		candorest = false;
@@ -4274,14 +4285,14 @@  pass_phiopt::execute (function *)
 	  }
 
       if (!candorest)
-	continue;
+	return;
 
-      phi = single_non_singleton_phi_for_edges (phis, e1, e2);
+      gphi *phi = single_non_singleton_phi_for_edges (phis, e1, e2);
       if (!phi)
-	continue;
+	return;
 
-      arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
-      arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
+      tree arg0 = gimple_phi_arg_def (phi, e1->dest_idx);
+      tree arg1 = gimple_phi_arg_def (phi, e2->dest_idx);
 
       /* Something is wrong if we cannot find the arguments in the PHI
 	  node.  */
@@ -4323,9 +4334,9 @@  pass_phiopt::execute (function *)
 	       && !diamond_p
 	       && spaceship_replacement (bb, bb1, e1, e2, phi, arg0, arg1))
 	cfgchanged = true;
-    }
+    };
 
-  free (bb_order);
+  execute_over_cond_phis (phiopt_exec);
 
   if (cfgchanged)
     return TODO_cleanup_cfg;
@@ -4412,9 +4423,6 @@  make_pass_cselim (gcc::context *ctxt)
 unsigned int
 pass_cselim::execute (function *)
 {
-  basic_block bb;
-  basic_block *bb_order;
-  unsigned n, i;
   bool cfgchanged = false;
   hash_set<tree> *nontrap = 0;
   unsigned todo = 0;
@@ -4430,71 +4438,10 @@  pass_cselim::execute (function *)
   /* Calculate the set of non-trapping memory accesses.  */
   nontrap = get_non_trapping ();
 
-  /* Search every basic block for COND_EXPR we may be able to optimize.
-
-     We walk the blocks in order that guarantees that a block with
-     a single predecessor is processed before the predecessor.
-     This ensures that we collapse inner ifs before visiting the
-     outer ones, and also that we do not try to visit a removed
-     block.  */
-  bb_order = single_pred_before_succ_order ();
-  n = n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS;
-
-  for (i = 0; i < n; i++)
+  auto cselim_exec = [&] (basic_block bb, basic_block bb1,
+			  basic_block bb2, edge e1, edge e2,
+			  bool diamond_p, gcond *)
     {
-      basic_block bb1, bb2;
-      edge e1, e2;
-      bool diamond_p = false;
-
-      bb = bb_order[i];
-
-      /* Check to see if the last statement is a GIMPLE_COND.  */
-      gcond *cond_stmt = safe_dyn_cast <gcond *> (*gsi_last_bb (bb));
-      if (!cond_stmt)
-	continue;
-
-      e1 = EDGE_SUCC (bb, 0);
-      bb1 = e1->dest;
-      e2 = EDGE_SUCC (bb, 1);
-      bb2 = e2->dest;
-
-      /* We cannot do the optimization on abnormal edges.  */
-      if ((e1->flags & EDGE_ABNORMAL) != 0
-	  || (e2->flags & EDGE_ABNORMAL) != 0)
-	continue;
-
-      /* If either bb1's succ or bb2 or bb2's succ is non NULL.  */
-      if (EDGE_COUNT (bb1->succs) == 0
-	  || EDGE_COUNT (bb2->succs) == 0)
-	continue;
-
-      /* Find the bb which is the fall through to the other.  */
-      if (EDGE_SUCC (bb1, 0)->dest == bb2)
-	;
-      else if (EDGE_SUCC (bb2, 0)->dest == bb1)
-	{
-	  std::swap (bb1, bb2);
-	  std::swap (e1, e2);
-	}
-      else if (EDGE_SUCC (bb1, 0)->dest == EDGE_SUCC (bb2, 0)->dest
-	       && single_succ_p (bb2))
-	{
-	  diamond_p = true;
-	  e2 = EDGE_SUCC (bb2, 0);
-	  /* Make sure bb2 is just a fall through. */
-	  if ((e2->flags & EDGE_FALLTHRU) == 0)
-	    continue;
-	}
-      else
-	continue;
-
-      e1 = EDGE_SUCC (bb1, 0);
-
-      /* Make sure that bb1 is just a fall through.  */
-      if (!single_succ_p (bb1)
-	  || (e1->flags & EDGE_FALLTHRU) == 0)
-	continue;
-
       if (diamond_p)
 	{
 	  basic_block bb3 = e1->dest;
@@ -4504,28 +4451,28 @@  pass_cselim::execute (function *)
 	     if always since we are sinking rather than
 	     hoisting. */
 	  if (EDGE_COUNT (bb3->preds) != 2)
-	    continue;
+	    return;
 	  if (cond_if_else_store_replacement (bb1, bb2, bb3))
 	    cfgchanged = true;
-	  continue;
+	  return;
 	}
 
       /* Also make sure that bb1 only have one predecessor and that it
 	 is bb.  */
       if (!single_pred_p (bb1)
 	  || single_pred (bb1) != bb)
-	continue;
+	return;
 
       /* bb1 is the middle block, bb2 the join block, bb the split block,
 	 e1 the fallthrough edge from bb1 to bb2.  We can't do the
 	 optimization if the join block has more than two predecessors.  */
       if (EDGE_COUNT (bb2->preds) > 2)
-	continue;
+	return;
       if (cond_store_replacement (bb1, bb2, e1, e2, nontrap))
 	cfgchanged = true;
-    }
+    };
 
-  free (bb_order);
+  execute_over_cond_phis (cselim_exec);
 
   delete nontrap;
   /* If the CFG has changed, we should cleanup the CFG.  */