Audio plugin host https://kx.studio/carla
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.

890 lines
33KB

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