[Beignet] [PATCH] Utest: Refine half and float convert functions.
junyan.he at inbox.com
junyan.he at inbox.com
Tue Dec 27 03:34:27 UTC 2016
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
More information about the Beignet
mailing list