blob: 1c67b6bd61cecc1764da6d9cda6c7519c7bd2e73 [file] [log] [blame]
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -07001/* crosstest.py --test=test_arith.cpp --test=test_arith_frem.ll \
Jan Voungf37fbbe2014-07-09 16:13:13 -07002 --test=test_arith_sqrt.ll --driver=test_arith_main.cpp \
3 --prefix=Subzero_ --output=test_arith */
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -07004
5#include <stdint.h>
6
Matt Wala7fa22d82014-07-17 12:41:31 -07007#include <climits> // CHAR_BIT
8#include <limits>
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -07009#include <cfloat>
Matt Wala7fa22d82014-07-17 12:41:31 -070010#include <cmath> // fmodf
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070011#include <cstring> // memcmp
12#include <iostream>
13
14// Include test_arith.h twice - once normally, and once within the
15// Subzero_ namespace, corresponding to the llc and Subzero translated
16// object files, respectively.
17#include "test_arith.h"
18namespace Subzero_ {
19#include "test_arith.h"
20}
21
Matt Wala7fa22d82014-07-17 12:41:31 -070022template <class T> bool inputsMayTriggerException(T Value1, T Value2) {
23 // Avoid HW divide-by-zero exception.
24 if (Value2 == 0)
25 return true;
26 // Avoid HW overflow exception (on x86-32). TODO: adjust
27 // for other architecture.
28 if (Value1 == std::numeric_limits<T>::min() && Value2 == -1)
29 return true;
30 return false;
31}
32
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070033template <typename TypeUnsigned, typename TypeSigned>
34void testsInt(size_t &TotalTests, size_t &Passes, size_t &Failures) {
35 typedef TypeUnsigned (*FuncTypeUnsigned)(TypeUnsigned, TypeUnsigned);
36 typedef TypeSigned (*FuncTypeSigned)(TypeSigned, TypeSigned);
Matt Wala35ec3732014-07-18 16:32:16 -070037 volatile unsigned Values[] = INT_VALUE_ARRAY;
38 const static size_t NumValues = sizeof(Values) / sizeof(*Values);
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070039 static struct {
40 const char *Name;
41 FuncTypeUnsigned FuncLlc;
42 FuncTypeUnsigned FuncSz;
43 bool ExcludeDivExceptions; // for divide related tests
44 } Funcs[] = {
45#define X(inst, op, isdiv) \
46 { \
47 STR(inst), (FuncTypeUnsigned)test##inst, \
48 (FuncTypeUnsigned)Subzero_::test##inst, isdiv \
49 } \
50 ,
51 UINTOP_TABLE
52#undef X
53#define X(inst, op, isdiv) \
54 { \
55 STR(inst), (FuncTypeUnsigned)(FuncTypeSigned)test##inst, \
56 (FuncTypeUnsigned)(FuncTypeSigned)Subzero_::test##inst, isdiv \
57 } \
58 ,
Matt Wala7fa22d82014-07-17 12:41:31 -070059 SINTOP_TABLE
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070060#undef X
Matt Wala7fa22d82014-07-17 12:41:31 -070061 };
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070062 const static size_t NumFuncs = sizeof(Funcs) / sizeof(*Funcs);
63
64 if (sizeof(TypeUnsigned) <= sizeof(uint32_t)) {
65 // This is the "normal" version of the loop nest, for 32-bit or
66 // narrower types.
67 for (size_t f = 0; f < NumFuncs; ++f) {
68 for (size_t i = 0; i < NumValues; ++i) {
69 for (size_t j = 0; j < NumValues; ++j) {
70 TypeUnsigned Value1 = Values[i];
71 TypeUnsigned Value2 = Values[j];
72 // Avoid HW divide-by-zero exception.
Matt Wala7fa22d82014-07-17 12:41:31 -070073 if (Funcs[f].ExcludeDivExceptions &&
74 inputsMayTriggerException<TypeSigned>(Value1, Value2))
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070075 continue;
76 ++TotalTests;
77 TypeUnsigned ResultSz = Funcs[f].FuncSz(Value1, Value2);
78 TypeUnsigned ResultLlc = Funcs[f].FuncLlc(Value1, Value2);
79 if (ResultSz == ResultLlc) {
80 ++Passes;
81 } else {
82 ++Failures;
Matt Wala7fa22d82014-07-17 12:41:31 -070083 std::cout << "test" << Funcs[f].Name
84 << (CHAR_BIT * sizeof(TypeUnsigned)) << "(" << Value1
85 << ", " << Value2 << "): sz=" << (unsigned)ResultSz
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070086 << " llc=" << (unsigned)ResultLlc << std::endl;
87 }
88 }
89 }
90 }
91 } else {
92 // This is the 64-bit version. Test values are synthesized from
93 // the 32-bit values in Values[].
94 for (size_t f = 0; f < NumFuncs; ++f) {
95 for (size_t iLo = 0; iLo < NumValues; ++iLo) {
96 for (size_t iHi = 0; iHi < NumValues; ++iHi) {
97 for (size_t jLo = 0; jLo < NumValues; ++jLo) {
98 for (size_t jHi = 0; jHi < NumValues; ++jHi) {
99 TypeUnsigned Value1 =
100 (((TypeUnsigned)Values[iHi]) << 32) + Values[iLo];
101 TypeUnsigned Value2 =
102 (((TypeUnsigned)Values[jHi]) << 32) + Values[jLo];
Matt Wala7fa22d82014-07-17 12:41:31 -0700103 if (Funcs[f].ExcludeDivExceptions &&
104 inputsMayTriggerException<TypeSigned>(Value1, Value2))
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700105 continue;
106 ++TotalTests;
107 TypeUnsigned ResultSz = Funcs[f].FuncSz(Value1, Value2);
108 TypeUnsigned ResultLlc = Funcs[f].FuncLlc(Value1, Value2);
109 if (ResultSz == ResultLlc) {
110 ++Passes;
111 } else {
112 ++Failures;
113 std::cout << "test" << Funcs[f].Name
Matt Wala7fa22d82014-07-17 12:41:31 -0700114 << (CHAR_BIT * sizeof(TypeUnsigned)) << "(" << Value1
115 << ", " << Value2 << "): sz=" << (unsigned)ResultSz
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700116 << " llc=" << (unsigned)ResultLlc << std::endl;
117 }
118 }
119 }
120 }
121 }
122 }
123 }
124}
125
Matt Wala7fa22d82014-07-17 12:41:31 -0700126// Vectors are deterministically constructed by selecting elements from
127// a pool of scalar values based on a pseudorandom sequence. Testing
128// all possible combinations of scalar values from the value table is
129// not tractable.
130// TODO: Replace with a portable PRNG from C++11.
131class PRNG {
132public:
133 PRNG(uint32_t Seed = 1) : State(Seed) {}
134
135 uint32_t operator()() {
136 // Lewis, Goodman, and Miller (1969)
137 State = (16807 * State) % 2147483647;
138 return State;
139 }
140
141private:
142 uint32_t State;
143};
144
145const static size_t MaxTestsPerFunc = 100000;
146
147template <typename Type, typename ElementType, typename CastType>
148void outputVector(const Type Vect) {
149 const static size_t NumElementsInType = sizeof(Type) / sizeof(ElementType);
150 for (size_t i = 0; i < NumElementsInType; ++i) {
151 if (i > 0)
152 std::cout << ", ";
153 std::cout << (CastType) Vect[i];
154 }
155}
156
157template <typename TypeUnsigned, typename TypeSigned,
158 typename ElementTypeUnsigned, typename ElementTypeSigned>
159void testsVecInt(size_t &TotalTests, size_t &Passes, size_t &Failures) {
160 typedef TypeUnsigned (*FuncTypeUnsigned)(TypeUnsigned, TypeUnsigned);
161 typedef TypeSigned (*FuncTypeSigned)(TypeSigned, TypeSigned);
Matt Wala35ec3732014-07-18 16:32:16 -0700162 volatile unsigned Values[] = INT_VALUE_ARRAY;
163 const static size_t NumValues = sizeof(Values) / sizeof(*Values);
Matt Wala7fa22d82014-07-17 12:41:31 -0700164 static struct {
165 const char *Name;
166 FuncTypeUnsigned FuncLlc;
167 FuncTypeUnsigned FuncSz;
168 bool ExcludeDivExceptions; // for divide related tests
169 } Funcs[] = {
170#define X(inst, op, isdiv) \
171 { \
172 STR(inst), (FuncTypeUnsigned)test##inst, \
173 (FuncTypeUnsigned)Subzero_::test##inst, isdiv \
174 } \
175 ,
176 UINTOP_TABLE
177#undef X
178#define X(inst, op, isdiv) \
179 { \
180 STR(inst), (FuncTypeUnsigned)(FuncTypeSigned)test##inst, \
181 (FuncTypeUnsigned)(FuncTypeSigned)Subzero_::test##inst, isdiv \
182 } \
183 ,
184 SINTOP_TABLE
185#undef X
186 };
187 const static size_t NumFuncs = sizeof(Funcs) / sizeof(*Funcs);
188 const static size_t NumElementsInType =
189 sizeof(TypeUnsigned) / sizeof(ElementTypeUnsigned);
190 for (size_t f = 0; f < NumFuncs; ++f) {
191 PRNG Index;
192 for (size_t i = 0; i < MaxTestsPerFunc; ++i) {
193 // Initialize the test vectors.
194 TypeUnsigned Value1, Value2;
195 for (size_t j = 0; j < NumElementsInType;) {
Matt Wala35ec3732014-07-18 16:32:16 -0700196 ElementTypeUnsigned Element1 = Values[Index() % NumValues];
197 ElementTypeUnsigned Element2 = Values[Index() % NumValues];
Matt Wala7fa22d82014-07-17 12:41:31 -0700198 if (Funcs[f].ExcludeDivExceptions &&
199 inputsMayTriggerException<ElementTypeSigned>(Element1, Element2))
200 continue;
201 Value1[j] = Element1;
202 Value2[j] = Element2;
203 ++j;
204 }
205 // Perform the test.
206 TypeUnsigned ResultSz = Funcs[f].FuncSz(Value1, Value2);
207 TypeUnsigned ResultLlc = Funcs[f].FuncLlc(Value1, Value2);
208 ++TotalTests;
209 if (!memcmp(&ResultSz, &ResultLlc, sizeof(ResultSz))) {
210 ++Passes;
211 } else {
212 std::cout << "test" << Funcs[f].Name << "v" << NumElementsInType << "i"
213 << (CHAR_BIT * sizeof(ElementTypeUnsigned)) << "(";
214 outputVector<TypeUnsigned, ElementTypeUnsigned, unsigned>(Value1);
215 std::cout << ", ";
216 outputVector<TypeUnsigned, ElementTypeUnsigned, unsigned>(Value2);
217 std::cout << "): sz=";
218 outputVector<TypeUnsigned, ElementTypeUnsigned, unsigned>(ResultSz);
219 std::cout << " llc=";
220 outputVector<TypeUnsigned, ElementTypeUnsigned, unsigned>(ResultLlc);
221 std::cout << std::endl;
222 }
223 }
224 }
225}
226
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700227template <typename Type>
228void testsFp(size_t &TotalTests, size_t &Passes, size_t &Failures) {
229 static const Type NegInf = -1.0 / 0.0;
230 static const Type PosInf = 1.0 / 0.0;
231 static const Type Nan = 0.0 / 0.0;
Jan Voungf37fbbe2014-07-09 16:13:13 -0700232 static const Type NegNan = -0.0 / 0.0;
Matt Wala7fa22d82014-07-17 12:41:31 -0700233 volatile Type Values[] = FP_VALUE_ARRAY(NegInf, PosInf, NegNan, Nan);
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700234 const static size_t NumValues = sizeof(Values) / sizeof(*Values);
235 typedef Type (*FuncType)(Type, Type);
236 static struct {
237 const char *Name;
238 FuncType FuncLlc;
239 FuncType FuncSz;
240 } Funcs[] = {
241#define X(inst, op, func) \
242 { STR(inst), (FuncType)test##inst, (FuncType)Subzero_::test##inst } \
243 ,
244 FPOP_TABLE
245#undef X
Matt Wala7fa22d82014-07-17 12:41:31 -0700246 };
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700247 const static size_t NumFuncs = sizeof(Funcs) / sizeof(*Funcs);
248
249 for (size_t f = 0; f < NumFuncs; ++f) {
250 for (size_t i = 0; i < NumValues; ++i) {
251 for (size_t j = 0; j < NumValues; ++j) {
252 Type Value1 = Values[i];
253 Type Value2 = Values[j];
254 ++TotalTests;
255 Type ResultSz = Funcs[f].FuncSz(Value1, Value2);
256 Type ResultLlc = Funcs[f].FuncLlc(Value1, Value2);
257 // Compare results using memcmp() in case they are both NaN.
258 if (!memcmp(&ResultSz, &ResultLlc, sizeof(Type))) {
259 ++Passes;
260 } else {
261 ++Failures;
262 std::cout << std::fixed << "test" << Funcs[f].Name
Matt Wala7fa22d82014-07-17 12:41:31 -0700263 << (CHAR_BIT * sizeof(Type)) << "(" << Value1 << ", "
264 << Value2 << "): sz=" << ResultSz << " llc=" << ResultLlc
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700265 << std::endl;
266 }
267 }
268 }
269 }
Jan Voungf37fbbe2014-07-09 16:13:13 -0700270 for (size_t i = 0; i < NumValues; ++i) {
271 Type Value = Values[i];
272 ++TotalTests;
273 Type ResultSz = Subzero_::mySqrt(Value);
274 Type ResultLlc = mySqrt(Value);
275 // Compare results using memcmp() in case they are both NaN.
276 if (!memcmp(&ResultSz, &ResultLlc, sizeof(Type))) {
277 ++Passes;
278 } else {
279 ++Failures;
Matt Wala7fa22d82014-07-17 12:41:31 -0700280 std::cout << std::fixed << "test_sqrt" << (CHAR_BIT * sizeof(Type)) << "("
281 << Value << "): sz=" << ResultSz << " llc=" << ResultLlc
Jan Voungf37fbbe2014-07-09 16:13:13 -0700282 << std::endl;
283 }
284 }
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700285}
286
Matt Wala7fa22d82014-07-17 12:41:31 -0700287void testsVecFp(size_t &TotalTests, size_t &Passes, size_t &Failures) {
288 static const float NegInf = -1.0 / 0.0;
289 static const float PosInf = 1.0 / 0.0;
290 static const float Nan = 0.0 / 0.0;
291 static const float NegNan = -0.0 / 0.0;
292 volatile float Values[] = FP_VALUE_ARRAY(NegInf, PosInf, NegNan, Nan);
293 const static size_t NumValues = sizeof(Values) / sizeof(*Values);
294 typedef v4f32 (*FuncType)(v4f32, v4f32);
295 static struct {
296 const char *Name;
297 FuncType FuncLlc;
298 FuncType FuncSz;
299 } Funcs[] = {
300#define X(inst, op, func) \
301 { STR(inst), (FuncType)test##inst, (FuncType)Subzero_::test##inst } \
302 ,
303 FPOP_TABLE
304#undef X
305 };
306 const static size_t NumFuncs = sizeof(Funcs) / sizeof(*Funcs);
307 const static size_t NumElementsInType = 4;
308 for (size_t f = 0; f < NumFuncs; ++f) {
309 PRNG Index;
310 for (size_t i = 0; i < MaxTestsPerFunc; ++i) {
311 // Initialize the test vectors.
312 v4f32 Value1, Value2;
313 for (size_t j = 0; j < NumElementsInType; ++j) {
Matt Wala35ec3732014-07-18 16:32:16 -0700314 Value1[j] = Values[Index() % NumValues];
315 Value2[j] = Values[Index() % NumValues];
Matt Wala7fa22d82014-07-17 12:41:31 -0700316 }
317 // Perform the test.
318 v4f32 ResultSz = Funcs[f].FuncSz(Value1, Value2);
319 v4f32 ResultLlc = Funcs[f].FuncLlc(Value1, Value2);
320 ++TotalTests;
321 if (!memcmp(&ResultSz, &ResultLlc, sizeof(ResultSz))) {
322 ++Passes;
323 } else {
324 ++Failures;
325 std::cout << std::fixed << "test" << Funcs[f].Name << "v4f32"
326 << "(";
327 outputVector<v4f32, float, float>(Value1);
328 std::cout << ", ";
329 outputVector<v4f32, float, float>(Value2);
330 std::cout << "): sz=";
331 outputVector<v4f32, float, float>(ResultSz);
332 std::cout << " llc=";
333 outputVector<v4f32, float, float>(ResultLlc);
334 std::cout << std::endl;
335 }
336 }
337 }
338}
339
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700340int main(int argc, char **argv) {
341 size_t TotalTests = 0;
342 size_t Passes = 0;
343 size_t Failures = 0;
344
345 testsInt<uint8_t, int8_t>(TotalTests, Passes, Failures);
346 testsInt<uint16_t, int16_t>(TotalTests, Passes, Failures);
347 testsInt<uint32_t, int32_t>(TotalTests, Passes, Failures);
348 testsInt<uint64_t, int64_t>(TotalTests, Passes, Failures);
Matt Wala7fa22d82014-07-17 12:41:31 -0700349 testsVecInt<v4ui32, v4si32, uint32_t, int32_t>(TotalTests, Passes, Failures);
350 testsVecInt<v8ui16, v8si16, uint16_t, int16_t>(TotalTests, Passes, Failures);
351 testsVecInt<v16ui8, v16si8, uint8_t, int8_t>(TotalTests, Passes, Failures);
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700352 testsFp<float>(TotalTests, Passes, Failures);
353 testsFp<double>(TotalTests, Passes, Failures);
Matt Wala7fa22d82014-07-17 12:41:31 -0700354 testsVecFp(TotalTests, Passes, Failures);
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700355
356 std::cout << "TotalTests=" << TotalTests << " Passes=" << Passes
357 << " Failures=" << Failures << "\n";
358 return Failures;
359}
Matt Wala7fa22d82014-07-17 12:41:31 -0700360
361extern "C" {
362// Subzero helpers
363 v4si32 Sz_shl_v4i32(v4si32 a, v4si32 b) { return a << b; }
364 v4si32 Sz_ashr_v4i32(v4si32 a, v4si32 b) { return a >> b; }
365 v4ui32 Sz_lshr_v4i32(v4ui32 a, v4ui32 b) { return a >> b; }
366 v4si32 Sz_sdiv_v4i32(v4si32 a, v4si32 b) { return a / b; }
367 v4ui32 Sz_udiv_v4i32(v4ui32 a, v4ui32 b) { return a / b; }
368 v4si32 Sz_srem_v4i32(v4si32 a, v4si32 b) { return a % b; }
369 v4ui32 Sz_urem_v4i32(v4ui32 a, v4ui32 b) { return a % b; }
370
371 v8si16 Sz_shl_v8i16(v8si16 a, v8si16 b) { return a << b; }
372 v8si16 Sz_ashr_v8i16(v8si16 a, v8si16 b) { return a >> b; }
373 v8ui16 Sz_lshr_v8i16(v8ui16 a, v8ui16 b) { return a >> b; }
374 v8si16 Sz_sdiv_v8i16(v8si16 a, v8si16 b) { return a / b; }
375 v8ui16 Sz_udiv_v8i16(v8ui16 a, v8ui16 b) { return a / b; }
376 v8si16 Sz_srem_v8i16(v8si16 a, v8si16 b) { return a % b; }
377 v8ui16 Sz_urem_v8i16(v8ui16 a, v8ui16 b) { return a % b; }
378
379 v16ui8 Sz_mul_v16i8(v16ui8 a, v16ui8 b) { return a * b; }
380 v16si8 Sz_shl_v16i8(v16si8 a, v16si8 b) { return a << b; }
381 v16si8 Sz_ashr_v16i8(v16si8 a, v16si8 b) { return a >> b; }
382 v16ui8 Sz_lshr_v16i8(v16ui8 a, v16ui8 b) { return a >> b; }
383 v16si8 Sz_sdiv_v16i8(v16si8 a, v16si8 b) { return a / b; }
384 v16ui8 Sz_udiv_v16i8(v16ui8 a, v16ui8 b) { return a / b; }
385 v16si8 Sz_srem_v16i8(v16si8 a, v16si8 b) { return a % b; }
386 v16ui8 Sz_urem_v16i8(v16ui8 a, v16ui8 b) { return a % b; }
387
388 v4f32 Sz_frem_v4f32(v4f32 a, v4f32 b) {
389 v4f32 Result;
390 for (int i = 0; i < 4; ++i)
391 Result[i] = fmodf(a[i], b[i]);
392 return Result;
393 }
394}