> On 26 Aug 2026, at 07:16, Andrea Pinski <[email protected]> > wrote: > > On Tue, Aug 11, 2026 at 11:33 PM <[email protected]> wrote: >> >> From: Kyrylo Tkachov <[email protected]> >> >> This is a rework of previously-approved >> https://gcc.gnu.org/pipermail/gcc-patches/2026-August/727208.html >> with the FP CCmode logic factored into a helper to make it reusable in patch >> 3. >> >> FCMP and FCMPE set NZCV identically. FCMPE also raises Invalid for a quiet >> NaN. When NaNs are not honoured, or floating-point operations cannot trap, >> this exception difference is not observable. >> >> For example, with -O2 -ffinite-math-only: >> >> int >> f (double a, double b) >> { >> return (a < b) + (a == b); >> } >> >> The ordered and equality comparisons used different condition modes, so >> AArch64 emitted two comparisons: >> >> fcmpe d0, d1 >> cset w0, mi >> fcmp d0, d1 >> cinc w0, w0, eq >> >> After this patch both operations use one comparison: >> >> fcmp d0, d1 >> cset w0, eq >> cinc w0, w0, mi >> >> Use CCFPmode for ordered comparisons too when the exception is not >> observable. >> Keep CCFPEmode when both NaNs and trapping operations are honoured. Move the >> rule into a helper that takes the comparison code and the operand mode, so >> that a caller which has no operand rtx can use it. >> >> Also anchor the existing FP assembly scans. The old expressions could cross >> line boundaries and incorrectly implied that FCCMP accepts a zero operand. >> >> The tests cover finite-math and non-trapping instruction selection, >> comparison >> reuse, and the default trapping behaviour. >> >> gcc/ >> >> * config/aarch64/aarch64.cc (aarch64_fp_cc_mode): New function. >> Use CCFPmode when the FCMPE exception is not observable. >> (aarch64_select_cc_mode): Use it. >> >> gcc/testsuite/ >> >> * gcc.target/aarch64/ccmp_1.c: Update and anchor the FP scans. >> * gcc.target/aarch64/fccmp_1.c: Update the expected mode. >> * gcc.target/aarch64/fccmp_3.c: New test. >> >> Signed-off-by: Kyrylo Tkachov <[email protected]> >> --- >> gcc/config/aarch64/aarch64.cc | 60 ++++++++++++---------- >> gcc/testsuite/gcc.target/aarch64/ccmp_1.c | 10 ++-- >> gcc/testsuite/gcc.target/aarch64/fccmp_1.c | 8 +-- >> gcc/testsuite/gcc.target/aarch64/fccmp_3.c | 18 +++++++ >> 4 files changed, 61 insertions(+), 35 deletions(-) >> create mode 100644 gcc/testsuite/gcc.target/aarch64/fccmp_3.c >> >> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc >> index 8e1eb2d7e33..0b73146b620 100644 >> --- a/gcc/config/aarch64/aarch64.cc >> +++ b/gcc/config/aarch64/aarch64.cc >> @@ -12674,40 +12674,46 @@ aarch64_emit_call_insn (rtx pat) >> return as_a<rtx_call_insn *> (insn); >> } >> >> +/* Return the condition code mode for comparison CODE of MODE floating-point >> + operands. FCMP and FCMPE set the same flags, but FCMPE also raises >> Invalid >> + for a quiet NaN. Use CCFPE only when that exception is observable. */ >> + >> +static machine_mode >> +aarch64_fp_cc_mode (rtx_code code, machine_mode mode) >> +{ >> + switch (code) >> + { >> + case EQ: >> + case NE: >> + case UNORDERED: >> + case ORDERED: >> + case UNLT: >> + case UNLE: >> + case UNGT: >> + case UNGE: >> + case UNEQ: >> + return CCFPmode; >> + >> + case LT: >> + case LE: >> + case GT: >> + case GE: >> + case LTGT: >> + return HONOR_NANS (mode) && flag_trapping_math ? CCFPEmode : CCFPmode; > > I think this should be written as the following: > if (!HONOR_NANS (mode) || !flag_trapping_math) > return CCFPmode; > switch (code) > .... > > Just so it is easier to understand that for non trapping everything > just uses CCFPmode and only trapping math we use CCFPEmode. >
Thanks, something like the attached?
> Now the question becomes for snans what should be done? Should
> CCFPEmode be used always then? Or something more complex? For now I
> think we can ignore that case but I suspect we might need to come up
> with a solution.
FCMP already raises Invalid for an sNaN, so sNaNs do not require CCFPE for
every comparison. FCMPE differs by also raising Invalid for a qNaN.
But yeah, we’ll need to look into that separately.
Thanks,
Kyrill
>
>> +
>> + default:
>> + gcc_unreachable ();
>> + }
>> +}
>> +
>> machine_mode
>> aarch64_select_cc_mode (RTX_CODE code, rtx x, rtx y)
>> {
>> machine_mode mode_x = GET_MODE (x);
>> rtx_code code_x = GET_CODE (x);
>>
>> - /* All floating point compares return CCFP if it is an equality
>> - comparison, and CCFPE otherwise. */
>> if (GET_MODE_CLASS (mode_x) == MODE_FLOAT)
>> - {
>> - switch (code)
>> - {
>> - case EQ:
>> - case NE:
>> - case UNORDERED:
>> - case ORDERED:
>> - case UNLT:
>> - case UNLE:
>> - case UNGT:
>> - case UNGE:
>> - case UNEQ:
>> - return CCFPmode;
>> -
>> - case LT:
>> - case LE:
>> - case GT:
>> - case GE:
>> - case LTGT:
>> - return CCFPEmode;
>> -
>> - default:
>> - gcc_unreachable ();
>> - }
>> - }
>> + return aarch64_fp_cc_mode (code, mode_x);
>>
>> /* Equality comparisons of short modes against zero can be performed
>> using the TST instruction with the appropriate bitmask. */
>> diff --git a/gcc/testsuite/gcc.target/aarch64/ccmp_1.c
>> b/gcc/testsuite/gcc.target/aarch64/ccmp_1.c
>> index 9b68c070f9d..e1975c59ba1 100644
>> --- a/gcc/testsuite/gcc.target/aarch64/ccmp_1.c
>> +++ b/gcc/testsuite/gcc.target/aarch64/ccmp_1.c
>> @@ -86,10 +86,12 @@ f13 (int a, int b)
>> /* { dg-final { scan-assembler "cmp\t(.)+35" } } */
>>
>> /* { dg-final { scan-assembler-times "\tcmp\tw\[0-9\]+, 0" 4 } } */
>> -/* { dg-final { scan-assembler-times "fcmpe\t(?:.)+0\\.0" 1 } } */
>> -/* { dg-final { scan-assembler-times "fcmp\t(?:.)+0\\.0" 1 } } */
>> +/* With -ffinite-math-only the signalling compares are not needed. */
>> +/* { dg-final { scan-assembler-times {\tfcmp\t[sd][0-9]+, #0\.0} 4 } } */
>> +/* { dg-final { scan-assembler-not {\tfcmpe\t} } } */
>>
>> /* { dg-final { scan-assembler "adds\t" } } */
>> /* { dg-final { scan-assembler-times "\tccmp\t" 11 } } */
>> -/* { dg-final { scan-assembler-times "fccmp\t.*0\\.0" 1 } } */
>> -/* { dg-final { scan-assembler-times "fccmpe\t.*0\\.0" 1 } } */
>> +/* FCCMP has no zero-immediate form, so both operands are registers. */
>> +/* { dg-final { scan-assembler-times {\tfccmp\t[sd][0-9]+, [sd][0-9]+,} 2 }
>> } */
>> +/* { dg-final { scan-assembler-not {\tfccmpe\t} } } */
>> diff --git a/gcc/testsuite/gcc.target/aarch64/fccmp_1.c
>> b/gcc/testsuite/gcc.target/aarch64/fccmp_1.c
>> index 96d6f717136..934bb0e560b 100644
>> --- a/gcc/testsuite/gcc.target/aarch64/fccmp_1.c
>> +++ b/gcc/testsuite/gcc.target/aarch64/fccmp_1.c
>> @@ -7,8 +7,8 @@
>>
>> /*
>> ** hf_lt:
>> -** fcmpe h0, h1
>> -** fccmpe h2, h3, 0, mi
>> +** fcmp h0, h1
>> +** fccmp h2, h3, 0, mi
>> ** cset w0, mi
>> ** ret
>> */
>> @@ -35,8 +35,8 @@ hf_eq (_Float16 a, _Float16 b, _Float16 c, _Float16 d)
>>
>> /*
>> ** hf_ior:
>> -** fcmpe h0, h1
>> -** fccmpe h2, h3, 8, pl
>> +** fcmp h0, h1
>> +** fccmp h2, h3, 8, pl
>> ** cset w0, mi
>> ** ret
>> */
>> diff --git a/gcc/testsuite/gcc.target/aarch64/fccmp_3.c
>> b/gcc/testsuite/gcc.target/aarch64/fccmp_3.c
>> new file mode 100644
>> index 00000000000..eb1505fc26f
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/aarch64/fccmp_3.c
>> @@ -0,0 +1,18 @@
>> +/* { dg-do compile } */
>> +/* { dg-options "-O2 -ffinite-math-only" } */
>> +/* { dg-final { check-function-bodies "**" "" } } */
>> +
>> +/* One condition code mode lets GCC reuse a compare of the same operands.
>> */
>> +
>> +/*
>> +** cse:
>> +** fcmp d0, d1
>> +** cset w0, eq
>> +** cinc w0, w0, mi
>> +** ret
>> +*/
>> +int
>> +cse (double a, double b)
>> +{
>> + return (a < b) + (a == b);
>> +}
>> --
>> 2.50.1 (Apple Git-155)
0002-aarch64-Use-one-FP-condition-mode-when-exceptions-ar.patch
Description: 0002-aarch64-Use-one-FP-condition-mode-when-exceptions-ar.patch
