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)
>
>

Reply via email to