From nobody Fri Oct 24 09:45:24 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) 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; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) 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 1519401976627276.76195068389836; Fri, 23 Feb 2018 08:06:16 -0800 (PST) Received: from localhost ([::1]:45436 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1epFrK-00044T-Kh for importer@patchew.org; Fri, 23 Feb 2018 11:06:06 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:46057) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1epFUl-00005E-TD for qemu-devel@nongnu.org; Fri, 23 Feb 2018 10:42:51 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1epFUj-0005pz-Sd for qemu-devel@nongnu.org; Fri, 23 Feb 2018 10:42:47 -0500 Received: from mail-wm0-x241.google.com ([2a00:1450:400c:c09::241]:37155) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1epFUj-0005nw-HV for qemu-devel@nongnu.org; Fri, 23 Feb 2018 10:42:45 -0500 Received: by mail-wm0-x241.google.com with SMTP id m207so5355983wma.2 for ; Fri, 23 Feb 2018 07:42:45 -0800 (PST) Received: from zen.linaro.local ([81.128.185.34]) by smtp.gmail.com with ESMTPSA id x10sm3240112wrc.64.2018.02.23.07.42.35 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 23 Feb 2018 07:42:38 -0800 (PST) Received: from zen.linaroharston (localhost [127.0.0.1]) by zen.linaro.local (Postfix) with ESMTP id 344913E1621; Fri, 23 Feb 2018 15:36:38 +0000 (GMT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=x3S4DfGu09BJ45IOGSKr0MykTXTkhmRYTHDy/86GXvE=; b=eO5ihyvxQTlkyVbmmujLvw8glG37uCmulY9hkgHTFPaEs1sZbhuZCR0TC8udh4tufZ XTH8erZimPjtvE2CvUShiyEZe3j/g+wexW8nZfrIqIygV8jFOr+oLxawGfv++RlcFUEa lhAQAZeP2GrDnnm6nJ+pL4r72emKVPvaHv+Gg= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=x3S4DfGu09BJ45IOGSKr0MykTXTkhmRYTHDy/86GXvE=; b=qCtazbXAFRod3xHbgwU1YckGzHnwT7qybAj+pL600cA9L92SF3ZX6sho8q9B2suWjp 0CFlSQJ98AU5Rakw5B2GoOx2XdfovpmCFZ8cj0RbvmAi4iAauwKSC02KiLDF5TfyL11+ UuJtKsHLVvgxu1qmnANgHryYd0ry03PC6+QoJsF+xqQgp2atGCxxNpMsYKKVSbhz7Ec/ Mq3DIVjfcHyS1mzUNC2FTFX2gQ40Z2NmLheCy51EgjjiA0a7X0FkZ77u1IAoyO4vJaPy 665wGkdGKN+phXH4FVzgCuTkl/7hFqktv7wp5hhpdh5Ew0pYNGXNEkIeMm5iAh+80Y3O o4GQ== X-Gm-Message-State: APf1xPAdujJI7Av1duJmE8YXDiVlMqcBQjAulbw0KOArFPzFdaazqWxg Hjld+OlsMEBDYuJ6cz0btUIdWw== X-Google-Smtp-Source: AG47ELv248MWaOFWxcNdw5McgyoRKaVWn/9GQ+1jx/Nofe09DYbskOfYXNmia2smvsSGBPfCcsjxig== X-Received: by 10.28.142.195 with SMTP id q186mr2001800wmd.83.1519400564214; Fri, 23 Feb 2018 07:42:44 -0800 (PST) From: =?UTF-8?q?Alex=20Benn=C3=A9e?= To: qemu-arm@nongnu.org Date: Fri, 23 Feb 2018 15:36:27 +0000 Message-Id: <20180223153636.29809-23-alex.bennee@linaro.org> X-Mailer: git-send-email 2.15.1 In-Reply-To: <20180223153636.29809-1-alex.bennee@linaro.org> References: <20180223153636.29809-1-alex.bennee@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: 2a00:1450:400c:c09::241 Subject: [Qemu-devel] [PATCH v3 22/31] 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: , Cc: =?UTF-8?q?Alex=20Benn=C3=A9e?= , richard.henderson@linaro.org, qemu-devel@nongnu.org, Peter Maydell Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 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 --- v3 - fix comment 2.0^-16 - f16_exp >=3D 29 (biased) - remove confusing comment about fpst --- target/arm/helper.c | 224 +++++++++++++++++++++++++++++-------------------= ---- target/arm/helper.h | 1 + 2 files changed, 128 insertions(+), 97 deletions(-) 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) -{ - /* 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); +/* 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. + */ =20 - /* return (double)s / 256.0 */ - return float64_div(int64_to_float64(q_int, s), float64_256, s); +static int recip_estimate(int input) +{ + 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) +/* + * 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. + */ + +static uint64_t call_recip_estimate(int *exp, int exp_off, uint64_t frac) { - 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; + uint32_t scaled, estimate; + uint64_t result_frac; + int result_exp; =20 - /* Generate the scaled number for the estimate function */ - if (exp =3D=3D 0) { + /* 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); - - estimate =3D recip_estimate(scaled, fpst); + /* scaled =3D UInt('1':fraction<51:44>) */ + scaled =3D deposit32(1 << 8, 0, 8, extract64(frac, 44, 8)); + estimate =3D recip_estimate(scaled); =20 - /* 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)); - - f64 =3D recip_estimate(f64, s); + input =3D extract32(a, 23, 9); + estimate =3D recip_estimate(input); =20 - 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) 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) --=20 2.15.1