qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Peter Maydell <peter.maydell@linaro.org>
To: qemu-devel@nongnu.org
Cc: "Tom Musta" <tommusta@gmail.com>,
	"Peter Crosthwaite" <peter.crosthwaite@xilinx.com>,
	patches@linaro.org, "Aurelien Jarno" <aurelien@aurel32.net>,
	"Michael Matz" <matz@suse.de>, "Alexander Graf" <agraf@suse.de>,
	"Claudio Fontana" <claudio.fontana@linaro.org>,
	"Dirk Mueller" <dmueller@suse.de>,
	"Will Newton" <will.newton@linaro.org>,
	"Laurent Desnogues" <laurent.desnogues@gmail.com>,
	"Alex Bennée" <alex.bennee@linaro.org>,
	kvmarm@lists.cs.columbia.edu,
	"Christoffer Dall" <christoffer.dall@linaro.org>,
	"Richard Henderson" <rth@twiddle.net>
Subject: [Qemu-devel] [PATCH 12/22] softfloat: Factor out RoundAndPackFloat16 and NormalizeFloat16Subnormal
Date: Tue, 31 Dec 2013 13:35:48 +0000	[thread overview]
Message-ID: <1388496958-3542-13-git-send-email-peter.maydell@linaro.org> (raw)
In-Reply-To: <1388496958-3542-1-git-send-email-peter.maydell@linaro.org>

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 <peter.maydell@linaro.org>
---
 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);
 }
 
 /*----------------------------------------------------------------------------
-- 
1.8.5

  parent reply	other threads:[~2013-12-31 13:58 UTC|newest]

Thread overview: 42+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-12-31 13:35 [Qemu-devel] [PATCH 00/22] A64 decoder patchset 6: rest of floating point Peter Maydell
2013-12-31 13:35 ` [Qemu-devel] [PATCH 01/22] softfloat: Fix exception flag handling for float32_to_float16() Peter Maydell
2013-12-31 13:35 ` [Qemu-devel] [PATCH 02/22] softfloat: Add float to 16bit integer conversions Peter Maydell
2013-12-31 14:18   ` Richard Henderson
2013-12-31 14:22     ` Peter Maydell
2013-12-31 14:29       ` Richard Henderson
2013-12-31 13:35 ` [Qemu-devel] [PATCH 03/22] softfloat: Add 16 bit integer to float conversions Peter Maydell
2013-12-31 14:21   ` Richard Henderson
2013-12-31 14:27     ` Peter Maydell
2013-12-31 14:35       ` Richard Henderson
2013-12-31 14:45         ` Peter Maydell
2013-12-31 13:35 ` [Qemu-devel] [PATCH 04/22] softfloat: Fix float64_to_uint64 Peter Maydell
2013-12-31 13:35 ` [Qemu-devel] [PATCH 05/22] softfloat: Only raise Invalid when conversions to int are out of range Peter Maydell
2013-12-31 13:35 ` [Qemu-devel] [PATCH 06/22] softfloat: Fix factor 2 error for scalbn on denormal inputs Peter Maydell
2013-12-31 13:35 ` [Qemu-devel] [PATCH 07/22] softfloat: Add float32_to_uint64() Peter Maydell
2013-12-31 13:35 ` [Qemu-devel] [PATCH 08/22] softfloat: Fix float64_to_uint64_round_to_zero Peter Maydell
2013-12-31 14:23   ` Richard Henderson
2013-12-31 13:35 ` [Qemu-devel] [PATCH 09/22] softfloat: Fix float64_to_uint32 Peter Maydell
2013-12-31 14:24   ` Richard Henderson
2013-12-31 13:35 ` [Qemu-devel] [PATCH 10/22] softfloat: Fix float64_to_uint32_round_to_zero Peter Maydell
2013-12-31 14:24   ` Richard Henderson
2013-12-31 13:35 ` [Qemu-devel] [PATCH 11/22] softfloat: Provide complete set of accessors for fp state Peter Maydell
2013-12-31 14:26   ` Richard Henderson
2013-12-31 13:35 ` Peter Maydell [this message]
2013-12-31 13:35 ` [Qemu-devel] [PATCH 13/22] softfloat: Add float16 <=> float64 conversion functions Peter Maydell
2013-12-31 13:35 ` [Qemu-devel] [PATCH 14/22] softfloat: Add support for ties-away rounding Peter Maydell
2013-12-31 14:51   ` Richard Henderson
2013-12-31 14:56     ` Peter Maydell
2013-12-31 14:59       ` Richard Henderson
2013-12-31 13:35 ` [Qemu-devel] [PATCH 15/22] target-arm: Prepare VFP_CONV_FIX helpers for A64 uses Peter Maydell
2013-12-31 15:00   ` Richard Henderson
2013-12-31 13:35 ` [Qemu-devel] [PATCH 16/22] target-arm: Rename A32 VFP conversion helpers Peter Maydell
2013-12-31 15:04   ` Richard Henderson
2013-12-31 13:35 ` [Qemu-devel] [PATCH 17/22] target-arm: Ignore most exceptions from scalbn when doing fixpoint conversion Peter Maydell
2013-12-31 15:17   ` Richard Henderson
2013-12-31 13:35 ` [Qemu-devel] [PATCH 18/22] target-arm: A64: Add extra VFP fixed point conversion helpers Peter Maydell
2013-12-31 15:18   ` Richard Henderson
2013-12-31 13:35 ` [Qemu-devel] [PATCH 19/22] target-arm: A64: Add "Floating-point<->fixed-point" instructions Peter Maydell
2013-12-31 13:35 ` [Qemu-devel] [PATCH 20/22] target-arm: A64: Add floating-point<->integer conversion instructions Peter Maydell
2013-12-31 13:35 ` [Qemu-devel] [PATCH 21/22] target-arm: A64: Add 1-source 32-to-32 and 64-to-64 FP instructions Peter Maydell
2013-12-31 13:35 ` [Qemu-devel] [PATCH 22/22] target-arm: A64: Add support for FCVT between half, single and double Peter Maydell
2014-01-02 19:12 ` [Qemu-devel] [PATCH 00/22] A64 decoder patchset 6: rest of floating point Tom Musta

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1388496958-3542-13-git-send-email-peter.maydell@linaro.org \
    --to=peter.maydell@linaro.org \
    --cc=agraf@suse.de \
    --cc=alex.bennee@linaro.org \
    --cc=aurelien@aurel32.net \
    --cc=christoffer.dall@linaro.org \
    --cc=claudio.fontana@linaro.org \
    --cc=dmueller@suse.de \
    --cc=kvmarm@lists.cs.columbia.edu \
    --cc=laurent.desnogues@gmail.com \
    --cc=matz@suse.de \
    --cc=patches@linaro.org \
    --cc=peter.crosthwaite@xilinx.com \
    --cc=qemu-devel@nongnu.org \
    --cc=rth@twiddle.net \
    --cc=tommusta@gmail.com \
    --cc=will.newton@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).