Hi Torbjorn,

> On 14 Sep 2026, at 08:47, Torbjorn SVENSSON <[email protected]> 
> wrote:
> 
> Hi,
> 
> This patch appears to introduce a regression for Cortex-M3/4/33. Other 
> Cortex-M targets that I test are either fine or unsupported.
> 
> Testing arm/short-it-ifcvt-2.c
> doing compile
> Executing on host: /build/r17-3970-g301afaab5b8eaf/bin/arm-none-eabi-gcc  
> /build/gcc_src/gcc/testsuite/gcc.target/arm/short-it-ifcvt-2.c  -mthumb 
> -march=armv7-m -mcpu=cortex-m3 -mfloat-abi=soft -mfpu=auto   
> -fdiagnostics-plain-output  -O2 -mthumb -mrestrict-it -ffat-lto-objects 
> -fno-ident -S     -o short-it-ifcvt-2.s    (timeout = 800)
> spawn -ignore SIGHUP /build/r17-3970-g301afaab5b8eaf/bin/arm-none-eabi-gcc 
> /build/gcc_src/gcc/testsuite/gcc.target/arm/short-it-ifcvt-2.c -mthumb 
> -march=armv7-m -mcpu=cortex-m3 -mfloat-abi=soft -mfpu=auto 
> -fdiagnostics-plain-output -O2 -mthumb -mrestrict-it -ffat-lto-objects 
> -fno-ident -S -o short-it-ifcvt-2.s
> pid is 3087 -3087
> pid is -1
> output is  status 0
> PASS: gcc.target/arm/short-it-ifcvt-2.c (test for excess errors)
> FAIL: gcc.target/arm/short-it-ifcvt-2.c scan-assembler b(gt|le)
> 
> Produced assembler with r17-3970-g301afaab5b8eaf:
>        .cpu cortex-m3
>        .arch armv7-m
>        .fpu softvfp
>        .eabi_attribute 20, 1
>        .eabi_attribute 21, 1
>        .eabi_attribute 23, 3
>        .eabi_attribute 24, 1
>        .eabi_attribute 25, 1
>        .eabi_attribute 26, 1
>        .eabi_attribute 30, 2
>        .eabi_attribute 34, 1
>        .eabi_attribute 18, 4
>        .file   "short-it-ifcvt-2.c"
>        .text
>        .align  1
>        .p2align 2,,3
>        .global f1
>        .syntax unified
>        .thumb
>        .thumb_func
>        .type   f1, %function
> f1:
>        @ args = 0, pretend = 0, frame = 0
>        @ frame_needed = 0, uses_anonymous_args = 0
>        @ link register save eliminated.
>        cmp     r0, #101
>        add     r3, r0, #1
>        itte    lt
>        rsblt   r1, r1, #0
>        rsblt   r3, r0, #0
>        rsbge   r2, r2, #0
>        add     r3, r3, r1
>        adds    r0, r3, r2
>        bx      lr
>        .size   f1, .-f1
> 
> Produced assembler with r17-3969-g17b02d8f2b385c:
>        .cpu cortex-m3
>        .arch armv7-m
>        .fpu softvfp
>        .eabi_attribute 20, 1
>        .eabi_attribute 21, 1
>        .eabi_attribute 23, 3
>        .eabi_attribute 24, 1
>        .eabi_attribute 25, 1
>        .eabi_attribute 26, 1
>        .eabi_attribute 30, 2
>        .eabi_attribute 34, 1
>        .eabi_attribute 18, 4
>        .file   "short-it-ifcvt-2.c"
>        .text
>        .align  1
>        .p2align 2,,3
>        .global f1
>        .syntax unified
>        .thumb
>        .thumb_func
>        .type   f1, %function
> f1:
>        @ args = 0, pretend = 0, frame = 0
>        @ frame_needed = 0, uses_anonymous_args = 0
>        @ link register save eliminated.
>        cmp     r0, #100
>        iteet   gt
>        addgt   r0, r0, #1
>        rsble   r0, r0, #0
>        rsble   r1, r1, #0
>        rsbgt   r2, r2, #0
>        add     r0, r0, r1
>        add     r0, r0, r2
>        bx      lr
>        .size   f1, .-f1
> 
> I do not know what the correct action here is since the expression,
> 
> /* { dg-final { scan-assembler "b(gt|le)" } } */
> 
> passes for some targets, like Cortex-M85, but fails for others.
> 
> Let me know if you want me to test something.
> 

It’s a testism. I’ll fix it with this attached patch.
Thanks,
Kyrill

