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