On Sun, Sep 20, 2026 at 10:25 AM Matt Turner <[email protected]> wrote:
>
> 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.
Ok.
>
> 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
>