Add an expander for isnan using integer arithmetic. Since isnan is
just a compare, enable it only with -fsignaling-nans to avoid
generating spurious exceptions. This fixes part of PR66462.
int isnan1 (float x) { return __builtin_isnan (x); }
Before:
fcmp s0, s0
cset w0, vs
ret
After:
fmov w1, s0
mov w0, -16777216
cmp w0, w1, lsl 1
cset w0, cc
ret
gcc:
PR middle-end/66462
* config/aarch64/aarch64.md (isnan<mode>2): Add new expander.
testsuite:
PR middle-end/66462
* gcc.target/aarch64/pr66462.c: Update test.
---
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index
a63839a84382146c18acf3e0997470b068436654..68f781d68d58f9a723f17652a3cf952d4e74090a
100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -7722,6 +7722,22 @@ (define_expand "isfinite<mode>2"
}
)
+(define_expand "isnan<mode>2"
+ [(match_operand:SI 0 "register_operand")
+ (match_operand:GPF 1 "register_operand")]
+ "TARGET_FLOAT && flag_signaling_nans"
+{
+ rtx op = lowpart_subreg (<V_INT_EQUIV>mode, operands[1], <MODE>mode);
+ rtx tmp = gen_reg_rtx (<V_INT_EQUIV>mode);
+ emit_move_insn (tmp, GEN_INT (HOST_WIDE_INT_M1U << (<mantissa_bits> + 1)));
+ rtx cc_reg = gen_rtx_REG (CC_SWPmode, CC_REGNUM);
+ emit_insn (gen_cmp_swp_lsl_reg<v_int_equiv> (op, GEN_INT (1), tmp));
+ rtx cmp = gen_rtx_fmt_ee (GTU, SImode, cc_reg, const0_rtx);
+ emit_insn (gen_aarch64_cstoresi (operands[0], cmp, cc_reg));
+ DONE;
+}
+)
+
;; -------------------------------------------------------------------
;; Reload support
;; -------------------------------------------------------------------
diff --git a/gcc/testsuite/gcc.target/aarch64/pr66462.c
b/gcc/testsuite/gcc.target/aarch64/pr66462.c
index
476d47c9b1928447da2042003135f21cbf795633..2bd734b3193c55e48bbcfb9459bdf160b8b9443f
100644
--- a/gcc/testsuite/gcc.target/aarch64/pr66462.c
+++ b/gcc/testsuite/gcc.target/aarch64/pr66462.c
@@ -44,6 +44,27 @@ static void t_fin (double x, bool res)
__builtin_abort ();
}
+static void t_nanf (float x, bool res)
+{
+ if (__builtin_isnan (x) != res)
+ __builtin_abort ();
+ if (__builtin_isnan (-x) != res)
+ __builtin_abort ();
+ if (fetestexcept (FE_INVALID))
+ __builtin_abort ();
+}
+
+static void t_nan (double x, bool res)
+{
+ if (__builtin_isnan (x) != res)
+ __builtin_abort ();
+ if (__builtin_isnan (-x) != res)
+ __builtin_abort ();
+ if (fetestexcept (FE_INVALID))
+ __builtin_abort ();
+}
+
+
int
main ()
{
@@ -73,5 +94,17 @@ main ()
t_fin (__builtin_nans (""), 0);
t_fin (__builtin_nan (""), 0);
+ t_nanf (0.0f, 0);
+ t_nanf (1.0f, 0);
+ t_nanf (__builtin_inff (), 0);
+ t_nanf (__builtin_nansf (""), 1);
+ t_nanf (__builtin_nanf (""), 1);
+
+ t_nan (0.0, 0);
+ t_nan (1.0, 0);
+ t_nan (__builtin_inf (), 0);
+ t_nan (__builtin_nans (""), 1);
+ t_nan (__builtin_nan (""), 1);
+
return 0;
}