https://gcc.gnu.org/g:e8fb8ba77cf7a1688a063690fad27fb584c77b38
commit r17-4523-ge8fb8ba77cf7a1688a063690fad27fb584c77b38 Author: Matt Turner <[email protected]> Date: Mon Sep 21 07:27:42 2026 -0600 [PATCH 3/5] AArch64: Add isnormal expander [PR 66462] 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 HFmode and BFmode are handled too. Neither has 16-bit integer arithmetic, so their encoding is zero-extended into a word first: int isnormal2 (_Float16 x) { return __builtin_isnormal (x); } Before: umov w0, v0.h[0] mvni v0.4h, 0x84, lsl 8 movi v30.4h, 0x4, lsl 8 fcvt s0, h0 and w0, w0, 32767 fcvt s30, h30 dup v31.4h, w0 fcvt s31, h31 fcmp s31, s0 cset w0, hi fcmp s31, s30 cset w1, lt orr w0, w0, w1 eor w0, w0, 1 ret After: umov w0, v0.h[0] ubfx w0, w0, 10, 5 sub w0, w0, #1 cmp w0, 30 cset w0, cc ret gcc/ChangeLog: PR middle-end/66462 * config/aarch64/aarch64.md (isnormal<mode>2): Add new expander. * config/aarch64/iterators.md (GPF_HF_BF): New mode iterator. (mantissa_bits): Add HF and BF. (V_INT_EQUIV): Add BF. gcc/testsuite/ChangeLog: PR middle-end/66462 * gcc.target/aarch64/pr66462.c: Add tests for isnormal, including _Float16 and __bf16. Diff: --- gcc/config/aarch64/aarch64.md | 29 ++++++++++++ gcc/config/aarch64/iterators.md | 7 ++- gcc/testsuite/gcc.target/aarch64/pr66462.c | 72 ++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 2 deletions(-) diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index b299ef14283c..625c9996348f 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -7900,6 +7900,35 @@ } ) +;; 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_HF_BF 1 "register_operand")] + "TARGET_FLOAT" +{ + scalar_int_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); + /* There is no 16-bit arithmetic, so work on the encoding of the 16-bit + formats in a word. */ + if (imode == HImode) + imode = SImode; + op = convert_to_mode (imode, op, 1); + 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 a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md index d41c8921d162..568786e37149 100644 --- a/gcc/config/aarch64/iterators.md +++ b/gcc/config/aarch64/iterators.md @@ -65,6 +65,9 @@ ;; Iterator for all 16-bit scalar floating point modes (HF, BF) (define_mode_iterator HFBF [HF BF]) +;; Iterator for all scalar floating point modes (HF, BF, SF, DF) +(define_mode_iterator GPF_HF_BF [HF BF SF DF]) + ;; Iterator for all integer modes (up to 64-bit) plus all General Purpose ;; Floating-point registers (32- and 64-bit modes). (define_mode_iterator ALLI_GPF [ALLI GPF]) @@ -1522,7 +1525,7 @@ (define_mode_attr half_mask [(HI "255") (SI "65535") (DI "4294967295")]) -(define_mode_attr mantissa_bits [(SF "23") (DF "52")]) +(define_mode_attr mantissa_bits [(HF "10") (BF "7") (SF "23") (DF "52")]) ;; For constraints used in scalar immediate vector moves (define_mode_attr hq [(HI "h") (QI "q")]) @@ -2502,7 +2505,7 @@ (V2SF "V2SI") (V4SF "V4SI") (DF "DI") (V2DF "V2DI") (SF "SI") (SI "SI") - (HF "HI") + (HF "HI") (BF "HI") (VNx16QI "VNx16QI") (VNx8HI "VNx8HI") (VNx8HF "VNx8HI") (VNx8BF "VNx8HI") diff --git a/gcc/testsuite/gcc.target/aarch64/pr66462.c b/gcc/testsuite/gcc.target/aarch64/pr66462.c index 2bd734b3193c..c6367ac16f68 100644 --- a/gcc/testsuite/gcc.target/aarch64/pr66462.c +++ b/gcc/testsuite/gcc.target/aarch64/pr66462.c @@ -64,6 +64,42 @@ 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 (); +} + + +/* Generate the _Float16 and __bf16 testers with a macro rather than + spelling out the same body for each type. */ +#define DEF_TEST(NAME, TYPE, PRED) \ +static void NAME (TYPE x, bool res) \ +{ \ + if (PRED (x) != res) \ + __builtin_abort (); \ + if (PRED (-x) != res) \ + __builtin_abort (); \ + if (fetestexcept (FE_INVALID)) \ + __builtin_abort (); \ +} + +DEF_TEST (t_normal16, _Float16, __builtin_isnormal) +DEF_TEST (t_normalbf, __bf16, __builtin_isnormal) int main () @@ -106,5 +142,41 @@ 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); + + t_normal16 (0.0f16, 0); + t_normal16 (1.0f16, 1); + t_normal16 (__FLT16_MIN__, 1); + t_normal16 (__FLT16_MAX__, 1); + t_normal16 (__FLT16_DENORM_MIN__, 0); + t_normal16 ((_Float16) __builtin_inff (), 0); + t_normal16 (__builtin_nansf16 (""), 0); + t_normal16 (__builtin_nanf16 (""), 0); + + t_normalbf (0.0bf16, 0); + t_normalbf (1.0bf16, 1); + t_normalbf (__BFLT16_MIN__, 1); + t_normalbf (__BFLT16_MAX__, 1); + t_normalbf (__BFLT16_DENORM_MIN__, 0); + t_normalbf ((__bf16) __builtin_inff (), 0); + t_normalbf (__builtin_nansf16b (""), 0); + t_normalbf ((__bf16) __builtin_nanf (""), 0); + return 0; }
