1 #include "HalideRuntime.h"
2 
3 extern "C" {
4 
5 // Will this work on big-endian?
halide_float16_bits_to_float(uint16_t bits)6 WEAK 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)66 WEAK 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