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