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
>

Reply via email to