Robin Dapp <rdapp....@gmail.com> writes:
> The attached v3 tracks the use of cond_earliest as you suggested
> and adds its cost in default_noce_conversion_profitable_p.
>
> Bootstrapped and regtested on x86 and p10, aarch64 still
> running.  Regtested on riscv64.
>
> Regards
>  Robin
>
> Before noce_find_if_block processes a block it sets up an if_info
> structure that holds the original costs.  At that point the costs of
> the then/else blocks have not been added so we only care about the
> "if" cost.
>
> The code originally used BRANCH_COST for that but was then changed
> to COST_N_INSNS (2) - a compare and a jump.
>
> This patch computes the jump costs via
>   insn_cost (if_info.jump, ...)
> under the assumption that the target takes BRANCH_COST into account
> when costing a jump instruction.
>
> In noce_convert_multiple_sets, we keep track of the need for the initial
> CC comparison.  If we needed it for the generated sequence we add its
> cost in default_noce_conversion_profitable_p.

I was looking at the code in more detail and just wanted to check.
We have:

  int last_needs_comparison = -1;

  bool ok = noce_convert_multiple_sets_1
    (if_info, &need_no_cmov, &rewired_src, &targets, &temporaries,
     &unmodified_insns, &last_needs_comparison);
  if (!ok)
      return false;

  /* If there are insns that overwrite part of the initial
     comparison, we can still omit creating temporaries for
     the last of them.
     As the second try will always create a less expensive,
     valid sequence, we do not need to compare and can discard
     the first one.  */
  if (last_needs_comparison != -1)
    {
      end_sequence ();
      start_sequence ();
      ok = noce_convert_multiple_sets_1
        (if_info, &need_no_cmov, &rewired_src, &targets, &temporaries,
         &unmodified_insns, &last_needs_comparison);
      /* Actually we should not fail anymore if we reached here,
         but better still check.  */
      if (!ok)
          return false;
    }

But noce_convert_multiple_sets_1 ends with:

  /* Even if we did not actually need the comparison, we want to make sure
     to try a second time in order to get rid of the temporaries.  */
  if (*last_needs_comparison == -1)
    *last_needs_comparison = 0;


  return true;

AFAICT that means that the first attempt is always redundant.

Have I missed something?

I don't know if this was something that Manolis's patches addressed.

Thanks,
Richard

>
> gcc/ChangeLog:
>
>       * ifcvt.cc (default_noce_conversion_profitable_p):  Add cost of
>       CC comparison.
>       (noce_convert_multiple_sets_1): Set use_cond_earliest.
>       (noce_process_if_block): Just use original cost.
>       (noce_find_if_block): Use insn_cost (jump_insn).
>       * ifcvt.h (struct noce_if_info): Add use_cond_earliest.
> ---
>  gcc/ifcvt.cc | 37 ++++++++++++++++++++++---------------
>  gcc/ifcvt.h  |  3 +++
>  2 files changed, 25 insertions(+), 15 deletions(-)
>
> diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc
> index 58ed42673e5..9b408eeb313 100644
> --- a/gcc/ifcvt.cc
> +++ b/gcc/ifcvt.cc
> @@ -814,7 +814,16 @@ default_noce_conversion_profitable_p (rtx_insn *seq,
>    /* Cost up the new sequence.  */
>    unsigned int cost = seq_cost (seq, speed_p);
>  
> -  if (cost <= if_info->original_cost)
> +  /* If the created sequence does not use cond_earliest (but the jump
> +     does) add its cost to the original_cost here.  */
> +  unsigned int cost_adjust = 0;
> +
> +  if (if_info->jump != if_info->cond_earliest
> +      && !if_info->use_cond_earliest)
> +    cost_adjust = insn_cost (if_info->cond_earliest,
> +                          if_info->speed_p);
> +
> +  if (cost <= if_info->original_cost + cost_adjust)
>      return true;
>  
>    /* When compiling for size, we can make a reasonably accurately guess
> @@ -3780,6 +3789,7 @@ noce_convert_multiple_sets_1 (struct noce_if_info 
> *if_info,
>         temp_dest = temp_dest2;
>         if (!second_try && read_comparison)
>           *last_needs_comparison = count;
> +       if_info->use_cond_earliest = true;
>       }
>        else
>       {
> @@ -3931,16 +3941,13 @@ noce_process_if_block (struct noce_if_info *if_info)
>       to calculate a value for x.
>       ??? For future expansion, further expand the "multiple X" rules.  */
>  
> -  /* First look for multiple SETS.  The original costs already include
> -     a base cost of COSTS_N_INSNS (2): one instruction for the compare
> -     (which we will be needing either way) and one instruction for the
> -     branch.  When comparing costs we want to use the branch instruction
> -     cost and the sets vs. the cmovs generated here.  Therefore subtract
> -     the costs of the compare before checking.
> -     ??? Actually, instead of the branch instruction costs we might want
> -     to use COSTS_N_INSNS (BRANCH_COST ()) as in other places.  */
> +  /* First look for multiple SETS.
> +     The original costs already include costs for the jump insn as well
> +     as for a CC comparison if there is any.
> +     If a target re-uses the existing CC comparison we keep track of that
> +     and add the costs in default default_noce_conversion_profitable_p.  */
>  
> -  unsigned potential_cost = if_info->original_cost - COSTS_N_INSNS (1);
> +  unsigned potential_cost = if_info->original_cost;
>    unsigned old_cost = if_info->original_cost;
>    if (!else_bb
>        && HAVE_conditional_move
> @@ -4696,6 +4703,7 @@ noce_find_if_block (basic_block test_bb, edge 
> then_edge, edge else_edge,
>    gcc_assert (if_info.rev_cond == NULL_RTX
>             || rev_cond_earliest == cond_earliest);
>    if_info.cond_earliest = cond_earliest;
> +  if_info.use_cond_earliest = false;
>    if_info.jump = jump;
>    if_info.then_else_reversed = then_else_reversed;
>    if_info.speed_p = speed_p;
> @@ -4703,11 +4711,10 @@ noce_find_if_block (basic_block test_bb, edge 
> then_edge, edge else_edge,
>      = targetm.max_noce_ifcvt_seq_cost (then_edge);
>    /* We'll add in the cost of THEN_BB and ELSE_BB later, when we check
>       that they are valid to transform.  We can't easily get back to the insn
> -     for COND (and it may not exist if we had to canonicalize to get COND),
> -     and jump_insns are always given a cost of 1 by seq_cost, so treat
> -     both instructions as having cost COSTS_N_INSNS (1).  */
> -  if_info.original_cost = COSTS_N_INSNS (2);
> -
> +     for COND (and it may not exist if we had to canonicalize to get COND).
> +     It is assumed that the costs of a jump insn are dependent on the
> +     branch costs.  */
> +  if_info.original_cost += insn_cost (if_info.jump, if_info.speed_p);
>  
>    /* Do the real work.  */
>  
> diff --git a/gcc/ifcvt.h b/gcc/ifcvt.h
> index 37147f99129..67d4f6a502e 100644
> --- a/gcc/ifcvt.h
> +++ b/gcc/ifcvt.h
> @@ -63,6 +63,9 @@ struct noce_if_info
>    /* New insns should be inserted before this one.  */
>    rtx_insn *cond_earliest;
>  
> +  /* Whether or not COND_EARLIEST is used in the resulting sequence.  */
> +  bool use_cond_earliest;
> +
>    /* Insns in the THEN and ELSE block.  There is always just this
>       one insns in those blocks.  The insns are single_set insns.
>       If there was no ELSE block, INSN_B is the last insn before

Reply via email to