The isinf, isfinite and isnan expanders are restricted to SFmode and
DFmode, so _Float16 and __bf16 still classify with FP comparisons.
Extend them to the two 16-bit formats.

Neither has 16-bit integer arithmetic, so zero-extend the encoding into
a word and shift the sign bit out of the top of that instead of out of
the top of the 16-bit value.

int isinf1 (_Float16 x) { return __builtin_isinf (x); }

Before:
        umov    w0, v0.h[0]
        mvni    v30.4h, 0x84, lsl 8
        fcvt    s30, h30
        and     w0, w0, 32767
        dup     v31.4h, w0
        fcvt    s31, h31
        fcmp    s31, s30
        cset    w0, eq
        ret

After:
        umov    w0, v0.h[0]
        mov     w1, -134217728
        cmp     w1, w0, lsl 17
        cset    w0, eq
        ret

gcc/ChangeLog:

        PR middle-end/66462
        * config/aarch64/aarch64.md (cmp_swp_<shift>_reg<mode>): Add a
        parameterized name.
        (isinf<mode>2): Use GPF_HF_BF and handle the 16-bit formats.
        (isfinite<mode>2): Likewise.
        (isnan<mode>2): Likewise.

gcc/testsuite/ChangeLog:

        PR middle-end/66462
        * gcc.target/aarch64/pr66462.c: Add _Float16 and __bf16 tests for
        isinf, isfinite and isnan.
---
 gcc/config/aarch64/aarch64.md              | 59 ++++++++++++++++------
 gcc/testsuite/gcc.target/aarch64/pr66462.c | 41 +++++++++++++++
 2 files changed, 84 insertions(+), 16 deletions(-)

diff --git ./gcc/config/aarch64/aarch64.md ./gcc/config/aarch64/aarch64.md
index 58383483b12..eb4436a9fc9 100644
--- ./gcc/config/aarch64/aarch64.md
+++ ./gcc/config/aarch64/aarch64.md
@@ -4697,7 +4697,7 @@
   [(set_attr "type" "fcmp<stype>")]
 )
 
-(define_insn "cmp_swp_<shift>_reg<mode>"
+(define_insn "@cmp_swp_<shift>_reg<mode>"
   [(set (reg:CC_SWP CC_REGNUM)
        (compare:CC_SWP (ASHIFT:GPI
                         (match_operand:GPI 0 "register_operand" "r")
@@ -7854,14 +7854,23 @@
 
 (define_expand "isinf<mode>2"
  [(match_operand:SI 0 "register_operand")
-  (match_operand:GPF 1 "register_operand")]
+  (match_operand:GPF_HF_BF 1 "register_operand")]
  "TARGET_FLOAT"
 {
-  rtx op = force_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)));
+  scalar_int_mode imode = <V_INT_EQUIV>mode;
+  rtx op = force_lowpart_subreg (imode, operands[1], <MODE>mode);
+  /* There is no 16-bit arithmetic, so zero-extend the encoding of the
+     16-bit formats into a word and shift the sign bit out of the top of
+     that instead.  */
+  if (imode == HImode)
+    imode = SImode;
+  op = convert_to_mode (imode, op, 1);
+  int pad = GET_MODE_BITSIZE (imode) - GET_MODE_BITSIZE (<MODE>mode);
+  rtx tmp = gen_reg_rtx (imode);
+  emit_move_insn (tmp, gen_int_mode (HOST_WIDE_INT_M1U
+                                    << (<mantissa_bits> + 1 + pad), imode));
   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));
+  emit_insn (gen_cmp_swp_reg (ASHIFT, imode, op, GEN_INT (1 + pad), tmp));
   rtx cmp = gen_rtx_fmt_ee (EQ, SImode, cc_reg, const0_rtx);
   emit_insn (gen_aarch64_cstoresi (operands[0], cmp, cc_reg));
   DONE;
@@ -7870,14 +7879,23 @@
 
 (define_expand "isfinite<mode>2"
  [(match_operand:SI 0 "register_operand")
-  (match_operand:GPF 1 "register_operand")]
+  (match_operand:GPF_HF_BF 1 "register_operand")]
  "TARGET_FLOAT"
 {
-  rtx op = force_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)));
+  scalar_int_mode imode = <V_INT_EQUIV>mode;
+  rtx op = force_lowpart_subreg (imode, operands[1], <MODE>mode);
+  /* There is no 16-bit arithmetic, so zero-extend the encoding of the
+     16-bit formats into a word and shift the sign bit out of the top of
+     that instead.  */
+  if (imode == HImode)
+    imode = SImode;
+  op = convert_to_mode (imode, op, 1);
+  int pad = GET_MODE_BITSIZE (imode) - GET_MODE_BITSIZE (<MODE>mode);
+  rtx tmp = gen_reg_rtx (imode);
+  emit_move_insn (tmp, gen_int_mode (HOST_WIDE_INT_M1U
+                                    << (<mantissa_bits> + 1 + pad), imode));
   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));
