Index: lldb/source/Core/DumpDataExtractor.cpp =================================================================== --- lldb/source/Core/DumpDataExtractor.cpp +++ lldb/source/Core/DumpDataExtractor.cpp @@ -27,6 +27,7 @@ #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/bit.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" @@ -47,21 +48,58 @@ #define NON_PRINTABLE_CHAR '.' -static float half2float(uint16_t half) { - union { - float f; - uint32_t u; - } u; - int32_t v = (int16_t)half; - - if (0 == (v & 0x7c00)) { - u.u = v & 0x80007FFFU; - return u.f * ldexpf(1, 125); +/// Takes two bytes of data, interprets it to a half precision float and then +/// returns that value extend to a single precision float. +static float half2float(uint16_t data) { + constexpr unsigned HalfBitsSignificant = 10; + // The exponent bias of half precision floats. + constexpr int HalfExpBias = 15; + struct IEEE754Half { + unsigned short significant : HalfBitsSignificant; + unsigned short exponent : 5; + unsigned short sign : 1; + bool IsSubnormal() const { return exponent == 0; } + bool isInfOrNaN() const { return exponent == 0b11111; } + }; + const IEEE754Half half = llvm::bit_cast(data); + + constexpr unsigned SingleBitsSignificant = 23; + // The exponent bias of single precision floats. + constexpr int SingleExpBias = 127; + struct IEEE754Single { + unsigned significant : SingleBitsSignificant; + unsigned exponent : 8; + unsigned sign : 1; + float AsFloat() const { return llvm::bit_cast(*this); } + }; + IEEE754Single single; + single.significant = half.significant; + single.exponent = half.exponent; + single.sign = half.sign; + + // Right align significant/NaN payload. + constexpr int SignificantBitDiff = + SingleBitsSignificant - HalfBitsSignificant; + single.significant <<= SignificantBitDiff; + + // For subnormal numbers we have a fixed exponent and we already shifted the + // significant to the right position. Take the different to the new + // exponent and multiply with that to get the single precision value. + if (half.IsSubnormal()) + return single.AsFloat() * ldexpf(1, SingleExpBias - HalfExpBias); + + // If the input was Inf/Nan, there is nothing left to do than marking the + // output as Inf/Nan. Sign bit and payload are already correct. + if (half.isInfOrNaN()) { + // Fill the exponent with ones to mark it as NaN/Inf. + single.exponent = 0xFF; + return single.AsFloat(); } - v <<= 13; - u.u = v | 0x70000000U; - return u.f * ldexpf(1, -112); + // For normal numbers, only adjust the exponent. Significant was already + // shifted to the right position. + single.exponent += SingleExpBias - HalfExpBias; + return single.AsFloat(); } static llvm::Optional GetAPInt(const DataExtractor &data,