8
8
9
9
#include " Test.h"
10
10
11
+ #include " utils/FPUtil/FPBits.h"
11
12
#include " utils/testutils/ExecuteFunction.h"
13
+ #include " llvm/ADT/StringExtras.h"
12
14
#include " llvm/ADT/StringRef.h"
13
15
#include " llvm/Support/raw_ostream.h"
14
16
@@ -32,77 +34,143 @@ class RunContext {
32
34
33
35
namespace internal {
34
36
37
+ // Display the first N hexadecimal digits of an integer in upper case.
38
+ template <typename T>
39
+ cpp::EnableIfType<cpp::IsIntegral<T>::Value, std::string>
40
+ uintToHex (T X, size_t Length = sizeof (T) * 2 ) {
41
+ std::string s (Length, ' 0' );
42
+
43
+ for (auto it = s.rbegin (), end = s.rend (); it != end; ++it, X >>= 4 ) {
44
+ unsigned char Mod = static_cast <unsigned char >(X) & 15 ;
45
+ *it = llvm::hexdigit (Mod, true );
46
+ }
47
+
48
+ return s;
49
+ }
50
+
51
+ // When the value is not floating-point type, just display it as normal.
52
+ template <typename ValType>
53
+ cpp::EnableIfType<!cpp::IsFloatingPointType<ValType>::Value, std::string>
54
+ describeValue (ValType Value) {
55
+ return std::to_string (Value);
56
+ }
57
+
58
+ template <> std::string describeValue<llvm::StringRef>(llvm::StringRef Value) {
59
+ return std::string (Value);
60
+ }
61
+
62
+ // When the value is __uint128_t, also show its hexadecimal digits.
63
+ // Using template to force exact match, prevent ambiguous promotion.
64
+ template <> std::string describeValue<__uint128_t >(__uint128_t Value) {
65
+ return " 0x" + uintToHex (Value);
66
+ }
67
+
68
+ // When the value is a floating point type, also show its sign | exponent |
69
+ // mantissa.
70
+ template <typename ValType>
71
+ cpp::EnableIfType<cpp::IsFloatingPointType<ValType>::Value, std::string>
72
+ describeValue (ValType Value) {
73
+ fputil::FPBits<ValType> Bits (Value);
74
+
75
+ if (Bits.isNaN ()) {
76
+ return " (NaN)" ;
77
+ } else if (Bits.isInf ()) {
78
+ return Bits.sign ? " (-Infinity)" : " (+Infinity)" ;
79
+ } else {
80
+ constexpr int ExponentWidthInHex =
81
+ (fputil::ExponentWidth<ValType>::value - 1 ) / 4 + 1 ;
82
+ constexpr int MantissaWidthInHex =
83
+ (fputil::MantissaWidth<ValType>::value - 1 ) / 4 + 1 ;
84
+
85
+ return std::string (" Sign: " ) + (Bits.sign ? ' 1' : ' 0' ) + " , Exponent: 0x" +
86
+ uintToHex<uint16_t >(Bits.exponent , ExponentWidthInHex) +
87
+ " , Mantissa: 0x" +
88
+ uintToHex<typename fputil::FPBits<ValType>::UIntType>(
89
+ Bits.mantissa , MantissaWidthInHex);
90
+ }
91
+ }
92
+
93
+ template <typename ValType>
94
+ void explainDifference (ValType LHS, ValType RHS, const char *LHSStr,
95
+ const char *RHSStr, const char *File, unsigned long Line,
96
+ llvm::StringRef OpString) {
97
+ size_t OffsetLength = OpString.size () > 2 ? OpString.size () - 2 : 0 ;
98
+ std::string Offset (OffsetLength, ' ' );
99
+
100
+ llvm::outs () << File << " :" << Line << " : FAILURE\n "
101
+ << Offset << " Expected: " << LHSStr << ' \n '
102
+ << Offset << " Which is: " << describeValue (LHS) << ' \n '
103
+ << " To be " << OpString << " : " << RHSStr << ' \n '
104
+ << Offset << " Which is: " << describeValue (RHS) << ' \n ' ;
105
+ }
106
+
107
+ template <typename ValType>
108
+ cpp::EnableIfType<!cpp::IsFloatingPointType<ValType>::Value, bool >
109
+ testEQ (ValType LHS, ValType RHS) {
110
+ return LHS == RHS;
111
+ }
112
+
113
+ // For floating points, we consider all NaNs are equal, and +0.0 is not equal to
114
+ // -0.0.
115
+ template <typename ValType>
116
+ cpp::EnableIfType<cpp::IsFloatingPointType<ValType>::Value, bool >
117
+ testEQ (ValType LHS, ValType RHS) {
118
+ fputil::FPBits<ValType> LHSBits (LHS), RHSBits (RHS);
119
+
120
+ return (LHSBits.isNaN () && RHSBits.isNaN ()) ||
121
+ (LHSBits.bitsAsUInt () == RHSBits.bitsAsUInt ());
122
+ }
123
+
35
124
template <typename ValType>
36
125
bool test (RunContext &Ctx, TestCondition Cond, ValType LHS, ValType RHS,
37
126
const char *LHSStr, const char *RHSStr, const char *File,
38
127
unsigned long Line) {
128
+ auto ExplainDifference = [=](llvm::StringRef OpString) {
129
+ explainDifference (LHS, RHS, LHSStr, RHSStr, File, Line, OpString);
130
+ };
131
+
39
132
switch (Cond) {
40
133
case Cond_EQ:
41
- if (LHS == RHS)
134
+ if (testEQ ( LHS, RHS) )
42
135
return true ;
43
136
44
137
Ctx.markFail ();
45
- llvm::outs () << File << " :" << Line << " : FAILURE\n "
46
- << " Expected: " << LHSStr << ' \n '
47
- << " Which is: " << LHS << ' \n '
48
- << " To be equal to: " << RHSStr << ' \n '
49
- << " Which is: " << RHS << ' \n ' ;
50
-
138
+ ExplainDifference (" equal to" );
51
139
return false ;
52
140
case Cond_NE:
53
- if (LHS != RHS)
141
+ if (! testEQ ( LHS, RHS) )
54
142
return true ;
55
143
56
144
Ctx.markFail ();
57
- llvm::outs () << File << " :" << Line << " : FAILURE\n "
58
- << " Expected: " << LHSStr << ' \n '
59
- << " Which is: " << LHS << ' \n '
60
- << " To be not equal to: " << RHSStr << ' \n '
61
- << " Which is: " << RHS << ' \n ' ;
145
+ ExplainDifference (" not equal to" );
62
146
return false ;
63
147
case Cond_LT:
64
148
if (LHS < RHS)
65
149
return true ;
66
150
67
151
Ctx.markFail ();
68
- llvm::outs () << File << " :" << Line << " : FAILURE\n "
69
- << " Expected: " << LHSStr << ' \n '
70
- << " Which is: " << LHS << ' \n '
71
- << " To be less than: " << RHSStr << ' \n '
72
- << " Which is: " << RHS << ' \n ' ;
152
+ ExplainDifference (" less than" );
73
153
return false ;
74
154
case Cond_LE:
75
155
if (LHS <= RHS)
76
156
return true ;
77
157
78
158
Ctx.markFail ();
79
- llvm::outs () << File << " :" << Line << " : FAILURE\n "
80
- << " Expected: " << LHSStr << ' \n '
81
- << " Which is: " << LHS << ' \n '
82
- << " To be less than or equal to: " << RHSStr << ' \n '
83
- << " Which is: " << RHS << ' \n ' ;
159
+ ExplainDifference (" less than or equal to" );
84
160
return false ;
85
161
case Cond_GT:
86
162
if (LHS > RHS)
87
163
return true ;
88
164
89
165
Ctx.markFail ();
90
- llvm::outs () << File << " :" << Line << " : FAILURE\n "
91
- << " Expected: " << LHSStr << ' \n '
92
- << " Which is: " << LHS << ' \n '
93
- << " To be greater than: " << RHSStr << ' \n '
94
- << " Which is: " << RHS << ' \n ' ;
166
+ ExplainDifference (" greater than" );
95
167
return false ;
96
168
case Cond_GE:
97
169
if (LHS >= RHS)
98
170
return true ;
99
171
100
172
Ctx.markFail ();
101
- llvm::outs () << File << " :" << Line << " : FAILURE\n "
102
- << " Expected: " << LHSStr << ' \n '
103
- << " Which is: " << LHS << ' \n '
104
- << " To be greater than or equal to: " << RHSStr << ' \n '
105
- << " Which is: " << RHS << ' \n ' ;
173
+ ExplainDifference (" greater than or equal to" );
106
174
return false ;
107
175
default :
108
176
Ctx.markFail ();
@@ -218,6 +286,26 @@ template bool Test::test<unsigned long long, 0>(
218
286
unsigned long long RHS, const char *LHSStr, const char *RHSStr,
219
287
const char *File, unsigned long Line);
220
288
289
+ template bool Test::test<__uint128_t , 0 >(RunContext &Ctx, TestCondition Cond,
290
+ __uint128_t LHS, __uint128_t RHS,
291
+ const char *LHSStr, const char *RHSStr,
292
+ const char *File, unsigned long Line);
293
+
294
+ template bool Test::test<float , 0 >(RunContext &Ctx, TestCondition Cond,
295
+ float LHS, float RHS, const char *LHSStr,
296
+ const char *RHSStr, const char *File,
297
+ unsigned long Line);
298
+
299
+ template bool Test::test<double , 0 >(RunContext &Ctx, TestCondition Cond,
300
+ double LHS, double RHS, const char *LHSStr,
301
+ const char *RHSStr, const char *File,
302
+ unsigned long Line);
303
+
304
+ template bool Test::test<long double , 0 >(RunContext &Ctx, TestCondition Cond,
305
+ long double LHS, long double RHS,
306
+ const char *LHSStr, const char *RHSStr,
307
+ const char *File, unsigned long Line);
308
+
221
309
bool Test::testStrEq (RunContext &Ctx, const char *LHS, const char *RHS,
222
310
const char *LHSStr, const char *RHSStr, const char *File,
223
311
unsigned long Line) {
0 commit comments