+  emit_insn (gen_cmp_swp_reg (ASHIFT, imode, op, GEN_INT (1 + pad), tmp));
   rtx cmp = gen_rtx_fmt_ee (LTU, SImode, cc_reg, const0_rtx);
   emit_insn (gen_aarch64_cstoresi (operands[0], cmp, cc_reg));
   DONE;
@@ -7886,14 +7904,23 @@
 
 (define_expand "isnan<mode>2"
  [(match_operand:SI 0 "register_operand")
-  (match_operand:GPF 1 "register_operand")]
+  (match_operand:GPF_HF_BF 1 "register_operand")]
  "TARGET_FLOAT && flag_signaling_nans"
 {
-  rtx op = force_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)));
+  scalar_int_mode imode = <V_INT_EQUIV>mode;
+  rtx op = force_lowpart_subreg (imode, operands[1], <MODE>mode);
+  /* There is no 16-bit arithmetic, so zero-extend the encoding of the
+     16-bit formats into a word and shift the sign bit out of the top of
+     that instead.  */
+  if (imode == HImode)
+    imode = SImode;
+  op = convert_to_mode (imode, op, 1);
+  int pad = GET_MODE_BITSIZE (imode) - GET_MODE_BITSIZE (<MODE>mode);
+  rtx tmp = gen_reg_rtx (imode);
+  emit_move_insn (tmp, gen_int_mode (HOST_WIDE_INT_M1U
+                                    << (<mantissa_bits> + 1 + pad), imode));
   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));
+  emit_insn (gen_cmp_swp_reg (ASHIFT, imode, op, GEN_INT (1 + pad), tmp));
   rtx cmp = gen_rtx_fmt_ee (GTU, SImode, cc_reg, const0_rtx);
   emit_insn (gen_aarch64_cstoresi (operands[0], cmp, cc_reg));
   DONE;
diff --git ./gcc/testsuite/gcc.target/aarch64/pr66462.c 
./gcc/testsuite/gcc.target/aarch64/pr66462.c
index c6367ac16f6..7fa7faf3d73 100644
--- ./gcc/testsuite/gcc.target/aarch64/pr66462.c
+++ ./gcc/testsuite/gcc.target/aarch64/pr66462.c
@@ -98,7 +98,14 @@ static void NAME (TYPE x, bool res)          \
     __builtin_abort ();                                \
 }
 
+DEF_TEST (t_inf16, _Float16, __builtin_isinf)
+DEF_TEST (t_fin16, _Float16, __builtin_isfinite)
+DEF_TEST (t_nan16, _Float16, __builtin_isnan)
 DEF_TEST (t_normal16, _Float16, __builtin_isnormal)
+
+DEF_TEST (t_infbf, __bf16, __builtin_isinf)
+DEF_TEST (t_finbf, __bf16, __builtin_isfinite)
+DEF_TEST (t_nanbf, __bf16, __builtin_isnan)
 DEF_TEST (t_normalbf, __bf16, __builtin_isnormal)
 
 int
@@ -160,6 +167,40 @@ main ()
   t_normal (__builtin_nans (""), 0);
   t_normal (__builtin_nan (""), 0);
 
+  t_inf16 (1.0f16, 0);
+  t_inf16 ((_Float16) __builtin_inff (), 1);
+  t_inf16 (__builtin_nansf16 (""), 0);
+  t_inf16 (__builtin_nanf16 (""), 0);
+
+  t_infbf (1.0bf16, 0);
+  t_infbf ((__bf16) __builtin_inff (), 1);
+  t_infbf (__builtin_nansf16b (""), 0);
+  t_infbf ((__bf16) __builtin_nanf (""), 0);
+
+  t_fin16 (0.0f16, 1);
+  t_fin16 (1.0f16, 1);
+  t_fin16 ((_Float16) __builtin_inff (), 0);
+  t_fin16 (__builtin_nansf16 (""), 0);
+  t_fin16 (__builtin_nanf16 (""), 0);
+
+  t_finbf (0.0bf16, 1);
+  t_finbf (1.0bf16, 1);
+  t_finbf ((__bf16) __builtin_inff (), 0);
+  t_finbf (__builtin_nansf16b (""), 0);
+  t_finbf ((__bf16) __builtin_nanf (""), 0);
+
+  t_nan16 (0.0f16, 0);
+  t_nan16 (1.0f16, 0);
+  t_nan16 ((_Float16) __builtin_inff (), 0);
+  t_nan16 (__builtin_nansf16 (""), 1);
+  t_nan16 (__builtin_nanf16 (""), 1);
+
+  t_nanbf (0.0bf16, 0);
+  t_nanbf (1.0bf16, 0);
+  t_nanbf ((__bf16) __builtin_inff (), 0);
+  t_nanbf (__builtin_nansf16b (""), 1);
+  t_nanbf ((__bf16) __builtin_nanf (""), 1);
+
   t_normal16 (0.0f16, 0);
   t_normal16 (1.0f16, 1);
   t_normal16 (__FLT16_MIN__, 1);
-- 
2.54.0

Reply via email to