From patchwork Tue Dec 31 13:35:48 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 22850 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ve0-f200.google.com (mail-ve0-f200.google.com [209.85.128.200]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id E6D0E218CC for ; Tue, 31 Dec 2013 13:58:17 +0000 (UTC) Received: by mail-ve0-f200.google.com with SMTP id jw12sf16088806veb.3 for ; Tue, 31 Dec 2013 05:58:16 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :list-post:list-help:list-archive:list-unsubscribe; bh=yAH5iXtW/flstbM78zUplvTi2gDLj7TDJgi1pd3GWng=; b=bxoRZmy8lbFRTbcU+nUHLh8Q2Dku/9DtXMN9NTjWcUSv9arXhuz1YaSpPWXb7LYDF+ GWtkt5AwHASNj41v5AR4bLECKKDYYp/rjIo3vNHqwcCMuCuYx1GgD1/Dvizg9SseZ7B5 B2kzI01kv1x0QDmujNqFpDs9kF7QFmoTRwOqDLJOp7OWMOZsDVB0DVht3fcTEqGBphRI iXnlYf1vuSn1n9kIbmZZ2bJFYPFv+/w5sQ/Ke+9b04kDCHFYb1QEyY4EnYqM1bYf6Zml c+HPTUKrWETfg9ovwQUYu65dhWFONIcxfi6Au94uz4fyOINzt+1Owh13/HNy5nYMCn74 pwJA== X-Gm-Message-State: ALoCoQnKWhGzugrr2WFoxbguYkwr40K8/yf/Af2M20uUehkwvG3Qj14zIc8lxCKnvMAAhFnGu+o+ X-Received: by 10.58.118.231 with SMTP id kp7mr5443155veb.36.1388498296579; Tue, 31 Dec 2013 05:58:16 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.71.237 with SMTP id y13ls3981132qeu.2.gmail; Tue, 31 Dec 2013 05:58:16 -0800 (PST) X-Received: by 10.52.96.99 with SMTP id dr3mr302574vdb.69.1388498296417; Tue, 31 Dec 2013 05:58:16 -0800 (PST) Received: from mail-ve0-f170.google.com (mail-ve0-f170.google.com [209.85.128.170]) by mx.google.com with ESMTPS id ef6si19152888ved.123.2013.12.31.05.58.16 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Tue, 31 Dec 2013 05:58:16 -0800 (PST) Received-SPF: neutral (google.com: 209.85.128.170 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.128.170; Received: by mail-ve0-f170.google.com with SMTP id oy12so6538020veb.15 for ; Tue, 31 Dec 2013 05:58:16 -0800 (PST) X-Received: by 10.220.248.202 with SMTP id mh10mr340984vcb.70.1388498296268; Tue, 31 Dec 2013 05:58:16 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.59.13.131 with SMTP id ey3csp666030ved; Tue, 31 Dec 2013 05:58:15 -0800 (PST) X-Received: by 10.180.90.37 with SMTP id bt5mr48298289wib.43.1388498295032; Tue, 31 Dec 2013 05:58:15 -0800 (PST) Received: from mnementh.archaic.org.uk (mnementh.archaic.org.uk. [2001:8b0:1d0::1]) by mx.google.com with ESMTPS id je1si14618622wic.5.2013.12.31.05.58.13 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Tue, 31 Dec 2013 05:58:14 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of pm215@archaic.org.uk designates 2001:8b0:1d0::1 as permitted sender) client-ip=2001:8b0:1d0::1; Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.80) (envelope-from ) id 1VxzUE-0000wR-RO; Tue, 31 Dec 2013 13:35:58 +0000 From: Peter Maydell To: qemu-devel@nongnu.org Cc: patches@linaro.org, Alexander Graf , Michael Matz , Claudio Fontana , Dirk Mueller , Laurent Desnogues , kvmarm@lists.cs.columbia.edu, Richard Henderson , =?UTF-8?q?Alex=20Benn=C3=A9e?= , Christoffer Dall , Will Newton , Peter Crosthwaite , Tom Musta , Aurelien Jarno Subject: [PATCH 12/22] softfloat: Factor out RoundAndPackFloat16 and NormalizeFloat16Subnormal Date: Tue, 31 Dec 2013 13:35:48 +0000 Message-Id: <1388496958-3542-13-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.10.4 In-Reply-To: <1388496958-3542-1-git-send-email-peter.maydell@linaro.org> References: <1388496958-3542-1-git-send-email-peter.maydell@linaro.org> X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: peter.maydell@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.128.170 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , In preparation for adding conversions between float16 and float64, factor out code currently done inline in the float16<=>float32 conversion functions into functions RoundAndPackFloat16 and NormalizeFloat16Subnormal along the lines of the existing versions for the other float types. Note that we change the handling of zExp from the inline code to match the API of the other RoundAndPackFloat functions; however we leave the positioning of the binary point between bits 22 and 23 rather than shifting it up to the high end of the word. Signed-off-by: Peter Maydell --- fpu/softfloat.c | 209 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 125 insertions(+), 84 deletions(-) diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 495f46f..925db05 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -3084,6 +3084,127 @@ static float16 packFloat16(flag zSign, int_fast16_t zExp, uint16_t zSig) (((uint32_t)zSign) << 15) + (((uint32_t)zExp) << 10) + zSig); } +/*---------------------------------------------------------------------------- +| Takes an abstract floating-point value having sign `zSign', exponent `zExp', +| and significand `zSig', and returns the proper half-precision floating- +| point value corresponding to the abstract input. Ordinarily, the abstract +| value is simply rounded and packed into the half-precision format, with +| the inexact exception raised if the abstract input cannot be represented +| exactly. However, if the abstract value is too large, the overflow and +| inexact exceptions are raised and an infinity or maximal finite value is +| returned. If the abstract value is too small, the input value is rounded to +| a subnormal number, and the underflow and inexact exceptions are raised if +| the abstract input cannot be represented exactly as a subnormal half- +| precision floating-point number. +| The `ieee' flag indicates whether to use IEEE standard half precision, or +| ARM-style "alternative representation", which omits the NaN and Inf +| encodings in order to raise the maximum representable exponent by one. +| The input significand `zSig' has its binary point between bits 22 +| and 23, which is 13 bits to the left of the usual location. This shifted +| significand must be normalized or smaller. If `zSig' is not normalized, +| `zExp' must be 0; in that case, the result returned is a subnormal number, +| and it must not require rounding. In the usual case that `zSig' is +| normalized, `zExp' must be 1 less than the ``true'' floating-point exponent. +| Note the slightly odd position of the binary point in zSig compared with the +| other roundAndPackFloat functions. This should probably be fixed if we +| need to implement more float16 routines than just conversion. +| The handling of underflow and overflow follows the IEC/IEEE Standard for +| Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +static float32 roundAndPackFloat16(flag zSign, int_fast16_t zExp, + uint32_t zSig, flag ieee STATUS_PARAM) +{ + int maxexp = ieee ? 29 : 30; + uint32_t mask; + uint32_t increment; + int8 roundingMode; + bool rounding_bumps_exp; + bool is_tiny = false; + + /* Calculate the mask of bits of the mantissa which are not + * representable in half-precision and will be lost. + */ + if (zExp < 1) { + /* Will be denormal in halfprec */ + mask = 0x00ffffff; + if (zExp >= -11) { + mask >>= 11 + zExp; + } + } else { + /* Normal number in halfprec */ + mask = 0x00001fff; + } + + roundingMode = STATUS(float_rounding_mode); + switch (roundingMode) { + case float_round_nearest_even: + increment = (mask + 1) >> 1; + if ((zSig & mask) == increment) { + increment = zSig & (increment << 1); + } + break; + case float_round_up: + increment = zSign ? 0 : mask; + break; + case float_round_down: + increment = zSign ? mask : 0; + break; + default: /* round_to_zero */ + increment = 0; + break; + } + + rounding_bumps_exp = (zSig + increment >= 0x01000000); + + if (zExp > maxexp || (zExp == maxexp && rounding_bumps_exp)) { + if (ieee) { + float_raise(float_flag_overflow | float_flag_inexact STATUS_VAR); + return packFloat16(zSign, 0x1f, 0); + } else { + float_raise(float_flag_invalid STATUS_VAR); + return packFloat16(zSign, 0x1f, 0x3ff); + } + } + + if (zExp < 0) { + /* Note that flush-to-zero does not affect half-precision results */ + is_tiny = + (STATUS(float_detect_tininess) == float_tininess_before_rounding) + || (zExp < -1) + || (!rounding_bumps_exp); + } + if (zSig & mask) { + float_raise(float_flag_inexact STATUS_VAR); + if (is_tiny) { + float_raise(float_flag_underflow STATUS_VAR); + } + } + + zSig += increment; + if (rounding_bumps_exp) { + zSig >>= 1; + zExp++; + } + + if (zExp < -10) { + return packFloat16(zSign, 0, 0); + } + if (zExp < 0) { + zSig >>= -zExp; + zExp = 0; + } + return packFloat16(zSign, zExp, zSig >> 13); +} + +static void normalizeFloat16Subnormal(uint32_t aSig, int_fast16_t *zExpPtr, + uint32_t *zSigPtr) +{ + int8_t shiftCount = countLeadingZeros32(aSig) - 21; + *zSigPtr = aSig << shiftCount; + *zExpPtr = 1 - shiftCount; +} + /* Half precision floats come in two formats: standard IEEE and "ARM" format. The latter gains extra exponent range by omitting the NaN/Inf encodings. */ @@ -3104,15 +3225,12 @@ float32 float16_to_float32(float16 a, flag ieee STATUS_PARAM) return packFloat32(aSign, 0xff, 0); } if (aExp == 0) { - int8 shiftCount; - if (aSig == 0) { return packFloat32(aSign, 0, 0); } - shiftCount = countLeadingZeros32( aSig ) - 21; - aSig = aSig << shiftCount; - aExp = -shiftCount; + normalizeFloat16Subnormal(aSig, &aExp, &aSig); + aExp--; } return packFloat32( aSign, aExp + 0x70, aSig << 13); } @@ -3122,12 +3240,6 @@ float16 float32_to_float16(float32 a, flag ieee STATUS_PARAM) flag aSign; int_fast16_t aExp; uint32_t aSig; - uint32_t mask; - uint32_t increment; - int8 roundingMode; - int maxexp = ieee ? 15 : 16; - bool rounding_bumps_exp; - bool is_tiny = false; a = float32_squash_input_denormal(a STATUS_VAR); @@ -3162,80 +3274,9 @@ float16 float32_to_float16(float32 a, flag ieee STATUS_PARAM) * codepath. */ aSig |= 0x00800000; - aExp -= 0x7f; - /* Calculate the mask of bits of the mantissa which are not - * representable in half-precision and will be lost. - */ - if (aExp < -14) { - /* Will be denormal in halfprec */ - mask = 0x00ffffff; - if (aExp >= -24) { - mask >>= 25 + aExp; - } - } else { - /* Normal number in halfprec */ - mask = 0x00001fff; - } + aExp -= 0x71; - roundingMode = STATUS(float_rounding_mode); - switch (roundingMode) { - case float_round_nearest_even: - increment = (mask + 1) >> 1; - if ((aSig & mask) == increment) { - increment = aSig & (increment << 1); - } - break; - case float_round_up: - increment = aSign ? 0 : mask; - break; - case float_round_down: - increment = aSign ? mask : 0; - break; - default: /* round_to_zero */ - increment = 0; - break; - } - - rounding_bumps_exp = (aSig + increment >= 0x01000000); - - if (aExp > maxexp || (aExp == maxexp && rounding_bumps_exp)) { - if (ieee) { - float_raise(float_flag_overflow | float_flag_inexact STATUS_VAR); - return packFloat16(aSign, 0x1f, 0); - } else { - float_raise(float_flag_invalid STATUS_VAR); - return packFloat16(aSign, 0x1f, 0x3ff); - } - } - - if (aExp < -14) { - /* Note that flush-to-zero does not affect half-precision results */ - is_tiny = - (STATUS(float_detect_tininess) == float_tininess_before_rounding) - || (aExp < -15) - || (!rounding_bumps_exp); - } - if (aSig & mask) { - float_raise(float_flag_inexact STATUS_VAR); - if (is_tiny) { - float_raise(float_flag_underflow STATUS_VAR); - } - } - - aSig += increment; - if (rounding_bumps_exp) { - aSig >>= 1; - aExp++; - } - - if (aExp < -24) { - return packFloat16(aSign, 0, 0); - } - if (aExp < -14) { - aSig >>= -14 - aExp; - aExp = -14; - } - return packFloat16(aSign, aExp + 14, aSig >> 13); + return roundAndPackFloat16(aSign, aExp, aSig, ieee STATUS_VAR); } /*----------------------------------------------------------------------------