On Tue, Aug 11, 2026 at 3:43 AM <[email protected]> wrote:
>
> From: Kyrylo Tkachov <[email protected]>
>
> 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.
>
> 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.
>
> Bootstrapped and tested on aarch64-none-linux-gnu.
> Ok for trunk?


> Thanks,
> Kyrill
>
> gcc/
>
>         * config/aarch64/aarch64.cc (aarch64_select_cc_mode): Use
>         CCFPmode when the FCMPE exception is not observable.
>
> 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              |  7 ++++---
>  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, 32 insertions(+), 11 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..e94b583d1bd 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -12680,8 +12680,8 @@ 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.  */
> +  /* FCMP and FCMPE set the same flags, but FCMPE also raises Invalid for a
> +     quiet NaN.  Use CCFPE only when that exception is observable.  */
>    if (GET_MODE_CLASS (mode_x) == MODE_FLOAT)
>      {
>        switch (code)
> @@ -12702,7 +12702,8 @@ aarch64_select_cc_mode (RTX_CODE code, rtx x, rtx y)
>         case GT:
>         case GE:
>         case LTGT:
> -         return CCFPEmode;
> +         return HONOR_NANS (mode_x) && flag_trapping_math
> +                ? CCFPEmode : CCFPmode;

It might be a good idea in the future, to pass down into this function
if x and y could be a NaN.
Otherwise Ok.

>
>         default:
>           gcc_unreachable ();
> 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