The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

843 lines
33KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. namespace juce
  20. {
  21. namespace dsp
  22. {
  23. namespace SIMDRegister_test_internal
  24. {
  25. template <typename type, typename = void> struct RandomPrimitive {};
  26. template <typename type>
  27. struct RandomPrimitive<type, typename std::enable_if<std::is_floating_point<type>::value>::type>
  28. {
  29. static type next (Random& random)
  30. {
  31. return static_cast<type> (std::is_signed<type>::value ? (random.nextFloat() * 16.0) - 8.0
  32. : (random.nextFloat() * 8.0));
  33. }
  34. };
  35. template <typename type>
  36. struct RandomPrimitive<type, typename std::enable_if<std::is_integral<type>::value>::type>
  37. {
  38. static type next (Random& random)
  39. {
  40. return static_cast<type> (random.nextInt64());
  41. }
  42. };
  43. template <typename type> struct RandomValue { static type next (Random& random) { return RandomPrimitive<type>::next (random); } };
  44. template <typename type>
  45. struct RandomValue<std::complex<type>>
  46. {
  47. static std::complex<type> next (Random& random)
  48. {
  49. return {RandomPrimitive<type>::next (random), RandomPrimitive<type>::next (random)};
  50. }
  51. };
  52. template <typename type>
  53. struct VecFiller
  54. {
  55. static void fill (type* dst, const int size, Random& random)
  56. {
  57. for (int i = 0; i < size; ++i)
  58. dst[i] = RandomValue<type>::next (random);
  59. }
  60. };
  61. // We need to specialise for complex types: otherwise GCC 6 gives
  62. // us an ICE internal compiler error after which the compiler seg faults.
  63. template <typename type>
  64. struct VecFiller<std::complex<type>>
  65. {
  66. static void fill (std::complex<type>* dst, const int size, Random& random)
  67. {
  68. for (int i = 0; i < size; ++i)
  69. dst[i] = std::complex<type> (RandomValue<type>::next (random), RandomValue<type>::next (random));
  70. }
  71. };
  72. template <typename type>
  73. struct VecFiller<SIMDRegister<type>>
  74. {
  75. static SIMDRegister<type> fill(Random& random)
  76. {
  77. constexpr int size = (int) SIMDRegister<type>::SIMDNumElements;
  78. #ifdef _MSC_VER
  79. __declspec(align(sizeof (SIMDRegister<type>))) type elements[size];
  80. #else
  81. type elements[size] __attribute__((aligned(sizeof (SIMDRegister<type>))));
  82. #endif
  83. VecFiller<type>::fill (elements, size, random);
  84. return SIMDRegister<type>::fromRawArray (elements);
  85. }
  86. };
  87. // Avoid visual studio warning
  88. template <typename type>
  89. static type safeAbs (type a)
  90. {
  91. return static_cast<type> (std::abs (static_cast<double> (a)));
  92. }
  93. template <typename type>
  94. static type safeAbs (std::complex<type> a)
  95. {
  96. return std::abs (a);
  97. }
  98. template <typename type>
  99. static double difference (type a)
  100. {
  101. return static_cast<double> (safeAbs (a));
  102. }
  103. template <typename type>
  104. static double difference (type a, type b)
  105. {
  106. return difference (a - b);
  107. }
  108. }
  109. // These tests need to be strictly run on all platforms supported by JUCE as the
  110. // SIMD code is highly platform dependant.
  111. class SIMDRegisterUnitTests : public UnitTest
  112. {
  113. public:
  114. SIMDRegisterUnitTests() : UnitTest ("SIMDRegister UnitTests", "DSP") {}
  115. //==============================================================================
  116. // Some helper classes
  117. template <typename type>
  118. static bool allValuesEqualTo (const SIMDRegister<type>& vec, const type scalar)
  119. {
  120. #ifdef _MSC_VER
  121. __declspec(align(sizeof (SIMDRegister<type>))) type elements[SIMDRegister<type>::SIMDNumElements];
  122. #else
  123. type elements[SIMDRegister<type>::SIMDNumElements] __attribute__((aligned(sizeof (SIMDRegister<type>))));
  124. #endif
  125. vec.copyToRawArray (elements);
  126. // as we do not want to rely on the access operator we cast this to a primitive pointer
  127. for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
  128. if (elements[i] != scalar) return false;
  129. return true;
  130. }
  131. template <typename type>
  132. static bool vecEqualToArray (const SIMDRegister<type>& vec, const type* array)
  133. {
  134. HeapBlock<type> vecElementsStorage (SIMDRegister<type>::SIMDNumElements * 2);
  135. auto* ptr = SIMDRegister<type>::getNextSIMDAlignedPtr (vecElementsStorage.getData());
  136. vec.copyToRawArray (ptr);
  137. for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
  138. {
  139. double delta = SIMDRegister_test_internal::difference (ptr[i], array[i]);
  140. if (delta > 1e-4)
  141. {
  142. DBG ("a: " << SIMDRegister_test_internal::difference (ptr[i]) << " b: " << SIMDRegister_test_internal::difference (array[i]) << " difference: " << delta);
  143. return false;
  144. }
  145. }
  146. return true;
  147. }
  148. template <typename type>
  149. static void copy (SIMDRegister<type>& vec, const type* ptr)
  150. {
  151. if (SIMDRegister<type>::isSIMDAligned (ptr))
  152. {
  153. vec = SIMDRegister<type>::fromRawArray (ptr);
  154. }
  155. else
  156. {
  157. for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
  158. vec[i] = ptr[i];
  159. }
  160. }
  161. //==============================================================================
  162. // Someuseful operations to test
  163. struct Addition
  164. {
  165. template <typename typeOne, typename typeTwo>
  166. static void inplace (typeOne& a, const typeTwo& b)
  167. {
  168. a += b;
  169. }
  170. template <typename typeOne, typename typeTwo>
  171. static typeOne outofplace (const typeOne& a, const typeTwo& b)
  172. {
  173. return a + b;
  174. }
  175. };
  176. struct Subtraction
  177. {
  178. template <typename typeOne, typename typeTwo>
  179. static void inplace (typeOne& a, const typeTwo& b)
  180. {
  181. a -= b;
  182. }
  183. template <typename typeOne, typename typeTwo>
  184. static typeOne outofplace (const typeOne& a, const typeTwo& b)
  185. {
  186. return a - b;
  187. }
  188. };
  189. struct Multiplication
  190. {
  191. template <typename typeOne, typename typeTwo>
  192. static void inplace (typeOne& a, const typeTwo& b)
  193. {
  194. a *= b;
  195. }
  196. template <typename typeOne, typename typeTwo>
  197. static typeOne outofplace (const typeOne& a, const typeTwo& b)
  198. {
  199. return a * b;
  200. }
  201. };
  202. struct BitAND
  203. {
  204. template <typename typeOne, typename typeTwo>
  205. static void inplace (typeOne& a, const typeTwo& b)
  206. {
  207. a &= b;
  208. }
  209. template <typename typeOne, typename typeTwo>
  210. static typeOne outofplace (const typeOne& a, const typeTwo& b)
  211. {
  212. return a & b;
  213. }
  214. };
  215. struct BitOR
  216. {
  217. template <typename typeOne, typename typeTwo>
  218. static void inplace (typeOne& a, const typeTwo& b)
  219. {
  220. a |= b;
  221. }
  222. template <typename typeOne, typename typeTwo>
  223. static typeOne outofplace (const typeOne& a, const typeTwo& b)
  224. {
  225. return a | b;
  226. }
  227. };
  228. struct BitXOR
  229. {
  230. template <typename typeOne, typename typeTwo>
  231. static void inplace (typeOne& a, const typeTwo& b)
  232. {
  233. a ^= b;
  234. }
  235. template <typename typeOne, typename typeTwo>
  236. static typeOne outofplace (const typeOne& a, const typeTwo& b)
  237. {
  238. return a ^ b;
  239. }
  240. };
  241. //==============================================================================
  242. // the individual tests
  243. struct InitializationTest
  244. {
  245. template <typename type>
  246. static void run (UnitTest& u, Random& random)
  247. {
  248. u.expect (allValuesEqualTo<type> (SIMDRegister<type>::expand (static_cast<type> (23)), 23));
  249. {
  250. #ifdef _MSC_VER
  251. __declspec(align(sizeof (SIMDRegister<type>))) type elements[SIMDRegister<type>::SIMDNumElements];
  252. #else
  253. type elements[SIMDRegister<type>::SIMDNumElements] __attribute__((aligned(sizeof (SIMDRegister<type>))));
  254. #endif
  255. SIMDRegister_test_internal::VecFiller<type>::fill (elements, SIMDRegister<type>::SIMDNumElements, random);
  256. SIMDRegister<type> a (SIMDRegister<type>::fromRawArray (elements));
  257. u.expect (vecEqualToArray (a, elements));
  258. SIMDRegister<type> b (a);
  259. a *= static_cast<type> (2);
  260. u.expect (vecEqualToArray (b, elements));
  261. }
  262. }
  263. };
  264. struct AccessTest
  265. {
  266. template <typename type>
  267. static void run (UnitTest& u, Random& random)
  268. {
  269. // set-up
  270. SIMDRegister<type> a;
  271. type array [SIMDRegister<type>::SIMDNumElements];
  272. SIMDRegister_test_internal::VecFiller<type>::fill (array, SIMDRegister<type>::SIMDNumElements, random);
  273. // Test non-const access operator
  274. for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
  275. a[i] = array[i];
  276. u.expect (vecEqualToArray (a, array));
  277. // Test const access operator
  278. const SIMDRegister<type>& b = a;
  279. for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
  280. u.expect (b[i] == array[i]);
  281. }
  282. };
  283. template <class Operation>
  284. struct OperatorTests
  285. {
  286. template <typename type>
  287. static void run (UnitTest& u, Random& random)
  288. {
  289. for (int n = 0; n < 100; ++n)
  290. {
  291. // set-up
  292. SIMDRegister<type> a (static_cast<type> (0));
  293. SIMDRegister<type> b (static_cast<type> (0));
  294. SIMDRegister<type> c (static_cast<type> (0));
  295. type array_a [SIMDRegister<type>::SIMDNumElements];
  296. type array_b [SIMDRegister<type>::SIMDNumElements];
  297. type array_c [SIMDRegister<type>::SIMDNumElements];
  298. SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
  299. SIMDRegister_test_internal::VecFiller<type>::fill (array_b, SIMDRegister<type>::SIMDNumElements, random);
  300. SIMDRegister_test_internal::VecFiller<type>::fill (array_c, SIMDRegister<type>::SIMDNumElements, random);
  301. copy (a, array_a); copy (b, array_b); copy (c, array_c);
  302. // test in-place with both params being vectors
  303. for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
  304. Operation::template inplace<type, type> (array_a[i], array_b[i]);
  305. Operation::template inplace<SIMDRegister<type>, SIMDRegister<type>> (a, b);
  306. u.expect (vecEqualToArray (a, array_a));
  307. u.expect (vecEqualToArray (b, array_b));
  308. SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
  309. SIMDRegister_test_internal::VecFiller<type>::fill (array_b, SIMDRegister<type>::SIMDNumElements, random);
  310. SIMDRegister_test_internal::VecFiller<type>::fill (array_c, SIMDRegister<type>::SIMDNumElements, random);
  311. copy (a, array_a); copy (b, array_b); copy (c, array_c);
  312. // test in-place with one param being scalar
  313. for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
  314. Operation::template inplace<type, type> (array_b[i], static_cast<type> (2));
  315. Operation::template inplace<SIMDRegister<type>, type> (b, 2);
  316. u.expect (vecEqualToArray (a, array_a));
  317. u.expect (vecEqualToArray (b, array_b));
  318. // set-up again
  319. SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
  320. SIMDRegister_test_internal::VecFiller<type>::fill (array_b, SIMDRegister<type>::SIMDNumElements, random);
  321. SIMDRegister_test_internal::VecFiller<type>::fill (array_c, SIMDRegister<type>::SIMDNumElements, random);
  322. copy (a, array_a); copy (b, array_b); copy (c, array_c);
  323. // test out-of-place with both params being vectors
  324. for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
  325. array_c[i] = Operation::template outofplace<type, type> (array_a[i], array_b[i]);
  326. c = Operation::template outofplace<SIMDRegister<type>, SIMDRegister<type>> (a, b);
  327. u.expect (vecEqualToArray (a, array_a));
  328. u.expect (vecEqualToArray (b, array_b));
  329. u.expect (vecEqualToArray (c, array_c));
  330. // test out-of-place with one param being scalar
  331. for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
  332. array_c[i] = Operation::template outofplace<type, type> (array_b[i], static_cast<type> (2));
  333. c = Operation::template outofplace<SIMDRegister<type>, type> (b, 2);
  334. u.expect (vecEqualToArray (a, array_a));
  335. u.expect (vecEqualToArray (b, array_b));
  336. u.expect (vecEqualToArray (c, array_c));
  337. }
  338. }
  339. };
  340. template <class Operation>
  341. struct BitOperatorTests
  342. {
  343. template <typename type>
  344. static void run (UnitTest& u, Random& random)
  345. {
  346. typedef typename SIMDRegister<type>::vMaskType vMaskType;
  347. typedef typename SIMDRegister<type>::MaskType MaskType;
  348. for (int n = 0; n < 100; ++n)
  349. {
  350. // Check flip sign bit and using as a union
  351. {
  352. type array_a [SIMDRegister<type>::SIMDNumElements];
  353. union ConversionUnion
  354. {
  355. inline ConversionUnion() : floatVersion (static_cast<type> (0)) {}
  356. inline ~ConversionUnion() {}
  357. SIMDRegister<type> floatVersion;
  358. vMaskType intVersion;
  359. } a, b;
  360. vMaskType bitmask = vMaskType::expand (static_cast<MaskType> (1) << (sizeof (MaskType) - 1));
  361. SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
  362. copy (a.floatVersion, array_a);
  363. copy (b.floatVersion, array_a);
  364. Operation::template inplace<SIMDRegister<type>, vMaskType> (a.floatVersion, bitmask);
  365. Operation::template inplace<vMaskType, vMaskType> (b.intVersion, bitmask);
  366. #ifdef _MSC_VER
  367. __declspec(align(sizeof (SIMDRegister<type>))) type elements[SIMDRegister<type>::SIMDNumElements];
  368. #else
  369. type elements[SIMDRegister<type>::SIMDNumElements] __attribute__((aligned(sizeof (SIMDRegister<type>))));
  370. #endif
  371. b.floatVersion.copyToRawArray (elements);
  372. u.expect (vecEqualToArray (a.floatVersion, elements));
  373. }
  374. // set-up
  375. SIMDRegister<type> a, c;
  376. vMaskType b;
  377. MaskType array_a [SIMDRegister<MaskType>::SIMDNumElements];
  378. MaskType array_b [SIMDRegister<MaskType>::SIMDNumElements];
  379. MaskType array_c [SIMDRegister<MaskType>::SIMDNumElements];
  380. type float_a [SIMDRegister<type>::SIMDNumElements];
  381. type float_c [SIMDRegister<type>::SIMDNumElements];
  382. SIMDRegister_test_internal::VecFiller<type>::fill (float_a, SIMDRegister<type>::SIMDNumElements, random);
  383. SIMDRegister_test_internal::VecFiller<MaskType>::fill (array_b, SIMDRegister<MaskType>::SIMDNumElements, random);
  384. SIMDRegister_test_internal::VecFiller<type>::fill (float_c, SIMDRegister<type>::SIMDNumElements, random);
  385. memcpy (array_a, float_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  386. memcpy (array_c, float_c, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  387. copy (a, float_a); copy (b, array_b); copy (c, float_c);
  388. // test in-place with both params being vectors
  389. for (size_t i = 0; i < SIMDRegister<MaskType>::SIMDNumElements; ++i)
  390. Operation::template inplace<MaskType, MaskType> (array_a[i], array_b[i]);
  391. memcpy (float_a, array_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  392. Operation::template inplace<SIMDRegister<type>, vMaskType> (a, b);
  393. u.expect (vecEqualToArray (a, float_a));
  394. u.expect (vecEqualToArray (b, array_b));
  395. SIMDRegister_test_internal::VecFiller<type>::fill (float_a, SIMDRegister<type>::SIMDNumElements, random);
  396. SIMDRegister_test_internal::VecFiller<MaskType>::fill (array_b, SIMDRegister<MaskType>::SIMDNumElements, random);
  397. SIMDRegister_test_internal::VecFiller<type>::fill (float_c, SIMDRegister<type>::SIMDNumElements, random);
  398. memcpy (array_a, float_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  399. memcpy (array_c, float_c, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  400. copy (a, float_a); copy (b, array_b); copy (c, float_c);
  401. // test in-place with one param being scalar
  402. for (size_t i = 0; i < SIMDRegister<MaskType>::SIMDNumElements; ++i)
  403. Operation::template inplace<MaskType, MaskType> (array_a[i], static_cast<MaskType> (9));
  404. memcpy (float_a, array_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  405. Operation::template inplace<SIMDRegister<type>, MaskType> (a, static_cast<MaskType> (9));
  406. u.expect (vecEqualToArray (a, float_a));
  407. u.expect (vecEqualToArray (b, array_b));
  408. // set-up again
  409. SIMDRegister_test_internal::VecFiller<type>::fill (float_a, SIMDRegister<type>::SIMDNumElements, random);
  410. SIMDRegister_test_internal::VecFiller<MaskType>::fill (array_b, SIMDRegister<MaskType>::SIMDNumElements, random);
  411. SIMDRegister_test_internal::VecFiller<type>::fill (float_c, SIMDRegister<type>::SIMDNumElements, random);
  412. memcpy (array_a, float_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  413. memcpy (array_c, float_c, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  414. copy (a, float_a); copy (b, array_b); copy (c, float_c);
  415. // test out-of-place with both params being vectors
  416. for (size_t i = 0; i < SIMDRegister<MaskType>::SIMDNumElements; ++i)
  417. {
  418. array_c[i] =
  419. Operation::template outofplace<MaskType, MaskType> (array_a[i], array_b[i]);
  420. }
  421. memcpy (float_a, array_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  422. memcpy (float_c, array_c, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  423. c = Operation::template outofplace<SIMDRegister<type>, vMaskType> (a, b);
  424. u.expect (vecEqualToArray (a, float_a));
  425. u.expect (vecEqualToArray (b, array_b));
  426. u.expect (vecEqualToArray (c, float_c));
  427. // test out-of-place with one param being scalar
  428. for (size_t i = 0; i < SIMDRegister<MaskType>::SIMDNumElements; ++i)
  429. array_c[i] = Operation::template outofplace<MaskType, MaskType> (array_a[i], static_cast<MaskType> (9));
  430. memcpy (float_a, array_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  431. memcpy (float_c, array_c, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  432. c = Operation::template outofplace<SIMDRegister<type>, MaskType> (a, static_cast<MaskType> (9));
  433. u.expect (vecEqualToArray (a, float_a));
  434. u.expect (vecEqualToArray (b, array_b));
  435. u.expect (vecEqualToArray (c, float_c));
  436. }
  437. }
  438. };
  439. struct CheckComparisonOps
  440. {
  441. template <typename type>
  442. static void run (UnitTest& u, Random& random)
  443. {
  444. typedef typename SIMDRegister<type>::vMaskType vMaskType;
  445. typedef typename SIMDRegister<type>::MaskType MaskType;
  446. for (int i = 0; i < 100; ++i)
  447. {
  448. // set-up
  449. type array_a [SIMDRegister<type>::SIMDNumElements];
  450. type array_b [SIMDRegister<type>::SIMDNumElements];
  451. MaskType array_eq [SIMDRegister<type>::SIMDNumElements];
  452. MaskType array_neq [SIMDRegister<type>::SIMDNumElements];
  453. MaskType array_lt [SIMDRegister<type>::SIMDNumElements];
  454. MaskType array_le [SIMDRegister<type>::SIMDNumElements];
  455. MaskType array_gt [SIMDRegister<type>::SIMDNumElements];
  456. MaskType array_ge [SIMDRegister<type>::SIMDNumElements];
  457. SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
  458. SIMDRegister_test_internal::VecFiller<type>::fill (array_b, SIMDRegister<type>::SIMDNumElements, random);
  459. // do check
  460. for (size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
  461. {
  462. array_eq [j] = (array_a[j] == array_b[j]) ? static_cast<MaskType> (-1) : 0;
  463. array_neq [j] = (array_a[j] != array_b[j]) ? static_cast<MaskType> (-1) : 0;
  464. array_lt [j] = (array_a[j] < array_b[j]) ? static_cast<MaskType> (-1) : 0;
  465. array_le [j] = (array_a[j] <= array_b[j]) ? static_cast<MaskType> (-1) : 0;
  466. array_gt [j] = (array_a[j] > array_b[j]) ? static_cast<MaskType> (-1) : 0;
  467. array_ge [j] = (array_a[j] >= array_b[j]) ? static_cast<MaskType> (-1) : 0;
  468. }
  469. SIMDRegister<type> a (static_cast<type> (0));
  470. SIMDRegister<type> b (static_cast<type> (0));
  471. vMaskType eq, neq, lt, le, gt, ge;
  472. copy (a, array_a);
  473. copy (b, array_b);
  474. eq = SIMDRegister<type>::equal (a, b);
  475. neq = SIMDRegister<type>::notEqual (a, b);
  476. lt = SIMDRegister<type>::lessThan (a, b);
  477. le = SIMDRegister<type>::lessThanOrEqual (a, b);
  478. gt = SIMDRegister<type>::greaterThan (a, b);
  479. ge = SIMDRegister<type>::greaterThanOrEqual (a, b);
  480. u.expect (vecEqualToArray (eq, array_eq ));
  481. u.expect (vecEqualToArray (neq, array_neq));
  482. u.expect (vecEqualToArray (lt, array_lt ));
  483. u.expect (vecEqualToArray (le, array_le ));
  484. u.expect (vecEqualToArray (gt, array_gt ));
  485. u.expect (vecEqualToArray (ge, array_ge ));
  486. do
  487. {
  488. SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
  489. SIMDRegister_test_internal::VecFiller<type>::fill (array_b, SIMDRegister<type>::SIMDNumElements, random);
  490. } while (std::equal (array_a, array_a + SIMDRegister<type>::SIMDNumElements, array_b));
  491. copy (a, array_a);
  492. copy (b, array_b);
  493. u.expect (a != b);
  494. u.expect (b != a);
  495. u.expect (! (a == b));
  496. u.expect (! (b == a));
  497. SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
  498. copy (a, array_a);
  499. copy (b, array_a);
  500. u.expect (a == b);
  501. u.expect (b == a);
  502. u.expect (! (a != b));
  503. u.expect (! (b != a));
  504. type scalar = a[0];
  505. a = SIMDRegister<type>::expand (scalar);
  506. u.expect (a == scalar);
  507. u.expect (! (a != scalar));
  508. scalar--;
  509. u.expect (a != scalar);
  510. u.expect (! (a == scalar));
  511. }
  512. }
  513. };
  514. struct CheckMultiplyAdd
  515. {
  516. template <typename type>
  517. static void run (UnitTest& u, Random& random)
  518. {
  519. // set-up
  520. type array_a [SIMDRegister<type>::SIMDNumElements];
  521. type array_b [SIMDRegister<type>::SIMDNumElements];
  522. type array_c [SIMDRegister<type>::SIMDNumElements];
  523. type array_d [SIMDRegister<type>::SIMDNumElements];
  524. SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
  525. SIMDRegister_test_internal::VecFiller<type>::fill (array_b, SIMDRegister<type>::SIMDNumElements, random);
  526. SIMDRegister_test_internal::VecFiller<type>::fill (array_c, SIMDRegister<type>::SIMDNumElements, random);
  527. SIMDRegister_test_internal::VecFiller<type>::fill (array_d, SIMDRegister<type>::SIMDNumElements, random);
  528. // check
  529. for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
  530. array_d[i] = array_a[i] + (array_b[i] * array_c[i]);
  531. SIMDRegister<type> a, b, c, d;
  532. copy (a, array_a);
  533. copy (b, array_b);
  534. copy (c, array_c);
  535. d = SIMDRegister<type>::multiplyAdd (a, b, c);
  536. u.expect (vecEqualToArray (d, array_d));
  537. }
  538. };
  539. struct CheckMinMax
  540. {
  541. template <typename type>
  542. static void run (UnitTest& u, Random& random)
  543. {
  544. for (int i = 0; i < 100; ++i)
  545. {
  546. type array_a [SIMDRegister<type>::SIMDNumElements];
  547. type array_b [SIMDRegister<type>::SIMDNumElements];
  548. type array_min [SIMDRegister<type>::SIMDNumElements];
  549. type array_max [SIMDRegister<type>::SIMDNumElements];
  550. for (size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
  551. {
  552. array_a[j] = static_cast<type> (random.nextInt (127));
  553. array_b[j] = static_cast<type> (random.nextInt (127));
  554. }
  555. for (size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
  556. {
  557. array_min[j] = (array_a[j] < array_b[j]) ? array_a[j] : array_b[j];
  558. array_max[j] = (array_a[j] > array_b[j]) ? array_a[j] : array_b[j];
  559. }
  560. SIMDRegister<type> a (static_cast<type> (0));
  561. SIMDRegister<type> b (static_cast<type> (0));
  562. SIMDRegister<type> vMin (static_cast<type> (0));
  563. SIMDRegister<type> vMax (static_cast<type> (0));
  564. copy (a, array_a);
  565. copy (b, array_b);
  566. vMin = jmin (a, b);
  567. vMax = jmax (a, b);
  568. u.expect (vecEqualToArray (vMin, array_min));
  569. u.expect (vecEqualToArray (vMax, array_max));
  570. copy (vMin, array_a);
  571. copy (vMax, array_a);
  572. vMin = SIMDRegister<type>::min (a, b);
  573. vMax = SIMDRegister<type>::max (a, b);
  574. u.expect (vecEqualToArray (vMin, array_min));
  575. u.expect (vecEqualToArray (vMax, array_max));
  576. }
  577. }
  578. };
  579. struct CheckSum
  580. {
  581. template <typename type>
  582. static void run (UnitTest& u, Random& random)
  583. {
  584. type array [SIMDRegister<type>::SIMDNumElements];
  585. type sumCheck = 0;
  586. SIMDRegister_test_internal::VecFiller<type>::fill (array, SIMDRegister<type>::SIMDNumElements, random);
  587. for (size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
  588. {
  589. sumCheck += array[j];
  590. }
  591. SIMDRegister<type> a;
  592. copy (a, array);
  593. u.expect (SIMDRegister_test_internal::difference (sumCheck, a.sum()) < 1e-4);
  594. }
  595. };
  596. struct CheckBoolEquals
  597. {
  598. template <typename type>
  599. static void run (UnitTest& u, Random& random)
  600. {
  601. bool is_signed = std::is_signed<type>::value;
  602. type array [SIMDRegister<type>::SIMDNumElements];
  603. auto value = is_signed ? static_cast<type> ((random.nextFloat() * 16.0) - 8.0)
  604. : static_cast<type> (random.nextFloat() * 8.0);
  605. std::fill (array, array + SIMDRegister<type>::SIMDNumElements, value);
  606. SIMDRegister<type> a, b;
  607. copy (a, array);
  608. u.expect (a == value);
  609. u.expect (! (a != value));
  610. value += 1;
  611. u.expect (a != value);
  612. u.expect (! (a == value));
  613. SIMDRegister_test_internal::VecFiller<type>::fill (array, SIMDRegister<type>::SIMDNumElements, random);
  614. copy (a, array);
  615. copy (b, array);
  616. u.expect (a == b);
  617. u.expect (! (a != b));
  618. SIMDRegister_test_internal::VecFiller<type>::fill (array, SIMDRegister<type>::SIMDNumElements, random);
  619. copy (b, array);
  620. u.expect (a != b);
  621. u.expect (! (a == b));
  622. }
  623. };
  624. //==============================================================================
  625. template <class TheTest>
  626. void runTestForAllTypes (const char* unitTestName)
  627. {
  628. beginTest (unitTestName);
  629. Random random = getRandom();
  630. TheTest::template run<float> (*this, random);
  631. TheTest::template run<double> (*this, random);
  632. TheTest::template run<int8_t> (*this, random);
  633. TheTest::template run<uint8_t> (*this, random);
  634. TheTest::template run<int16_t> (*this, random);
  635. TheTest::template run<uint16_t>(*this, random);
  636. TheTest::template run<int32_t> (*this, random);
  637. TheTest::template run<uint32_t>(*this, random);
  638. TheTest::template run<int64_t> (*this, random);
  639. TheTest::template run<uint64_t>(*this, random);
  640. TheTest::template run<std::complex<float>> (*this, random);
  641. TheTest::template run<std::complex<double>> (*this, random);
  642. }
  643. template <class TheTest>
  644. void runTestNonComplex (const char* unitTestName)
  645. {
  646. beginTest (unitTestName);
  647. Random random = getRandom();
  648. TheTest::template run<float> (*this, random);
  649. TheTest::template run<double> (*this, random);
  650. TheTest::template run<int8_t> (*this, random);
  651. TheTest::template run<uint8_t> (*this, random);
  652. TheTest::template run<int16_t> (*this, random);
  653. TheTest::template run<uint16_t>(*this, random);
  654. TheTest::template run<int32_t> (*this, random);
  655. TheTest::template run<uint32_t>(*this, random);
  656. TheTest::template run<int64_t> (*this, random);
  657. TheTest::template run<uint64_t>(*this, random);
  658. }
  659. void runTest()
  660. {
  661. runTestForAllTypes<InitializationTest> ("InitializationTest");
  662. runTestForAllTypes<AccessTest> ("AccessTest");
  663. runTestForAllTypes<OperatorTests<Addition>> ("AdditionOperators");
  664. runTestForAllTypes<OperatorTests<Subtraction>> ("SubtractionOperators");
  665. runTestForAllTypes<OperatorTests<Multiplication>> ("MultiplicationOperators");
  666. runTestForAllTypes<BitOperatorTests<BitAND>> ("BitANDOperators");
  667. runTestForAllTypes<BitOperatorTests<BitOR>> ("BitOROperators");
  668. runTestForAllTypes<BitOperatorTests<BitXOR>> ("BitXOROperators");
  669. runTestNonComplex<CheckComparisonOps> ("CheckComparisons");
  670. runTestNonComplex<CheckBoolEquals> ("CheckBoolEquals");
  671. runTestNonComplex<CheckMinMax> ("CheckMinMax");
  672. runTestForAllTypes<CheckMultiplyAdd> ("CheckMultiplyAdd");
  673. runTestForAllTypes<CheckSum> ("CheckSum");
  674. }
  675. };
  676. static SIMDRegisterUnitTests SIMDRegisterUnitTests;
  677. } // namespace dsp
  678. } // namespace juce