29namespace SIMDRegister_test_internal
31 template <
typename type>
32 struct RandomPrimitive
34 static type next (Random& random)
36 if constexpr (std::is_floating_point_v<type>)
38 return static_cast<type
> (std::is_signed_v<type> ? (random.nextFloat() * 16.0) - 8.0
39 : (random.nextFloat() * 8.0));
41 else if constexpr (std::is_integral_v<type>)
43 return static_cast<type
> (random.nextInt64());
48 template <
typename type>
51 static type next (Random& random)
53 return RandomPrimitive<type>::next (random);
57 template <
typename type>
58 struct RandomValue<std::complex<type>>
60 static std::complex<type> next (Random& random)
62 return {RandomPrimitive<type>::next (random), RandomPrimitive<type>::next (random)};
66 template <
typename type>
67 static void fillVec (type* dst, Random& random)
71 return RandomValue<type>::next (random);
76 template <
typename type>
77 static type safeAbs (type a)
79 return static_cast<type
> (std::abs (
static_cast<double> (a)));
82 template <
typename type>
83 static type safeAbs (std::complex<type> a)
88 template <
typename type>
89 static double difference (type a)
91 return static_cast<double> (safeAbs (a));
94 template <
typename type>
95 static double difference (type a, type b)
97 return difference (a - b);
104class SIMDRegisterUnitTests final :
public UnitTest
107 template <
typename>
struct Tag {};
109 SIMDRegisterUnitTests()
110 :
UnitTest (
"SIMDRegister UnitTests", UnitTestCategories::dsp)
115 template <
typename type>
116 static bool allValuesEqualTo (
const SIMDRegister<type>& vec,
const type scalar)
120 vec.copyToRawArray (elements);
123 return std::all_of (std::begin (elements), std::end (elements), [scalar] (
const auto x) {
return exactlyEqual (x, scalar); });
126 template <
typename type>
127 static bool vecEqualToArray (
const SIMDRegister<type>& vec,
const type* array)
131 vec.copyToRawArray (ptr);
133 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
135 double delta = SIMDRegister_test_internal::difference (ptr[i], array[i]);
138 DBG (
"a: " << SIMDRegister_test_internal::difference (ptr[i]) <<
" b: " << SIMDRegister_test_internal::difference (array[i]) <<
" difference: " << delta);
146 template <
typename type>
147 static void copy (SIMDRegister<type>& vec,
const type* ptr)
155 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
164 template <
typename typeOne,
typename typeTwo>
165 static void inplace (typeOne& a,
const typeTwo& b)
170 template <
typename typeOne,
typename typeTwo>
171 static typeOne outofplace (
const typeOne& a,
const typeTwo& b)
179 template <
typename typeOne,
typename typeTwo>
180 static void inplace (typeOne& a,
const typeTwo& b)
185 template <
typename typeOne,
typename typeTwo>
186 static typeOne outofplace (
const typeOne& a,
const typeTwo& b)
192 struct Multiplication
194 template <
typename typeOne,
typename typeTwo>
195 static void inplace (typeOne& a,
const typeTwo& b)
200 template <
typename typeOne,
typename typeTwo>
201 static typeOne outofplace (
const typeOne& a,
const typeTwo& b)
209 template <
typename typeOne,
typename typeTwo>
210 static void inplace (typeOne& a,
const typeTwo& b)
215 template <
typename typeOne,
typename typeTwo>
216 static typeOne outofplace (
const typeOne& a,
const typeTwo& b)
224 template <
typename typeOne,
typename typeTwo>
225 static void inplace (typeOne& a,
const typeTwo& b)
230 template <
typename typeOne,
typename typeTwo>
231 static typeOne outofplace (
const typeOne& a,
const typeTwo& b)
239 template <
typename typeOne,
typename typeTwo>
240 static void inplace (typeOne& a,
const typeTwo& b)
245 template <
typename typeOne,
typename typeTwo>
246 static typeOne outofplace (
const typeOne& a,
const typeTwo& b)
254 struct InitializationTest
256 template <
typename type>
257 static void run (
UnitTest& u, Random& random, Tag<type>)
267 SIMDRegister_test_internal::fillVec (elements, random);
270 u.expect (vecEqualToArray (a, elements));
272 SIMDRegister<type> b (a);
273 a *=
static_cast<type
> (2);
275 u.expect (vecEqualToArray (b, elements));
282 template <
typename type>
283 static void run (
UnitTest& u, Random& random, Tag<type>)
286 SIMDRegister<type> a;
289 SIMDRegister_test_internal::fillVec (array, random);
292 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
295 u.expect (vecEqualToArray (a, array));
298 const SIMDRegister<type>& b = a;
300 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
301 u.expect (exactlyEqual (b[i], array[i]));
305 template <
class Operation>
308 template <
typename type>
309 static void run (
UnitTest& u, Random& random, Tag<type>)
311 for (
int n = 0; n < 100; ++n)
314 SIMDRegister<type> a (
static_cast<type
> (0));
315 SIMDRegister<type> b (
static_cast<type
> (0));
316 SIMDRegister<type> c (
static_cast<type
> (0));
322 SIMDRegister_test_internal::fillVec (array_a, random);
323 SIMDRegister_test_internal::fillVec (array_b, random);
324 SIMDRegister_test_internal::fillVec (array_c, random);
326 copy (a, array_a); copy (b, array_b); copy (c, array_c);
329 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
330 Operation::template inplace<type, type> (array_a[i], array_b[i]);
332 Operation::template inplace<SIMDRegister<type>, SIMDRegister<type>> (a, b);
334 u.expect (vecEqualToArray (a, array_a));
335 u.expect (vecEqualToArray (b, array_b));
337 SIMDRegister_test_internal::fillVec (array_a, random);
338 SIMDRegister_test_internal::fillVec (array_b, random);
339 SIMDRegister_test_internal::fillVec (array_c, random);
341 copy (a, array_a); copy (b, array_b); copy (c, array_c);
344 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
345 Operation::template inplace<type, type> (array_b[i],
static_cast<type
> (2));
347 Operation::template inplace<SIMDRegister<type>, type> (b, 2);
349 u.expect (vecEqualToArray (a, array_a));
350 u.expect (vecEqualToArray (b, array_b));
353 SIMDRegister_test_internal::fillVec (array_a, random);
354 SIMDRegister_test_internal::fillVec (array_b, random);
355 SIMDRegister_test_internal::fillVec (array_c, random);
356 copy (a, array_a); copy (b, array_b); copy (c, array_c);
359 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
360 array_c[i] = Operation::template outofplace<type, type> (array_a[i], array_b[i]);
362 c = Operation::template outofplace<SIMDRegister<type>, SIMDRegister<type>> (a, b);
364 u.expect (vecEqualToArray (a, array_a));
365 u.expect (vecEqualToArray (b, array_b));
366 u.expect (vecEqualToArray (c, array_c));
369 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
370 array_c[i] = Operation::template outofplace<type, type> (array_b[i],
static_cast<type
> (2));
372 c = Operation::template outofplace<SIMDRegister<type>, type> (b, 2);
374 u.expect (vecEqualToArray (a, array_a));
375 u.expect (vecEqualToArray (b, array_b));
376 u.expect (vecEqualToArray (c, array_c));
381 template <
class Operation>
382 struct BitOperatorTests
384 template <
typename type>
385 static void run (
UnitTest& u, Random& random, Tag<type>)
390 for (
int n = 0; n < 100; ++n)
396 union ConversionUnion
398 inline ConversionUnion() : floatVersion (static_cast<type> (0)) {}
399 inline ~ConversionUnion() {}
400 SIMDRegister<type> floatVersion;
401 vMaskType intVersion;
404 vMaskType bitmask = vMaskType::expand (
static_cast<MaskType
> (1) << (
sizeof (MaskType) - 1));
405 SIMDRegister_test_internal::fillVec (array_a, random);
406 copy (a.floatVersion, array_a);
407 copy (b.floatVersion, array_a);
409 Operation::template inplace<SIMDRegister<type>, vMaskType> (a.floatVersion, bitmask);
410 Operation::template inplace<vMaskType, vMaskType> (b.intVersion, bitmask);
417 b.floatVersion.copyToRawArray (elements);
419 u.expect (vecEqualToArray (a.floatVersion, elements));
423 SIMDRegister<type> a, c;
433 SIMDRegister_test_internal::fillVec (float_a, random);
434 SIMDRegister_test_internal::fillVec (array_b, random);
435 SIMDRegister_test_internal::fillVec (float_c, random);
439 copy (a, float_a); copy (b, array_b); copy (c, float_c);
442 for (
size_t i = 0; i < SIMDRegister<MaskType>::SIMDNumElements; ++i)
443 Operation::template inplace<MaskType, MaskType> (array_a[i], array_b[i]);
446 Operation::template inplace<SIMDRegister<type>, vMaskType> (a, b);
448 u.expect (vecEqualToArray (a, float_a));
449 u.expect (vecEqualToArray (b, array_b));
451 SIMDRegister_test_internal::fillVec (float_a, random);
452 SIMDRegister_test_internal::fillVec (array_b, random);
453 SIMDRegister_test_internal::fillVec (float_c, random);
456 copy (a, float_a); copy (b, array_b); copy (c, float_c);
459 for (
size_t i = 0; i < SIMDRegister<MaskType>::SIMDNumElements; ++i)
460 Operation::template inplace<MaskType, MaskType> (array_a[i],
static_cast<MaskType
> (9));
463 Operation::template inplace<SIMDRegister<type>, MaskType> (a,
static_cast<MaskType
> (9));
465 u.expect (vecEqualToArray (a, float_a));
466 u.expect (vecEqualToArray (b, array_b));
469 SIMDRegister_test_internal::fillVec (float_a, random);
470 SIMDRegister_test_internal::fillVec (array_b, random);
471 SIMDRegister_test_internal::fillVec (float_c, random);
474 copy (a, float_a); copy (b, array_b); copy (c, float_c);
477 for (
size_t i = 0; i < SIMDRegister<MaskType>::SIMDNumElements; ++i)
480 Operation::template outofplace<MaskType, MaskType> (array_a[i], array_b[i]);
485 c = Operation::template outofplace<SIMDRegister<type>, vMaskType> (a, b);
487 u.expect (vecEqualToArray (a, float_a));
488 u.expect (vecEqualToArray (b, array_b));
489 u.expect (vecEqualToArray (c, float_c));
492 for (
size_t i = 0; i < SIMDRegister<MaskType>::SIMDNumElements; ++i)
493 array_c[i] = Operation::template outofplace<MaskType, MaskType> (array_a[i],
static_cast<MaskType
> (9));
497 c = Operation::template outofplace<SIMDRegister<type>, MaskType> (a,
static_cast<MaskType
> (9));
499 u.expect (vecEqualToArray (a, float_a));
500 u.expect (vecEqualToArray (b, array_b));
501 u.expect (vecEqualToArray (c, float_c));
506 struct CheckComparisonOps
508 template <
typename type>
509 static void run (
UnitTest& u, Random& random, Tag<type>)
514 for (
int i = 0; i < 100; ++i)
527 SIMDRegister_test_internal::fillVec (array_a, random);
528 SIMDRegister_test_internal::fillVec (array_b, random);
531 for (
size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
533 array_eq [j] = ( exactlyEqual (array_a[j], array_b[j])) ?
static_cast<MaskType
> (-1) : 0;
534 array_neq [j] = (! exactlyEqual (array_a[j], array_b[j])) ?
static_cast<MaskType
> (-1) : 0;
535 array_lt [j] = (array_a[j] < array_b[j]) ?
static_cast<MaskType
> (-1) : 0;
536 array_le [j] = (array_a[j] <= array_b[j]) ?
static_cast<MaskType
> (-1) : 0;
537 array_gt [j] = (array_a[j] > array_b[j]) ?
static_cast<MaskType
> (-1) : 0;
538 array_ge [j] = (array_a[j] >= array_b[j]) ?
static_cast<MaskType
> (-1) : 0;
541 SIMDRegister<type> a (
static_cast<type
> (0));
542 SIMDRegister<type> b (
static_cast<type
> (0));
544 vMaskType eq, neq, lt, le, gt, ge;
556 u.expect (vecEqualToArray (eq, array_eq ));
557 u.expect (vecEqualToArray (neq, array_neq));
558 u.expect (vecEqualToArray (lt, array_lt ));
559 u.expect (vecEqualToArray (le, array_le ));
560 u.expect (vecEqualToArray (gt, array_gt ));
561 u.expect (vecEqualToArray (ge, array_ge ));
565 SIMDRegister_test_internal::fillVec (array_a, random);
566 SIMDRegister_test_internal::fillVec (array_b, random);
573 u.expect (! (a == b));
574 u.expect (! (b == a));
576 SIMDRegister_test_internal::fillVec (array_a, random);
582 u.expect (! (a != b));
583 u.expect (! (b != a));
588 u.expect (a == scalar);
589 u.expect (! (a != scalar));
593 u.expect (a != scalar);
594 u.expect (! (a == scalar));
599 struct CheckMultiplyAdd
601 template <
typename type>
602 static void run (
UnitTest& u, Random& random, Tag<type>)
610 SIMDRegister_test_internal::fillVec (array_a, random);
611 SIMDRegister_test_internal::fillVec (array_b, random);
612 SIMDRegister_test_internal::fillVec (array_c, random);
613 SIMDRegister_test_internal::fillVec (array_d, random);
616 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
617 array_d[i] = array_a[i] + (array_b[i] * array_c[i]);
619 SIMDRegister<type> a, b, c, d;
627 u.expect (vecEqualToArray (d, array_d));
633 template <
typename type>
634 static void run (
UnitTest& u, Random& random, Tag<type>)
636 for (
int i = 0; i < 100; ++i)
643 for (
size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
645 array_a[j] =
static_cast<type
> (random.nextInt (127));
646 array_b[j] =
static_cast<type
> (random.nextInt (127));
649 for (
size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
651 array_min[j] = (array_a[j] < array_b[j]) ? array_a[j] : array_b[j];
652 array_max[j] = (array_a[j] > array_b[j]) ? array_a[j] : array_b[j];
655 SIMDRegister<type> a (
static_cast<type
> (0));
656 SIMDRegister<type> b (
static_cast<type
> (0));
657 SIMDRegister<type> vMin (
static_cast<type
> (0));
658 SIMDRegister<type> vMax (
static_cast<type
> (0));
666 u.expect (vecEqualToArray (vMin, array_min));
667 u.expect (vecEqualToArray (vMax, array_max));
669 copy (vMin, array_a);
670 copy (vMax, array_a);
675 u.expect (vecEqualToArray (vMin, array_min));
676 u.expect (vecEqualToArray (vMax, array_max));
683 template <
typename type>
684 static void run (
UnitTest& u, Random& random, Tag<type>)
688 SIMDRegister_test_internal::fillVec (array, random);
690 using AddedType =
decltype (type{} + type{});
691 const auto sumCheck = (type) std::accumulate (std::begin (array), std::end (array), AddedType{});
693 SIMDRegister<type> a;
696 u.expect (SIMDRegister_test_internal::difference (sumCheck, a.sum()) < 1e-4);
702 template <
typename type>
703 static void run (
UnitTest& u, Random& random, Tag<type>)
708 SIMDRegister_test_internal::fillVec (inArray, random);
710 SIMDRegister<type> a;
714 auto calcAbs = [] (type x) -> type {
return x >= type (0) ? x : type (-x); };
716 for (
size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
717 outArray[j] = calcAbs (inArray[j]);
719 u.expect (vecEqualToArray (a, outArray));
725 template <
typename type>
726 static void run (
UnitTest& u, Random& random, Tag<type>)
731 SIMDRegister_test_internal::fillVec (inArray, random);
733 SIMDRegister<type> a;
737 for (
size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
738 outArray[j] = (type) (int) inArray[j];
740 u.expect (vecEqualToArray (a, outArray));
744 struct CheckBoolEquals
746 template <
typename type>
747 static void run (
UnitTest& u, Random& random, Tag<type>)
751 auto value = std::is_signed_v<type> ?
static_cast<type
> ((random.nextFloat() * 16.0) - 8.0)
752 : static_cast<type> (random.nextFloat() * 8.0);
755 SIMDRegister<type> a, b;
758 u.expect (a == value);
759 u.expect (! (a != value));
762 u.expect (a != value);
763 u.expect (! (a == value));
765 SIMDRegister_test_internal::fillVec (array, random);
770 u.expect (! (a != b));
772 SIMDRegister_test_internal::fillVec (array, random);
776 u.expect (! (a == b));
781 template <
class TheTest>
782 void runTestFloatingPoint (
const char* unitTestName, TheTest)
788 TheTest::run (*
this, random, Tag<float> {});
789 TheTest::run (*
this, random, Tag<double>{});
793 template <
class TheTest>
794 void runTestForAllTypes (
const char* unitTestName, TheTest)
800 TheTest::run (*
this, random, Tag<float> {});
801 TheTest::run (*
this, random, Tag<double> {});
802 TheTest::run (*
this, random, Tag<int8_t> {});
803 TheTest::run (*
this, random, Tag<uint8_t> {});
804 TheTest::run (*
this, random, Tag<int16_t> {});
805 TheTest::run (*
this, random, Tag<uint16_t> {});
806 TheTest::run (*
this, random, Tag<int32_t> {});
807 TheTest::run (*
this, random, Tag<uint32_t> {});
808 TheTest::run (*
this, random, Tag<int64_t> {});
809 TheTest::run (*
this, random, Tag<uint64_t> {});
810 TheTest::run (*
this, random, Tag<std::complex<float>> {});
811 TheTest::run (*
this, random, Tag<std::complex<double>>{});
814 template <
class TheTest>
815 void runTestNonComplex (
const char* unitTestName, TheTest)
821 TheTest::run (*
this, random, Tag<float> {});
822 TheTest::run (*
this, random, Tag<double> {});
823 TheTest::run (*
this, random, Tag<int8_t> {});
824 TheTest::run (*
this, random, Tag<uint8_t> {});
825 TheTest::run (*
this, random, Tag<int16_t> {});
826 TheTest::run (*
this, random, Tag<uint16_t>{});
827 TheTest::run (*
this, random, Tag<int32_t> {});
828 TheTest::run (*
this, random, Tag<uint32_t>{});
829 TheTest::run (*
this, random, Tag<int64_t> {});
830 TheTest::run (*
this, random, Tag<uint64_t>{});
833 template <
class TheTest>
834 void runTestSigned (
const char* unitTestName, TheTest)
840 TheTest::run (*
this, random, Tag<float> {});
841 TheTest::run (*
this, random, Tag<double> {});
842 TheTest::run (*
this, random, Tag<int8_t> {});
843 TheTest::run (*
this, random, Tag<int16_t>{});
844 TheTest::run (*
this, random, Tag<int32_t>{});
845 TheTest::run (*
this, random, Tag<int64_t>{});
850 runTestForAllTypes (
"InitializationTest", InitializationTest{});
852 runTestForAllTypes (
"AccessTest", AccessTest{});
854 runTestForAllTypes (
"AdditionOperators", OperatorTests<Addition>{});
855 runTestForAllTypes (
"SubtractionOperators", OperatorTests<Subtraction>{});
856 runTestForAllTypes (
"MultiplicationOperators", OperatorTests<Multiplication>{});
858 runTestForAllTypes (
"BitANDOperators", BitOperatorTests<BitAND>{});
859 runTestForAllTypes (
"BitOROperators", BitOperatorTests<BitOR>{});
860 runTestForAllTypes (
"BitXOROperators", BitOperatorTests<BitXOR>{});
862 runTestNonComplex (
"CheckComparisons", CheckComparisonOps{});
863 runTestNonComplex (
"CheckBoolEquals", CheckBoolEquals{});
864 runTestNonComplex (
"CheckMinMax", CheckMinMax{});
866 runTestForAllTypes (
"CheckMultiplyAdd", CheckMultiplyAdd{});
867 runTestForAllTypes (
"CheckSum", CheckSum{});
869 runTestSigned (
"CheckAbs", CheckAbs{});
871 runTestFloatingPoint (
"CheckTruncate", CheckTruncate{});
875static 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
SIMDInternal::MaskType< ElementType > MaskType
static vMaskType JUCE_VECTOR_CALLTYPE lessThanOrEqual(SIMDRegister a, SIMDRegister b) noexcept
static SIMDRegister JUCE_VECTOR_CALLTYPE fromRawArray(const ElementType *a) noexcept
static vMaskType JUCE_VECTOR_CALLTYPE notEqual(SIMDRegister a, SIMDRegister b) noexcept