blob: 682fce88955820c1a1a770555e4d11d276ec9d5c [file] [log] [blame]
Matt Wala89a7c2b2014-07-22 10:55:30 -07001//===- subzero/crosstest/test_arith_main.cpp - Driver for tests -----------===//
2//
3// The Subzero Code Generator
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Driver for crosstesting arithmetic operations
11//
12//===----------------------------------------------------------------------===//
13
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070014/* crosstest.py --test=test_arith.cpp --test=test_arith_frem.ll \
Jan Voungf37fbbe2014-07-09 16:13:13 -070015 --test=test_arith_sqrt.ll --driver=test_arith_main.cpp \
16 --prefix=Subzero_ --output=test_arith */
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070017
18#include <stdint.h>
19
Matt Wala7fa22d82014-07-17 12:41:31 -070020#include <climits> // CHAR_BIT
21#include <limits>
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070022#include <cfloat>
Matt Wala7fa22d82014-07-17 12:41:31 -070023#include <cmath> // fmodf
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070024#include <cstring> // memcmp
25#include <iostream>
26
27// Include test_arith.h twice - once normally, and once within the
28// Subzero_ namespace, corresponding to the llc and Subzero translated
29// object files, respectively.
30#include "test_arith.h"
31namespace Subzero_ {
32#include "test_arith.h"
33}
34
Matt Wala7fa22d82014-07-17 12:41:31 -070035template <class T> bool inputsMayTriggerException(T Value1, T Value2) {
36 // Avoid HW divide-by-zero exception.
37 if (Value2 == 0)
38 return true;
39 // Avoid HW overflow exception (on x86-32). TODO: adjust
40 // for other architecture.
41 if (Value1 == std::numeric_limits<T>::min() && Value2 == -1)
42 return true;
43 return false;
44}
45
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070046template <typename TypeUnsigned, typename TypeSigned>
47void testsInt(size_t &TotalTests, size_t &Passes, size_t &Failures) {
48 typedef TypeUnsigned (*FuncTypeUnsigned)(TypeUnsigned, TypeUnsigned);
49 typedef TypeSigned (*FuncTypeSigned)(TypeSigned, TypeSigned);
Matt Wala35ec3732014-07-18 16:32:16 -070050 volatile unsigned Values[] = INT_VALUE_ARRAY;
51 const static size_t NumValues = sizeof(Values) / sizeof(*Values);
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070052 static struct {
53 const char *Name;
54 FuncTypeUnsigned FuncLlc;
55 FuncTypeUnsigned FuncSz;
56 bool ExcludeDivExceptions; // for divide related tests
57 } Funcs[] = {
58#define X(inst, op, isdiv) \
59 { \
60 STR(inst), (FuncTypeUnsigned)test##inst, \
61 (FuncTypeUnsigned)Subzero_::test##inst, isdiv \
62 } \
63 ,
64 UINTOP_TABLE
65#undef X
66#define X(inst, op, isdiv) \
67 { \
68 STR(inst), (FuncTypeUnsigned)(FuncTypeSigned)test##inst, \
69 (FuncTypeUnsigned)(FuncTypeSigned)Subzero_::test##inst, isdiv \
70 } \
71 ,
Matt Wala7fa22d82014-07-17 12:41:31 -070072 SINTOP_TABLE
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070073#undef X
Matt Wala7fa22d82014-07-17 12:41:31 -070074 };
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070075 const static size_t NumFuncs = sizeof(Funcs) / sizeof(*Funcs);
76
77 if (sizeof(TypeUnsigned) <= sizeof(uint32_t)) {
78 // This is the "normal" version of the loop nest, for 32-bit or
79 // narrower types.
80 for (size_t f = 0; f < NumFuncs; ++f) {
81 for (size_t i = 0; i < NumValues; ++i) {
82 for (size_t j = 0; j < NumValues; ++j) {
83 TypeUnsigned Value1 = Values[i];
84 TypeUnsigned Value2 = Values[j];
85 // Avoid HW divide-by-zero exception.
Matt Wala7fa22d82014-07-17 12:41:31 -070086 if (Funcs[f].ExcludeDivExceptions &&
87 inputsMayTriggerException<TypeSigned>(Value1, Value2))
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070088 continue;
89 ++TotalTests;
90 TypeUnsigned ResultSz = Funcs[f].FuncSz(Value1, Value2);
91 TypeUnsigned ResultLlc = Funcs[f].FuncLlc(Value1, Value2);
92 if (ResultSz == ResultLlc) {
93 ++Passes;
94 } else {
95 ++Failures;
Matt Wala7fa22d82014-07-17 12:41:31 -070096 std::cout << "test" << Funcs[f].Name
97 << (CHAR_BIT * sizeof(TypeUnsigned)) << "(" << Value1
98 << ", " << Value2 << "): sz=" << (unsigned)ResultSz
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -070099 << " llc=" << (unsigned)ResultLlc << std::endl;
100 }
101 }
102 }
103 }
104 } else {
105 // This is the 64-bit version. Test values are synthesized from
106 // the 32-bit values in Values[].
107 for (size_t f = 0; f < NumFuncs; ++f) {
108 for (size_t iLo = 0; iLo < NumValues; ++iLo) {
109 for (size_t iHi = 0; iHi < NumValues; ++iHi) {
110 for (size_t jLo = 0; jLo < NumValues; ++jLo) {
111 for (size_t jHi = 0; jHi < NumValues; ++jHi) {
112 TypeUnsigned Value1 =
113 (((TypeUnsigned)Values[iHi]) << 32) + Values[iLo];
114 TypeUnsigned Value2 =
115 (((TypeUnsigned)Values[jHi]) << 32) + Values[jLo];
Matt Wala7fa22d82014-07-17 12:41:31 -0700116 if (Funcs[f].ExcludeDivExceptions &&
117 inputsMayTriggerException<TypeSigned>(Value1, Value2))
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700118 continue;
119 ++TotalTests;
120 TypeUnsigned ResultSz = Funcs[f].FuncSz(Value1, Value2);
121 TypeUnsigned ResultLlc = Funcs[f].FuncLlc(Value1, Value2);
122 if (ResultSz == ResultLlc) {
123 ++Passes;
124 } else {
125 ++Failures;
126 std::cout << "test" << Funcs[f].Name
Matt Wala7fa22d82014-07-17 12:41:31 -0700127 << (CHAR_BIT * sizeof(TypeUnsigned)) << "(" << Value1
128 << ", " << Value2 << "): sz=" << (unsigned)ResultSz
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700129 << " llc=" << (unsigned)ResultLlc << std::endl;
130 }
131 }
132 }
133 }
134 }
135 }
136 }
137}
138
Matt Wala7fa22d82014-07-17 12:41:31 -0700139const static size_t MaxTestsPerFunc = 100000;
140
Matt Wala89a7c2b2014-07-22 10:55:30 -0700141template <typename TypeUnsignedLabel, typename TypeSignedLabel>
Matt Wala7fa22d82014-07-17 12:41:31 -0700142void testsVecInt(size_t &TotalTests, size_t &Passes, size_t &Failures) {
Matt Wala89a7c2b2014-07-22 10:55:30 -0700143 typedef typename Vectors<TypeUnsignedLabel>::Ty TypeUnsigned;
144 typedef typename Vectors<TypeSignedLabel>::Ty TypeSigned;
145 typedef typename Vectors<TypeUnsignedLabel>::ElementTy ElementTypeUnsigned;
146 typedef typename Vectors<TypeSignedLabel>::ElementTy ElementTypeSigned;
147
Matt Wala7fa22d82014-07-17 12:41:31 -0700148 typedef TypeUnsigned (*FuncTypeUnsigned)(TypeUnsigned, TypeUnsigned);
149 typedef TypeSigned (*FuncTypeSigned)(TypeSigned, TypeSigned);
Matt Wala35ec3732014-07-18 16:32:16 -0700150 volatile unsigned Values[] = INT_VALUE_ARRAY;
151 const static size_t NumValues = sizeof(Values) / sizeof(*Values);
Matt Wala7fa22d82014-07-17 12:41:31 -0700152 static struct {
153 const char *Name;
154 FuncTypeUnsigned FuncLlc;
155 FuncTypeUnsigned FuncSz;
156 bool ExcludeDivExceptions; // for divide related tests
157 } Funcs[] = {
158#define X(inst, op, isdiv) \
159 { \
160 STR(inst), (FuncTypeUnsigned)test##inst, \
161 (FuncTypeUnsigned)Subzero_::test##inst, isdiv \
162 } \
163 ,
164 UINTOP_TABLE
165#undef X
166#define X(inst, op, isdiv) \
167 { \
168 STR(inst), (FuncTypeUnsigned)(FuncTypeSigned)test##inst, \
169 (FuncTypeUnsigned)(FuncTypeSigned)Subzero_::test##inst, isdiv \
170 } \
171 ,
172 SINTOP_TABLE
173#undef X
174 };
175 const static size_t NumFuncs = sizeof(Funcs) / sizeof(*Funcs);
Matt Wala89a7c2b2014-07-22 10:55:30 -0700176 const static size_t NumElementsInType = Vectors<TypeUnsigned>::NumElements;
Matt Wala7fa22d82014-07-17 12:41:31 -0700177 for (size_t f = 0; f < NumFuncs; ++f) {
178 PRNG Index;
179 for (size_t i = 0; i < MaxTestsPerFunc; ++i) {
180 // Initialize the test vectors.
181 TypeUnsigned Value1, Value2;
182 for (size_t j = 0; j < NumElementsInType;) {
Matt Wala35ec3732014-07-18 16:32:16 -0700183 ElementTypeUnsigned Element1 = Values[Index() % NumValues];
184 ElementTypeUnsigned Element2 = Values[Index() % NumValues];
Matt Wala7fa22d82014-07-17 12:41:31 -0700185 if (Funcs[f].ExcludeDivExceptions &&
186 inputsMayTriggerException<ElementTypeSigned>(Element1, Element2))
187 continue;
188 Value1[j] = Element1;
189 Value2[j] = Element2;
190 ++j;
191 }
192 // Perform the test.
193 TypeUnsigned ResultSz = Funcs[f].FuncSz(Value1, Value2);
194 TypeUnsigned ResultLlc = Funcs[f].FuncLlc(Value1, Value2);
195 ++TotalTests;
196 if (!memcmp(&ResultSz, &ResultLlc, sizeof(ResultSz))) {
197 ++Passes;
198 } else {
Matt Wala89a7c2b2014-07-22 10:55:30 -0700199 ++Failures;
Matt Wala7fa22d82014-07-17 12:41:31 -0700200 std::cout << "test" << Funcs[f].Name << "v" << NumElementsInType << "i"
Matt Wala89a7c2b2014-07-22 10:55:30 -0700201 << (CHAR_BIT * sizeof(ElementTypeUnsigned)) << "("
202 << vectAsString<TypeUnsignedLabel>(Value1) << ","
203 << vectAsString<TypeUnsignedLabel>(Value2)
204 << "): sz=" << vectAsString<TypeUnsignedLabel>(ResultSz)
205 << " llc=" << vectAsString<TypeUnsignedLabel>(ResultLlc)
206 << std::endl;
Matt Wala7fa22d82014-07-17 12:41:31 -0700207 }
208 }
209 }
210}
211
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700212template <typename Type>
213void testsFp(size_t &TotalTests, size_t &Passes, size_t &Failures) {
214 static const Type NegInf = -1.0 / 0.0;
215 static const Type PosInf = 1.0 / 0.0;
216 static const Type Nan = 0.0 / 0.0;
Jan Voungf37fbbe2014-07-09 16:13:13 -0700217 static const Type NegNan = -0.0 / 0.0;
Matt Wala7fa22d82014-07-17 12:41:31 -0700218 volatile Type Values[] = FP_VALUE_ARRAY(NegInf, PosInf, NegNan, Nan);
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700219 const static size_t NumValues = sizeof(Values) / sizeof(*Values);
220 typedef Type (*FuncType)(Type, Type);
221 static struct {
222 const char *Name;
223 FuncType FuncLlc;
224 FuncType FuncSz;
225 } Funcs[] = {
226#define X(inst, op, func) \
227 { STR(inst), (FuncType)test##inst, (FuncType)Subzero_::test##inst } \
228 ,
229 FPOP_TABLE
230#undef X
Matt Wala7fa22d82014-07-17 12:41:31 -0700231 };
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700232 const static size_t NumFuncs = sizeof(Funcs) / sizeof(*Funcs);
233
234 for (size_t f = 0; f < NumFuncs; ++f) {
235 for (size_t i = 0; i < NumValues; ++i) {
236 for (size_t j = 0; j < NumValues; ++j) {
237 Type Value1 = Values[i];
238 Type Value2 = Values[j];
239 ++TotalTests;
240 Type ResultSz = Funcs[f].FuncSz(Value1, Value2);
241 Type ResultLlc = Funcs[f].FuncLlc(Value1, Value2);
242 // Compare results using memcmp() in case they are both NaN.
243 if (!memcmp(&ResultSz, &ResultLlc, sizeof(Type))) {
244 ++Passes;
245 } else {
246 ++Failures;
247 std::cout << std::fixed << "test" << Funcs[f].Name
Matt Wala7fa22d82014-07-17 12:41:31 -0700248 << (CHAR_BIT * sizeof(Type)) << "(" << Value1 << ", "
249 << Value2 << "): sz=" << ResultSz << " llc=" << ResultLlc
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700250 << std::endl;
251 }
252 }
253 }
254 }
Jan Voungf37fbbe2014-07-09 16:13:13 -0700255 for (size_t i = 0; i < NumValues; ++i) {
256 Type Value = Values[i];
257 ++TotalTests;
258 Type ResultSz = Subzero_::mySqrt(Value);
259 Type ResultLlc = mySqrt(Value);
260 // Compare results using memcmp() in case they are both NaN.
261 if (!memcmp(&ResultSz, &ResultLlc, sizeof(Type))) {
262 ++Passes;
263 } else {
264 ++Failures;
Matt Wala7fa22d82014-07-17 12:41:31 -0700265 std::cout << std::fixed << "test_sqrt" << (CHAR_BIT * sizeof(Type)) << "("
266 << Value << "): sz=" << ResultSz << " llc=" << ResultLlc
Jan Voungf37fbbe2014-07-09 16:13:13 -0700267 << std::endl;
268 }
269 }
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700270}
271
Matt Wala7fa22d82014-07-17 12:41:31 -0700272void testsVecFp(size_t &TotalTests, size_t &Passes, size_t &Failures) {
273 static const float NegInf = -1.0 / 0.0;
274 static const float PosInf = 1.0 / 0.0;
275 static const float Nan = 0.0 / 0.0;
276 static const float NegNan = -0.0 / 0.0;
277 volatile float Values[] = FP_VALUE_ARRAY(NegInf, PosInf, NegNan, Nan);
278 const static size_t NumValues = sizeof(Values) / sizeof(*Values);
279 typedef v4f32 (*FuncType)(v4f32, v4f32);
280 static struct {
281 const char *Name;
282 FuncType FuncLlc;
283 FuncType FuncSz;
284 } Funcs[] = {
285#define X(inst, op, func) \
286 { STR(inst), (FuncType)test##inst, (FuncType)Subzero_::test##inst } \
287 ,
288 FPOP_TABLE
289#undef X
290 };
291 const static size_t NumFuncs = sizeof(Funcs) / sizeof(*Funcs);
292 const static size_t NumElementsInType = 4;
293 for (size_t f = 0; f < NumFuncs; ++f) {
294 PRNG Index;
295 for (size_t i = 0; i < MaxTestsPerFunc; ++i) {
296 // Initialize the test vectors.
297 v4f32 Value1, Value2;
298 for (size_t j = 0; j < NumElementsInType; ++j) {
Matt Wala35ec3732014-07-18 16:32:16 -0700299 Value1[j] = Values[Index() % NumValues];
300 Value2[j] = Values[Index() % NumValues];
Matt Wala7fa22d82014-07-17 12:41:31 -0700301 }
302 // Perform the test.
303 v4f32 ResultSz = Funcs[f].FuncSz(Value1, Value2);
304 v4f32 ResultLlc = Funcs[f].FuncLlc(Value1, Value2);
305 ++TotalTests;
306 if (!memcmp(&ResultSz, &ResultLlc, sizeof(ResultSz))) {
307 ++Passes;
308 } else {
309 ++Failures;
Matt Wala89a7c2b2014-07-22 10:55:30 -0700310 std::cout << "test" << Funcs[f].Name << "v4f32"
311 << "(" << vectAsString<v4f32>(Value1) << ","
312 << vectAsString<v4f32>(Value2)
313 << "): sz=" << vectAsString<v4f32>(ResultSz) << " llc"
314 << vectAsString<v4f32>(ResultLlc) << std::endl;
Matt Wala7fa22d82014-07-17 12:41:31 -0700315 }
316 }
317 }
318}
319
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700320int main(int argc, char **argv) {
321 size_t TotalTests = 0;
322 size_t Passes = 0;
323 size_t Failures = 0;
324
325 testsInt<uint8_t, int8_t>(TotalTests, Passes, Failures);
326 testsInt<uint16_t, int16_t>(TotalTests, Passes, Failures);
327 testsInt<uint32_t, int32_t>(TotalTests, Passes, Failures);
328 testsInt<uint64_t, int64_t>(TotalTests, Passes, Failures);
Matt Wala89a7c2b2014-07-22 10:55:30 -0700329 testsVecInt<v4ui32, v4si32>(TotalTests, Passes, Failures);
330 testsVecInt<v8ui16, v8si16>(TotalTests, Passes, Failures);
331 testsVecInt<v16ui8, v16si8>(TotalTests, Passes, Failures);
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700332 testsFp<float>(TotalTests, Passes, Failures);
333 testsFp<double>(TotalTests, Passes, Failures);
Matt Wala7fa22d82014-07-17 12:41:31 -0700334 testsVecFp(TotalTests, Passes, Failures);
Jim Stichnoth5bc2b1d2014-05-22 13:38:48 -0700335
336 std::cout << "TotalTests=" << TotalTests << " Passes=" << Passes
337 << " Failures=" << Failures << "\n";
338 return Failures;
339}
Matt Wala7fa22d82014-07-17 12:41:31 -0700340
341extern "C" {
342// Subzero helpers
343 v4si32 Sz_shl_v4i32(v4si32 a, v4si32 b) { return a << b; }
344 v4si32 Sz_ashr_v4i32(v4si32 a, v4si32 b) { return a >> b; }
345 v4ui32 Sz_lshr_v4i32(v4ui32 a, v4ui32 b) { return a >> b; }
346 v4si32 Sz_sdiv_v4i32(v4si32 a, v4si32 b) { return a / b; }
347 v4ui32 Sz_udiv_v4i32(v4ui32 a, v4ui32 b) { return a / b; }
348 v4si32 Sz_srem_v4i32(v4si32 a, v4si32 b) { return a % b; }
349 v4ui32 Sz_urem_v4i32(v4ui32 a, v4ui32 b) { return a % b; }
350
351 v8si16 Sz_shl_v8i16(v8si16 a, v8si16 b) { return a << b; }
352 v8si16 Sz_ashr_v8i16(v8si16 a, v8si16 b) { return a >> b; }
353 v8ui16 Sz_lshr_v8i16(v8ui16 a, v8ui16 b) { return a >> b; }
354 v8si16 Sz_sdiv_v8i16(v8si16 a, v8si16 b) { return a / b; }
355 v8ui16 Sz_udiv_v8i16(v8ui16 a, v8ui16 b) { return a / b; }
356 v8si16 Sz_srem_v8i16(v8si16 a, v8si16 b) { return a % b; }
357 v8ui16 Sz_urem_v8i16(v8ui16 a, v8ui16 b) { return a % b; }
358
359 v16ui8 Sz_mul_v16i8(v16ui8 a, v16ui8 b) { return a * b; }
360 v16si8 Sz_shl_v16i8(v16si8 a, v16si8 b) { return a << b; }
361 v16si8 Sz_ashr_v16i8(v16si8 a, v16si8 b) { return a >> b; }
362 v16ui8 Sz_lshr_v16i8(v16ui8 a, v16ui8 b) { return a >> b; }
363 v16si8 Sz_sdiv_v16i8(v16si8 a, v16si8 b) { return a / b; }
364 v16ui8 Sz_udiv_v16i8(v16ui8 a, v16ui8 b) { return a / b; }
365 v16si8 Sz_srem_v16i8(v16si8 a, v16si8 b) { return a % b; }
366 v16ui8 Sz_urem_v16i8(v16ui8 a, v16ui8 b) { return a % b; }
367
368 v4f32 Sz_frem_v4f32(v4f32 a, v4f32 b) {
369 v4f32 Result;
370 for (int i = 0; i < 4; ++i)
371 Result[i] = fmodf(a[i], b[i]);
372 return Result;
373 }
374}