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)