1 #include "HalideRuntime.h" 2 3 extern "C" { 4 5 // Will this work on big-endian? halide_float16_bits_to_float(uint16_t bits)6WEAK float halide_float16_bits_to_float(uint16_t bits) { 7 uint32_t signMask = (bits & 0x8000) << 16; 8 union { 9 float asFloat; 10 uint32_t asUInt; 11 } result; 12 13 uint32_t significandBits = (bits & 0x3ff); 14 15 // Half has exponent stored as bias-15 16 int exponent = ((bits & 0x7c00) >> 10); 17 exponent -= 15; 18 19 if (exponent == -15 && significandBits != 0) { 20 // Subnormal number 21 // Every subnormal in binary16 is represented as 22 // a normal number in binary32 so we need to convert 23 // to a normalised form. 24 25 // Find index (right to left starting at zero) of the most significant 26 // bit in significand. 27 uint32_t newSignificand = significandBits; 28 // Is it safe to use this built-in? 29 int leadingZeros = __builtin_clz(significandBits); 30 int setMSB = 31 - leadingZeros; 31 // Zero the leading bit which isn't represented in the IEEE-754 2008 binary32 normalised format 32 newSignificand &= ~(1 << setMSB); 33 // Now move bits into the correct position 34 newSignificand <<= (23 - setMSB); 35 // Compute the new exponent for the normalised form 36 int newExponent = -24 + setMSB; // (-14 - (10 - setMSB)) 37 uint32_t reEncodedExponent = newExponent + 127; 38 result.asUInt = signMask | (reEncodedExponent << 23) | newSignificand; 39 40 } else { 41 // Normalised number, NaN, zero or infinity. 42 // Here we can just zero extended the significand 43 // and re-encode the exponent as appropriate 44 // 45 // In binary16 the stored significand is 10 bits and 46 // in binary32 the stored significant is 23 bits so 47 // we need to shift left by 13 bits. 48 significandBits <<= 13; 49 50 uint32_t reEncodedExponent; 51 if (exponent == -15) { 52 // Zero 53 reEncodedExponent = 0x00; 54 } else if (exponent == 16) { 55 // NaN or Infinity 56 reEncodedExponent = 0xff; 57 } else { 58 // Normal number (exponent stored as bias 127) 59 reEncodedExponent = exponent + 127; 60 } 61 result.asUInt = signMask | (reEncodedExponent << 23) | significandBits; 62 } 63 return result.asFloat; 64 } 65 halide_float16_bits_to_double(uint16_t bits)66WEAK double halide_float16_bits_to_double(uint16_t bits) { 67 // Just use native support for converting between float 68 // and double 69 float valueAsFloat = halide_float16_bits_to_float(bits); 70 return (double)valueAsFloat; 71 } 72 } 73