> Kind regards,
> Torbjörn
> 
> On 2026-09-01 07:38, [email protected] wrote:
>> From: Kyrylo Tkachov <[email protected]>
>> The diamond conversion currently requires one arm's live-out destinations
>> to contain the other's.  This rejects diamonds in which the arms update
>> different values, although a destination can keep its incoming value on the
>> path that does not assign it.
>> For example, convert
>>   then:                    else:
>>     x = a;                   z = c;
>>     y = b;                   w = d;
>> to
>>   z_tmp = c;
>>   w_tmp = d;
>>   x = cond ? a : x;
>>   y = cond ? b : y;
>>   z = cond ? z : z_tmp;
>>   w = cond ? w : w_tmp;
>> Build the metadata for both arms once.  Append an output entry for the last
>> else definition of each live-out destination that the then arm does not
>> define.  The existing conditional-move loop then selects between the else
>> temporary and the incoming value for these entries.  It continues to select
>> between the then and else values for shared entries.
>> Form the union of the live-out destinations and permit arm-only destinations
>> and one-set arms.  Do not restrict partially overlapping sets based on the
>> source of a shared destination.  Keep the CFG arm order and evaluate the else
>> arm into temporaries.  Include the complete live-out union and the appended
>> output entries in the conversion limit.
>> Add execution and code-generation tests for disjoint and partially
>> overlapping outputs, one-set arms, cross-arm incoming values, repeated
>> definitions, condition inputs, unequal output counts, condition-code
>> clobbers, and the final output limit.
>> Bootstrapped and tested on aarch64-none-linux-gnu.
>> Ok fro trunk?
>> Thanks,
>> Kyrill
>> gcc/ChangeLog:
>> PR tree-optimization/125557
>> * ifcvt.cc (noce_convert_multiple_sets): Build metadata for both arms.
>> Append entries for else-only live-out destinations, enforce the final
>> output limit, and preserve the then-arm source location.
>> (noce_convert_multiple_sets_1): Consume the unified output metadata.
>> Select incoming values for destinations defined by only one arm.
>> (init_noce_multiple_sets_info): Initialize stable metadata fields.
>> (bb_ok_for_noce_convert_multiple_sets): Remove final-source
>> classification.
>> (noce_process_if_block): Form the union of the arm live-outs, accept
>> arm-only destinations and one-set arms without a shared-source gate, and
>> keep the CFG arm order.
>> gcc/testsuite/ChangeLog:
>> PR tree-optimization/125557
>> * gcc.target/aarch64/ifcvt_multiple_sets_diamond_4.c: Test disjoint,
>> partially overlapping, and one-set outputs.
>> * gcc.target/aarch64/ifcvt_multiple_sets_diamond_5.c: Update expected
>> code generation for the fixed arm order.
>> * gcc.target/aarch64/ifcvt_multiple_sets_diamond_6.c: New test.
>> * gcc.target/aarch64/ifcvt_multiple_sets_diamond_7.c: New test.
>> * gcc.target/i386/ifcvt-multiple-sets-diamond-1.c: Test disjoint outputs
>> with a condition-code clobber.
>> Co-authored-by: Cui Lili <[email protected]>
>> Signed-off-by: Kyrylo Tkachov <[email protected]>
>> ---
>>  gcc/ifcvt.cc                                  | 237 +++++++++---------
>>  .../aarch64/ifcvt_multiple_sets_diamond_4.c   |  83 +++---
>>  .../aarch64/ifcvt_multiple_sets_diamond_5.c   |   3 +-
>>  .../aarch64/ifcvt_multiple_sets_diamond_6.c   | 100 ++++++++
>>  .../aarch64/ifcvt_multiple_sets_diamond_7.c   |  26 ++
>>  .../i386/ifcvt-multiple-sets-diamond-1.c      |  25 +-
>>  6 files changed, 315 insertions(+), 159 deletions(-)
>>  create mode 100644 
>> gcc/testsuite/gcc.target/aarch64/ifcvt_multiple_sets_diamond_6.c
>>  create mode 100644 
>> gcc/testsuite/gcc.target/aarch64/ifcvt_multiple_sets_diamond_7.c
>> diff --git a/gcc/ifcvt.cc b/gcc/ifcvt.cc
>> index b976ac9acc3..049e2560298 100644
>> --- a/gcc/ifcvt.cc
>> +++ b/gcc/ifcvt.cc
>> @@ -102,7 +102,9 @@ static rtx_insn *block_has_only_trap (basic_block);
>>  static void init_noce_multiple_sets_info (basic_block,
>>    auto_delete_vec<noce_multiple_sets_info> &);
>>  static bool noce_convert_multiple_sets_1 (struct noce_if_info *,
>> -  auto_delete_vec<noce_multiple_sets_info> &, int *, bool *);
>> +  auto_delete_vec<noce_multiple_sets_info> &,
>> +  auto_delete_vec<noce_multiple_sets_info> &, unsigned,
>> +  const vec<unsigned> &, int *, bool *);
>>  
>>  /* Count the number of non-jump active insns in BB.  */
>>  @@ -3970,7 +3972,7 @@ try_emit_cmove_seq (struct noce_if_info *if_info, rtx 
>> temp,
>>     conditional set to use the temporary we introduced earlier.
>>       IF_INFO contains the useful information about the block structure and
>> -   jump instructions.  For an IF-THEN-ELSE-JOIN, first evaluate the 
>> secondary
>> +   jump instructions.  For an IF-THEN-ELSE-JOIN, first evaluate the else
>>     arm's sets into temporaries and retain their final values for the
>>     conditional moves.  Return true if the replacement is valid and 
>> profitable
>>     and its CFG changes have been committed, otherwise return false.  */
>> @@ -3995,13 +3997,59 @@ noce_convert_multiple_sets (struct noce_if_info 
>> *if_info)
>>      auto_delete_vec<noce_multiple_sets_info> insn_info;
>>    init_noce_multiple_sets_info (then_bb, insn_info);
>> +  gcc_assert (!insn_info.is_empty ());
>> +  unsigned then_count = insn_info.length ();
>> +  location_t sequence_location
>> +    = INSN_LOCATION (insn_info.last ()->unmodified_insn);
>> +
>> +  auto_delete_vec<noce_multiple_sets_info> else_insn_info;
>> +  auto_vec<unsigned> else_only_indices;
>> +  if (else_bb)
>> +    {
>> +      init_noce_multiple_sets_info (else_bb, else_insn_info);
>> +
>> +      /* Add one output entry for each live-out destination that is set only
>> + by the else arm.  Record the last definition, which holds the
>> + value that reaches the join.  */
>> +      auto_bitmap then_dests, seen;
>> +      for (unsigned i = 0; i < then_count; ++i)
>> + bitmap_set_bit (then_dests, REGNO (insn_info[i]->target));
>> +
>> +      for (int i = else_insn_info.length () - 1; i >= 0; --i)
>> + if (else_insn_info[i]->need_cmov
>> +    && !bitmap_bit_p (then_dests,
>> +      REGNO (else_insn_info[i]->target))
>> +    && bitmap_set_bit (seen, REGNO (else_insn_info[i]->target)))
>> +  else_only_indices.safe_push (i);
>> +      else_only_indices.reverse ();
>> +
>> +      unsigned i, else_index;
>> +      FOR_EACH_VEC_ELT (else_only_indices, i, else_index)
>> + {
>> +  noce_multiple_sets_info *info = new noce_multiple_sets_info;
>> +  noce_multiple_sets_info *else_info = else_insn_info[else_index];
>> +  info->target = else_info->target;
>> +  info->temporary = NULL_RTX;
>> +  info->unmodified_insn = else_info->unmodified_insn;
>> +  info->need_cmov = true;
>> +  insn_info.safe_push (info);
>> + }
>> +    }
>> +
>> +  /* Include else-only outputs when enforcing the conversion limit.  */
>> +  if (insn_info.length () > (unsigned) param_max_rtl_if_conversion_insns)
>> +    {
>> +      end_sequence ();
>> +      return false;
>> +    }
>>      int last_needs_comparison = -1;
>>      bool use_cond_earliest = false;
>>      bool ok = noce_convert_multiple_sets_1
>> -    (if_info, insn_info, &last_needs_comparison, &use_cond_earliest);
>> +    (if_info, insn_info, else_insn_info, then_count, else_only_indices,
>> +     &last_needs_comparison, &use_cond_earliest);
>>    if (!ok)
>>        return false;
>>  @@ -4013,17 +4061,14 @@ noce_convert_multiple_sets (struct noce_if_info 
>> *if_info)
>>    end_sequence ();
>>    start_sequence ();
>>    ok = noce_convert_multiple_sets_1
>> -    (if_info, insn_info, &last_needs_comparison, &use_cond_earliest);
>> +    (if_info, insn_info, else_insn_info, then_count, else_only_indices,
>> +     &last_needs_comparison, &use_cond_earliest);
>>      /* Actually we should not fail anymore if we reached here,
>>       but better still check.  */
>>    if (!ok)
>>      return false;
>>  -  /* We must have seen some sort of insn to insert, otherwise we were
>> -     given an empty BB to convert, and we can't handle that.  */
>> -  gcc_assert (!insn_info.is_empty ());
>> -
>>    /* Now fixup the assignments.
>>       PR116405: Iterate in reverse order and keep track of the targets so 
>> that
>>       a move does not overwrite a subsequent value when multiple instructions
>> @@ -4092,8 +4137,7 @@ noce_convert_multiple_sets (struct noce_if_info 
>> *if_info)
>>    if (noce_clobbers_live_cc_p (test_bb, seq))
>>      return false;
>>  -  emit_insn_before_setloc (seq, if_info->jump,
>> -   INSN_LOCATION (insn_info.last ()->unmodified_insn));
>> +  emit_insn_before_setloc (seq, if_info->jump, sequence_location);
>>      /* Clean up the THEN (and, for a diamond, ELSE) block and the edges 
>> into and
>>       out of the if-region.  An IF-THEN-ELSE-JOIN has no test->join edge.
>> @@ -4123,8 +4167,10 @@ noce_convert_multiple_sets (struct noce_if_info 
>> *if_info)
>>  }
>>    /* Try to emit the multiple-set conversion described by IF_INFO.  
>> INSN_INFO
>> -   holds the primary-arm metadata.  For a diamond, evaluate the secondary 
>> arm
>> -   first and retain its final values for the conditional moves.
>> +   holds THEN_COUNT then-arm entries followed by entries for the else-only
>> +   definitions recorded in ELSE_ONLY_INDICES.  For a diamond,
>> +   evaluate ELSE_INSN_INFO first and retain its final values for the
>> +   conditional moves.
>>       LAST_NEEDS_COMPARISON is -1 on the first attempt.  Record in it the 
>> last set
>>     that needs a temporary to preserve the comparison, then use that boundary
>> @@ -4135,10 +4181,13 @@ noce_convert_multiple_sets (struct noce_if_info 
>> *if_info)
>>  static bool
>>  noce_convert_multiple_sets_1 (struct noce_if_info *if_info,
>>        auto_delete_vec<noce_multiple_sets_info> &insn_info,
>> +      auto_delete_vec<noce_multiple_sets_info>
>> + &else_insn_info,
>> +      unsigned then_count,
>> +      const vec<unsigned> &else_only_indices,
>>        int *last_needs_comparison,
>>        bool *use_cond_earliest)
>>  {
>> -  basic_block then_bb = if_info->then_bb;
>>    rtx_insn *jump = if_info->jump;
>>    rtx_insn *cond_earliest;
>>  @@ -4152,19 +4201,16 @@ noce_convert_multiple_sets_1 (struct noce_if_info 
>> *if_info,
>>    if (rev_cc_cmp)
>>      rev_cc_cmp = copy_rtx (rev_cc_cmp);
>>  -  rtx_insn *insn;
>>    int count = 0;
>>    bool second_try = *last_needs_comparison != -1;
>>    *use_cond_earliest = false;
>> -  auto_delete_vec<noce_multiple_sets_info> else_insn_info;
>>      /* For an IF-THEN-ELSE-JOIN, emit the else block's computations first 
>> into
>>       fresh temporaries.  This leaves the incoming register values available 
>> to
>> -     the then block.  The conditional moves below select the then values or
>> -     these else values.  */
>> +     the then arm.  The conditional moves below select the then or else
>> +     values.  */
>>    if (if_info->else_bb)
>>      {
>> -      init_noce_multiple_sets_info (if_info->else_bb, else_insn_info);
>>        int else_count = 0;
>>        rtx_insn *before_else = get_last_insn ();
>>        location_t saved_location = curr_insn_location ();
>> @@ -4190,9 +4236,7 @@ noce_convert_multiple_sets_1 (struct noce_if_info 
>> *if_info,
>>    set_curr_insn_location (INSN_LOCATION (else_insn));
>>    rtx temporary = copy_to_mode_reg (GET_MODE (target), value);
>>  -  info->target = target;
>>    info->temporary = temporary;
>> -  info->unmodified_insn = else_insn;
>>    else_count++;
>>   }
>>  @@ -4224,39 +4268,50 @@ noce_convert_multiple_sets_1 (struct noce_if_info 
>> *if_info,
>>   }
>>      }
>>  -  FOR_BB_INSNS (then_bb, insn)
>> +  for (count = 0; count < (int) insn_info.length (); ++count)
>>      {
>> -      /* Skip over non-insns.  */
>> -      if (!active_insn_p (insn))
>> - continue;
>> -
>>        noce_multiple_sets_info *info = insn_info[count];
>> -
>> +      rtx_insn *insn = info->unmodified_insn;
>>        rtx set = single_set (insn);
>>        gcc_checking_assert (set);
>>  -      rtx target = SET_DEST (set);
>> +      rtx target = info->target;
>>        rtx temp;
>> +      rtx new_val;
>> +      rtx old_val;
>>  -      rtx new_val = SET_SRC (set);
>> +      if ((unsigned) count < then_count)
>> + {
>> +  new_val = SET_SRC (set);
>>  -      int i, ii;
>> -      FOR_EACH_VEC_ELT (info->rewired_src, i, ii)
>> - new_val = simplify_replace_rtx (new_val, insn_info[ii]->target,
>> - insn_info[ii]->temporary);
>> +  int i, ii;
>> +  FOR_EACH_VEC_ELT (info->rewired_src, i, ii)
>> +    new_val = simplify_replace_rtx (new_val, insn_info[ii]->target,
>> +    insn_info[ii]->temporary);
>>  -      rtx old_val = target;
>> +  old_val = target;
>>  -      /* Use the final value assigned to TARGET on the else arm.  Scanning 
>> in
>> - reverse is important when the arm assigns the same register more than
>> - once.  */
>> -      if (if_info->else_bb)
>> - for (int j = else_insn_info.length () - 1; j >= 0; --j)
>> -  if (rtx_equal_p (target, else_insn_info[j]->target))
>> -    {
>> -      old_val = else_insn_info[j]->temporary;
>> -      break;
>> -    }
>> +  /* Use the final value assigned to TARGET on the else arm.
>> +     Scanning in reverse is important when the arm assigns the same
>> +     register more than once.  */
>> +  if (if_info->else_bb)
>> +    for (int j = else_insn_info.length () - 1; j >= 0; --j)
>> +      if (rtx_equal_p (target, else_insn_info[j]->target))
>> + {
>> +  old_val = else_insn_info[j]->temporary;
>> +  break;
>> + }
>> + }
>> +      else
>> + {
>> +  unsigned else_index
>> +    = else_only_indices[(unsigned) count - then_count];
>> +  noce_multiple_sets_info *else_info = else_insn_info[else_index];
>> +  gcc_checking_assert (rtx_equal_p (target, else_info->target));
>> +
>> +  new_val = target;
>> +  old_val = else_info->temporary;
>> + }
>>          /* As we are transforming
>>   if (x > y)
>> @@ -4451,11 +4506,7 @@ noce_convert_multiple_sets_1 (struct noce_if_info 
>> *if_info,
>>        emit_insn (seq);
>>          /* Bookkeeping.  */
>> -      count++;
>> -
>> -      info->target = target;
>>        info->temporary = temp_dest;
>> -      info->unmodified_insn = insn;
>>      }
>>      /* Even if we did not actually need the comparison, we want to make sure
>> @@ -4515,9 +4566,7 @@ init_noce_multiple_sets_info (basic_block bb,
>>   continue;
>>          noce_multiple_sets_info *info = new noce_multiple_sets_info;
>> -      info->target = NULL_RTX;
>>        info->temporary = NULL_RTX;
>> -      info->unmodified_insn = NULL;
>>        insn_info.safe_push (info);
>>          rtx set = single_set (insn);
>> @@ -4527,6 +4576,8 @@ init_noce_multiple_sets_info (basic_block bb,
>>        rtx dest = SET_DEST (set);
>>          gcc_checking_assert (REG_P (dest) && !HARD_REGISTER_P (dest));
>> +      info->target = dest;
>> +      info->unmodified_insn = insn;
>>        info->need_cmov = bitmap_bit_p (bb_live_out, REGNO (dest));
>>          /* Check if the current SET's source mentions any previously seen
>> @@ -4547,24 +4598,20 @@ init_noce_multiple_sets_info (basic_block bb,
>>  /* Return true iff basic block TEST_BB is suitable for conversion to a
>>     series of conditional moves.  Unless REQUIRE_MULTIPLE is false, also 
>> check
>>     that we have more than one set (other routines can handle a single set
>> -   better than we would).  A diamond arm may have a single set when it is
>> -   selected as the secondary arm.  Require no more than
>> -   PARAM_MAX_RTL_IF_CONVERSION_INSNS sets.  While going through the insns 
>> store
>> -   the sum of their potential costs in COST.  On success, if LIVE_OUT_DESTS 
>> is
>> -   nonnull, record the distinct pseudo destinations that are live out of
>> +   better than we would).  A diamond arm may have a single set.
>> +   Require no more than PARAM_MAX_RTL_IF_CONVERSION_INSNS sets.  While going
>> +   through the insns, store the sum of their potential costs in COST.  On
>> +   success, if LIVE_OUT_DESTS is nonnull, record the distinct pseudo
>> +   destinations that are live out of
>>     TEST_BB.  If HAS_NON_SIMPLE_SRC is nonnull, set it when an instruction
>>     source is neither a constant nor a register operand.  On success, if
>> -   NONREG_LIVE_OUT_DESTS is nonnull, record live-out destinations whose last
>> -   RTL definition has a non-register source.  Constants are non-register
>> -   sources.  On success, if INSN_COUNT is nonnull, store the number of 
>> active
>> -   sets in it.  */
>> +   INSN_COUNT is nonnull, store the number of active sets in it.  */
>>    static bool
>>  bb_ok_for_noce_convert_multiple_sets (basic_block test_bb, unsigned *cost,
>>        bool require_multiple = true,
>>        bitmap live_out_dests = NULL,
>>        bool *has_non_simple_src = NULL,
>> -      bitmap nonreg_live_out_dests = NULL,
>>        unsigned *insn_count = NULL)
>>  {
>>    rtx_insn *insn;
>> @@ -4576,10 +4623,8 @@ bb_ok_for_noce_convert_multiple_sets (basic_block 
>> test_bb, unsigned *cost,
>>      bitmap_clear (live_out_dests);
>>    if (has_non_simple_src)
>>      *has_non_simple_src = false;
>> -  if (nonreg_live_out_dests)
>> -    bitmap_clear (nonreg_live_out_dests);
>>    bitmap bb_live_out = NULL;
>> -  if (live_out_dests || nonreg_live_out_dests)
>> +  if (live_out_dests)
>>      bb_live_out = df_get_live_out (test_bb);
>>      FOR_BB_INSNS (test_bb, insn)
>> @@ -4619,17 +4664,7 @@ bb_ok_for_noce_convert_multiple_sets (basic_block 
>> test_bb, unsigned *cost,
>>   return false;
>>          if (bb_live_out && bitmap_bit_p (bb_live_out, REGNO (dest)))
>> - {
>> -  if (live_out_dests)
>> -    bitmap_set_bit (live_out_dests, REGNO (dest));
>> -  if (nonreg_live_out_dests)
>> -    {
>> -      if (register_operand (src, VOIDmode))
>> - bitmap_clear_bit (nonreg_live_out_dests, REGNO (dest));
>> -      else
>> - bitmap_set_bit (nonreg_live_out_dests, REGNO (dest));
>> -    }
>> - }
>> + bitmap_set_bit (live_out_dests, REGNO (dest));
>>          potential_cost += insn_cost (insn, speed_p);
>>  @@ -4641,7 +4676,7 @@ bb_ok_for_noce_convert_multiple_sets (basic_block 
>> test_bb, unsigned *cost,
>>    /* If we would only put out one conditional move, the other strategies
>>       this pass tries are better optimized and will be more appropriate, so
>>       require more than one set unless REQUIRE_MULTIPLE is false.  A diamond
>> -     arm may have one set when it is selected as the secondary arm.
>> +     arm may have one set.
>>       Some targets want to strictly limit the number of conditional moves
>>       that are emitted, they set this through PARAM, we need to respect
>>       that.  */
>> @@ -4697,9 +4732,8 @@ noce_process_if_block (struct noce_if_info *if_info)
>>       The later patterns require jumps to be more expensive.
>>       For the diamond case, defer diamonds with only register and constant
>>       assignments in both arms to the existing simple conditional-move
>> -     handling.  Use an arm that sets at least two distinct live-out pseudos 
>> as
>> -     the primary arm.  Every live-out destination set by the secondary arm
>> -     must also be set by the primary arm.
>> +     handling.  Require at least two distinct live-out pseudos across the
>> +     arms.
>>       ??? For future expansion, further expand the "multiple X" rules.  */
>>      /* First look for multiple SETS.
>> @@ -4713,8 +4747,6 @@ noce_process_if_block (struct noce_if_info *if_info)
>>    unsigned ms_then_insn_count = 0, ms_else_insn_count = 0;
>>    bool ms_then_has_non_simple_src, ms_else_has_non_simple_src;
>>    auto_bitmap ms_then_live_out_dests, ms_else_live_out_dests;
>> -  auto_bitmap ms_then_nonreg_live_out_dests;
>> -  auto_bitmap ms_else_nonreg_live_out_dests;
>>    noce_if_info ms_if_info = *if_info;
>>    bool multiple_sets_p = false;
>>  @@ -4727,48 +4759,25 @@ noce_process_if_block (struct noce_if_info *if_info)
>>         && bb_ok_for_noce_convert_multiple_sets
>>      (then_bb, &ms_then_cost, false,
>>       ms_then_live_out_dests, &ms_then_has_non_simple_src,
>> -     ms_then_nonreg_live_out_dests, &ms_then_insn_count)
>> +     &ms_then_insn_count)
>>         && bb_ok_for_noce_convert_multiple_sets
>>      (else_bb, &ms_else_cost, false,
>>       ms_else_live_out_dests, &ms_else_has_non_simple_src,
>> -     ms_else_nonreg_live_out_dests, &ms_else_insn_count))
>> +     &ms_else_insn_count))
>>   {
>> -  /* Keep this path for diamonds that share a live-out whose last RTL
>> -     definition has a non-register source in at least one arm.  This
>> -     includes a value computed in one arm and forwarded by the
>> -     other.  */
>> -  bool has_shared_nonreg_live_out
>> -    = (bitmap_intersect_p (ms_then_nonreg_live_out_dests,
>> -   ms_else_live_out_dests)
>> -       || bitmap_intersect_p (ms_else_nonreg_live_out_dests,
>> -      ms_then_live_out_dests));
>> -
>> -  if ((ms_then_has_non_simple_src || ms_else_has_non_simple_src)
>> -      && has_shared_nonreg_live_out)
>> -    {
>> -      if (bitmap_count_bits (ms_then_live_out_dests) >= 2
>> -  && !bitmap_intersect_compl_p (ms_else_live_out_dests,
>> - ms_then_live_out_dests))
>> - multiple_sets_p = true;
>> -      else if (bitmap_count_bits (ms_else_live_out_dests) >= 2
>> -       && !bitmap_intersect_compl_p (ms_then_live_out_dests,
>> - ms_else_live_out_dests))
>> - {
>> -  /* The branch-target arm is the compatible multi-set
>> -     superset.  Make it the primary arm and reverse the select
>> -     orientation.  */
>> -  std::swap (ms_if_info.then_bb, ms_if_info.else_bb);
>> -  ms_if_info.then_else_reversed
>> -    = !ms_if_info.then_else_reversed;
>> -  std::swap (ms_then_cost, ms_else_cost);
>> -  std::swap (ms_then_insn_count, ms_else_insn_count);
>> -  multiple_sets_p = true;
>> - }
>> -    }
>> +  auto_bitmap ms_live_out_dests;
>> +  bitmap_ior (ms_live_out_dests, ms_then_live_out_dests,
>> +      ms_else_live_out_dests);
>> +  unsigned output_count = bitmap_count_bits (ms_live_out_dests);
>> +
>> +  if (output_count >= 2
>> +      && output_count <= (unsigned) param_max_rtl_if_conversion_insns
>> +      && (ms_then_has_non_simple_src || ms_else_has_non_simple_src))
>> +    multiple_sets_p = true;
>>   }
>>      }
>>  -  /* The diamond conversion evaluates the secondary arm unconditionally.
>> +  /* The diamond conversion evaluates the else arm unconditionally.
>>       Honor the target limit on the number of instructions made
>>       unconditional.  */
>>    if (multiple_sets_p
>> diff --git 
>> a/gcc/testsuite/gcc.target/aarch64/ifcvt_multiple_sets_diamond_4.c 
>> b/gcc/testsuite/gcc.target/aarch64/ifcvt_multiple_sets_diamond_4.c
>> index 428d7f51cc5..a6c8e400aee 100644
>> --- a/gcc/testsuite/gcc.target/aarch64/ifcvt_multiple_sets_diamond_4.c
>> +++ b/gcc/testsuite/gcc.target/aarch64/ifcvt_multiple_sets_diamond_4.c
>> @@ -1,41 +1,58 @@
>>  /* { dg-do run } */
>> -/* { dg-options "-O2 --param=max-rtl-if-conversion-unpredictable-cost=100 
>> -fdump-rtl-ce1" } */
>> +/* { dg-options "-O2 -fno-ssa-phiopt -fno-tree-ter -fno-tree-coalesce-vars 
>> -fdump-rtl-ce1" } */
>> +/* { dg-additional-options 
>> "--param=max-rtl-if-conversion-unpredictable-cost=100 
>> --param=max-rtl-if-conversion-predictable-cost=100" } */
>>  -volatile long ga, gt, ge;
>> +volatile long ga, gt, ge, gw;
>>    __attribute__ ((noipa)) void
>> -convertible (long c, long p, long q)
>> +disjoint_arm_values (long a, long b, long c, long d, long s,
>> +     long x, long y, long z, long w)
>>  {
>> -  long a, t;
>> -  if (c > 7)
>> +  if (s > 0)
>>      {
>> -      a = p + 1;
>> -      t = q + 2;
>> +      x = a;
>> +      y = b - 2;
>>      }
>>    else
>>      {
>> -      a = p - 3;
>> -      t = q - 4;
>> +      z = c;
>> +      w = d - 4;
>>      }
>> -  ga = a;
>> -  gt = t;
>> +  ga = x;
>> +  gt = y;
>> +  ge = z;
>> +  gw = w;
>>  }
>>  +/* Each arm has one set and defines a different live-out destination.  */
>>  __attribute__ ((noipa)) void
>> -reject_arm_only_values (long c, long p, long q, long t, long e)
>> +single_set_arms (long c, long a, long b, long x, long y)
>>  {
>> -  long a;
>> -  if (c > 7)
>> +  if (c > 0)
>> +    x = a + 1;
>> +  else
>> +    y = b - 1;
>> +  ga = x;
>> +  gt = y;
>> +}
>> +
>> +/* The arms share X through register copies and compute distinct live-out
>> +   destinations.  */
>> +__attribute__ ((noipa)) void
>> +partially_overlapping_values (long c, long a, long b,
>> +      long x, long t, long e)
>> +{
>> +  if (c > 0)
>>      {
>> -      a = p + 1;
>> -      t = q + 2;
>> +      x = a;
>> +      t = b + 1;
>>      }
>>    else
>>      {
>> -      a = p - 3;
>> -      e = q - 4;
>> +      x = b;
>> +      e = a - 1;
>>      }
>> -  ga = a;
>> +  ga = x;
>>    gt = t;
>>    ge = e;
>>  }
>> @@ -43,23 +60,27 @@ reject_arm_only_values (long c, long p, long q, long t, 
>> long e)
>>  __attribute__ ((optimize ("O0"))) int
>>  main (void)
>>  {
>> -  convertible (8, 10, 20);
>> -  if (ga != 11 || gt != 22)
>> +  disjoint_arm_values (10, 20, 30, 40, 1, 50, 60, 70, 80);
>> +  if (ga != 10 || gt != 18 || ge != 70 || gw != 80)
>> +    __builtin_abort ();
>> +  disjoint_arm_values (10, 20, 30, 40, 0, 50, 60, 70, 80);
>> +  if (ga != 50 || gt != 60 || ge != 30 || gw != 36)
>> +    __builtin_abort ();
>> +
>> +  single_set_arms (1, 10, 20, 30, 40);
>> +  if (ga != 11 || gt != 40)
>>      __builtin_abort ();
>> -  convertible (7, 10, 20);
>> -  if (ga != 7 || gt != 16)
>> +  single_set_arms (0, 10, 20, 30, 40);
>> +  if (ga != 30 || gt != 19)
>>      __builtin_abort ();
>>  -  reject_arm_only_values (8, 10, 20, 31, 47);
>> -  if (ga != 11 || gt != 22 || ge != 47)
>> +  partially_overlapping_values (1, 10, 20, 30, 40, 50);
>> +  if (ga != 10 || gt != 21 || ge != 50)
>>      __builtin_abort ();
>> -  reject_arm_only_values (7, 10, 20, 31, 47);
>> -  if (ga != 7 || gt != 31 || ge != 16)
>> +  partially_overlapping_values (0, 10, 20, 30, 40, 50);
>> +  if (ga != 20 || gt != 40 || ge != 9)
>>      __builtin_abort ();
>>    return 0;
>>  }
>>  -/* The first diamond is handled by the existing conditional-move path.  The
>> -   second must be rejected because each arm has a live-out value not 
>> assigned
>> -   by the other arm.  */
>> -/* { dg-final { scan-rtl-dump-not "if-conversion succeeded through 
>> noce_convert_multiple_sets" "ce1" } } */
>> +/* { dg-final { scan-rtl-dump-times "if-conversion succeeded through 
>> noce_convert_multiple_sets" 3 "ce1" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/aarch64/ifcvt_multiple_sets_diamond_5.c 
>> b/gcc/testsuite/gcc.target/aarch64/ifcvt_multiple_sets_diamond_5.c
>> index 7490df7ddc0..ccf21441089 100644
>> --- a/gcc/testsuite/gcc.target/aarch64/ifcvt_multiple_sets_diamond_5.c
>> +++ b/gcc/testsuite/gcc.target/aarch64/ifcvt_multiple_sets_diamond_5.c
>> @@ -23,8 +23,7 @@ f (const unsigned char *p, unsigned long tag)
>>  }
>>    /* { dg-final { scan-rtl-dump-times "if-conversion succeeded through 
>> noce_convert_multiple_sets" 1 "ce1" } } */
>> -/* { dg-final { scan-assembler-times "\tcsinc\t" 1 } } */
>> -/* { dg-final { scan-assembler-times "\tcsel\t" 1 } } */
>> +/* { dg-final { scan-assembler-times "\tcsinc\t" 2 } } */
>>  /* { dg-final { scan-assembler-times "\tldrb\t" 1 } } */
>>  /* { dg-final { scan-assembler-not {\tb(eq|ne)\t} } } */
>>  /* { dg-final { scan-assembler-not {\tcbn?z\t} } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/aarch64/ifcvt_multiple_sets_diamond_6.c 
>> b/gcc/testsuite/gcc.target/aarch64/ifcvt_multiple_sets_diamond_6.c
>> new file mode 100644
>> index 00000000000..a6e7be9c22a
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/aarch64/ifcvt_multiple_sets_diamond_6.c
>> @@ -0,0 +1,100 @@
>> +/* Test dependencies in diamonds with arm-only live-out destinations.  */
>> +/* { dg-do run } */
>> +/* { dg-options "-O2 -fno-tree-ter -fno-tree-coalesce-vars -fdump-rtl-ce1" 
>> } */
>> +/* { dg-additional-options 
>> "--param=max-rtl-if-conversion-unpredictable-cost=100 
>> --param=max-rtl-if-conversion-predictable-cost=100" } */
>> +
>> +volatile long ga, gt, ge, gu;
>> +
>> +/* Each arm reads the value that the other arm can replace.  The else
>> +   arm also defines E twice with a dependent live-out value in between.  */
>> +__attribute__ ((noipa)) void
>> +cross_arm_repeated (long c, long p, long q, long t, long e)
>> +{
>> +  long k;
>> +  if (c > 7)
>> +    {
>> +      t = e + p;
>> +      k = q + 1;
>> +    }
>> +  else
>> +    {
>> +      e = t + q;
>> +      k = e ^ p;
>> +      e = k + 3;
>> +    }
>> +  ga = k;
>> +  gt = t;
>> +  ge = e;
>> +}
>> +
>> +/* C is both a condition input and an arm-only live-out destination.  */
>> +__attribute__ ((noipa)) void
>> +condition_input (long c, long p, long q, long a)
>> +{
>> +  long t;
>> +  if (c > 7)
>> +    {
>> +      a = p + 1;
>> +      t = q + 2;
>> +    }
>> +  else
>> +    {
>> +      t = p - 3;
>> +      c = q - 4;
>> +    }
>> +  ga = a;
>> +  gt = t;
>> +  ge = c;
>> +}
>> +
>> +/* One arm has more live-out destinations.  The conversion keeps the CFG arm
>> +   order.  */
>> +__attribute__ ((noipa)) void
>> +unequal_output_counts (long c, long p, long q, long t, long e, long u)
>> +{
>> +  long a;
>> +  if (__builtin_expect (c > 7, 1))
>> +    {
>> +      a = p + 1;
>> +      t = q + 2;
>> +    }
>> +  else
>> +    {
>> +      a = p - 3;
>> +      e = q - 4;
>> +      u = p + q;
>> +    }
>> +  ga = a;
>> +  gt = t;
>> +  ge = e;
>> +  gu = u;
>> +}
>> +
>> +__attribute__ ((optimize ("O0"))) int
>> +main (void)
>> +{
>> +  cross_arm_repeated (8, 10, 20, 31, 47);
>> +  if (ga != 21 || gt != 57 || ge != 47)
>> +    __builtin_abort ();
>> +  cross_arm_repeated (7, 10, 20, 31, 47);
>> +  if (ga != 57 || gt != 31 || ge != 60)
>> +    __builtin_abort ();
>> +
>> +  condition_input (8, 10, 20, 47);
>> +  if (ga != 11 || gt != 22 || ge != 8)
>> +    __builtin_abort ();
>> +  condition_input (7, 10, 20, 47);
>> +  if (ga != 47 || gt != 7 || ge != 16)
>> +    __builtin_abort ();
>> +
>> +  unequal_output_counts (8, 10, 20, 31, 47, 59);
>> +  if (ga != 11 || gt != 22 || ge != 47 || gu != 59)
>> +    __builtin_abort ();
>> +  unequal_output_counts (7, 10, 20, 31, 47, 59);
>> +  if (ga != 7 || gt != 31 || ge != 16 || gu != 30)
>> +    __builtin_abort ();
>> +
>> +  return 0;
>> +}
>> +
>> +/* { dg-final { scan-rtl-dump-times "if-conversion succeeded through 
>> noce_convert_multiple_sets" 3 "ce1" } } */
>> diff --git 
>> a/gcc/testsuite/gcc.target/aarch64/ifcvt_multiple_sets_diamond_7.c 
>> b/gcc/testsuite/gcc.target/aarch64/ifcvt_multiple_sets_diamond_7.c
>> new file mode 100644
>> index 00000000000..f72223f6808
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/aarch64/ifcvt_multiple_sets_diamond_7.c
>> @@ -0,0 +1,26 @@
>> +/* Include arm-only outputs in the multiple-set conversion limit.  */
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -fno-tree-ter -fno-tree-coalesce-vars -fdump-rtl-ce1" 
>> } */
>> +/* { dg-additional-options "--param=max-rtl-if-conversion-insns=3 
>> --param=max-rtl-if-conversion-unpredictable-cost=100" } */
>> +
>> +void sink3 (long, long, long);
>> +
>> +void
>> +f (long c, long p, long q, long t, long e)
>> +{
>> +  long a;
>> +  if (c > 7)
>> +    {
>> +      a = p + 1;
>> +      t = a + q;
>> +      a = t + 3;
>> +    }
>> +  else
>> +    {
>> +      a = p - 3;
>> +      e = q - 4;
>> +    }
>> +  sink3 (a, t, e);
>> +}
>> +
>> +/* { dg-final { scan-rtl-dump-not "if-conversion succeeded through 
>> noce_convert_multiple_sets" "ce1" } } */
>> diff --git a/gcc/testsuite/gcc.target/i386/ifcvt-multiple-sets-diamond-1.c 
>> b/gcc/testsuite/gcc.target/i386/ifcvt-multiple-sets-diamond-1.c
>> index fb4491074f3..c23f9a75967 100644
>> --- a/gcc/testsuite/gcc.target/i386/ifcvt-multiple-sets-diamond-1.c
>> +++ b/gcc/testsuite/gcc.target/i386/ifcvt-multiple-sets-diamond-1.c
>> @@ -1,27 +1,27 @@
>>  /* { dg-do run } */
>>  /* { dg-require-effective-target lp64 } */
>>  /* { dg-options "-O2 -mtune=generic -fdump-rtl-ce1" } */
>> -/* { dg-additional-options 
>> "--param=max-rtl-if-conversion-predictable-cost=100" } */
>> +/* { dg-additional-options "--param=max-rtl-if-conversion-insns=3 
>> --param=max-rtl-if-conversion-predictable-cost=100 
>> --param=max-rtl-if-conversion-unpredictable-cost=100" } */
>>  -/* The single-set arm is the likely fallthrough block.  Speculative 
>> arithmetic
>> -   clobbers FLAGS, so each conditional move must re-materialize the
>> +/* The arms have disjoint live-out destinations.  The speculative xor
>> +   clobbers FLAGS, so the conversion must not reuse the incoming
>>     comparison.  */
>>  -volatile long ga, gb;
>> +volatile long ga, gb, gd;
>>    __attribute__ ((noipa)) void
>> -f (long c, long x, long y, long b)
>> +f (long c, long x, long y, long a, long b, long d)
>>  {
>> -  long a;
>> -  if (__builtin_expect (c <= 7, 1))
>> -    a = y + 3;
>> -  else
>> +  if (__builtin_expect (c > 7, 0))
>>      {
>>        a = x + 1;
>>        b = y + 2;
>>      }
>> +  else
>> +    d = x ^ y;
>>    ga = a;
>>    gb = b;
>> +  gd = d;
>>  }
>>    /* Keep the runtime driver out of noce so that the dump count is specific 
>> to
>> @@ -33,9 +33,10 @@ main (void)
>>      for (long x = -8; x != 9; ++x)
>>        for (long y = -8; y != 9; ++y)
>>   {
>> -  f (c, x, y, 4);
>> -  if (ga != (c > 7 ? x + 1 : y + 3)
>> -      || gb != (c > 7 ? y + 2 : 4))
>> +  f (c, x, y, 2, 4, 6);
>> +  if (ga != (c > 7 ? x + 1 : 2)
>> +      || gb != (c > 7 ? y + 2 : 4)
>> +      || gd != (c > 7 ? 6 : (x ^ y)))
>>      __builtin_abort ();
>>   }
>>    return 0;
> 

Attachment: 0001-testsuite-arm-Fix-short-IT-ifcvt-test.patch
Description: 0001-testsuite-arm-Fix-short-IT-ifcvt-test.patch

Reply via email to