Add an expander for isnormal using integer arithmetic.  This is
typically faster and avoids generating spurious exceptions on
signaling NaNs.  This fixes part of PR66462.

int isnormal1 (float x) { return __builtin_isnormal (x); }

Before:
        fabs    s0, s0
        mov     w0, 2139095039
        fmov    s31, w0
        fcmp    s0, s31
        movi    v31.2s, 0x80, lsl 16
        fccmp   s0, s31, 1, ls
        cset    w0, lt
        eor     w0, w0, 1
        ret

After:
        fmov    w0, s0
        ubfx    w0, w0, 23, 8
        sub     w0, w0, #1
        cmp     w0, 254
        cset    w0, cc
        ret

gcc/ChangeLog:

        PR middle-end/66462
        * config/aarch64/aarch64.md (isnormal<mode>2): Add new expander.

gcc/testsuite/ChangeLog:

        PR middle-end/66462
        * gcc.target/aarch64/pr66462.c: Add tests for isnormal.
---
 gcc/config/aarch64/aarch64.md              | 24 ++++++++++++++
 gcc/testsuite/gcc.target/aarch64/pr66462.c | 38 ++++++++++++++++++++++
 2 files changed, 62 insertions(+)

diff --git ./gcc/config/aarch64/aarch64.md ./gcc/config/aarch64/aarch64.md
index 4ae5c074cd1..bf7dc993d56 100644
--- ./gcc/config/aarch64/aarch64.md
+++ ./gcc/config/aarch64/aarch64.md
@@ -7900,6 +7900,30 @@
 }
 )
 
+;; A number is normal iff its exponent field E is neither 0 nor all ones,
+;; i.e. (unsigned) (E - 1) < EXP_MAX - 1.
+(define_expand "isnormal<mode>2"
+ [(match_operand:SI 0 "register_operand")
+  (match_operand:GPF 1 "register_operand")]
+ "TARGET_FLOAT"
+{
+  machine_mode imode = <V_INT_EQUIV>mode;
+  int exp_bits = GET_MODE_BITSIZE (<MODE>mode) - <mantissa_bits> - 1;
+  HOST_WIDE_INT exp_max = (HOST_WIDE_INT_1 << exp_bits) - 1;
+  rtx op = force_lowpart_subreg (imode, operands[1], <MODE>mode);
+  op = expand_simple_binop (imode, LSHIFTRT, op, GEN_INT (<mantissa_bits>),
+                           NULL_RTX, 1, OPTAB_DIRECT);
+  op = expand_simple_binop (imode, AND, op, GEN_INT (exp_max),
+                           NULL_RTX, 1, OPTAB_DIRECT);
+  op = expand_simple_binop (imode, PLUS, op, constm1_rtx,
+                           NULL_RTX, 1, OPTAB_DIRECT);
+  rtx cc_reg = aarch64_gen_compare_reg (LTU, op, GEN_INT (exp_max - 1));
+  rtx cmp = gen_rtx_fmt_ee (LTU, SImode, cc_reg, const0_rtx);
+  emit_insn (gen_aarch64_cstoresi (operands[0], cmp, cc_reg));
+  DONE;
+}
+)
+
 ;; -------------------------------------------------------------------
 ;; Reload support
 ;; -------------------------------------------------------------------
diff --git ./gcc/testsuite/gcc.target/aarch64/pr66462.c 
./gcc/testsuite/gcc.target/aarch64/pr66462.c
index 2bd734b3193..b5f719bf2d8 100644
--- ./gcc/testsuite/gcc.target/aarch64/pr66462.c
+++ ./gcc/testsuite/gcc.target/aarch64/pr66462.c
@@ -64,6 +64,26 @@ static void t_nan (double x, bool res)
     __builtin_abort ();
 }
 
+static void t_normalf (float x, bool res)
+{
+  if (__builtin_isnormal (x) != res)
+    __builtin_abort ();
+  if (__builtin_isnormal (-x) != res)
+    __builtin_abort ();
+  if (fetestexcept (FE_INVALID))
+    __builtin_abort ();
+}
+
+static void t_normal (double x, bool res)
+{
+  if (__builtin_isnormal (x) != res)
+    __builtin_abort ();
+  if (__builtin_isnormal (-x) != res)
+    __builtin_abort ();
+  if (fetestexcept (FE_INVALID))
+    __builtin_abort ();
+}
+
 
 int
 main ()
@@ -106,5 +126,23 @@ main ()
   t_nan (__builtin_nans (""), 1);
   t_nan (__builtin_nan (""), 1);
 
+  t_normalf (0.0f, 0);
+  t_normalf (1.0f, 1);
+  t_normalf (__FLT_MIN__, 1);
+  t_normalf (__FLT_MAX__, 1);
+  t_normalf (__FLT_DENORM_MIN__, 0);
+  t_normalf (__builtin_inff (), 0);
+  t_normalf (__builtin_nansf (""), 0);
+  t_normalf (__builtin_nanf (""), 0);
+
+  t_normal (0.0, 0);
+  t_normal (1.0, 1);
+  t_normal (__DBL_MIN__, 1);
+  t_normal (__DBL_MAX__, 1);
+  t_normal (__DBL_DENORM_MIN__, 0);
+  t_normal (__builtin_inf (), 0);
+  t_normal (__builtin_nans (""), 0);
+  t_normal (__builtin_nan (""), 0);
+
   return 0;
 }
-- 
2.54.0

Reply via email to