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