32 namespace SIMDRegister_test_internal
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
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());
58 template <
typename type>
61 static std::complex<type> next (
Random& random)
68 template <
typename type>
71 static void fill (type* dst,
const int size,
Random& random)
73 for (
int i = 0; i < size; ++i)
80 template <
typename type>
83 static void fill (std::complex<type>* dst,
const int size,
Random& random)
85 for (
int i = 0; i < size; ++i)
90 template <
typename type>
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);
140 :
UnitTest (
"SIMDRegister UnitTests", UnitTestCategories::dsp)
145 template <
typename type>
157 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
158 if (elements[i] != scalar)
return false;
163 template <
typename type>
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>
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)
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)
293 template <
typename type>
307 u.
expect (vecEqualToArray (a, elements));
310 a *=
static_cast<type
> (2);
312 u.
expect (vecEqualToArray (b, elements));
319 template <
typename type>
329 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
332 u.
expect (vecEqualToArray (a, array));
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>
348 for (
int n = 0; n < 100; ++n)
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]);
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]);
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>
421 template <
typename type>
427 for (
int n = 0; n < 100; ++n)
433 union ConversionUnion
435 inline ConversionUnion() : floatVersion (
static_cast<type
> (0)) {}
436 inline ~ConversionUnion() {}
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));
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));
545 template <
typename type>
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;
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 ));
626 u.
expect (! (a != scalar));
631 u.
expect (! (a == scalar));
638 template <
typename type>
653 for (
size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
654 array_d[i] = array_a[i] + (array_b[i] * array_c[i]);
664 u.
expect (vecEqualToArray (d, array_d));
670 template <
typename type>
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];
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>
728 for (
size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
730 sumCheck += array[j];
736 u.
expect (SIMDRegister_test_internal::difference (sumCheck, a.
sum()) < 1e-4);
742 template <
typename type>
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>
777 for (
size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
778 outArray[j] = (type) (int) inArray[j];
780 u.
expect (vecEqualToArray (a, outArray));
786 template <
typename type>
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);
800 u.
expect (! (a != value));
804 u.
expect (! (a == value));
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");
916 static SIMDRegisterUnitTests SIMDRegisterUnitTests;
Very simple container class to hold a pointer to some data on the heap.
ElementType * getData() const noexcept
Returns a raw pointer to the allocated data.
A random number generator.
float nextFloat() noexcept
Returns the next random floating-point number.
int nextInt() noexcept
Returns the next random 32 bit integer.
int64 nextInt64() noexcept
Returns the next 64-bit random number.
This is a base class for classes that perform a unit test.
UnitTest(const String &name, const String &category=String())
Creates a test with the given name and optionally places it in a category.
void beginTest(const String &testName)
Tells the system that a new subsection of tests is beginning.
void expect(bool testResult, const String &failureMessage=String())
Checks that the result of a test is true, and logs this result.
Random getRandom() const
Returns a shared RNG that all unit tests should use.
void runTest()
Implement this method in your subclass to actually run your tests.
A wrapper around the platform's native SIMD register type.
static SIMDRegister JUCE_VECTOR_CALLTYPE truncate(SIMDRegister a) noexcept
Truncates each element to its integer part.
static SIMDRegister JUCE_VECTOR_CALLTYPE expand(ElementType s) noexcept
Creates a new SIMDRegister from the corresponding scalar primitive.
ElementType sum() const noexcept
Returns a scalar which is the sum of all elements of the receiver.
void JUCE_VECTOR_CALLTYPE copyToRawArray(ElementType *a) const noexcept
Copies the elements of the SIMDRegister to a scalar array in memory.
static SIMDRegister JUCE_VECTOR_CALLTYPE max(SIMDRegister a, SIMDRegister b) noexcept
Returns a new vector where each element is the maximum of the corresponding element of a and b.
static vMaskType JUCE_VECTOR_CALLTYPE greaterThanOrEqual(SIMDRegister a, SIMDRegister b) noexcept
Returns a SIMDRegister of the corresponding integral type where each element has each bit set if the ...
static vMaskType JUCE_VECTOR_CALLTYPE greaterThan(SIMDRegister a, SIMDRegister b) noexcept
Returns a SIMDRegister of the corresponding integral type where each element has each bit set if the ...
static SIMDRegister JUCE_VECTOR_CALLTYPE abs(SIMDRegister a) noexcept
Returns the absolute value of each element.
static vMaskType JUCE_VECTOR_CALLTYPE equal(SIMDRegister a, SIMDRegister b) noexcept
Returns a SIMDRegister of the corresponding integral type where each element has each bit set if the ...
static SIMDRegister JUCE_VECTOR_CALLTYPE multiplyAdd(SIMDRegister a, const SIMDRegister b, SIMDRegister c) noexcept
Multiplies b and c and adds the result to a.
static vMaskType JUCE_VECTOR_CALLTYPE lessThan(SIMDRegister a, SIMDRegister b) noexcept
Returns a SIMDRegister of the corresponding integral type where each element has each bit set if the ...
static SIMDRegister JUCE_VECTOR_CALLTYPE min(SIMDRegister a, SIMDRegister b) noexcept
Returns a new vector where each element is the minimum of the corresponding element of a and b.
static vMaskType JUCE_VECTOR_CALLTYPE lessThanOrEqual(SIMDRegister a, SIMDRegister b) noexcept
Returns a SIMDRegister of the corresponding integral type where each element has each bit set if the ...
static ElementType * getNextSIMDAlignedPtr(ElementType *ptr) noexcept
Returns the next position in memory where isSIMDAligned returns true.
typename SIMDInternal::MaskTypeFor< ElementType >::type MaskType
The corresponding primitive integer type, for example, this will be int32_t if type is a float.
static SIMDRegister JUCE_VECTOR_CALLTYPE fromRawArray(const ElementType *a) noexcept
Creates a new SIMDRegister from the first SIMDNumElements of a scalar array.
static vMaskType JUCE_VECTOR_CALLTYPE notEqual(SIMDRegister a, SIMDRegister b) noexcept
Returns a SIMDRegister of the corresponding integral type where each element has each bit set if the ...