|
14 | 14 | #include "llvm/Support/raw_ostream.h" |
15 | 15 | #include <cmath> |
16 | 16 |
|
| 17 | +constexpr uint16_t Float16BitSign = 0x8000; |
| 18 | +constexpr uint16_t Float16BitExp = 0x7c00; |
| 19 | +constexpr uint16_t Float16BitMantissa = 0x03ff; |
| 20 | + |
17 | 21 | // limited to float, double, and long double |
18 | 22 | template <typename T> static bool isDenorm(T F) { |
19 | 23 | return std::fpclassify(F) == FP_SUBNORMAL; |
20 | 24 | } |
21 | 25 |
|
22 | 26 | static bool isFloat16NAN(uint16_t Val) { |
23 | | - return (Val & 0x7c00) == 0x7c00 && (Val & 0x03ff) != 0; |
| 27 | + return (Val & Float16BitExp) == Float16BitExp && |
| 28 | + (Val & Float16BitMantissa) != 0; |
24 | 29 | } |
25 | 30 |
|
26 | 31 | static bool compareDoubleULP(const double &FSrc, const double &FRef, |
@@ -64,12 +69,23 @@ static bool compareFloatULP(const float &FSrc, const float &FRef, |
64 | 69 |
|
65 | 70 | static bool compareFloat16ULP(const uint16_t &FSrc, const uint16_t &FRef, |
66 | 71 | unsigned ULPTolerance) { |
| 72 | + // Treat +0 and -0 as equal |
| 73 | + if ((FSrc & ~Float16BitSign) == 0 && (FRef & ~Float16BitSign) == 0) |
| 74 | + return true; |
67 | 75 | if (FSrc == FRef) |
68 | 76 | return true; |
69 | 77 | if (isFloat16NAN(FSrc) || isFloat16NAN(FRef)) |
70 | 78 | return isFloat16NAN(FRef) && isFloat16NAN(FSrc); |
| 79 | + |
| 80 | + // Map to monotonic ordering for correct ULP diff |
| 81 | + auto ToOrdered = [](uint16_t H) -> int { |
| 82 | + return (H & Float16BitSign) ? (~H & 0xFFFF) : (H | Float16BitSign); |
| 83 | + }; |
| 84 | + |
71 | 85 | // 16-bit floating point numbers must preserve denorms |
72 | | - const int Diff = FSrc - FRef; |
| 86 | + const int IntFSrc = ToOrdered(FSrc); |
| 87 | + const int IntFRef = ToOrdered(FRef); |
| 88 | + const int Diff = IntFSrc - IntFRef; |
73 | 89 | const unsigned int AbsDiff = Diff < 0 ? -Diff : Diff; |
74 | 90 | return AbsDiff <= ULPTolerance; |
75 | 91 | } |
|
0 commit comments