"Richard Earnshaw (foss)" <[email protected]> writes:
> On 22/03/2026 18:24, Richard Sandiford wrote:
>> Muhammad Kamran <[email protected]> writes:
>>> The pattern expands uaddc sum into:
>>> cmp openand[4], #1
>>> adcs operand[0], operand[2], operand[3]
>>> cset operand[1], cs
>>>
>>> Carry chained uaddc expansion results in a rount trip CC -> register -> CC.
>>> Remove that round-trip as CSET-like materialization does not clobber flags,
>>> so CC already carries the same bit.
>>>
>>> gcc/ChangeLog:
>>>
>>>     * config/aarch64/aarch64.md
>>>     (uaddc<mode>5): Expansion pattern for uaddc<m>5
>>>     (*aarch64_setc_from_carry_combine_cc_c_<mode>) Post-combine no-op split
>>>     pattern for carry chain elimination in CC_Cmode
>>>     (*aarch64_setc_from_carry_combine_cc_adc_<mode> Post-combine no-op
>>>     split for carry chain elimination in CC_ADCmode
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>>     * gcc.target/aarch64/uaddcm5.c: test chained uaddc expansion
>>> ---
>>>  gcc/config/aarch64/aarch64.md              | 60 ++++++++++++++++++++++
>>>  gcc/testsuite/gcc.target/aarch64/uaddcm5.c | 26 ++++++++++
>>>  2 files changed, 86 insertions(+)
>>>  create mode 100644 gcc/testsuite/gcc.target/aarch64/uaddcm5.c
>>>
>>> diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
>>> index df5f72ab94c..e875bcaec28 100644
>>> --- a/gcc/config/aarch64/aarch64.md
>>> +++ b/gcc/config/aarch64/aarch64.md
>>> @@ -3390,6 +3390,66 @@ (define_insn "*add<mode>3_carryinC"
>>>    [(set_attr "type" "adc_reg")]
>>>  )
>>>  
>>> +(define_expand "uaddc<mode>5"
>>> +  [(match_operand:GPI 0 "register_operand")
>>> +   (match_operand:GPI 1 "register_operand")
>>> +   (match_operand:GPI 2 "register_operand")
>>> +   (match_operand:GPI 3 "register_operand")
>>> +   (match_operand:GPI 4 "nonmemory_operand")]
>>> +  ""
>>> +{
>>> +  if (operands[4] == const0_rtx)
>>> +    {
>>> +      emit_insn (gen_add<mode>3_compareC (operands[0], operands[2],
>>> +                                     operands[3]));
>>> +      rtx cc = gen_rtx_REG (CC_Cmode, CC_REGNUM);
>>> +      rtx pat = gen_rtx_LTU (<MODE>mode, cc, const0_rtx);
>>> +      emit_insn (gen_rtx_SET (operands[1], pat));
>>> +    }
>>> +  else
>>> +    {
>>> +      rtx cin = force_reg (<MODE>mode, operands[4]);
>>> +      rtx cc = gen_rtx_REG (CC_Cmode, CC_REGNUM);
>>> +      rtx adc_cc = gen_rtx_REG (CC_ADCmode, CC_REGNUM);
>>> +      rtx cmp = gen_rtx_COMPARE (CC_Cmode,
>>> +                            gen_rtx_PLUS (<MODE>mode, cin, constm1_rtx),
>>> +                            cin);
>>> +      emit_insn (gen_rtx_SET (cc, cmp));
>>> +      emit_insn (gen_add<mode>3_carryinC (operands[0], operands[2],
>>> +                                     operands[3]));
>>> +      rtx pat = gen_rtx_GEU (<MODE>mode, adc_cc, const0_rtx);
>>> +      emit_insn (gen_rtx_SET (operands[1], pat));
>>> +    }
>>> +  DONE;
>>> +})
>>> +
>>> +;; The uaddc expansion results in a rount trip CC -> register -> CC.  
>>> Remove
>>> +;; that round-trip as CSET-like materialization does not clobber flags, so 
>>> CC
>>> +;; already carries the same bit.
>>> +(define_insn_and_split "*aarch64_setc_from_carry_combine_cc_c_<mode>"
>>> +  [(set (reg:CC_C CC_REGNUM)
>>> +   (compare:CC_C
>>> +     (neg:GPI
>>> +       (geu:GPI (reg:CC_C CC_REGNUM) (const_int 0)))
>>> +     (ltu:GPI (reg:CC_C CC_REGNUM) (const_int 0))))]
>>> +  ""
>>> +  "#"
>>> +  "&& 1"
>>> +  [(const_int 0)]
>>> +  "emit_note (NOTE_INSN_DELETED); DONE;")
>> 
>> If we want this kind of simplification to be target-specific,
>> I think we should add a dedicated mechanism for it, rather than using
>> define_insn_and_split.  There are two reasons, one kind of subjective
>> and one more practical:
>> 
>> (1) The instruction above is never really intended to be an instruction
>>     and is not needed to preserve RTL semantics (since it's a nop in
>>     RTL terms as well as machine terms).  It also adds overhead by
>>     taking up insn codes and requiring entries in recog_data etc.
>> 
>>     In other words, it seems like we're using define_insn_and_split
>>     because it's already there, rather than because it's what we would
>>     choose if we were starting from scratch.
>> 
>> (2) As a simplification rule, the above is really:
>> 
>>       (compare:CC_C (neg:M (geu:M X (const_int 0)))
>>                     (ltu:M X (const_int 0)))
>> 
>>       -> X
>> 
>
> Isn't this only true if X also has mode CC_C? It surely isn't valid
> when X has, say, SImode since the compare outputs a different mode to
> that.  Perhaps you're just assuming that.

Yeah, like you say, that was implicit, since any X->Y simplify-rtx.cc
rule requires X and Y to have the same mode.  But I should have been
more explicit.

> I'm trying to get my brain around whether this can be generalized further 
> though: is it true in general that
>
>      (compare:ANY_CC (neg:M (geu:M X:ANY_CC (const_int 0)))
>                      (ltu:M X:ANY_CC (const_int 0)))
>      -> X

Yeah, thinking again, maybe not.  I suppose a target-independent
optimisation would need to check how the compare result is used,
or would need to query the target to see whether the CC mode only
supports unsigned comparisons.  An lt comparison (say) on the compare
result wouldn't necessarily be the same as an lt comparison on X.

But since for these carry-ins the result is used in things like:

            (ltu:GPI (reg:CC_C CC_REGNUM) (const_int 0))

would it be enough to have rules like:

     (ltu:M1 (compare:M2 (neg:M3 (geu:M3 X:M2 (const_int 0)))
                         (ltu:M3 X:M2 (const_int 0)))
             (const_int 0))

     -> (ltu:M1 X:M2 (const_int 0))

?  AFAICT that really would be OK for all M2.

The idea of using a target hook to describe reversed CC modes would
still apply for the mixed CC_C/CC_ADC case.  That is:

     (ltu:M1 (compare:M2 (neg:M3 (geu:M3 X:M4 (const_int 0)))
                         (ltu:M3 X:M4 (const_int 0)))
             (const_int 0))

     -> (geu:M1 X:M4 (const_int 0))

when M2 is the reverse of M4.

The same thing would apply to an outer geu with the compare
operands reversed.

Richard

Reply via email to