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

Yang, Rong R rong.r.yang at intel.com
Wed Dec 28 08:09:04 UTC 2016


LGTM, pushed, thanks.

> -----Original Message-----
> From: Beignet [mailto:beignet-bounces at lists.freedesktop.org] On Behalf Of
> junyan.he at inbox.com
> Sent: Tuesday, December 27, 2016 11:34
> To: beignet at lists.freedesktop.org
> Subject: [Beignet] [PATCH] Utest: Refine half and float convert functions.
> 
> From: Junyan He <junyan.he at intel.com>
> 
> Signed-off-by: Junyan He <junyan.he at 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 at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/beignet


More information about the Beignet mailing list