Utest: Refine half and float convert functions.

Submitted by junyan.he@inbox.com on Dec. 27, 2016, 3:34 a.m.

Details

Message ID 1482809667-31065-1-git-send-email-junyan.he@inbox.com
State New
Headers show
Series "Utest: Refine half and float convert functions." ( rev: 1 ) in Beignet

Not browsing as part of any series.

Commit Message

junyan.he@inbox.com Dec. 27, 2016, 3:34 a.m.
From: Junyan He <junyan.he@intel.com>

Signed-off-by: Junyan He <junyan.he@intel.com>
---
 utests/utest_helper.cpp | 171 +++++++++++++++++++++++++-----------------------
 1 file changed, 90 insertions(+), 81 deletions(-)

Patch hide | download patch | download mbox

diff --git a/utests/utest_helper.cpp b/utests/utest_helper.cpp
index f1a4bdd..b57d2ad 100644
--- a/utests/utest_helper.cpp
+++ b/utests/utest_helper.cpp
@@ -992,110 +992,119 @@  int cl_check_half(void)
   return 1;
 }
 
-uint32_t __half_to_float(uint16_t h, bool* isInf, bool* infSign)
+uint32_t __half_to_float(uint16_t h, bool *isInf, bool *infSign)
 {
-  struct __FP32 {
-    uint32_t mantissa:23;
-    uint32_t exponent:8;
-    uint32_t sign:1;
-  };
-  struct __FP16 {
-    uint32_t mantissa:10;
-    uint32_t exponent:5;
-    uint32_t sign:1;
-  };
-  uint32_t f;
-  __FP32 o;
-  memset(&o, 0, sizeof(o));
-  __FP16 i;
-  memcpy(&i, &h, sizeof(uint16_t));
+  uint32_t out_val = 0;
+  uint16_t sign = (h & 0x8000) >> 15;
+  uint16_t exp = (h & 0x7c00) >> 10;
+  uint16_t fraction = h & 0x03ff;
 
   if (isInf)
     *isInf = false;
   if (infSign)
     *infSign = false;
 
-  if (i.exponent == 0 && i.mantissa == 0) // (Signed) zero
-    o.sign = i.sign;
-  else {
-    if (i.exponent == 0) { // Denormal (converts to normalized)
-      // Adjust mantissa so it's normalized (and keep
-      // track of exponent adjustment)
-      int e = -1;
-      uint m = i.mantissa;
-      do {
-        e++;
-        m <<= 1;
-      } while ((m & 0x400) == 0);
-
-      o.mantissa = (m & 0x3ff) << 13;
-      o.exponent = 127 - 15 - e;
-      o.sign = i.sign;
-    } else if (i.exponent == 0x1f) { // Inf/NaN
-      // NOTE: Both can be handled with same code path
-      // since we just pass through mantissa bits.
-      o.mantissa = i.mantissa << 13;
-      o.exponent = 255;
-      o.sign = i.sign;
-
-      if (isInf) {
-        *isInf = (i.mantissa == 0);
-        if (infSign)
-          *infSign = !i.sign;
-      }
-    } else { // Normalized number
-      o.mantissa = i.mantissa << 13;
-      o.exponent = 127 - 15 + i.exponent;
-      o.sign = i.sign;
+  if (exp == 0 && fraction == 0) { // (Signed) zero
+    return (sign << 31);
+  }
+
+  if (exp == 0) { // subnormal mode
+    assert(fraction > 0);
+    exp = -1;
+    do {
+      fraction = fraction << 1;
+      exp++;
+    } while ((fraction & 0x400) == 0);
+    exp = 127 - exp - 15;
+    out_val = (sign << 31) | ((exp & 0xff) << 23) | ((fraction & 0x3ff) << 13);
+    return out_val;
+  }
+
+  if (exp == 0x1f) {     // inf or NAN
+    if (fraction == 0) { // inf
+      out_val = (sign << 31) | (255 << 23);
+      if (isInf)
+        *isInf = true;
+      if (infSign)
+        *infSign = (sign == 0) ? 1 : 0;
+
+      return out_val;
+    } else { // NAN mode
+      out_val = (sign << 31) | (255 << 23) | 0x7fffff;
+      return out_val;
     }
   }
 
-  memcpy(&f, &o, sizeof(uint32_t));
-  return f;
+  // Easy case, just convert.
+  exp = 127 - 15 + exp;
+  out_val = (sign << 31) | ((exp & 0xff) << 23) | ((fraction & 0x3ff) << 13);
+  return out_val;
 }
 
-
 uint16_t __float_to_half(uint32_t x)
 {
-  uint16_t bits = (x >> 16) & 0x8000; /* Get the sign */
-  uint16_t m = (x >> 12) & 0x07ff; /* Keep one extra bit for rounding */
-  unsigned int e = (x >> 23) & 0xff; /* Using int is faster here */
-
-  /* If zero, or denormal, or exponent underflows too much for a denormal
-   * half, return signed zero. */
-  if (e < 103)
-    return bits;
-
-  /* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
-  if (e > 142) {
-    bits |= 0x7c00u;
-    /* If exponent was 0xff and one mantissa bit was set, it means NaN,
-     * not Inf, so make sure we set one mantissa bit too. */
-    bits |= e == 255 && (x & 0x007fffffu);
-    return bits;
+  uint16_t sign = (x & 0x80000000) >> 31;
+  uint16_t exp = (x & 0x7F800000) >> 23;
+  uint32_t fraction = (x & 0x7fffff);
+  uint16_t out_val = 0;
+
+  /* Handle the float NAN format. */
+  if (exp == 0xFF && fraction != 0) {
+    /* return a NAN half. */
+    out_val = (sign << 15) | (0x7C00) | (fraction & 0x3ff);
+    return out_val;
   }
 
-  /* If exponent underflows but not too much, return a denormal */
-  if (e < 113) {
-    m |= 0x0800u;
-    /* Extra rounding may overflow and set mantissa to 0 and exponent
-     * to 1, which is OK. */
-    bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1);
-    return bits;
+  /* Float exp is from -126~127, half exp is from -14~15 */
+  if (exp - 127 > 15) { // Should overflow.
+    /* return +- inf. */
+    out_val = (sign << 15) | (0x7C00);
+    return out_val;
   }
 
-  bits |= ((e - 112) << 10) | (m >> 1);
-  /* Extra rounding. An overflow will set mantissa to 0 and increment
-   * the exponent, which is OK. */
-  bits += m & 1;
-  return bits;
+  /* half has 10 bits fraction, so have chance to convet to
+     (-1)^sign X 2^(-14) X 0.fraction form. But if the
+     exp - 127 < -14 - 10, we must have unerflow. */
+  if (exp < -14 + 127 - 10) { // Should underflow.
+    /* Return zero without subnormal numbers. */
+    out_val = (sign << 15);
+    return out_val;
+  }
+
+  if (exp < -14 + 127) { //May underflow, but may use subnormal numbers
+    int shift = -(exp - 127 + 14);
+    assert(shift > 0);
+    assert(shift <= 10);
+    fraction = fraction | 0x0800000; // in 1.significantbits2, add the 1
+    fraction = fraction >> shift;
+    // To half fraction
+    fraction = (fraction & 0x7ff000) >> 12;
+    out_val = (sign << 15) | ((fraction >> 1) & 0x3ff);
+    if (fraction & 0x01)
+      out_val++;
+    return out_val;
+  }
+
+  /* Easy case, just convert. */
+  fraction = (fraction & 0x7ff000) >> 12;
+  exp = exp - 127 + 15;
+  assert(exp > 0);
+  assert(exp < 0x01f);
+  out_val = (sign << 15) | (exp << 10) | ((fraction >> 1) & 0x3ff);
+  if (fraction & 0x01)
+    out_val++;
+  return out_val;
 }
-uint32_t as_uint(float f) {
+
+uint32_t as_uint(float f)
+{
   union uint32_cast _tmp;
   _tmp._float = f;
   return _tmp._uint;
 }
-float as_float(uint32_t i) {
+
+float as_float(uint32_t i)
+{
   union uint32_cast _tmp;
   _tmp._uint = i;
   return _tmp._float;

Comments

LGTM, pushed, thanks.

> -----Original Message-----

> From: Beignet [mailto:beignet-bounces@lists.freedesktop.org] On Behalf Of

> junyan.he@inbox.com

> Sent: Tuesday, December 27, 2016 11:34

> To: beignet@lists.freedesktop.org

> Subject: [Beignet] [PATCH] Utest: Refine half and float convert functions.

> 

> From: Junyan He <junyan.he@intel.com>

> 

> Signed-off-by: Junyan He <junyan.he@intel.com>

> ---

>  utests/utest_helper.cpp | 171 +++++++++++++++++++++++++----------------

> -------

>  1 file changed, 90 insertions(+), 81 deletions(-)

> 

> diff --git a/utests/utest_helper.cpp b/utests/utest_helper.cpp index

> f1a4bdd..b57d2ad 100644

> --- a/utests/utest_helper.cpp

> +++ b/utests/utest_helper.cpp

> @@ -992,110 +992,119 @@ int cl_check_half(void)

>    return 1;

>  }

> 

> -uint32_t __half_to_float(uint16_t h, bool* isInf, bool* infSign)

> +uint32_t __half_to_float(uint16_t h, bool *isInf, bool *infSign)

>  {

> -  struct __FP32 {

> -    uint32_t mantissa:23;

> -    uint32_t exponent:8;

> -    uint32_t sign:1;

> -  };

> -  struct __FP16 {

> -    uint32_t mantissa:10;

> -    uint32_t exponent:5;

> -    uint32_t sign:1;

> -  };

> -  uint32_t f;

> -  __FP32 o;

> -  memset(&o, 0, sizeof(o));

> -  __FP16 i;

> -  memcpy(&i, &h, sizeof(uint16_t));

> +  uint32_t out_val = 0;

> +  uint16_t sign = (h & 0x8000) >> 15;

> +  uint16_t exp = (h & 0x7c00) >> 10;

> +  uint16_t fraction = h & 0x03ff;

> 

>    if (isInf)

>      *isInf = false;

>    if (infSign)

>      *infSign = false;

> 

> -  if (i.exponent == 0 && i.mantissa == 0) // (Signed) zero

> -    o.sign = i.sign;

> -  else {

> -    if (i.exponent == 0) { // Denormal (converts to normalized)

> -      // Adjust mantissa so it's normalized (and keep

> -      // track of exponent adjustment)

> -      int e = -1;

> -      uint m = i.mantissa;

> -      do {

> -        e++;

> -        m <<= 1;

> -      } while ((m & 0x400) == 0);

> -

> -      o.mantissa = (m & 0x3ff) << 13;

> -      o.exponent = 127 - 15 - e;

> -      o.sign = i.sign;

> -    } else if (i.exponent == 0x1f) { // Inf/NaN

> -      // NOTE: Both can be handled with same code path

> -      // since we just pass through mantissa bits.

> -      o.mantissa = i.mantissa << 13;

> -      o.exponent = 255;

> -      o.sign = i.sign;

> -

> -      if (isInf) {

> -        *isInf = (i.mantissa == 0);

> -        if (infSign)

> -          *infSign = !i.sign;

> -      }

> -    } else { // Normalized number

> -      o.mantissa = i.mantissa << 13;

> -      o.exponent = 127 - 15 + i.exponent;

> -      o.sign = i.sign;

> +  if (exp == 0 && fraction == 0) { // (Signed) zero

> +    return (sign << 31);

> +  }

> +

> +  if (exp == 0) { // subnormal mode

> +    assert(fraction > 0);

> +    exp = -1;

> +    do {

> +      fraction = fraction << 1;

> +      exp++;

> +    } while ((fraction & 0x400) == 0);

> +    exp = 127 - exp - 15;

> +    out_val = (sign << 31) | ((exp & 0xff) << 23) | ((fraction & 0x3ff) << 13);

> +    return out_val;

> +  }

> +

> +  if (exp == 0x1f) {     // inf or NAN

> +    if (fraction == 0) { // inf

> +      out_val = (sign << 31) | (255 << 23);

> +      if (isInf)

> +        *isInf = true;

> +      if (infSign)

> +        *infSign = (sign == 0) ? 1 : 0;

> +

> +      return out_val;

> +    } else { // NAN mode

> +      out_val = (sign << 31) | (255 << 23) | 0x7fffff;

> +      return out_val;

>      }

>    }

> 

> -  memcpy(&f, &o, sizeof(uint32_t));

> -  return f;

> +  // Easy case, just convert.

> +  exp = 127 - 15 + exp;

> +  out_val = (sign << 31) | ((exp & 0xff) << 23) | ((fraction & 0x3ff)

> + << 13);  return out_val;

>  }

> 

> -

>  uint16_t __float_to_half(uint32_t x)

>  {

> -  uint16_t bits = (x >> 16) & 0x8000; /* Get the sign */

> -  uint16_t m = (x >> 12) & 0x07ff; /* Keep one extra bit for rounding */

> -  unsigned int e = (x >> 23) & 0xff; /* Using int is faster here */

> -

> -  /* If zero, or denormal, or exponent underflows too much for a denormal

> -   * half, return signed zero. */

> -  if (e < 103)

> -    return bits;

> -

> -  /* If NaN, return NaN. If Inf or exponent overflow, return Inf. */

> -  if (e > 142) {

> -    bits |= 0x7c00u;

> -    /* If exponent was 0xff and one mantissa bit was set, it means NaN,

> -     * not Inf, so make sure we set one mantissa bit too. */

> -    bits |= e == 255 && (x & 0x007fffffu);

> -    return bits;

> +  uint16_t sign = (x & 0x80000000) >> 31;  uint16_t exp = (x &

> + 0x7F800000) >> 23;  uint32_t fraction = (x & 0x7fffff);  uint16_t

> + out_val = 0;

> +

> +  /* Handle the float NAN format. */

> +  if (exp == 0xFF && fraction != 0) {

> +    /* return a NAN half. */

> +    out_val = (sign << 15) | (0x7C00) | (fraction & 0x3ff);

> +    return out_val;

>    }

> 

> -  /* If exponent underflows but not too much, return a denormal */

> -  if (e < 113) {

> -    m |= 0x0800u;

> -    /* Extra rounding may overflow and set mantissa to 0 and exponent

> -     * to 1, which is OK. */

> -    bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1);

> -    return bits;

> +  /* Float exp is from -126~127, half exp is from -14~15 */  if (exp -

> + 127 > 15) { // Should overflow.

> +    /* return +- inf. */

> +    out_val = (sign << 15) | (0x7C00);

> +    return out_val;

>    }

> 

> -  bits |= ((e - 112) << 10) | (m >> 1);

> -  /* Extra rounding. An overflow will set mantissa to 0 and increment

> -   * the exponent, which is OK. */

> -  bits += m & 1;

> -  return bits;

> +  /* half has 10 bits fraction, so have chance to convet to

> +     (-1)^sign X 2^(-14) X 0.fraction form. But if the

> +     exp - 127 < -14 - 10, we must have unerflow. */  if (exp < -14 +

> + 127 - 10) { // Should underflow.

> +    /* Return zero without subnormal numbers. */

> +    out_val = (sign << 15);

> +    return out_val;

> +  }

> +

> +  if (exp < -14 + 127) { //May underflow, but may use subnormal numbers

> +    int shift = -(exp - 127 + 14);

> +    assert(shift > 0);

> +    assert(shift <= 10);

> +    fraction = fraction | 0x0800000; // in 1.significantbits2, add the 1

> +    fraction = fraction >> shift;

> +    // To half fraction

> +    fraction = (fraction & 0x7ff000) >> 12;

> +    out_val = (sign << 15) | ((fraction >> 1) & 0x3ff);

> +    if (fraction & 0x01)

> +      out_val++;

> +    return out_val;

> +  }

> +

> +  /* Easy case, just convert. */

> +  fraction = (fraction & 0x7ff000) >> 12;  exp = exp - 127 + 15;

> + assert(exp > 0);  assert(exp < 0x01f);  out_val = (sign << 15) | (exp

> + << 10) | ((fraction >> 1) & 0x3ff);  if (fraction & 0x01)

> +    out_val++;

> +  return out_val;

>  }

> -uint32_t as_uint(float f) {

> +

> +uint32_t as_uint(float f)

> +{

>    union uint32_cast _tmp;

>    _tmp._float = f;

>    return _tmp._uint;

>  }

> -float as_float(uint32_t i) {

> +

> +float as_float(uint32_t i)

> +{

>    union uint32_cast _tmp;

>    _tmp._uint = i;

>    return _tmp._float;

> --

> 2.7.4

> 

> 

> 

> _______________________________________________

> Beignet mailing list

> Beignet@lists.freedesktop.org

> https://lists.freedesktop.org/mailman/listinfo/beignet