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