Home | History | Annotate | Download | only in crosstest
      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 <climits> // CHAR_BIT
     21 #include <limits>
     22 #include <cfloat>
     23 #include <cmath>   // fmodf
     24 #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"
     31 
     32 namespace Subzero_ {
     33 #include "test_arith.h"
     34 }
     35 
     36 #include "insertelement.h"
     37 #include "xdefs.h"
     38 
     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>
     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   ,
     71       UINTOP_TABLE
     72 #undef X
     73 #define X(inst, op, isdiv, isshift)                                            \
     74   { STR(inst), NULL, NULL, test##inst, Subzero_::test##inst, isdiv }           \
     75   ,
     76           SINTOP_TABLE
     77 #undef X
     78 #define X(mult_by)                                                             \
     79   {                                                                            \
     80     "Mult-By-" STR(mult_by), testMultiplyBy##mult_by,                          \
     81         Subzero_::testMultiplyBy##mult_by, NULL, NULL, false                   \
     82   }                                                                            \
     83   , {"Mult-By-Neg-" STR(mult_by), testMultiplyByNeg##mult_by,                  \
     84      Subzero_::testMultiplyByNeg##mult_by, NULL, NULL, false},
     85               MULIMM_TABLE};
     86 #undef X
     87   const static size_t NumFuncs = sizeof(Funcs) / sizeof(*Funcs);
     88 
     89   if (sizeof(TypeUnsigned) <= sizeof(uint32_t)) {
     90     // This is the "normal" version of the loop nest, for 32-bit or
     91     // narrower types.
     92     for (size_t f = 0; f < NumFuncs; ++f) {
     93       for (size_t i = 0; i < NumValues; ++i) {
     94         for (size_t j = 0; j < NumValues; ++j) {
     95           TypeUnsigned Value1 = Values[i];
     96           TypeUnsigned Value2 = Values[j];
     97           // Avoid HW divide-by-zero exception.
     98           if (Funcs[f].ExcludeDivExceptions &&
     99               inputsMayTriggerException<TypeSigned>(Value1, Value2))
    100             continue;
    101           ++TotalTests;
    102           TypeUnsigned ResultSz, ResultLlc;
    103           if (Funcs[f].FuncSzUnsigned) {
    104             ResultSz = Funcs[f].FuncSzUnsigned(Value1, Value2);
    105             ResultLlc = Funcs[f].FuncLlcUnsigned(Value1, Value2);
    106           } else {
    107             ResultSz = Funcs[f].FuncSzSigned(Value1, Value2);
    108             ResultLlc = Funcs[f].FuncLlcSigned(Value1, Value2);
    109           }
    110           if (ResultSz == ResultLlc) {
    111             ++Passes;
    112           } else {
    113             ++Failures;
    114             std::cout << "test" << Funcs[f].Name
    115                       << (CHAR_BIT * sizeof(TypeUnsigned)) << "(" << Value1
    116                       << ", " << Value2 << "): sz=" << (unsigned)ResultSz
    117                       << " llc=" << (unsigned)ResultLlc << "\n";
    118           }
    119         }
    120       }
    121     }
    122   } else {
    123     // This is the 64-bit version.  Test values are synthesized from
    124     // the 32-bit values in Values[].
    125     for (size_t f = 0; f < NumFuncs; ++f) {
    126       for (size_t iLo = 0; iLo < NumValues; ++iLo) {
    127         for (size_t iHi = 0; iHi < NumValues; ++iHi) {
    128           for (size_t jLo = 0; jLo < NumValues; ++jLo) {
    129             for (size_t jHi = 0; jHi < NumValues; ++jHi) {
    130               TypeUnsigned Value1 =
    131                   (((TypeUnsigned)Values[iHi]) << 32) + Values[iLo];
    132               TypeUnsigned Value2 =
    133                   (((TypeUnsigned)Values[jHi]) << 32) + Values[jLo];
    134               if (Funcs[f].ExcludeDivExceptions &&
    135                   inputsMayTriggerException<TypeSigned>(Value1, Value2))
    136                 continue;
    137               ++TotalTests;
    138               TypeUnsigned ResultSz, ResultLlc;
    139               if (Funcs[f].FuncSzUnsigned) {
    140                 ResultSz = Funcs[f].FuncSzUnsigned(Value1, Value2);
    141                 ResultLlc = Funcs[f].FuncLlcUnsigned(Value1, Value2);
    142               } else {
    143                 ResultSz = Funcs[f].FuncSzSigned(Value1, Value2);
    144                 ResultLlc = Funcs[f].FuncLlcSigned(Value1, Value2);
    145               }
    146               if (ResultSz == ResultLlc) {
    147                 ++Passes;
    148               } else {
    149                 ++Failures;
    150                 std::cout << "test" << Funcs[f].Name
    151                           << (CHAR_BIT * sizeof(TypeUnsigned)) << "(" << Value1
    152                           << ", " << Value2 << "): sz=" << (uint64)ResultSz
    153                           << " llc=" << (uint64)ResultLlc << "\n";
    154               }
    155             }
    156           }
    157         }
    158       }
    159     }
    160   }
    161 }
    162 
    163 const static size_t MaxTestsPerFunc = 100000;
    164 
    165 template <typename TypeUnsignedLabel, typename TypeSignedLabel>
    166 void testsVecInt(size_t &TotalTests, size_t &Passes, size_t &Failures) {
    167   typedef typename Vectors<TypeUnsignedLabel>::Ty TypeUnsigned;
    168   typedef typename Vectors<TypeSignedLabel>::Ty TypeSigned;
    169   typedef typename Vectors<TypeUnsignedLabel>::ElementTy ElementTypeUnsigned;
    170   typedef typename Vectors<TypeSignedLabel>::ElementTy ElementTypeSigned;
    171 
    172   typedef TypeUnsigned (*FuncTypeUnsigned)(TypeUnsigned, TypeUnsigned);
    173   typedef TypeSigned (*FuncTypeSigned)(TypeSigned, TypeSigned);
    174   volatile unsigned Values[] = INT_VALUE_ARRAY;
    175   const static size_t NumValues = sizeof(Values) / sizeof(*Values);
    176   static struct {
    177     // For functions that operate on unsigned values, the
    178     // FuncLlcSigned and FuncSzSigned fields are NULL.  For functions
    179     // that operate on signed values, the FuncLlcUnsigned and
    180     // FuncSzUnsigned fields are NULL.
    181     const char *Name;
    182     FuncTypeUnsigned FuncLlcUnsigned;
    183     FuncTypeUnsigned FuncSzUnsigned;
    184     FuncTypeSigned FuncLlcSigned;
    185     FuncTypeSigned FuncSzSigned;
    186     bool ExcludeDivExceptions; // for divide related tests
    187     bool MaskShiftOperations;  // for shift related tests
    188   } Funcs[] = {
    189 #define X(inst, op, isdiv, isshift)                                            \
    190   { STR(inst), test##inst, Subzero_::test##inst, NULL, NULL, isdiv, isshift }  \
    191   ,
    192       UINTOP_TABLE
    193 #undef X
    194 #define X(inst, op, isdiv, isshift)                                            \
    195   { STR(inst), NULL, NULL, test##inst, Subzero_::test##inst, isdiv, isshift }  \
    196   ,
    197           SINTOP_TABLE
    198 #undef X
    199   };
    200   const static size_t NumFuncs = sizeof(Funcs) / sizeof(*Funcs);
    201   const static size_t NumElementsInType = Vectors<TypeUnsigned>::NumElements;
    202   for (size_t f = 0; f < NumFuncs; ++f) {
    203     PRNG Index;
    204     for (size_t i = 0; i < MaxTestsPerFunc; ++i) {
    205       // Initialize the test vectors.
    206       TypeUnsigned Value1, Value2;
    207       for (size_t j = 0; j < NumElementsInType; ++j) {
    208         ElementTypeUnsigned Element1 = Values[Index() % NumValues];
    209         ElementTypeUnsigned Element2 = Values[Index() % NumValues];
    210         if (Funcs[f].ExcludeDivExceptions &&
    211             inputsMayTriggerException<ElementTypeSigned>(Element1, Element2))
    212           continue;
    213         if (Funcs[f].MaskShiftOperations)
    214           Element2 &= CHAR_BIT * sizeof(ElementTypeUnsigned) - 1;
    215         setElement(Value1, j, Element1);
    216         setElement(Value2, j, Element2);
    217       }
    218       // Perform the test.
    219       TypeUnsigned ResultSz, ResultLlc;
    220       ++TotalTests;
    221       if (Funcs[f].FuncSzUnsigned) {
    222         ResultSz = Funcs[f].FuncSzUnsigned(Value1, Value2);
    223         ResultLlc = Funcs[f].FuncLlcUnsigned(Value1, Value2);
    224       } else {
    225         ResultSz = Funcs[f].FuncSzSigned(Value1, Value2);
    226         ResultLlc = Funcs[f].FuncLlcSigned(Value1, Value2);
    227       }
    228       if (!memcmp(&ResultSz, &ResultLlc, sizeof(ResultSz))) {
    229         ++Passes;
    230       } else {
    231         ++Failures;
    232         std::cout << "test" << Funcs[f].Name << "v" << NumElementsInType << "i"
    233                   << (CHAR_BIT * sizeof(ElementTypeUnsigned)) << "("
    234                   << vectAsString<TypeUnsignedLabel>(Value1) << ","
    235                   << vectAsString<TypeUnsignedLabel>(Value2)
    236                   << "): sz=" << vectAsString<TypeUnsignedLabel>(ResultSz)
    237                   << " llc=" << vectAsString<TypeUnsignedLabel>(ResultLlc)
    238                   << "\n";
    239       }
    240     }
    241   }
    242 }
    243 
    244 template <typename Type>
    245 void testsFp(size_t &TotalTests, size_t &Passes, size_t &Failures) {
    246   static const Type NegInf = -1.0 / 0.0;
    247   static const Type PosInf = 1.0 / 0.0;
    248   static const Type Nan = 0.0 / 0.0;
    249   static const Type NegNan = -0.0 / 0.0;
    250   volatile Type Values[] = FP_VALUE_ARRAY(NegInf, PosInf, NegNan, Nan);
    251   const static size_t NumValues = sizeof(Values) / sizeof(*Values);
    252   typedef Type (*FuncType)(Type, Type);
    253   static struct {
    254     const char *Name;
    255     FuncType FuncLlc;
    256     FuncType FuncSz;
    257   } Funcs[] = {
    258 #define X(inst, op, func)                                                      \
    259   { STR(inst), (FuncType)test##inst, (FuncType)Subzero_::test##inst }          \
    260   ,
    261       FPOP_TABLE
    262 #undef X
    263   };
    264   const static size_t NumFuncs = sizeof(Funcs) / sizeof(*Funcs);
    265 
    266   for (size_t f = 0; f < NumFuncs; ++f) {
    267     for (size_t i = 0; i < NumValues; ++i) {
    268       for (size_t j = 0; j < NumValues; ++j) {
    269         Type Value1 = Values[i];
    270         Type Value2 = Values[j];
    271         ++TotalTests;
    272         Type ResultSz = Funcs[f].FuncSz(Value1, Value2);
    273         Type ResultLlc = Funcs[f].FuncLlc(Value1, Value2);
    274         // Compare results using memcmp() in case they are both NaN.
    275         if (!memcmp(&ResultSz, &ResultLlc, sizeof(Type))) {
    276           ++Passes;
    277         } else {
    278           ++Failures;
    279           std::cout << std::fixed << "test" << Funcs[f].Name
    280                     << (CHAR_BIT * sizeof(Type)) << "(" << Value1 << ", "
    281                     << Value2 << "): sz=" << ResultSz << " llc=" << ResultLlc
    282                     << "\n";
    283         }
    284       }
    285     }
    286   }
    287   for (size_t i = 0; i < NumValues; ++i) {
    288     Type Value = Values[i];
    289     ++TotalTests;
    290     Type ResultSz = Subzero_::mySqrt(Value);
    291     Type ResultLlc = mySqrt(Value);
    292     // Compare results using memcmp() in case they are both NaN.
    293     if (!memcmp(&ResultSz, &ResultLlc, sizeof(Type))) {
    294       ++Passes;
    295     } else {
    296       ++Failures;
    297       std::cout << std::fixed << "test_sqrt" << (CHAR_BIT * sizeof(Type)) << "("
    298                 << Value << "): sz=" << ResultSz << " llc=" << ResultLlc
    299                 << "\n";
    300     }
    301     ++TotalTests;
    302     ResultSz = Subzero_::myFabs(Value);
    303     ResultLlc = myFabs(Value);
    304     // Compare results using memcmp() in case they are both NaN.
    305     if (!memcmp(&ResultSz, &ResultLlc, sizeof(Type))) {
    306       ++Passes;
    307     } else {
    308       ++Failures;
    309       std::cout << std::fixed << "test_fabs" << (CHAR_BIT * sizeof(Type)) << "("
    310                 << Value << "): sz=" << ResultSz << " llc=" << ResultLlc
    311                 << "\n";
    312     }
    313   }
    314 }
    315 
    316 void testsVecFp(size_t &TotalTests, size_t &Passes, size_t &Failures) {
    317   static const float NegInf = -1.0 / 0.0;
    318   static const float PosInf = 1.0 / 0.0;
    319   static const float Nan = 0.0 / 0.0;
    320   static const float NegNan = -0.0 / 0.0;
    321   volatile float Values[] = FP_VALUE_ARRAY(NegInf, PosInf, NegNan, Nan);
    322   const static size_t NumValues = sizeof(Values) / sizeof(*Values);
    323   typedef v4f32 (*FuncType)(v4f32, v4f32);
    324   static struct {
    325     const char *Name;
    326     FuncType FuncLlc;
    327     FuncType FuncSz;
    328   } Funcs[] = {
    329 #define X(inst, op, func)                                                      \
    330   { STR(inst), (FuncType)test##inst, (FuncType)Subzero_::test##inst }          \
    331   ,
    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 
    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