32namespace SIMDRegister_test_internal
34 template <
typename type,
typename =
void>
struct RandomPrimitive {};
36 template <
typename type>
37 struct RandomPrimitive<type, typename std::enable_if<std::is_floating_point<type>::value>::type>
39 static type next (Random& random)
41 return static_cast<type
> (std::is_signed<type>::value ? (random.nextFloat() * 16.0) - 8.0
42 : (random.nextFloat() * 8.0));
47 template <
typename type>
48 struct RandomPrimitive<type, typename std::enable_if<std::is_integral<type>::value>::type>
50 static type next (Random& random)
52 return static_cast<type
> (random.nextInt64());
57 template <
typename type>
struct RandomValue {
static type next (Random& random) {
return RandomPrimitive<type>::next (random); } };
58 template <
typename type>
59 struct RandomValue<std::complex<type>>
61 static std::complex<type> next (Random& random)
63 return {RandomPrimitive<type>::next (random), RandomPrimitive<type>::next (random)};
68 template <
typename type>
71 static void fill (type* dst,
const int size, Random& random)
73 for (
int i = 0; i < size; ++i)
74 dst[i] = RandomValue<type>::next (random);
80 template <
typename type>
81 struct VecFiller<std::complex<type>>
83 static void fill (std::complex<type>* dst,
const int size, Random& random)
85 for (
int i = 0; i < size; ++i)
86 dst[i] = std::complex<type> (RandomValue<type>::next (random), RandomValue<type>::next (random));
90 template <
typename type>
91 struct VecFiller<SIMDRegister<type>>
93 static SIMDRegister<type> fill (Random& random)
97 __declspec(align(
sizeof (SIMDRegister<type>))) type elements[size];
99 type elements[(size_t) size] __attribute__((aligned(
sizeof (SIMDRegister<type>))));
102 VecFiller<type>::fill (elements, size, random);
108 template <
typename type>
109 static type safeAbs (type a)
111 return static_cast<type
> (std::abs (
static_cast<double> (a)));
114 template <
typename type>
115 static type safeAbs (std::complex<type> a)
120 template <
typename type>
121 static double difference (type a)
123 return static_cast<double> (safeAbs (a));
126 template <
typename type>
127 static double difference (type a, type b)
129 return difference (a - b);
136class SIMDRegisterUnitTests :
public UnitTest
139 SIMDRegisterUnitTests()
140 :
UnitTest (
"SIMDRegister UnitTests", UnitTestCategories::dsp)
145 template <
typename type>
146 static bool allValuesEqualTo (
const SIMDRegister<type>& vec,
const type scalar)
154 vec.copyToRawArray (elements);
157 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
158 if (elements[i] != scalar)
return false;
163 template <
typename type>
164 static bool vecEqualToArray (
const SIMDRegister<type>& vec,
const type* array)
168 vec.copyToRawArray (ptr);
170 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
172 double delta = SIMDRegister_test_internal::difference (ptr[i], array[i]);
175 DBG (
"a: " << SIMDRegister_test_internal::difference (ptr[i]) <<
" b: " << SIMDRegister_test_internal::difference (array[i]) <<
" difference: " << delta);
183 template <
typename type>
184 static void copy (SIMDRegister<type>& vec,
const type* ptr)
192 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
201 template <
typename typeOne,
typename typeTwo>
202 static void inplace (typeOne& a,
const typeTwo& b)
207 template <
typename typeOne,
typename typeTwo>
208 static typeOne outofplace (
const typeOne& a,
const typeTwo& b)
216 template <
typename typeOne,
typename typeTwo>
217 static void inplace (typeOne& a,
const typeTwo& b)
222 template <
typename typeOne,
typename typeTwo>
223 static typeOne outofplace (
const typeOne& a,
const typeTwo& b)
229 struct Multiplication
231 template <
typename typeOne,
typename typeTwo>
232 static void inplace (typeOne& a,
const typeTwo& b)
237 template <
typename typeOne,
typename typeTwo>
238 static typeOne outofplace (
const typeOne& a,
const typeTwo& b)
246 template <
typename typeOne,
typename typeTwo>
247 static void inplace (typeOne& a,
const typeTwo& b)
252 template <
typename typeOne,
typename typeTwo>
253 static typeOne outofplace (
const typeOne& a,
const typeTwo& b)
261 template <
typename typeOne,
typename typeTwo>
262 static void inplace (typeOne& a,
const typeTwo& b)
267 template <
typename typeOne,
typename typeTwo>
268 static typeOne outofplace (
const typeOne& a,
const typeTwo& b)
276 template <
typename typeOne,
typename typeTwo>
277 static void inplace (typeOne& a,
const typeTwo& b)
282 template <
typename typeOne,
typename typeTwo>
283 static typeOne outofplace (
const typeOne& a,
const typeTwo& b)
291 struct InitializationTest
293 template <
typename type>
294 static void run (UnitTest& u, Random& random)
307 u.expect (vecEqualToArray (a, elements));
309 SIMDRegister<type> b (a);
310 a *=
static_cast<type
> (2);
312 u.expect (vecEqualToArray (b, elements));
319 template <
typename type>
320 static void run (UnitTest& u, Random& random)
323 SIMDRegister<type> a;
329 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
332 u.expect (vecEqualToArray (a, array));
335 const SIMDRegister<type>& b = a;
337 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
338 u.expect (b[i] == array[i]);
342 template <
class Operation>
345 template <
typename type>
346 static void run (UnitTest& u, Random& random)
348 for (
int n = 0; n < 100; ++n)
351 SIMDRegister<type> a (
static_cast<type
> (0));
352 SIMDRegister<type> b (
static_cast<type
> (0));
353 SIMDRegister<type> c (
static_cast<type
> (0));
363 copy (a, array_a); copy (b, array_b); copy (c, array_c);
366 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
367 Operation::template inplace<type, type> (array_a[i], array_b[i]);
369 Operation::template inplace<SIMDRegister<type>, SIMDRegister<type>> (a, b);
371 u.expect (vecEqualToArray (a, array_a));
372 u.expect (vecEqualToArray (b, array_b));
378 copy (a, array_a); copy (b, array_b); copy (c, array_c);
381 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
382 Operation::template inplace<type, type> (array_b[i],
static_cast<type
> (2));
384 Operation::template inplace<SIMDRegister<type>, type> (b, 2);
386 u.expect (vecEqualToArray (a, array_a));
387 u.expect (vecEqualToArray (b, array_b));
393 copy (a, array_a); copy (b, array_b); copy (c, array_c);
396 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
397 array_c[i] = Operation::template outofplace<type, type> (array_a[i], array_b[i]);
399 c = Operation::template outofplace<SIMDRegister<type>, SIMDRegister<type>> (a, b);
401 u.expect (vecEqualToArray (a, array_a));
402 u.expect (vecEqualToArray (b, array_b));
403 u.expect (vecEqualToArray (c, array_c));
406 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
407 array_c[i] = Operation::template outofplace<type, type> (array_b[i],
static_cast<type
> (2));
409 c = Operation::template outofplace<SIMDRegister<type>, type> (b, 2);
411 u.expect (vecEqualToArray (a, array_a));
412 u.expect (vecEqualToArray (b, array_b));
413 u.expect (vecEqualToArray (c, array_c));
418 template <
class Operation>
419 struct BitOperatorTests
421 template <
typename type>
422 static void run (UnitTest& u, Random& random)
427 for (
int n = 0; n < 100; ++n)
433 union ConversionUnion
435 inline ConversionUnion() : floatVersion (static_cast<type> (0)) {}
436 inline ~ConversionUnion() {}
437 SIMDRegister<type> floatVersion;
438 vMaskType intVersion;
441 vMaskType bitmask = vMaskType::expand (
static_cast<MaskType
> (1) << (
sizeof (MaskType) - 1));
443 copy (a.floatVersion, array_a);
444 copy (b.floatVersion, array_a);
446 Operation::template inplace<SIMDRegister<type>, vMaskType> (a.floatVersion, bitmask);
447 Operation::template inplace<vMaskType, vMaskType> (b.intVersion, bitmask);
454 b.floatVersion.copyToRawArray (elements);
456 u.expect (vecEqualToArray (a.floatVersion, elements));
460 SIMDRegister<type> a, c;
476 copy (a, float_a); copy (b, array_b); copy (c, float_c);
479 for (
size_t i = 0; i < SIMDRegister<MaskType>::SIMDNumElements; ++i)
480 Operation::template inplace<MaskType, MaskType> (array_a[i], array_b[i]);
483 Operation::template inplace<SIMDRegister<type>, vMaskType> (a, b);
485 u.expect (vecEqualToArray (a, float_a));
486 u.expect (vecEqualToArray (b, array_b));
493 copy (a, float_a); copy (b, array_b); copy (c, float_c);
496 for (
size_t i = 0; i < SIMDRegister<MaskType>::SIMDNumElements; ++i)
497 Operation::template inplace<MaskType, MaskType> (array_a[i],
static_cast<MaskType
> (9));
500 Operation::template inplace<SIMDRegister<type>, MaskType> (a,
static_cast<MaskType
> (9));
502 u.expect (vecEqualToArray (a, float_a));
503 u.expect (vecEqualToArray (b, array_b));
511 copy (a, float_a); copy (b, array_b); copy (c, float_c);
514 for (
size_t i = 0; i < SIMDRegister<MaskType>::SIMDNumElements; ++i)
517 Operation::template outofplace<MaskType, MaskType> (array_a[i], array_b[i]);
522 c = Operation::template outofplace<SIMDRegister<type>, vMaskType> (a, b);
524 u.expect (vecEqualToArray (a, float_a));
525 u.expect (vecEqualToArray (b, array_b));
526 u.expect (vecEqualToArray (c, float_c));
529 for (
size_t i = 0; i < SIMDRegister<MaskType>::SIMDNumElements; ++i)
530 array_c[i] = Operation::template outofplace<MaskType, MaskType> (array_a[i],
static_cast<MaskType
> (9));
534 c = Operation::template outofplace<SIMDRegister<type>, MaskType> (a,
static_cast<MaskType
> (9));
536 u.expect (vecEqualToArray (a, float_a));
537 u.expect (vecEqualToArray (b, array_b));
538 u.expect (vecEqualToArray (c, float_c));
543 struct CheckComparisonOps
545 template <
typename type>
546 static void run (UnitTest& u, Random& random)
551 for (
int i = 0; i < 100; ++i)
568 for (
size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
570 array_eq [j] = (array_a[j] == array_b[j]) ?
static_cast<MaskType
> (-1) : 0;
571 array_neq [j] = (array_a[j] != array_b[j]) ?
static_cast<MaskType
> (-1) : 0;
572 array_lt [j] = (array_a[j] < array_b[j]) ?
static_cast<MaskType
> (-1) : 0;
573 array_le [j] = (array_a[j] <= array_b[j]) ?
static_cast<MaskType
> (-1) : 0;
574 array_gt [j] = (array_a[j] > array_b[j]) ?
static_cast<MaskType
> (-1) : 0;
575 array_ge [j] = (array_a[j] >= array_b[j]) ?
static_cast<MaskType
> (-1) : 0;
578 SIMDRegister<type> a (
static_cast<type
> (0));
579 SIMDRegister<type> b (
static_cast<type
> (0));
581 vMaskType eq, neq, lt, le, gt, ge;
593 u.expect (vecEqualToArray (eq, array_eq ));
594 u.expect (vecEqualToArray (neq, array_neq));
595 u.expect (vecEqualToArray (lt, array_lt ));
596 u.expect (vecEqualToArray (le, array_le ));
597 u.expect (vecEqualToArray (gt, array_gt ));
598 u.expect (vecEqualToArray (ge, array_ge ));
610 u.expect (! (a == b));
611 u.expect (! (b == a));
619 u.expect (! (a != b));
620 u.expect (! (b != a));
625 u.expect (a == scalar);
626 u.expect (! (a != scalar));
630 u.expect (a != scalar);
631 u.expect (! (a == scalar));
636 struct CheckMultiplyAdd
638 template <
typename type>
639 static void run (UnitTest& u, Random& random)
653 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
654 array_d[i] = array_a[i] + (array_b[i] * array_c[i]);
656 SIMDRegister<type> a, b, c, d;
664 u.expect (vecEqualToArray (d, array_d));
670 template <
typename type>
671 static void run (UnitTest& u, Random& random)
673 for (
int i = 0; i < 100; ++i)
680 for (
size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
682 array_a[j] =
static_cast<type
> (random.nextInt (127));
683 array_b[j] =
static_cast<type
> (random.nextInt (127));
686 for (
size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
688 array_min[j] = (array_a[j] < array_b[j]) ? array_a[j] : array_b[j];
689 array_max[j] = (array_a[j] > array_b[j]) ? array_a[j] : array_b[j];
692 SIMDRegister<type> a (
static_cast<type
> (0));
693 SIMDRegister<type> b (
static_cast<type
> (0));
694 SIMDRegister<type> vMin (
static_cast<type
> (0));
695 SIMDRegister<type> vMax (
static_cast<type
> (0));
703 u.expect (vecEqualToArray (vMin, array_min));
704 u.expect (vecEqualToArray (vMax, array_max));
706 copy (vMin, array_a);
707 copy (vMax, array_a);
712 u.expect (vecEqualToArray (vMin, array_min));
713 u.expect (vecEqualToArray (vMax, array_max));
720 template <
typename type>
721 static void run (UnitTest& u, Random& random)
728 for (
size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
730 sumCheck += array[j];
733 SIMDRegister<type> a;
736 u.expect (SIMDRegister_test_internal::difference (sumCheck, a.sum()) < 1e-4);
742 template <
typename type>
743 static void run (UnitTest& u, Random& random)
750 SIMDRegister<type> a;
754 auto calcAbs = [] (type x) -> type {
return x >= type (0) ? x : -x; };
756 for (
size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
757 outArray[j] = calcAbs (inArray[j]);
759 u.expect (vecEqualToArray (a, outArray));
765 template <
typename type>
766 static void run (UnitTest& u, Random& random)
773 SIMDRegister<type> a;
777 for (
size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
778 outArray[j] = (type) (int) inArray[j];
780 u.expect (vecEqualToArray (a, outArray));
784 struct CheckBoolEquals
786 template <
typename type>
787 static void run (UnitTest& u, Random& random)
789 bool is_signed = std::is_signed<type>::value;
792 auto value = is_signed ?
static_cast<type
> ((random.nextFloat() * 16.0) - 8.0)
793 : static_cast<type> (random.nextFloat() * 8.0);
796 SIMDRegister<type> a, b;
799 u.expect (a == value);
800 u.expect (! (a != value));
803 u.expect (a != value);
804 u.expect (! (a == value));
811 u.expect (! (a != b));
817 u.expect (! (a == b));
822 template <
class TheTest>
823 void runTestFloatingPoint (
const char* unitTestName)
829 TheTest::template run<float> (*
this, random);
830 TheTest::template run<double> (*
this, random);
834 template <
class TheTest>
835 void runTestForAllTypes (
const char* unitTestName)
841 TheTest::template run<float> (*
this, random);
842 TheTest::template run<double> (*
this, random);
843 TheTest::template run<int8_t> (*
this, random);
844 TheTest::template run<uint8_t> (*
this, random);
845 TheTest::template run<int16_t> (*
this, random);
846 TheTest::template run<uint16_t>(*
this, random);
847 TheTest::template run<int32_t> (*
this, random);
848 TheTest::template run<uint32_t>(*
this, random);
849 TheTest::template run<int64_t> (*
this, random);
850 TheTest::template run<uint64_t>(*
this, random);
851 TheTest::template run<std::complex<float>> (*
this, random);
852 TheTest::template run<std::complex<double>> (*
this, random);
855 template <
class TheTest>
856 void runTestNonComplex (
const char* unitTestName)
862 TheTest::template run<float> (*
this, random);
863 TheTest::template run<double> (*
this, random);
864 TheTest::template run<int8_t> (*
this, random);
865 TheTest::template run<uint8_t> (*
this, random);
866 TheTest::template run<int16_t> (*
this, random);
867 TheTest::template run<uint16_t>(*
this, random);
868 TheTest::template run<int32_t> (*
this, random);
869 TheTest::template run<uint32_t>(*
this, random);
870 TheTest::template run<int64_t> (*
this, random);
871 TheTest::template run<uint64_t>(*
this, random);
874 template <
class TheTest>
875 void runTestSigned (
const char* unitTestName)
881 TheTest::template run<float> (*
this, random);
882 TheTest::template run<double> (*
this, random);
883 TheTest::template run<int8_t> (*
this, random);
884 TheTest::template run<int16_t> (*
this, random);
885 TheTest::template run<int32_t> (*
this, random);
886 TheTest::template run<int64_t> (*
this, random);
891 runTestForAllTypes<InitializationTest> (
"InitializationTest");
893 runTestForAllTypes<AccessTest> (
"AccessTest");
895 runTestForAllTypes<OperatorTests<Addition>> (
"AdditionOperators");
896 runTestForAllTypes<OperatorTests<Subtraction>> (
"SubtractionOperators");
897 runTestForAllTypes<OperatorTests<Multiplication>> (
"MultiplicationOperators");
899 runTestForAllTypes<BitOperatorTests<BitAND>> (
"BitANDOperators");
900 runTestForAllTypes<BitOperatorTests<BitOR>> (
"BitOROperators");
901 runTestForAllTypes<BitOperatorTests<BitXOR>> (
"BitXOROperators");
903 runTestNonComplex<CheckComparisonOps> (
"CheckComparisons");
904 runTestNonComplex<CheckBoolEquals> (
"CheckBoolEquals");
905 runTestNonComplex<CheckMinMax> (
"CheckMinMax");
907 runTestForAllTypes<CheckMultiplyAdd> (
"CheckMultiplyAdd");
908 runTestForAllTypes<CheckSum> (
"CheckSum");
910 runTestSigned<CheckAbs> (
"CheckAbs");
912 runTestFloatingPoint<CheckTruncate> (
"CheckTruncate");
916static SIMDRegisterUnitTests SIMDRegisterUnitTests;
UnitTest(const String &name, const String &category=String())
void beginTest(const String &testName)
static SIMDRegister JUCE_VECTOR_CALLTYPE truncate(SIMDRegister a) noexcept
static SIMDRegister JUCE_VECTOR_CALLTYPE expand(ElementType s) noexcept
static SIMDRegister JUCE_VECTOR_CALLTYPE max(SIMDRegister a, SIMDRegister b) noexcept
static ElementType * getNextSIMDAlignedPtr(ElementType *ptr) noexcept
static vMaskType JUCE_VECTOR_CALLTYPE greaterThanOrEqual(SIMDRegister a, SIMDRegister b) noexcept
static vMaskType JUCE_VECTOR_CALLTYPE greaterThan(SIMDRegister a, SIMDRegister b) noexcept
static bool isSIMDAligned(const ElementType *ptr) noexcept
static SIMDRegister JUCE_VECTOR_CALLTYPE abs(SIMDRegister a) noexcept
SIMDRegister< MaskType > vMaskType
static vMaskType JUCE_VECTOR_CALLTYPE equal(SIMDRegister a, SIMDRegister b) noexcept
static SIMDRegister JUCE_VECTOR_CALLTYPE multiplyAdd(SIMDRegister a, const SIMDRegister b, SIMDRegister c) noexcept
static vMaskType JUCE_VECTOR_CALLTYPE lessThan(SIMDRegister a, SIMDRegister b) noexcept
static SIMDRegister JUCE_VECTOR_CALLTYPE min(SIMDRegister a, SIMDRegister b) noexcept
static constexpr size_t SIMDNumElements
static vMaskType JUCE_VECTOR_CALLTYPE lessThanOrEqual(SIMDRegister a, SIMDRegister b) noexcept
typename SIMDInternal::MaskTypeFor< ElementType >::type MaskType
static SIMDRegister JUCE_VECTOR_CALLTYPE fromRawArray(const ElementType *a) noexcept
static vMaskType JUCE_VECTOR_CALLTYPE notEqual(SIMDRegister a, SIMDRegister b) noexcept