From nobody Thu Dec 18 22:26:07 2025 Delivered-To: importer@patchew.org Received-SPF: temperror (zoho.com: Error in retrieving data from DNS) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=temperror (zoho.com: Error in retrieving data from DNS) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=linaro.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 151990513118326.634125365250725; Thu, 1 Mar 2018 03:52:11 -0800 (PST) Received: from localhost ([::1]:55864 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1erMks-0007QC-61 for importer@patchew.org; Thu, 01 Mar 2018 06:52:10 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:34002) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1erMK5-0003tx-29 for qemu-devel@nongnu.org; Thu, 01 Mar 2018 06:24:31 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1erMK3-0008D9-3V for qemu-devel@nongnu.org; Thu, 01 Mar 2018 06:24:29 -0500 Received: from orth.archaic.org.uk ([2001:8b0:1d0::2]:46718) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1erMK2-0008Cl-Nv for qemu-devel@nongnu.org; Thu, 01 Mar 2018 06:24:27 -0500 Received: from pm215 by orth.archaic.org.uk with local (Exim 4.89) (envelope-from ) id 1erMK1-0000eu-QL for qemu-devel@nongnu.org; Thu, 01 Mar 2018 11:24:25 +0000 From: Peter Maydell To: qemu-devel@nongnu.org Date: Thu, 1 Mar 2018 11:23:51 +0000 Message-Id: <20180301112403.12487-31-peter.maydell@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180301112403.12487-1-peter.maydell@linaro.org> References: <20180301112403.12487-1-peter.maydell@linaro.org> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2001:8b0:1d0::2 Subject: [Qemu-devel] [PULL 30/42] arm/helper.c: re-factor recpe and add recepe_f16 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_6 Z_629925259 SPT_0 From: Alex Benn=C3=A9e It looks like the ARM ARM has simplified the pseudo code for the calculation which is done on a fixed point 9 bit integer maths. So while adding f16 we can also clean this up to be a little less heavy on the floating point and just return the fractional part and leave the calle's to do the final packing of the result. Signed-off-by: Alex Benn=C3=A9e Reviewed-by: Richard Henderson Message-id: 20180227143852.11175-23-alex.bennee@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.h | 1 + target/arm/helper.c | 226 +++++++++++++++++++++++++++++-------------------= ---- 2 files changed, 129 insertions(+), 98 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index c0f35592ff..81d7baed6d 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -192,6 +192,7 @@ DEF_HELPER_4(vfp_muladds, f32, f32, f32, f32, ptr) =20 DEF_HELPER_3(recps_f32, f32, f32, f32, env) DEF_HELPER_3(rsqrts_f32, f32, f32, f32, env) +DEF_HELPER_FLAGS_2(recpe_f16, TCG_CALL_NO_RWG, f16, f16, ptr) DEF_HELPER_FLAGS_2(recpe_f32, TCG_CALL_NO_RWG, f32, f32, ptr) DEF_HELPER_FLAGS_2(recpe_f64, TCG_CALL_NO_RWG, f64, f64, ptr) DEF_HELPER_FLAGS_2(rsqrte_f32, TCG_CALL_NO_RWG, f32, f32, ptr) diff --git a/target/arm/helper.c b/target/arm/helper.c index 6e3dadb754..e2d0ff0b4c 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -11523,80 +11523,75 @@ float32 HELPER(rsqrts_f32)(float32 a, float32 b, = CPUARMState *env) * int->float conversions at run-time. */ #define float64_256 make_float64(0x4070000000000000LL) #define float64_512 make_float64(0x4080000000000000LL) +#define float16_maxnorm make_float16(0x7bff) #define float32_maxnorm make_float32(0x7f7fffff) #define float64_maxnorm make_float64(0x7fefffffffffffffLL) =20 /* Reciprocal functions * * The algorithm that must be used to calculate the estimate - * is specified by the ARM ARM, see FPRecipEstimate() + * is specified by the ARM ARM, see FPRecipEstimate()/RecipEstimate */ =20 -static float64 recip_estimate(float64 a, float_status *real_fp_status) +/* See RecipEstimate() + * + * input is a 9 bit fixed point number + * input range 256 .. 511 for a number from 0.5 <=3D x < 1.0. + * result range 256 .. 511 for a number from 1.0 to 511/256. + */ + +static int recip_estimate(int input) { - /* These calculations mustn't set any fp exception flags, - * so we use a local copy of the fp_status. - */ - float_status dummy_status =3D *real_fp_status; - float_status *s =3D &dummy_status; - /* q =3D (int)(a * 512.0) */ - float64 q =3D float64_mul(float64_512, a, s); - int64_t q_int =3D float64_to_int64_round_to_zero(q, s); - - /* r =3D 1.0 / (((double)q + 0.5) / 512.0) */ - q =3D int64_to_float64(q_int, s); - q =3D float64_add(q, float64_half, s); - q =3D float64_div(q, float64_512, s); - q =3D float64_div(float64_one, q, s); - - /* s =3D (int)(256.0 * r + 0.5) */ - q =3D float64_mul(q, float64_256, s); - q =3D float64_add(q, float64_half, s); - q_int =3D float64_to_int64_round_to_zero(q, s); - - /* return (double)s / 256.0 */ - return float64_div(int64_to_float64(q_int, s), float64_256, s); + int a, b, r; + assert(256 <=3D input && input < 512); + a =3D (input * 2) + 1; + b =3D (1 << 19) / a; + r =3D (b + 1) >> 1; + assert(256 <=3D r && r < 512); + return r; } =20 -/* Common wrapper to call recip_estimate */ -static float64 call_recip_estimate(float64 num, int off, float_status *fps= t) -{ - uint64_t val64 =3D float64_val(num); - uint64_t frac =3D extract64(val64, 0, 52); - int64_t exp =3D extract64(val64, 52, 11); - uint64_t sbit; - float64 scaled, estimate; +/* + * Common wrapper to call recip_estimate + * + * The parameters are exponent and 64 bit fraction (without implicit + * bit) where the binary point is nominally at bit 52. Returns a + * float64 which can then be rounded to the appropriate size by the + * callee. + */ =20 - /* Generate the scaled number for the estimate function */ - if (exp =3D=3D 0) { +static uint64_t call_recip_estimate(int *exp, int exp_off, uint64_t frac) +{ + uint32_t scaled, estimate; + uint64_t result_frac; + int result_exp; + + /* Handle sub-normals */ + if (*exp =3D=3D 0) { if (extract64(frac, 51, 1) =3D=3D 0) { - exp =3D -1; - frac =3D extract64(frac, 0, 50) << 2; + *exp =3D -1; + frac <<=3D 2; } else { - frac =3D extract64(frac, 0, 51) << 1; + frac <<=3D 1; } } =20 - /* scaled =3D '0' : '01111111110' : fraction<51:44> : Zeros(44); */ - scaled =3D make_float64((0x3feULL << 52) - | extract64(frac, 44, 8) << 44); + /* scaled =3D UInt('1':fraction<51:44>) */ + scaled =3D deposit32(1 << 8, 0, 8, extract64(frac, 44, 8)); + estimate =3D recip_estimate(scaled); =20 - estimate =3D recip_estimate(scaled, fpst); - - /* Build new result */ - val64 =3D float64_val(estimate); - sbit =3D 0x8000000000000000ULL & val64; - exp =3D off - exp; - frac =3D extract64(val64, 0, 52); - - if (exp =3D=3D 0) { - frac =3D 1ULL << 51 | extract64(frac, 1, 51); - } else if (exp =3D=3D -1) { - frac =3D 1ULL << 50 | extract64(frac, 2, 50); - exp =3D 0; + result_exp =3D exp_off - *exp; + result_frac =3D deposit64(0, 44, 8, estimate); + if (result_exp =3D=3D 0) { + result_frac =3D deposit64(result_frac >> 1, 51, 1, 1); + } else if (result_exp =3D=3D -1) { + result_frac =3D deposit64(result_frac >> 2, 50, 2, 1); + result_exp =3D 0; } =20 - return make_float64(sbit | (exp << 52) | frac); + *exp =3D result_exp; + + return result_frac; } =20 static bool round_to_inf(float_status *fpst, bool sign_bit) @@ -11615,18 +11610,63 @@ static bool round_to_inf(float_status *fpst, bool= sign_bit) g_assert_not_reached(); } =20 +float16 HELPER(recpe_f16)(float16 input, void *fpstp) +{ + float_status *fpst =3D fpstp; + float16 f16 =3D float16_squash_input_denormal(input, fpst); + uint32_t f16_val =3D float16_val(f16); + uint32_t f16_sign =3D float16_is_neg(f16); + int f16_exp =3D extract32(f16_val, 10, 5); + uint32_t f16_frac =3D extract32(f16_val, 0, 10); + uint64_t f64_frac; + + if (float16_is_any_nan(f16)) { + float16 nan =3D f16; + if (float16_is_signaling_nan(f16, fpst)) { + float_raise(float_flag_invalid, fpst); + nan =3D float16_maybe_silence_nan(f16, fpst); + } + if (fpst->default_nan_mode) { + nan =3D float16_default_nan(fpst); + } + return nan; + } else if (float16_is_infinity(f16)) { + return float16_set_sign(float16_zero, float16_is_neg(f16)); + } else if (float16_is_zero(f16)) { + float_raise(float_flag_divbyzero, fpst); + return float16_set_sign(float16_infinity, float16_is_neg(f16)); + } else if (float16_abs(f16) < (1 << 8)) { + /* Abs(value) < 2.0^-16 */ + float_raise(float_flag_overflow | float_flag_inexact, fpst); + if (round_to_inf(fpst, f16_sign)) { + return float16_set_sign(float16_infinity, f16_sign); + } else { + return float16_set_sign(float16_maxnorm, f16_sign); + } + } else if (f16_exp >=3D 29 && fpst->flush_to_zero) { + float_raise(float_flag_underflow, fpst); + return float16_set_sign(float16_zero, float16_is_neg(f16)); + } + + f64_frac =3D call_recip_estimate(&f16_exp, 29, + ((uint64_t) f16_frac) << (52 - 10)); + + /* result =3D sign : result_exp<4:0> : fraction<51:42> */ + f16_val =3D deposit32(0, 15, 1, f16_sign); + f16_val =3D deposit32(f16_val, 10, 5, f16_exp); + f16_val =3D deposit32(f16_val, 0, 10, extract64(f64_frac, 52 - 10, 10)= ); + return make_float16(f16_val); +} + float32 HELPER(recpe_f32)(float32 input, void *fpstp) { float_status *fpst =3D fpstp; float32 f32 =3D float32_squash_input_denormal(input, fpst); uint32_t f32_val =3D float32_val(f32); - uint32_t f32_sbit =3D 0x80000000ULL & f32_val; - int32_t f32_exp =3D extract32(f32_val, 23, 8); + bool f32_sign =3D float32_is_neg(f32); + int f32_exp =3D extract32(f32_val, 23, 8); uint32_t f32_frac =3D extract32(f32_val, 0, 23); - float64 f64, r64; - uint64_t r64_val; - int64_t r64_exp; - uint64_t r64_frac; + uint64_t f64_frac; =20 if (float32_is_any_nan(f32)) { float32 nan =3D f32; @@ -11643,30 +11683,27 @@ float32 HELPER(recpe_f32)(float32 input, void *fp= stp) } else if (float32_is_zero(f32)) { float_raise(float_flag_divbyzero, fpst); return float32_set_sign(float32_infinity, float32_is_neg(f32)); - } else if ((f32_val & ~(1ULL << 31)) < (1ULL << 21)) { + } else if (float32_abs(f32) < (1ULL << 21)) { /* Abs(value) < 2.0^-128 */ float_raise(float_flag_overflow | float_flag_inexact, fpst); - if (round_to_inf(fpst, f32_sbit)) { - return float32_set_sign(float32_infinity, float32_is_neg(f32)); + if (round_to_inf(fpst, f32_sign)) { + return float32_set_sign(float32_infinity, f32_sign); } else { - return float32_set_sign(float32_maxnorm, float32_is_neg(f32)); + return float32_set_sign(float32_maxnorm, f32_sign); } } else if (f32_exp >=3D 253 && fpst->flush_to_zero) { float_raise(float_flag_underflow, fpst); return float32_set_sign(float32_zero, float32_is_neg(f32)); } =20 + f64_frac =3D call_recip_estimate(&f32_exp, 253, + ((uint64_t) f32_frac) << (52 - 23)); =20 - f64 =3D make_float64(((int64_t)(f32_exp) << 52) | (int64_t)(f32_frac) = << 29); - r64 =3D call_recip_estimate(f64, 253, fpst); - r64_val =3D float64_val(r64); - r64_exp =3D extract64(r64_val, 52, 11); - r64_frac =3D extract64(r64_val, 0, 52); - - /* result =3D sign : result_exp<7:0> : fraction<51:29>; */ - return make_float32(f32_sbit | - (r64_exp & 0xff) << 23 | - extract64(r64_frac, 29, 24)); + /* result =3D sign : result_exp<7:0> : fraction<51:29> */ + f32_val =3D deposit32(0, 31, 1, f32_sign); + f32_val =3D deposit32(f32_val, 23, 8, f32_exp); + f32_val =3D deposit32(f32_val, 0, 23, extract64(f64_frac, 52 - 23, 23)= ); + return make_float32(f32_val); } =20 float64 HELPER(recpe_f64)(float64 input, void *fpstp) @@ -11674,12 +11711,9 @@ float64 HELPER(recpe_f64)(float64 input, void *fps= tp) float_status *fpst =3D fpstp; float64 f64 =3D float64_squash_input_denormal(input, fpst); uint64_t f64_val =3D float64_val(f64); - uint64_t f64_sbit =3D 0x8000000000000000ULL & f64_val; - int64_t f64_exp =3D extract64(f64_val, 52, 11); - float64 r64; - uint64_t r64_val; - int64_t r64_exp; - uint64_t r64_frac; + bool f64_sign =3D float64_is_neg(f64); + int f64_exp =3D extract64(f64_val, 52, 11); + uint64_t f64_frac =3D extract64(f64_val, 0, 52); =20 /* Deal with any special cases */ if (float64_is_any_nan(f64)) { @@ -11700,25 +11734,23 @@ float64 HELPER(recpe_f64)(float64 input, void *fp= stp) } else if ((f64_val & ~(1ULL << 63)) < (1ULL << 50)) { /* Abs(value) < 2.0^-1024 */ float_raise(float_flag_overflow | float_flag_inexact, fpst); - if (round_to_inf(fpst, f64_sbit)) { - return float64_set_sign(float64_infinity, float64_is_neg(f64)); + if (round_to_inf(fpst, f64_sign)) { + return float64_set_sign(float64_infinity, f64_sign); } else { - return float64_set_sign(float64_maxnorm, float64_is_neg(f64)); + return float64_set_sign(float64_maxnorm, f64_sign); } } else if (f64_exp >=3D 2045 && fpst->flush_to_zero) { float_raise(float_flag_underflow, fpst); return float64_set_sign(float64_zero, float64_is_neg(f64)); } =20 - r64 =3D call_recip_estimate(f64, 2045, fpst); - r64_val =3D float64_val(r64); - r64_exp =3D extract64(r64_val, 52, 11); - r64_frac =3D extract64(r64_val, 0, 52); + f64_frac =3D call_recip_estimate(&f64_exp, 2045, f64_frac); =20 - /* result =3D sign : result_exp<10:0> : fraction<51:0> */ - return make_float64(f64_sbit | - ((r64_exp & 0x7ff) << 52) | - r64_frac); + /* result =3D sign : result_exp<10:0> : fraction<51:0>; */ + f64_val =3D deposit64(0, 63, 1, f64_sign); + f64_val =3D deposit64(f64_val, 52, 11, f64_exp); + f64_val =3D deposit64(f64_val, 0, 52, f64_frac); + return make_float64(f64_val); } =20 /* The algorithm that must be used to calculate the estimate @@ -11907,19 +11939,17 @@ float64 HELPER(rsqrte_f64)(float64 input, void *f= pstp) =20 uint32_t HELPER(recpe_u32)(uint32_t a, void *fpstp) { - float_status *s =3D fpstp; - float64 f64; + /* float_status *s =3D fpstp; */ + int input, estimate; =20 if ((a & 0x80000000) =3D=3D 0) { return 0xffffffff; } =20 - f64 =3D make_float64((0x3feULL << 52) - | ((int64_t)(a & 0x7fffffff) << 21)); + input =3D extract32(a, 23, 9); + estimate =3D recip_estimate(input); =20 - f64 =3D recip_estimate(f64, s); - - return 0x80000000 | ((float64_val(f64) >> 21) & 0x7fffffff); + return deposit32(0, (32 - 9), 9, estimate); } =20 uint32_t HELPER(rsqrte_u32)(uint32_t a, void *fpstp) --=20 2.16.2