From nobody Mon Feb 9 19:30:01 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=linaro.org ARC-Seal: i=1; a=rsa-sha256; t=1603212838; cv=none; d=zohomail.com; s=zohoarc; b=e9dJOa0bUpt+KHmlHebyVTnQASNT5AchLaUJN2SIekbL4ZkkgtvQHcOSapPvaOZvDYKz/47Bmn25k/J5fnW5rJ3bld5p8C99tuMKVQJ48cr87xfSKYCSuLskH0y5WMwN4DMdf96F6EjNex7HCPdI3R9KtaCKf3BDY+W3ul7Dkf4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1603212838; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=eYa6Q4RE3MycBw08Hofq/5V0wFL9wifbiVGcaMm5vtU=; b=elgYmSX+9z8DoqKognlO8M8OLvO+sxY3bOpoG4/j9tG6N9BmgKVYBsCdRG4J2yOw9H6UFZanX9ScuXrt3i1M+n0ygBYZoVaQpiuPOIK4d+bQwSrPRdm++YAJE1FZKpwpg58sqwmMTMHUM0CdrDidsxCpsC0hMjVv39JSRlaTKfU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1603212838766736.0410348969681; Tue, 20 Oct 2020 09:53:58 -0700 (PDT) Received: from localhost ([::1]:54896 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kUutZ-0001bd-V2 for importer@patchew.org; Tue, 20 Oct 2020 12:53:57 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:49434) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kUue9-0007wf-6l for qemu-devel@nongnu.org; Tue, 20 Oct 2020 12:38:02 -0400 Received: from mail-wr1-x429.google.com ([2a00:1450:4864:20::429]:33797) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1kUue2-000104-Na for qemu-devel@nongnu.org; Tue, 20 Oct 2020 12:38:00 -0400 Received: by mail-wr1-x429.google.com with SMTP id i1so2978681wro.1 for ; Tue, 20 Oct 2020 09:37:54 -0700 (PDT) Received: from zen.linaroharston ([51.148.130.216]) by smtp.gmail.com with ESMTPSA id d30sm3988261wrc.19.2020.10.20.09.37.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Oct 2020 09:37:44 -0700 (PDT) Received: from zen.lan (localhost [127.0.0.1]) by zen.linaroharston (Postfix) with ESMTP id 62AE11FF96; Tue, 20 Oct 2020 17:37:40 +0100 (BST) 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=eYa6Q4RE3MycBw08Hofq/5V0wFL9wifbiVGcaMm5vtU=; b=liD8uhbwwVGL07PJL2ZBbsD0vJq0ODIn1Ez7pzEKVlDJ2B1tiGejZ3pKO3MUexwMiq XhET1RrUjQHWSvS5Hh+Gvu9ebdc1aN1Lx7qOqPSeN2mAgG3JOeOBG8tibps9mQciLME3 bq81NkovadjHnSh2k+9OLSqcC81Uevlf46zdQFLrUwmgohSWpzJwT72mCT1RFvaKkPbm 9ijMVjX5eant/h+vbNxPtGzdmYMHOqWD8zbgE6YsljFwEu6/zHE5HkoI8y4ndTHjOIyS IX/0zHRRvZmMs/wYVcypBdcLCaCheid26qlnx6449rDsV08rUq/reZNu2fihz9hRqNEq XDzg== 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=eYa6Q4RE3MycBw08Hofq/5V0wFL9wifbiVGcaMm5vtU=; b=m1lXENPTSppItoPxQ4D5G/SboHPZAGIjHQPxx104xJ5R7rPg84OxHETjOFMrYtVTv8 +c4+jMBvUyk4qHYdqMyAPtXveYQwjAxt9adkErVC9A0IuFaFPsMeXzjieIJ5uL5WwcQA 5alETkm+WWFt348NaSSkJUvR814htKhk5gATKAvbSEqzeUYHDe89e8gQiynHDKJEzTVs t/CU/G+4QCnlV/C4Lq9aAZSRz4Wz0Qgk7W6HGa0/Zomf/zhjBvhbK3v+bIMFau/sFvtx BOU3KxjDMdJ8Pym8dmvC6ajlWcq/Csz4oQX0CB2DPEXkWJlF9+3C/psRkteDCXMRoz0s qlyw== X-Gm-Message-State: AOAM530sx+zf/Ba/B1O0iWvrQVeZHWIjZW3XQmgUIZ1BWuSQyitVEqTo akQY5Fb1wtoD4zbAVbI4acE6qg== X-Google-Smtp-Source: ABdhPJwX7rqVP5zKEwc2NEVTIug9bbAUz+BzG8lIVzqn0sr89NPcy8EiwL5QO8nPegC/5igpCzEm8w== X-Received: by 2002:adf:ee4c:: with SMTP id w12mr4319211wro.22.1603211873167; Tue, 20 Oct 2020 09:37:53 -0700 (PDT) From: =?UTF-8?q?Alex=20Benn=C3=A9e?= To: qemu-devel@nongnu.org Subject: [RFC PATCH 8/8] softfloat: implement addsub_floats128 using Uint128 and new style code Date: Tue, 20 Oct 2020 17:37:38 +0100 Message-Id: <20201020163738.27700-9-alex.bennee@linaro.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201020163738.27700-1-alex.bennee@linaro.org> References: <20201020163738.27700-1-alex.bennee@linaro.org> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2a00:1450:4864:20::429; envelope-from=alex.bennee@linaro.org; helo=mail-wr1-x429.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , cota@braap.org, =?UTF-8?q?Alex=20Benn=C3=A9e?= , Aurelien Jarno Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) This inevitably leads to duplication of almost identical functions for the 128 bit and the 64/32/16 bit code. We will try and address that later. The expanded code is longer than the previous softfloat code and we see a drop in performance from ~85 MFlops to ~72 MFlops. Signed-off-by: Alex Benn=C3=A9e --- include/fpu/softfloat-macros.h | 17 + fpu/softfloat.c | 586 ++++++++++++++++++++------------- fpu/softfloat-specialize.c.inc | 39 +++ 3 files changed, 421 insertions(+), 221 deletions(-) diff --git a/include/fpu/softfloat-macros.h b/include/fpu/softfloat-macros.h index 95d88d05b8..8e6158886d 100644 --- a/include/fpu/softfloat-macros.h +++ b/include/fpu/softfloat-macros.h @@ -259,6 +259,23 @@ static inline void =20 } =20 +/* as above with Uint128 */ +static inline Uint128 shift128RightJammingUint128(Int128 in, int count) +{ + Uint128 out; + + if (count =3D=3D 0) { + out =3D in; + } else if ( count < 128 ) { + Uint128 jam_mask =3D uint128_sub(uint128_lshift(1, count), 1); + int shifted_away =3D uint128_and(in, jam_mask) !=3D 0; + out =3D uint128_or(uint128_rshift(in, count), shifted_away); + } else { + out =3D ( in !=3D 0 ); + } + return out; +} + /*------------------------------------------------------------------------= ---- | Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' ri= ght | by 64 _plus_ the number of bits given in `count'. The shifted result is diff --git a/fpu/softfloat.c b/fpu/softfloat.c index e038434a07..694616bb3d 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -517,9 +517,20 @@ typedef struct { bool sign; } FloatParts; =20 +/* Similar for float128. */ +typedef struct { + Uint128 frac; + int32_t exp; + FloatClass cls; + bool sign; +} FloatParts128; + #define DECOMPOSED_BINARY_POINT (64 - 2) #define DECOMPOSED_IMPLICIT_BIT (1ull << DECOMPOSED_BINARY_POINT) #define DECOMPOSED_OVERFLOW_BIT (DECOMPOSED_IMPLICIT_BIT << 1) +#define DECOMPOSED128_BINARY_POINT (128 - 2) +#define DECOMPOSED128_IMPLICIT_BIT (uint128_lshift(1, DECOMPOSED128_BINARY= _POINT)) +#define DECOMPOSED128_OVERFLOW_BIT (uint128_lshift(DECOMPOSED128_IMPLICIT_= BIT, 1)) =20 /* Structure holding all of the relevant parameters for a format. * exp_size: the size of the exponent field @@ -559,6 +570,13 @@ typedef struct { .round_mask =3D (1ull << (DECOMPOSED_BINARY_POINT - F)) - 1, \ .roundeven_mask =3D (2ull << (DECOMPOSED_BINARY_POINT - F)) - 1 =20 +#define FLOAT128_PARAMS(E, F) \ + .exp_size =3D E, \ + .exp_bias =3D ((1 << E) - 1) >> 1, \ + .exp_max =3D (1 << E) - 1, \ + .frac_size =3D F, \ + .frac_shift =3D DECOMPOSED128_BINARY_POINT - F, + static const FloatFmt float16_params =3D { FLOAT_PARAMS(5, 10) }; @@ -580,6 +598,16 @@ static const FloatFmt float64_params =3D { FLOAT_PARAMS(11, 52) }; =20 +static const FloatFmt float128_params =3D { + FLOAT128_PARAMS(15, 112) + /* the remaining fields are not used for 128 bit ops */ + .frac_lsb =3D 0, + .frac_lsbm1 =3D 0, + .round_mask =3D 0, + .roundeven_mask =3D 0, + .arm_althp =3D false +}; + /* Unpack a float to parts, but do not canonicalize. */ static inline FloatParts unpack_raw(FloatFmt fmt, uint64_t raw) { @@ -593,6 +621,18 @@ static inline FloatParts unpack_raw(FloatFmt fmt, uint= 64_t raw) }; } =20 +static inline FloatParts128 unpack128_raw(FloatFmt fmt, Uint128 raw) +{ + const int sign_pos =3D fmt.frac_size + fmt.exp_size; + + return (FloatParts128) { + .cls =3D float_class_unclassified, + .sign =3D extract128(raw, sign_pos, 1), + .exp =3D extract128(raw, fmt.frac_size, fmt.exp_size), + .frac =3D extract128(raw, 0, fmt.frac_size), + }; +} + static inline FloatParts float16_unpack_raw(float16 f) { return unpack_raw(float16_params, f); @@ -613,6 +653,11 @@ static inline FloatParts float64_unpack_raw(float64 f) return unpack_raw(float64_params, f); } =20 +static inline FloatParts128 float128_unpack_raw(float128 f) +{ + return unpack128_raw(float128_params, uint128_make128(f.low, f.high)); +} + /* Pack a float from parts, but do not canonicalize. */ static inline uint64_t pack_raw(FloatFmt fmt, FloatParts p) { @@ -621,6 +666,13 @@ static inline uint64_t pack_raw(FloatFmt fmt, FloatPar= ts p) return deposit64(ret, sign_pos, 1, p.sign); } =20 +static inline Uint128 pack128_raw(FloatFmt fmt, FloatParts128 p) +{ + const int sign_pos =3D fmt.frac_size + fmt.exp_size; + Uint128 ret =3D deposit128(p.frac, fmt.frac_size, fmt.exp_size, p.exp); + return deposit128(ret, sign_pos, 1, p.sign); +} + static inline float16 float16_pack_raw(FloatParts p) { return make_float16(pack_raw(float16_params, p)); @@ -641,6 +693,12 @@ static inline float64 float64_pack_raw(FloatParts p) return make_float64(pack_raw(float64_params, p)); } =20 +static inline float128 float128_pack_raw(FloatParts128 p) +{ + Uint128 out =3D pack128_raw(float128_params, p); + return make_float128(uint128_gethi(out), uint128_getlo(out)); +} + /*------------------------------------------------------------------------= ---- | Functions and definitions to determine: (1) whether tininess for underf= low | is detected before or after rounding by default, (2) what (if anything) @@ -684,6 +742,41 @@ static FloatParts sf_canonicalize(FloatParts part, con= st FloatFmt *parm, return part; } =20 +/* Almost exactly the same as sf_canonicalize except 128 bit */ +static FloatParts128 sf128_canonicalize(FloatParts128 part, const FloatFmt= *parm, + float_status *status) +{ + bool frac_is_zero =3D uint128_eq(part.frac, uint128_zero()); + if (part.exp =3D=3D parm->exp_max) { + if (frac_is_zero) { + part.cls =3D float_class_inf; + } else { + part.frac =3D uint128_lshift(part.frac, parm->frac_shift); + part.cls =3D (parts128_is_snan_frac(part.frac, status) + ? float_class_snan : float_class_qnan); + } + } else if (part.exp =3D=3D 0) { + if (likely(frac_is_zero)) { + part.cls =3D float_class_zero; + } else if (status->flush_inputs_to_zero) { + float_raise(float_flag_input_denormal, status); + part.cls =3D float_class_zero; + part.frac =3D uint128_zero(); + } else { + int shift =3D clz128(part.frac) - 1; + part.cls =3D float_class_normal; + part.exp =3D parm->frac_shift - parm->exp_bias - shift + 1; + part.frac =3D uint128_lshift(part.frac, shift); + } + } else { + Uint128 imp_bit =3D uint128_lshift(1, DECOMPOSED128_BINARY_POINT); + part.cls =3D float_class_normal; + part.exp -=3D parm->exp_bias; + part.frac =3D uint128_add(imp_bit, uint128_lshift(part.frac, parm-= >frac_shift)); + } + return part; +} + /* Round and uncanonicalize a floating-point number by parts. There * are FRAC_SHIFT bits that may require rounding at the bottom of the * fraction; these bits will be removed. The exponent will be biased @@ -836,6 +929,144 @@ static FloatParts round_canonical(FloatParts p, float= _status *s, return p; } =20 +/* As above but wider */ +static FloatParts128 round128_canonical(FloatParts128 p, float_status *s, + const FloatFmt *parm) +{ + /* Do these by hand rather than widening the FloatFmt structure */ + const Uint128 frac_lsb =3D uint128_lshift(1, DECOMPOSED128_BINARY_POIN= T - parm->frac_size); + const Uint128 frac_lsbm1 =3D uint128_lshift(1, (DECOMPOSED128_BINARY_P= OINT - parm->frac_size) - 1); + const Uint128 round_mask =3D uint128_sub(frac_lsb, 1); + const Uint128 roundeven_mask =3D uint128_sub(uint128_lshift(2, DECOMPO= SED128_BINARY_POINT - parm->frac_size), 1); + const int exp_max =3D parm->exp_max; + const int frac_shift =3D parm->frac_shift; + Uint128 frac, inc; + int exp, flags =3D 0; + bool overflow_norm; + + frac =3D p.frac; + exp =3D p.exp; + + switch (p.cls) { + case float_class_normal: + switch (s->float_rounding_mode) { + case float_round_nearest_even: + overflow_norm =3D false; + inc =3D ((frac & roundeven_mask) !=3D frac_lsbm1 ? frac_lsbm1 = : 0); + break; + case float_round_ties_away: + overflow_norm =3D false; + inc =3D frac_lsbm1; + break; + case float_round_to_zero: + overflow_norm =3D true; + inc =3D 0; + break; + case float_round_up: + inc =3D p.sign ? 0 : round_mask; + overflow_norm =3D p.sign; + break; + case float_round_down: + inc =3D p.sign ? round_mask : 0; + overflow_norm =3D !p.sign; + break; + case float_round_to_odd: + overflow_norm =3D true; + inc =3D frac & frac_lsb ? 0 : round_mask; + break; + default: + g_assert_not_reached(); + } + + exp +=3D parm->exp_bias; + if (likely(exp > 0)) { + if (frac & round_mask) { + flags |=3D float_flag_inexact; + frac +=3D inc; + if (frac & DECOMPOSED128_OVERFLOW_BIT) { + frac >>=3D 1; + exp++; + } + } + frac >>=3D frac_shift; + + if (unlikely(exp >=3D exp_max)) { + flags |=3D float_flag_overflow | float_flag_inexact; + if (overflow_norm) { + exp =3D exp_max - 1; + frac =3D -1; + } else { + p.cls =3D float_class_inf; + goto do_inf; + } + } + } else if (s->flush_to_zero) { + flags |=3D float_flag_output_denormal; + p.cls =3D float_class_zero; + goto do_zero; + } else { + bool is_tiny =3D s->tininess_before_rounding + || (exp < 0) + || !(uint128_and(uint128_add(frac, inc), DECOMPOSE= D128_OVERFLOW_BIT)); + + frac =3D shift128RightJammingUint128(frac, 1 - exp); + if (frac & round_mask) { + /* Need to recompute round-to-even. */ + switch (s->float_rounding_mode) { + case float_round_nearest_even: + inc =3D ((uint128_and(frac, roundeven_mask)) !=3D frac= _lsbm1 + ? frac_lsbm1 : 0); + break; + case float_round_to_odd: + inc =3D uint128_and(frac, frac_lsb ? 0 : round_mask); + break; + default: + break; + } + flags |=3D float_flag_inexact; + uint128_add(frac, inc); + } + + exp =3D (uint128_and(frac, DECOMPOSED128_IMPLICIT_BIT) ? 1 : 0= ); + frac =3D uint128_rshift(frac, parm->frac_shift); + + if (is_tiny && (flags & float_flag_inexact)) { + flags |=3D float_flag_underflow; + } + if (exp =3D=3D 0 && frac =3D=3D 0) { + p.cls =3D float_class_zero; + } + } + break; + + case float_class_zero: + do_zero: + exp =3D 0; + frac =3D 0; + break; + + case float_class_inf: + do_inf: + exp =3D exp_max; + frac =3D 0; + break; + + case float_class_qnan: + case float_class_snan: + exp =3D exp_max; + frac =3D uint128_rshift(frac, parm->frac_shift); + break; + + default: + g_assert_not_reached(); + } + + float_raise(flags, s); + p.exp =3D exp; + p.frac =3D frac; + return p; +} + /* Explicit FloatFmt version */ static FloatParts float16a_unpack_canonical(float16 f, float_status *s, const FloatFmt *params) @@ -889,6 +1120,16 @@ static float64 float64_round_pack_canonical(FloatPart= s p, float_status *s) return float64_pack_raw(round_canonical(p, s, &float64_params)); } =20 +static FloatParts128 float128_unpack_canonical(float128 f, float_status *s) +{ + return sf128_canonicalize(float128_unpack_raw(f), &float128_params, s); +} + +static float128 float128_round_pack_canonical(FloatParts128 p, float_statu= s *s) +{ + return float128_pack_raw(round128_canonical(p, s, &float128_params)); +} + static FloatParts return_nan(FloatParts a, float_status *s) { switch (a.cls) { @@ -1018,6 +1259,110 @@ static FloatParts addsub_floats(FloatParts a, Float= Parts b, bool subtract, g_assert_not_reached(); } =20 +/* As above but with Uint128 fractions */ +static FloatParts128 pick_nan128(FloatParts128 a, FloatParts128 b, float_s= tatus *s) +{ + if (is_snan(a.cls) || is_snan(b.cls)) { + s->float_exception_flags |=3D float_flag_invalid; + } + + if (s->default_nan_mode) { + return parts128_default_nan(s); + } else { + if (pickNaN(a.cls, b.cls, + a.frac > b.frac || + (a.frac =3D=3D b.frac && a.sign < b.sign), s)) { + a =3D b; + } + if (is_snan(a.cls)) { + return parts128_silence_nan(a, s); + } + } + return a; +} + +static FloatParts128 addsub_floats128(FloatParts128 a, FloatParts128 b, bo= ol subtract, + float_status *s) +{ + bool a_sign =3D a.sign; + bool b_sign =3D b.sign ^ subtract; + + if (a_sign !=3D b_sign) { + /* Subtraction */ + + if (a.cls =3D=3D float_class_normal && b.cls =3D=3D float_class_no= rmal) { + if (a.exp > b.exp || (a.exp =3D=3D b.exp && a.frac >=3D b.frac= )) { + b.frac =3D shift128RightJammingUint128(b.frac, a.exp - b.e= xp); + a.frac =3D uint128_sub(a.frac, b.frac); + } else { + a.frac =3D shift128RightJammingUint128(a.frac, b.exp - a.e= xp); + a.frac =3D uint128_sub(b.frac, a.frac); + a.exp =3D b.exp; + a_sign ^=3D 1; + } + + if (a.frac =3D=3D 0) { + a.cls =3D float_class_zero; + a.sign =3D s->float_rounding_mode =3D=3D float_round_down; + } else { + int shift =3D clz128(a.frac) - 1; + a.frac =3D uint128_lshift(a.frac, shift); + a.exp =3D a.exp - shift; + a.sign =3D a_sign; + } + return a; + } + if (is_nan(a.cls) || is_nan(b.cls)) { + return pick_nan128(a, b, s); + } + if (a.cls =3D=3D float_class_inf) { + if (b.cls =3D=3D float_class_inf) { + float_raise(float_flag_invalid, s); + return parts128_default_nan(s); + } + return a; + } + if (a.cls =3D=3D float_class_zero && b.cls =3D=3D float_class_zero= ) { + a.sign =3D s->float_rounding_mode =3D=3D float_round_down; + return a; + } + if (a.cls =3D=3D float_class_zero || b.cls =3D=3D float_class_inf)= { + b.sign =3D a_sign ^ 1; + return b; + } + if (b.cls =3D=3D float_class_zero) { + return a; + } + } else { + /* Addition */ + if (a.cls =3D=3D float_class_normal && b.cls =3D=3D float_class_no= rmal) { + if (a.exp > b.exp) { + b.frac =3D shift128RightJammingUint128(b.frac, a.exp - b.e= xp); + } else if (a.exp < b.exp) { + a.frac =3D shift128RightJammingUint128(a.frac, b.exp - a.e= xp); + a.exp =3D b.exp; + } + a.frac =3D uint128_add(a.frac, b.frac); + if (a.frac & DECOMPOSED128_OVERFLOW_BIT) { + a.frac =3D shift128RightJammingUint128(a.frac, 1); + a.exp +=3D 1; + } + return a; + } + if (is_nan(a.cls) || is_nan(b.cls)) { + return pick_nan128(a, b, s); + } + if (a.cls =3D=3D float_class_inf || b.cls =3D=3D float_class_zero)= { + return a; + } + if (b.cls =3D=3D float_class_inf || a.cls =3D=3D float_class_zero)= { + b.sign =3D b_sign; + return b; + } + } + g_assert_not_reached(); +} + /* * Returns the result of adding or subtracting the floating-point * values `a' and `b'. The operation is performed according to the @@ -1157,6 +1502,26 @@ float64_sub(float64 a, float64 b, float_status *s) return float64_addsub(a, b, s, hard_f64_sub, soft_f64_sub); } =20 +float128 QEMU_FLATTEN +float128_add(float128 a, float128 b, float_status *status) +{ + FloatParts128 pa =3D float128_unpack_canonical(a, status); + FloatParts128 pb =3D float128_unpack_canonical(b, status); + FloatParts128 pr =3D addsub_floats128(pa, pb, false, status); + + return float128_round_pack_canonical(pr, status); +} + +float128 QEMU_FLATTEN +float128_sub(float128 a, float128 b, float_status *status) +{ + FloatParts128 pa =3D float128_unpack_canonical(a, status); + FloatParts128 pb =3D float128_unpack_canonical(b, status); + FloatParts128 pr =3D addsub_floats128(pa, pb, true, status); + + return float128_round_pack_canonical(pr, status); +} + /* * Returns the result of adding or subtracting the bfloat16 * values `a' and `b'. @@ -6921,227 +7286,6 @@ float128 float128_round_to_int(float128 a, float_st= atus *status) =20 } =20 -/*------------------------------------------------------------------------= ---- -| Returns the result of adding the absolute values of the quadruple-precis= ion -| floating-point values `a' and `b'. If `zSign' is 1, the sum is negated -| before being returned. `zSign' is ignored if the result is a NaN. -| The addition is performed according to the IEC/IEEE Standard for Binary -| Floating-Point Arithmetic. -*-------------------------------------------------------------------------= ---*/ - -static float128 addFloat128Sigs(float128 a, float128 b, bool zSign, - float_status *status) -{ - int32_t aExp, bExp, zExp; - uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; - int32_t expDiff; - - aSig1 =3D extractFloat128Frac1( a ); - aSig0 =3D extractFloat128Frac0( a ); - aExp =3D extractFloat128Exp( a ); - bSig1 =3D extractFloat128Frac1( b ); - bSig0 =3D extractFloat128Frac0( b ); - bExp =3D extractFloat128Exp( b ); - expDiff =3D aExp - bExp; - if ( 0 < expDiff ) { - if ( aExp =3D=3D 0x7FFF ) { - if (aSig0 | aSig1) { - return propagateFloat128NaN(a, b, status); - } - return a; - } - if ( bExp =3D=3D 0 ) { - --expDiff; - } - else { - bSig0 |=3D UINT64_C(0x0001000000000000); - } - shift128ExtraRightJamming( - bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 ); - zExp =3D aExp; - } - else if ( expDiff < 0 ) { - if ( bExp =3D=3D 0x7FFF ) { - if (bSig0 | bSig1) { - return propagateFloat128NaN(a, b, status); - } - return packFloat128( zSign, 0x7FFF, 0, 0 ); - } - if ( aExp =3D=3D 0 ) { - ++expDiff; - } - else { - aSig0 |=3D UINT64_C(0x0001000000000000); - } - shift128ExtraRightJamming( - aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 ); - zExp =3D bExp; - } - else { - if ( aExp =3D=3D 0x7FFF ) { - if ( aSig0 | aSig1 | bSig0 | bSig1 ) { - return propagateFloat128NaN(a, b, status); - } - return a; - } - add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); - if ( aExp =3D=3D 0 ) { - if (status->flush_to_zero) { - if (zSig0 | zSig1) { - float_raise(float_flag_output_denormal, status); - } - return packFloat128(zSign, 0, 0, 0); - } - return packFloat128( zSign, 0, zSig0, zSig1 ); - } - zSig2 =3D 0; - zSig0 |=3D UINT64_C(0x0002000000000000); - zExp =3D aExp; - goto shiftRight1; - } - aSig0 |=3D UINT64_C(0x0001000000000000); - add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); - --zExp; - if ( zSig0 < UINT64_C(0x0002000000000000) ) goto roundAndPack; - ++zExp; - shiftRight1: - shift128ExtraRightJamming( - zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 ); - roundAndPack: - return roundAndPackFloat128(zSign, zExp, zSig0, zSig1, zSig2, status); - -} - -/*------------------------------------------------------------------------= ---- -| Returns the result of subtracting the absolute values of the quadruple- -| precision floating-point values `a' and `b'. If `zSign' is 1, the -| difference is negated before being returned. `zSign' is ignored if the -| result is a NaN. The subtraction is performed according to the IEC/IEEE -| Standard for Binary Floating-Point Arithmetic. -*-------------------------------------------------------------------------= ---*/ - -static float128 subFloat128Sigs(float128 a, float128 b, bool zSign, - float_status *status) -{ - int32_t aExp, bExp, zExp; - uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1; - int32_t expDiff; - - aSig1 =3D extractFloat128Frac1( a ); - aSig0 =3D extractFloat128Frac0( a ); - aExp =3D extractFloat128Exp( a ); - bSig1 =3D extractFloat128Frac1( b ); - bSig0 =3D extractFloat128Frac0( b ); - bExp =3D extractFloat128Exp( b ); - expDiff =3D aExp - bExp; - shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 ); - shortShift128Left( bSig0, bSig1, 14, &bSig0, &bSig1 ); - if ( 0 < expDiff ) goto aExpBigger; - if ( expDiff < 0 ) goto bExpBigger; - if ( aExp =3D=3D 0x7FFF ) { - if ( aSig0 | aSig1 | bSig0 | bSig1 ) { - return propagateFloat128NaN(a, b, status); - } - float_raise(float_flag_invalid, status); - return float128_default_nan(status); - } - if ( aExp =3D=3D 0 ) { - aExp =3D 1; - bExp =3D 1; - } - if ( bSig0 < aSig0 ) goto aBigger; - if ( aSig0 < bSig0 ) goto bBigger; - if ( bSig1 < aSig1 ) goto aBigger; - if ( aSig1 < bSig1 ) goto bBigger; - return packFloat128(status->float_rounding_mode =3D=3D float_round_dow= n, - 0, 0, 0); - bExpBigger: - if ( bExp =3D=3D 0x7FFF ) { - if (bSig0 | bSig1) { - return propagateFloat128NaN(a, b, status); - } - return packFloat128( zSign ^ 1, 0x7FFF, 0, 0 ); - } - if ( aExp =3D=3D 0 ) { - ++expDiff; - } - else { - aSig0 |=3D UINT64_C(0x4000000000000000); - } - shift128RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 ); - bSig0 |=3D UINT64_C(0x4000000000000000); - bBigger: - sub128( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 ); - zExp =3D bExp; - zSign ^=3D 1; - goto normalizeRoundAndPack; - aExpBigger: - if ( aExp =3D=3D 0x7FFF ) { - if (aSig0 | aSig1) { - return propagateFloat128NaN(a, b, status); - } - return a; - } - if ( bExp =3D=3D 0 ) { - --expDiff; - } - else { - bSig0 |=3D UINT64_C(0x4000000000000000); - } - shift128RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 ); - aSig0 |=3D UINT64_C(0x4000000000000000); - aBigger: - sub128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); - zExp =3D aExp; - normalizeRoundAndPack: - --zExp; - return normalizeRoundAndPackFloat128(zSign, zExp - 14, zSig0, zSig1, - status); - -} - -/*------------------------------------------------------------------------= ---- -| Returns the result of adding the quadruple-precision floating-point valu= es -| `a' and `b'. The operation is performed according to the IEC/IEEE Stand= ard -| for Binary Floating-Point Arithmetic. -*-------------------------------------------------------------------------= ---*/ - -float128 float128_add(float128 a, float128 b, float_status *status) -{ - bool aSign, bSign; - - aSign =3D extractFloat128Sign( a ); - bSign =3D extractFloat128Sign( b ); - if ( aSign =3D=3D bSign ) { - return addFloat128Sigs(a, b, aSign, status); - } - else { - return subFloat128Sigs(a, b, aSign, status); - } - -} - -/*------------------------------------------------------------------------= ---- -| Returns the result of subtracting the quadruple-precision floating-point -| values `a' and `b'. The operation is performed according to the IEC/IEEE -| Standard for Binary Floating-Point Arithmetic. -*-------------------------------------------------------------------------= ---*/ - -float128 float128_sub(float128 a, float128 b, float_status *status) -{ - bool aSign, bSign; - - aSign =3D extractFloat128Sign( a ); - bSign =3D extractFloat128Sign( b ); - if ( aSign =3D=3D bSign ) { - return subFloat128Sigs(a, b, aSign, status); - } - else { - return addFloat128Sigs(a, b, aSign, status); - } - -} - /*------------------------------------------------------------------------= ---- | Returns the result of multiplying the quadruple-precision floating-point | values `a' and `b'. The operation is performed according to the IEC/IEEE diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index c2f87addb2..347896bf57 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -125,6 +125,16 @@ static bool parts_is_snan_frac(uint64_t frac, float_st= atus *status) } } =20 +static bool parts128_is_snan_frac(Uint128 frac, float_status *status) +{ + if (no_signaling_nans(status)) { + return false; + } else { + bool msb =3D extract128(frac, DECOMPOSED128_BINARY_POINT - 1, 1); + return msb =3D=3D snan_bit_is_one(status); + } +} + /*------------------------------------------------------------------------= ---- | The pattern for a default generated deconstructed floating-point NaN. *-------------------------------------------------------------------------= ---*/ @@ -169,6 +179,23 @@ static FloatParts parts_default_nan(float_status *stat= us) }; } =20 +static FloatParts128 parts128_default_nan(float_status *status) +{ + bool sign =3D 0; + Uint128 frac; + + /* !snan_bit_is_one, set sign and msb */ + frac =3D uint128_lshift(1, DECOMPOSED128_BINARY_POINT - 1); + sign =3D 1; + + return (FloatParts128) { + .cls =3D float_class_qnan, + .sign =3D sign, + .exp =3D INT_MAX, + .frac =3D frac + }; +} + /*------------------------------------------------------------------------= ---- | Returns a quiet NaN from a signalling NaN for the deconstructed | floating-point parts. @@ -191,6 +218,18 @@ static FloatParts parts_silence_nan(FloatParts a, floa= t_status *status) return a; } =20 +static FloatParts128 parts128_silence_nan(FloatParts128 a, float_status *s= tatus) +{ + g_assert(!no_signaling_nans(status)); + if (snan_bit_is_one(status)) { + return parts128_default_nan(status); + } else { + a.frac =3D uint128_or(a.frac, int128_lshift(1, DECOMPOSED128_BINAR= Y_POINT - 1)); + } + a.cls =3D float_class_qnan; + return a; +} + /*------------------------------------------------------------------------= ---- | The pattern for a default generated extended double-precision NaN. *-------------------------------------------------------------------------= ---*/ --=20 2.20.1