• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- 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 
14 /* crosstest.py --test=test_arith.cpp --test=test_arith_frem.ll \
15    --test=test_arith_sqrt.ll --driver=test_arith_main.cpp \
16    --prefix=Subzero_ --output=test_arith */
17 
18 #include <stdint.h>
19 
20 #include <cfloat>
21 #include <climits> // CHAR_BIT
22 #include <cmath>   // fmodf
23 #include <cstring> // memcmp
24 #include <iostream>
25 #include <limits>
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"
31 
32 namespace Subzero_ {
33 #include "test_arith.h"
34 }
35 
36 #include "insertelement.h"
37 #include "xdefs.h"
38 
inputsMayTriggerException(T Value1,T Value2)39 template <class T> bool inputsMayTriggerException(T Value1, T Value2) {
40   // Avoid HW divide-by-zero exception.
41   if (Value2 == 0)
42     return true;
43   // Avoid HW overflow exception (on x86-32).  TODO: adjust
44   // for other architecture.
45   if (Value1 == std::numeric_limits<T>::min() && Value2 == -1)
46     return true;
47   return false;
48 }
49 
50 template <typename TypeUnsigned, typename TypeSigned>
testsInt(size_t & TotalTests,size_t & Passes,size_t & Failures)51 void testsInt(size_t &TotalTests, size_t &Passes, size_t &Failures) {
52   typedef TypeUnsigned (*FuncTypeUnsigned)(TypeUnsigned, TypeUnsigned);
53   typedef TypeSigned (*FuncTypeSigned)(TypeSigned, TypeSigned);
54   volatile unsigned Values[] = INT_VALUE_ARRAY;
55   const static size_t NumValues = sizeof(Values) / sizeof(*Values);
56   static struct {
57     // For functions that operate on unsigned values, the
58     // FuncLlcSigned and FuncSzSigned fields are NULL.  For functions
59     // that operate on signed values, the FuncLlcUnsigned and
60     // FuncSzUnsigned fields are NULL.
61     const char *Name;
62     FuncTypeUnsigned FuncLlcUnsigned;
63     FuncTypeUnsigned FuncSzUnsigned;
64     FuncTypeSigned FuncLlcSigned;
65     FuncTypeSigned FuncSzSigned;
66     bool ExcludeDivExceptions; // for divide related tests
67   } Funcs[] = {
68 #define X(inst, op, isdiv, isshift)                                            \
69   {STR(inst), test##inst, Subzero_::test##inst, NULL, NULL, isdiv},
70       UINTOP_TABLE
71 #undef X
72 #define X(inst, op, isdiv, isshift)                                            \
73   {STR(inst), NULL, NULL, test##inst, Subzero_::test##inst, isdiv},
74           SINTOP_TABLE
75 #undef X
76 #define X(mult_by)                                                             \
77   {"Mult-By-" STR(mult_by),                                                    \
78    testMultiplyBy##mult_by,                                                    \
79    Subzero_::testMultiplyBy##mult_by,                                          \
80    NULL,                                                                       \
81    NULL,                                                                       \
82    false},                                                                     \
83       {"Mult-By-Neg-" STR(mult_by),                                            \
84        testMultiplyByNeg##mult_by,                                             \
85        Subzero_::testMultiplyByNeg##mult_by,                                   \
86        NULL,                                                                   \
87        NULL,                                                                   \
88        false},
89               MULIMM_TABLE};
90 #undef X
91   const static size_t NumFuncs = sizeof(Funcs) / sizeof(*Funcs);
92 
93   if (sizeof(TypeUnsigned) <= sizeof(uint32_t)) {
94     // This is the "normal" version of the loop nest, for 32-bit or
95     // narrower types.
96     for (size_t f = 0; f < NumFuncs; ++f) {
97       for (size_t i = 0; i < NumValues; ++i) {
98         for (size_t j = 0; j < NumValues; ++j) {
99           TypeUnsigned Value1 = Values[i];
100           TypeUnsigned Value2 = Values[j];
101           // Avoid HW divide-by-zero exception.
102           if (Funcs[f].ExcludeDivExceptions &&
103               inputsMayTriggerException<TypeSigned>(Value1, Value2))
104             continue;
105           ++TotalTests;
106           TypeUnsigned ResultSz, ResultLlc;
107           if (Funcs[f].FuncSzUnsigned) {
108             ResultSz = Funcs[f].FuncSzUnsigned(Value1, Value2);
109             ResultLlc = Funcs[f].FuncLlcUnsigned(Value1, Value2);
110           } else {
111             ResultSz = Funcs[f].FuncSzSigned(Value1, Value2);
112             ResultLlc = Funcs[f].FuncLlcSigned(Value1, Value2);
113           }
114           if (ResultSz == ResultLlc) {
115             ++Passes;
116           } else {
117             ++Failures;
118             std::cout << "test" << Funcs[f].Name
119                       << (CHAR_BIT * sizeof(TypeUnsigned)) << "(" << Value1
120                       << ", " << Value2 << "): sz=" << (unsigned)ResultSz
121                       << " llc=" << (unsigned)ResultLlc << "\n";
122           }
123         }
124       }
125     }
126   } else {
127     // This is the 64-bit version.  Test values are synthesized from
128     // the 32-bit values in Values[].
129     for (size_t f = 0; f < NumFuncs; ++f) {
130       for (size_t iLo = 0; iLo < NumValues; ++iLo) {
131         for (size_t iHi = 0; iHi < NumValues; ++iHi) {
132           for (size_t jLo = 0; jLo < NumValues; ++jLo) {
133             for (size_t jHi = 0; jHi < NumValues; ++jHi) {
134               TypeUnsigned Value1 =
135                   (((TypeUnsigned)Values[iHi]) << 32) + Values[iLo];
136               TypeUnsigned Value2 =
137                   (((TypeUnsigned)Values[jHi]) << 32) + Values[jLo];
138               if (Funcs[f].ExcludeDivExceptions &&
139                   inputsMayTriggerException<TypeSigned>(Value1, Value2))
140                 continue;
141               ++TotalTests;
142               TypeUnsigned ResultSz, ResultLlc;
143               if (Funcs[f].FuncSzUnsigned) {
144                 ResultSz = Funcs[f].FuncSzUnsigned(Value1, Value2);
145                 ResultLlc = Funcs[f].FuncLlcUnsigned(Value1, Value2);
146               } else {
147                 ResultSz = Funcs[f].FuncSzSigned(Value1, Value2);
148                 ResultLlc = Funcs[f].FuncLlcSigned(Value1, Value2);
149               }
150               if (ResultSz == ResultLlc) {
151                 ++Passes;
152               } else {
153                 ++Failures;
154                 std::cout << "test" << Funcs[f].Name
155                           << (CHAR_BIT * sizeof(TypeUnsigned)) << "(" << Value1
156                           << ", " << Value2 << "): sz=" << (uint64)ResultSz
157                           << " llc=" << (uint64)ResultLlc << "\n";
158               }
159             }
160           }
161         }
162       }
163     }
164   }
165 }
166 
167 const static size_t MaxTestsPerFunc = 100000;
168 
169 template <typename TypeUnsignedLabel, typename TypeSignedLabel>
testsVecInt(size_t & TotalTests,size_t & Passes,size_t & Failures)170 void testsVecInt(size_t &TotalTests, size_t &Passes, size_t &Failures) {
171   typedef typename Vectors<TypeUnsignedLabel>::Ty TypeUnsigned;
172   typedef typename Vectors<TypeSignedLabel>::Ty TypeSigned;
173   typedef typename Vectors<TypeUnsignedLabel>::ElementTy ElementTypeUnsigned;
174   typedef typename Vectors<TypeSignedLabel>::ElementTy ElementTypeSigned;
175 
176   typedef TypeUnsigned (*FuncTypeUnsigned)(TypeUnsigned, TypeUnsigned);
177   typedef TypeSigned (*FuncTypeSigned)(TypeSigned, TypeSigned);
178   volatile unsigned Values[] = INT_VALUE_ARRAY;
179   const static size_t NumValues = sizeof(Values) / sizeof(*Values);
180   static struct {
181     // For functions that operate on unsigned values, the
182     // FuncLlcSigned and FuncSzSigned fields are NULL.  For functions
183     // that operate on signed values, the FuncLlcUnsigned and
184     // FuncSzUnsigned fields are NULL.
185     const char *Name;
186     FuncTypeUnsigned FuncLlcUnsigned;
187     FuncTypeUnsigned FuncSzUnsigned;
188     FuncTypeSigned FuncLlcSigned;
189     FuncTypeSigned FuncSzSigned;
190     bool ExcludeDivExceptions; // for divide related tests
191     bool MaskShiftOperations;  // for shift related tests
192   } Funcs[] = {
193 #define X(inst, op, isdiv, isshift)                                            \
194   {STR(inst), test##inst, Subzero_::test##inst, NULL, NULL, isdiv, isshift},
195       UINTOP_TABLE
196 #undef X
197 #define X(inst, op, isdiv, isshift)                                            \
198   {STR(inst), NULL, NULL, test##inst, Subzero_::test##inst, isdiv, isshift},
199           SINTOP_TABLE
200 #undef X
201   };
202   const static size_t NumFuncs = sizeof(Funcs) / sizeof(*Funcs);
203   const static size_t NumElementsInType = Vectors<TypeUnsigned>::NumElements;
204   for (size_t f = 0; f < NumFuncs; ++f) {
205     PRNG Index;
206     for (size_t i = 0; i < MaxTestsPerFunc; ++i) {
207       // Initialize the test vectors.
208       TypeUnsigned Value1, Value2;
209       for (size_t j = 0; j < NumElementsInType; ++j) {
210         ElementTypeUnsigned Element1 = Values[Index() % NumValues];
211         ElementTypeUnsigned Element2 = Values[Index() % NumValues];
212         if (Funcs[f].ExcludeDivExceptions &&
213             inputsMayTriggerException<ElementTypeSigned>(Element1, Element2))
214           continue;
215         if (Funcs[f].MaskShiftOperations)
216           Element2 &= CHAR_BIT * sizeof(ElementTypeUnsigned) - 1;
217         setElement(Value1, j, Element1);
218         setElement(Value2, j, Element2);
219       }
220       // Perform the test.
221       TypeUnsigned ResultSz, ResultLlc;
222       ++TotalTests;
223       if (Funcs[f].FuncSzUnsigned) {
224         ResultSz = Funcs[f].FuncSzUnsigned(Value1, Value2);
225         ResultLlc = Funcs[f].FuncLlcUnsigned(Value1, Value2);
226       } else {
227         ResultSz = Funcs[f].FuncSzSigned(Value1, Value2);
228         ResultLlc = Funcs[f].FuncLlcSigned(Value1, Value2);
229       }
230       if (!memcmp(&ResultSz, &ResultLlc, sizeof(ResultSz))) {
231         ++Passes;
232       } else {
233         ++Failures;
234         std::cout << "test" << Funcs[f].Name << "v" << NumElementsInType << "i"
235                   << (CHAR_BIT * sizeof(ElementTypeUnsigned)) << "("
236                   << vectAsString<TypeUnsignedLabel>(Value1) << ","
237                   << vectAsString<TypeUnsignedLabel>(Value2)
238                   << "): sz=" << vectAsString<TypeUnsignedLabel>(ResultSz)
239                   << " llc=" << vectAsString<TypeUnsignedLabel>(ResultLlc)
240                   << "\n";
241       }
242     }
243   }
244 }
245 
246 template <typename Type>
testsFp(size_t & TotalTests,size_t & Passes,size_t & Failures)247 void testsFp(size_t &TotalTests, size_t &Passes, size_t &Failures) {
248   static const Type NegInf = -1.0 / 0.0;
249   static const Type PosInf = 1.0 / 0.0;
250   static const Type Nan = 0.0 / 0.0;
251   static const Type NegNan = -0.0 / 0.0;
252   volatile Type Values[] = FP_VALUE_ARRAY(NegInf, PosInf, NegNan, Nan);
253   const static size_t NumValues = sizeof(Values) / sizeof(*Values);
254   typedef Type (*FuncType)(Type, Type);
255   static struct {
256     const char *Name;
257     FuncType FuncLlc;
258     FuncType FuncSz;
259   } Funcs[] = {
260 #define X(inst, op, func)                                                      \
261   {STR(inst), (FuncType)test##inst, (FuncType)Subzero_::test##inst},
262       FPOP_TABLE
263 #undef X
264   };
265   const static size_t NumFuncs = sizeof(Funcs) / sizeof(*Funcs);
266 
267   for (size_t f = 0; f < NumFuncs; ++f) {
268     for (size_t i = 0; i < NumValues; ++i) {
269       for (size_t j = 0; j < NumValues; ++j) {
270         Type Value1 = Values[i];
271         Type Value2 = Values[j];
272         ++TotalTests;
273         Type ResultSz = Funcs[f].FuncSz(Value1, Value2);
274         Type ResultLlc = Funcs[f].FuncLlc(Value1, Value2);
275         // Compare results using memcmp() in case they are both NaN.
276         if (!memcmp(&ResultSz, &ResultLlc, sizeof(Type))) {
277           ++Passes;
278         } else {
279           ++Failures;
280           std::cout << std::fixed << "test" << Funcs[f].Name
281                     << (CHAR_BIT * sizeof(Type)) << "(" << Value1 << ", "
282                     << Value2 << "): sz=" << ResultSz << " llc=" << ResultLlc
283                     << "\n";
284         }
285       }
286     }
287   }
288   for (size_t i = 0; i < NumValues; ++i) {
289     Type Value = Values[i];
290     ++TotalTests;
291     Type ResultSz = Subzero_::mySqrt(Value);
292     Type ResultLlc = mySqrt(Value);
293     // Compare results using memcmp() in case they are both NaN.
294     if (!memcmp(&ResultSz, &ResultLlc, sizeof(Type))) {
295       ++Passes;
296     } else {
297       ++Failures;
298       std::cout << std::fixed << "test_sqrt" << (CHAR_BIT * sizeof(Type)) << "("
299                 << Value << "): sz=" << ResultSz << " llc=" << ResultLlc
300                 << "\n";
301     }
302     ++TotalTests;
303     ResultSz = Subzero_::myFabs(Value);
304     ResultLlc = myFabs(Value);
305     // Compare results using memcmp() in case they are both NaN.
306     if (!memcmp(&ResultSz, &ResultLlc, sizeof(Type))) {
307       ++Passes;
308     } else {
309       ++Failures;
310       std::cout << std::fixed << "test_fabs" << (CHAR_BIT * sizeof(Type)) << "("
311                 << Value << "): sz=" << ResultSz << " llc=" << ResultLlc
312                 << "\n";
313     }
314   }
315 }
316 
testsVecFp(size_t & TotalTests,size_t & Passes,size_t & Failures)317 void testsVecFp(size_t &TotalTests, size_t &Passes, size_t &Failures) {
318   static const float NegInf = -1.0 / 0.0;
319   static const float PosInf = 1.0 / 0.0;
320   static const float Nan = 0.0 / 0.0;
321   static const float NegNan = -0.0 / 0.0;
322   volatile float Values[] = FP_VALUE_ARRAY(NegInf, PosInf, NegNan, Nan);
323   const static size_t NumValues = sizeof(Values) / sizeof(*Values);
324   typedef v4f32 (*FuncType)(v4f32, v4f32);
325   static struct {
326     const char *Name;
327     FuncType FuncLlc;
328     FuncType FuncSz;
329   } Funcs[] = {
330 #define X(inst, op, func)                                                      \
331   {STR(inst), (FuncType)test##inst, (FuncType)Subzero_::test##inst},
332       FPOP_TABLE
333 #undef X
334   };
335   const static size_t NumFuncs = sizeof(Funcs) / sizeof(*Funcs);
336   const static size_t NumElementsInType = 4;
337   for (size_t f = 0; f < NumFuncs; ++f) {
338     PRNG Index;
339     for (size_t i = 0; i < MaxTestsPerFunc; ++i) {
340       // Initialize the test vectors.
341       v4f32 Value1, Value2;
342       for (size_t j = 0; j < NumElementsInType; ++j) {
343         setElement(Value1, j, Values[Index() % NumValues]);
344         setElement(Value2, j, Values[Index() % NumValues]);
345       }
346       // Perform the test.
347       v4f32 ResultSz = Funcs[f].FuncSz(Value1, Value2);
348       v4f32 ResultLlc = Funcs[f].FuncLlc(Value1, Value2);
349       ++TotalTests;
350       if (!memcmp(&ResultSz, &ResultLlc, sizeof(ResultSz))) {
351         ++Passes;
352       } else {
353         ++Failures;
354         std::cout << "test" << Funcs[f].Name << "v4f32"
355                   << "(" << vectAsString<v4f32>(Value1) << ","
356                   << vectAsString<v4f32>(Value2)
357                   << "): sz=" << vectAsString<v4f32>(ResultSz) << " llc"
358                   << vectAsString<v4f32>(ResultLlc) << "\n";
359       }
360       // Special case for unary fabs operation.  Use Value1, ignore Value2.
361       ResultSz = Subzero_::myFabs(Value1);
362       ResultLlc = myFabs(Value1);
363       ++TotalTests;
364       if (!memcmp(&ResultSz, &ResultLlc, sizeof(ResultSz))) {
365         ++Passes;
366       } else {
367         ++Failures;
368         std::cout << "test_fabs_v4f32"
369                   << "(" << vectAsString<v4f32>(Value1)
370                   << "): sz=" << vectAsString<v4f32>(ResultSz) << " llc"
371                   << vectAsString<v4f32>(ResultLlc) << "\n";
372       }
373     }
374   }
375 }
376 
main(int argc,char * argv[])377 int main(int argc, char *argv[]) {
378   size_t TotalTests = 0;
379   size_t Passes = 0;
380   size_t Failures = 0;
381 
382   testsInt<bool, bool>(TotalTests, Passes, Failures);
383   testsInt<uint8_t, myint8_t>(TotalTests, Passes, Failures);
384   testsInt<uint16_t, int16_t>(TotalTests, Passes, Failures);
385   testsInt<uint32_t, int32_t>(TotalTests, Passes, Failures);
386   testsInt<uint64, int64>(TotalTests, Passes, Failures);
387   testsVecInt<v4ui32, v4si32>(TotalTests, Passes, Failures);
388   testsVecInt<v8ui16, v8si16>(TotalTests, Passes, Failures);
389   testsVecInt<v16ui8, v16si8>(TotalTests, Passes, Failures);
390   testsFp<float>(TotalTests, Passes, Failures);
391   testsFp<double>(TotalTests, Passes, Failures);
392   testsVecFp(TotalTests, Passes, Failures);
393 
394   std::cout << "TotalTests=" << TotalTests << " Passes=" << Passes
395             << " Failures=" << Failures << "\n";
396   return Failures;
397 }
398