On Wed, Aug 26, 2026 at 12:08 AM Kyrylo Tkachov <[email protected]> wrote:
>
>
>
> > 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?
Yes. (And this is ok once tested)
>
> > 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)
>
>