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.

920 lines
36KB

  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_t) 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 dependent.
  111. class SIMDRegisterUnitTests : public UnitTest
  112. {
  113. public:
  114. SIMDRegisterUnitTests()
  115. : UnitTest ("SIMDRegister UnitTests", UnitTestCategories::dsp)
  116. {}
  117. //==============================================================================
  118. // Some helper classes
  119. template <typename type>
  120. static bool allValuesEqualTo (const SIMDRegister<type>& vec, const type scalar)
  121. {
  122. #ifdef _MSC_VER
  123. __declspec(align(sizeof (SIMDRegister<type>))) type elements[SIMDRegister<type>::SIMDNumElements];
  124. #else
  125. type elements[SIMDRegister<type>::SIMDNumElements] __attribute__((aligned(sizeof (SIMDRegister<type>))));
  126. #endif
  127. vec.copyToRawArray (elements);
  128. // as we do not want to rely on the access operator we cast this to a primitive pointer
  129. for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
  130. if (elements[i] != scalar) return false;
  131. return true;
  132. }
  133. template <typename type>
  134. static bool vecEqualToArray (const SIMDRegister<type>& vec, const type* array)
  135. {
  136. HeapBlock<type> vecElementsStorage (SIMDRegister<type>::SIMDNumElements * 2);
  137. auto* ptr = SIMDRegister<type>::getNextSIMDAlignedPtr (vecElementsStorage.getData());
  138. vec.copyToRawArray (ptr);
  139. for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
  140. {
  141. double delta = SIMDRegister_test_internal::difference (ptr[i], array[i]);
  142. if (delta > 1e-4)
  143. {
  144. DBG ("a: " << SIMDRegister_test_internal::difference (ptr[i]) << " b: " << SIMDRegister_test_internal::difference (array[i]) << " difference: " << delta);
  145. return false;
  146. }
  147. }
  148. return true;
  149. }
  150. template <typename type>
  151. static void copy (SIMDRegister<type>& vec, const type* ptr)
  152. {
  153. if (SIMDRegister<type>::isSIMDAligned (ptr))
  154. {
  155. vec = SIMDRegister<type>::fromRawArray (ptr);
  156. }
  157. else
  158. {
  159. for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
  160. vec[i] = ptr[i];
  161. }
  162. }
  163. //==============================================================================
  164. // Someuseful operations to test
  165. struct Addition
  166. {
  167. template <typename typeOne, typename typeTwo>
  168. static void inplace (typeOne& a, const typeTwo& b)
  169. {
  170. a += b;
  171. }
  172. template <typename typeOne, typename typeTwo>
  173. static typeOne outofplace (const typeOne& a, const typeTwo& b)
  174. {
  175. return a + b;
  176. }
  177. };
  178. struct Subtraction
  179. {
  180. template <typename typeOne, typename typeTwo>
  181. static void inplace (typeOne& a, const typeTwo& b)
  182. {
  183. a -= b;
  184. }
  185. template <typename typeOne, typename typeTwo>
  186. static typeOne outofplace (const typeOne& a, const typeTwo& b)
  187. {
  188. return a - b;
  189. }
  190. };
  191. struct Multiplication
  192. {
  193. template <typename typeOne, typename typeTwo>
  194. static void inplace (typeOne& a, const typeTwo& b)
  195. {
  196. a *= b;
  197. }
  198. template <typename typeOne, typename typeTwo>
  199. static typeOne outofplace (const typeOne& a, const typeTwo& b)
  200. {
  201. return a * b;
  202. }
  203. };
  204. struct BitAND
  205. {
  206. template <typename typeOne, typename typeTwo>
  207. static void inplace (typeOne& a, const typeTwo& b)
  208. {
  209. a &= b;
  210. }
  211. template <typename typeOne, typename typeTwo>
  212. static typeOne outofplace (const typeOne& a, const typeTwo& b)
  213. {
  214. return a & b;
  215. }
  216. };
  217. struct BitOR
  218. {
  219. template <typename typeOne, typename typeTwo>
  220. static void inplace (typeOne& a, const typeTwo& b)
  221. {
  222. a |= b;
  223. }
  224. template <typename typeOne, typename typeTwo>
  225. static typeOne outofplace (const typeOne& a, const typeTwo& b)
  226. {
  227. return a | b;
  228. }
  229. };
  230. struct BitXOR
  231. {
  232. template <typename typeOne, typename typeTwo>
  233. static void inplace (typeOne& a, const typeTwo& b)
  234. {
  235. a ^= b;
  236. }
  237. template <typename typeOne, typename typeTwo>
  238. static typeOne outofplace (const typeOne& a, const typeTwo& b)
  239. {
  240. return a ^ b;
  241. }
  242. };
  243. //==============================================================================
  244. // the individual tests
  245. struct InitializationTest
  246. {
  247. template <typename type>
  248. static void run (UnitTest& u, Random& random)
  249. {
  250. u.expect (allValuesEqualTo<type> (SIMDRegister<type>::expand (static_cast<type> (23)), 23));
  251. {
  252. #ifdef _MSC_VER
  253. __declspec(align(sizeof (SIMDRegister<type>))) type elements[SIMDRegister<type>::SIMDNumElements];
  254. #else
  255. type elements[SIMDRegister<type>::SIMDNumElements] __attribute__((aligned(sizeof (SIMDRegister<type>))));
  256. #endif
  257. SIMDRegister_test_internal::VecFiller<type>::fill (elements, SIMDRegister<type>::SIMDNumElements, random);
  258. SIMDRegister<type> a (SIMDRegister<type>::fromRawArray (elements));
  259. u.expect (vecEqualToArray (a, elements));
  260. SIMDRegister<type> b (a);
  261. a *= static_cast<type> (2);
  262. u.expect (vecEqualToArray (b, elements));
  263. }
  264. }
  265. };
  266. struct AccessTest
  267. {
  268. template <typename type>
  269. static void run (UnitTest& u, Random& random)
  270. {
  271. // set-up
  272. SIMDRegister<type> a;
  273. type array [SIMDRegister<type>::SIMDNumElements];
  274. SIMDRegister_test_internal::VecFiller<type>::fill (array, SIMDRegister<type>::SIMDNumElements, random);
  275. // Test non-const access operator
  276. for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
  277. a[i] = array[i];
  278. u.expect (vecEqualToArray (a, array));
  279. // Test const access operator
  280. const SIMDRegister<type>& b = a;
  281. for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
  282. u.expect (b[i] == array[i]);
  283. }
  284. };
  285. template <class Operation>
  286. struct OperatorTests
  287. {
  288. template <typename type>
  289. static void run (UnitTest& u, Random& random)
  290. {
  291. for (int n = 0; n < 100; ++n)
  292. {
  293. // set-up
  294. SIMDRegister<type> a (static_cast<type> (0));
  295. SIMDRegister<type> b (static_cast<type> (0));
  296. SIMDRegister<type> c (static_cast<type> (0));
  297. type array_a [SIMDRegister<type>::SIMDNumElements];
  298. type array_b [SIMDRegister<type>::SIMDNumElements];
  299. type array_c [SIMDRegister<type>::SIMDNumElements];
  300. SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
  301. SIMDRegister_test_internal::VecFiller<type>::fill (array_b, SIMDRegister<type>::SIMDNumElements, random);
  302. SIMDRegister_test_internal::VecFiller<type>::fill (array_c, SIMDRegister<type>::SIMDNumElements, random);
  303. copy (a, array_a); copy (b, array_b); copy (c, array_c);
  304. // test in-place with both params being vectors
  305. for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
  306. Operation::template inplace<type, type> (array_a[i], array_b[i]);
  307. Operation::template inplace<SIMDRegister<type>, SIMDRegister<type>> (a, b);
  308. u.expect (vecEqualToArray (a, array_a));
  309. u.expect (vecEqualToArray (b, array_b));
  310. SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
  311. SIMDRegister_test_internal::VecFiller<type>::fill (array_b, SIMDRegister<type>::SIMDNumElements, random);
  312. SIMDRegister_test_internal::VecFiller<type>::fill (array_c, SIMDRegister<type>::SIMDNumElements, random);
  313. copy (a, array_a); copy (b, array_b); copy (c, array_c);
  314. // test in-place with one param being scalar
  315. for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
  316. Operation::template inplace<type, type> (array_b[i], static_cast<type> (2));
  317. Operation::template inplace<SIMDRegister<type>, type> (b, 2);
  318. u.expect (vecEqualToArray (a, array_a));
  319. u.expect (vecEqualToArray (b, array_b));
  320. // set-up again
  321. SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
  322. SIMDRegister_test_internal::VecFiller<type>::fill (array_b, SIMDRegister<type>::SIMDNumElements, random);
  323. SIMDRegister_test_internal::VecFiller<type>::fill (array_c, SIMDRegister<type>::SIMDNumElements, random);
  324. copy (a, array_a); copy (b, array_b); copy (c, array_c);
  325. // test out-of-place with both params being vectors
  326. for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
  327. array_c[i] = Operation::template outofplace<type, type> (array_a[i], array_b[i]);
  328. c = Operation::template outofplace<SIMDRegister<type>, SIMDRegister<type>> (a, b);
  329. u.expect (vecEqualToArray (a, array_a));
  330. u.expect (vecEqualToArray (b, array_b));
  331. u.expect (vecEqualToArray (c, array_c));
  332. // test out-of-place with one param being scalar
  333. for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
  334. array_c[i] = Operation::template outofplace<type, type> (array_b[i], static_cast<type> (2));
  335. c = Operation::template outofplace<SIMDRegister<type>, type> (b, 2);
  336. u.expect (vecEqualToArray (a, array_a));
  337. u.expect (vecEqualToArray (b, array_b));
  338. u.expect (vecEqualToArray (c, array_c));
  339. }
  340. }
  341. };
  342. template <class Operation>
  343. struct BitOperatorTests
  344. {
  345. template <typename type>
  346. static void run (UnitTest& u, Random& random)
  347. {
  348. typedef typename SIMDRegister<type>::vMaskType vMaskType;
  349. typedef typename SIMDRegister<type>::MaskType MaskType;
  350. for (int n = 0; n < 100; ++n)
  351. {
  352. // Check flip sign bit and using as a union
  353. {
  354. type array_a [SIMDRegister<type>::SIMDNumElements];
  355. union ConversionUnion
  356. {
  357. inline ConversionUnion() : floatVersion (static_cast<type> (0)) {}
  358. inline ~ConversionUnion() {}
  359. SIMDRegister<type> floatVersion;
  360. vMaskType intVersion;
  361. } a, b;
  362. vMaskType bitmask = vMaskType::expand (static_cast<MaskType> (1) << (sizeof (MaskType) - 1));
  363. SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
  364. copy (a.floatVersion, array_a);
  365. copy (b.floatVersion, array_a);
  366. Operation::template inplace<SIMDRegister<type>, vMaskType> (a.floatVersion, bitmask);
  367. Operation::template inplace<vMaskType, vMaskType> (b.intVersion, bitmask);
  368. #ifdef _MSC_VER
  369. __declspec(align(sizeof (SIMDRegister<type>))) type elements[SIMDRegister<type>::SIMDNumElements];
  370. #else
  371. type elements[SIMDRegister<type>::SIMDNumElements] __attribute__((aligned(sizeof (SIMDRegister<type>))));
  372. #endif
  373. b.floatVersion.copyToRawArray (elements);
  374. u.expect (vecEqualToArray (a.floatVersion, elements));
  375. }
  376. // set-up
  377. SIMDRegister<type> a, c;
  378. vMaskType b;
  379. MaskType array_a [SIMDRegister<MaskType>::SIMDNumElements];
  380. MaskType array_b [SIMDRegister<MaskType>::SIMDNumElements];
  381. MaskType array_c [SIMDRegister<MaskType>::SIMDNumElements];
  382. type float_a [SIMDRegister<type>::SIMDNumElements];
  383. type float_c [SIMDRegister<type>::SIMDNumElements];
  384. SIMDRegister_test_internal::VecFiller<type>::fill (float_a, SIMDRegister<type>::SIMDNumElements, random);
  385. SIMDRegister_test_internal::VecFiller<MaskType>::fill (array_b, SIMDRegister<MaskType>::SIMDNumElements, random);
  386. SIMDRegister_test_internal::VecFiller<type>::fill (float_c, SIMDRegister<type>::SIMDNumElements, random);
  387. memcpy (array_a, float_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  388. memcpy (array_c, float_c, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  389. copy (a, float_a); copy (b, array_b); copy (c, float_c);
  390. // test in-place with both params being vectors
  391. for (size_t i = 0; i < SIMDRegister<MaskType>::SIMDNumElements; ++i)
  392. Operation::template inplace<MaskType, MaskType> (array_a[i], array_b[i]);
  393. memcpy (float_a, array_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  394. Operation::template inplace<SIMDRegister<type>, vMaskType> (a, b);
  395. u.expect (vecEqualToArray (a, float_a));
  396. u.expect (vecEqualToArray (b, array_b));
  397. SIMDRegister_test_internal::VecFiller<type>::fill (float_a, SIMDRegister<type>::SIMDNumElements, random);
  398. SIMDRegister_test_internal::VecFiller<MaskType>::fill (array_b, SIMDRegister<MaskType>::SIMDNumElements, random);
  399. SIMDRegister_test_internal::VecFiller<type>::fill (float_c, SIMDRegister<type>::SIMDNumElements, random);
  400. memcpy (array_a, float_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  401. memcpy (array_c, float_c, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  402. copy (a, float_a); copy (b, array_b); copy (c, float_c);
  403. // test in-place with one param being scalar
  404. for (size_t i = 0; i < SIMDRegister<MaskType>::SIMDNumElements; ++i)
  405. Operation::template inplace<MaskType, MaskType> (array_a[i], static_cast<MaskType> (9));
  406. memcpy (float_a, array_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  407. Operation::template inplace<SIMDRegister<type>, MaskType> (a, static_cast<MaskType> (9));
  408. u.expect (vecEqualToArray (a, float_a));
  409. u.expect (vecEqualToArray (b, array_b));
  410. // set-up again
  411. SIMDRegister_test_internal::VecFiller<type>::fill (float_a, SIMDRegister<type>::SIMDNumElements, random);
  412. SIMDRegister_test_internal::VecFiller<MaskType>::fill (array_b, SIMDRegister<MaskType>::SIMDNumElements, random);
  413. SIMDRegister_test_internal::VecFiller<type>::fill (float_c, SIMDRegister<type>::SIMDNumElements, random);
  414. memcpy (array_a, float_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  415. memcpy (array_c, float_c, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  416. copy (a, float_a); copy (b, array_b); copy (c, float_c);
  417. // test out-of-place with both params being vectors
  418. for (size_t i = 0; i < SIMDRegister<MaskType>::SIMDNumElements; ++i)
  419. {
  420. array_c[i] =
  421. Operation::template outofplace<MaskType, MaskType> (array_a[i], array_b[i]);
  422. }
  423. memcpy (float_a, array_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  424. memcpy (float_c, array_c, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  425. c = Operation::template outofplace<SIMDRegister<type>, vMaskType> (a, b);
  426. u.expect (vecEqualToArray (a, float_a));
  427. u.expect (vecEqualToArray (b, array_b));
  428. u.expect (vecEqualToArray (c, float_c));
  429. // test out-of-place with one param being scalar
  430. for (size_t i = 0; i < SIMDRegister<MaskType>::SIMDNumElements; ++i)
  431. array_c[i] = Operation::template outofplace<MaskType, MaskType> (array_a[i], static_cast<MaskType> (9));
  432. memcpy (float_a, array_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  433. memcpy (float_c, array_c, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
  434. c = Operation::template outofplace<SIMDRegister<type>, MaskType> (a, static_cast<MaskType> (9));
  435. u.expect (vecEqualToArray (a, float_a));
  436. u.expect (vecEqualToArray (b, array_b));
  437. u.expect (vecEqualToArray (c, float_c));
  438. }
  439. }
  440. };
  441. struct CheckComparisonOps
  442. {
  443. template <typename type>
  444. static void run (UnitTest& u, Random& random)
  445. {
  446. typedef typename SIMDRegister<type>::vMaskType vMaskType;
  447. typedef typename SIMDRegister<type>::MaskType MaskType;
  448. for (int i = 0; i < 100; ++i)
  449. {
  450. // set-up
  451. type array_a [SIMDRegister<type>::SIMDNumElements];
  452. type array_b [SIMDRegister<type>::SIMDNumElements];
  453. MaskType array_eq [SIMDRegister<type>::SIMDNumElements];
  454. MaskType array_neq [SIMDRegister<type>::SIMDNumElements];
  455. MaskType array_lt [SIMDRegister<type>::SIMDNumElements];
  456. MaskType array_le [SIMDRegister<type>::SIMDNumElements];
  457. MaskType array_gt [SIMDRegister<type>::SIMDNumElements];
  458. MaskType array_ge [SIMDRegister<type>::SIMDNumElements];
  459. SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
  460. SIMDRegister_test_internal::VecFiller<type>::fill (array_b, SIMDRegister<type>::SIMDNumElements, random);
  461. // do check
  462. for (size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
  463. {
  464. array_eq [j] = (array_a[j] == array_b[j]) ? static_cast<MaskType> (-1) : 0;
  465. array_neq [j] = (array_a[j] != array_b[j]) ? static_cast<MaskType> (-1) : 0;
  466. array_lt [j] = (array_a[j] < array_b[j]) ? static_cast<MaskType> (-1) : 0;
  467. array_le [j] = (array_a[j] <= array_b[j]) ? static_cast<MaskType> (-1) : 0;
  468. array_gt [j] = (array_a[j] > array_b[j]) ? static_cast<MaskType> (-1) : 0;
  469. array_ge [j] = (array_a[j] >= array_b[j]) ? static_cast<MaskType> (-1) : 0;
  470. }
  471. SIMDRegister<type> a (static_cast<type> (0));
  472. SIMDRegister<type> b (static_cast<type> (0));
  473. vMaskType eq, neq, lt, le, gt, ge;
  474. copy (a, array_a);
  475. copy (b, array_b);
  476. eq = SIMDRegister<type>::equal (a, b);
  477. neq = SIMDRegister<type>::notEqual (a, b);
  478. lt = SIMDRegister<type>::lessThan (a, b);
  479. le = SIMDRegister<type>::lessThanOrEqual (a, b);
  480. gt = SIMDRegister<type>::greaterThan (a, b);
  481. ge = SIMDRegister<type>::greaterThanOrEqual (a, b);
  482. u.expect (vecEqualToArray (eq, array_eq ));
  483. u.expect (vecEqualToArray (neq, array_neq));
  484. u.expect (vecEqualToArray (lt, array_lt ));
  485. u.expect (vecEqualToArray (le, array_le ));
  486. u.expect (vecEqualToArray (gt, array_gt ));
  487. u.expect (vecEqualToArray (ge, array_ge ));
  488. do
  489. {
  490. SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
  491. SIMDRegister_test_internal::VecFiller<type>::fill (array_b, SIMDRegister<type>::SIMDNumElements, random);
  492. } while (std::equal (array_a, array_a + SIMDRegister<type>::SIMDNumElements, array_b));
  493. copy (a, array_a);
  494. copy (b, array_b);
  495. u.expect (a != b);
  496. u.expect (b != a);
  497. u.expect (! (a == b));
  498. u.expect (! (b == a));
  499. SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
  500. copy (a, array_a);
  501. copy (b, array_a);
  502. u.expect (a == b);
  503. u.expect (b == a);
  504. u.expect (! (a != b));
  505. u.expect (! (b != a));
  506. type scalar = a[0];
  507. a = SIMDRegister<type>::expand (scalar);
  508. u.expect (a == scalar);
  509. u.expect (! (a != scalar));
  510. scalar--;
  511. u.expect (a != scalar);
  512. u.expect (! (a == scalar));
  513. }
  514. }
  515. };
  516. struct CheckMultiplyAdd
  517. {
  518. template <typename type>
  519. static void run (UnitTest& u, Random& random)
  520. {
  521. // set-up
  522. type array_a [SIMDRegister<type>::SIMDNumElements];
  523. type array_b [SIMDRegister<type>::SIMDNumElements];
  524. type array_c [SIMDRegister<type>::SIMDNumElements];
  525. type array_d [SIMDRegister<type>::SIMDNumElements];
  526. SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
  527. SIMDRegister_test_internal::VecFiller<type>::fill (array_b, SIMDRegister<type>::SIMDNumElements, random);
  528. SIMDRegister_test_internal::VecFiller<type>::fill (array_c, SIMDRegister<type>::SIMDNumElements, random);
  529. SIMDRegister_test_internal::VecFiller<type>::fill (array_d, SIMDRegister<type>::SIMDNumElements, random);
  530. // check
  531. for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
  532. array_d[i] = array_a[i] + (array_b[i] * array_c[i]);
  533. SIMDRegister<type> a, b, c, d;
  534. copy (a, array_a);
  535. copy (b, array_b);
  536. copy (c, array_c);
  537. d = SIMDRegister<type>::multiplyAdd (a, b, c);
  538. u.expect (vecEqualToArray (d, array_d));
  539. }
  540. };
  541. struct CheckMinMax
  542. {
  543. template <typename type>
  544. static void run (UnitTest& u, Random& random)
  545. {
  546. for (int i = 0; i < 100; ++i)
  547. {
  548. type array_a [SIMDRegister<type>::SIMDNumElements];
  549. type array_b [SIMDRegister<type>::SIMDNumElements];
  550. type array_min [SIMDRegister<type>::SIMDNumElements];
  551. type array_max [SIMDRegister<type>::SIMDNumElements];
  552. for (size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
  553. {
  554. array_a[j] = static_cast<type> (random.nextInt (127));
  555. array_b[j] = static_cast<type> (random.nextInt (127));
  556. }
  557. for (size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
  558. {
  559. array_min[j] = (array_a[j] < array_b[j]) ? array_a[j] : array_b[j];
  560. array_max[j] = (array_a[j] > array_b[j]) ? array_a[j] : array_b[j];
  561. }
  562. SIMDRegister<type> a (static_cast<type> (0));
  563. SIMDRegister<type> b (static_cast<type> (0));
  564. SIMDRegister<type> vMin (static_cast<type> (0));
  565. SIMDRegister<type> vMax (static_cast<type> (0));
  566. copy (a, array_a);
  567. copy (b, array_b);
  568. vMin = jmin (a, b);
  569. vMax = jmax (a, b);
  570. u.expect (vecEqualToArray (vMin, array_min));
  571. u.expect (vecEqualToArray (vMax, array_max));
  572. copy (vMin, array_a);
  573. copy (vMax, array_a);
  574. vMin = SIMDRegister<type>::min (a, b);
  575. vMax = SIMDRegister<type>::max (a, b);
  576. u.expect (vecEqualToArray (vMin, array_min));
  577. u.expect (vecEqualToArray (vMax, array_max));
  578. }
  579. }
  580. };
  581. struct CheckSum
  582. {
  583. template <typename type>
  584. static void run (UnitTest& u, Random& random)
  585. {
  586. type array [SIMDRegister<type>::SIMDNumElements];
  587. type sumCheck = 0;
  588. SIMDRegister_test_internal::VecFiller<type>::fill (array, SIMDRegister<type>::SIMDNumElements, random);
  589. for (size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
  590. {
  591. sumCheck += array[j];
  592. }
  593. SIMDRegister<type> a;
  594. copy (a, array);
  595. u.expect (SIMDRegister_test_internal::difference (sumCheck, a.sum()) < 1e-4);
  596. }
  597. };
  598. struct CheckAbs
  599. {
  600. template <typename type>
  601. static void run (UnitTest& u, Random& random)
  602. {
  603. type inArray[SIMDRegister<type>::SIMDNumElements];
  604. type outArray[SIMDRegister<type>::SIMDNumElements];
  605. SIMDRegister_test_internal::VecFiller<type>::fill (inArray, SIMDRegister<type>::SIMDNumElements, random);
  606. SIMDRegister<type> a;
  607. copy (a, inArray);
  608. a = SIMDRegister<type>::abs (a);
  609. auto calcAbs = [] (type x) -> type { return x >= type (0) ? x : -x; };
  610. for (size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
  611. outArray[j] = calcAbs (inArray[j]);
  612. u.expect (vecEqualToArray (a, outArray));
  613. }
  614. };
  615. struct CheckTruncate
  616. {
  617. template <typename type>
  618. static void run (UnitTest& u, Random& random)
  619. {
  620. type inArray[SIMDRegister<type>::SIMDNumElements];
  621. type outArray[SIMDRegister<type>::SIMDNumElements];
  622. SIMDRegister_test_internal::VecFiller<type>::fill (inArray, SIMDRegister<type>::SIMDNumElements, random);
  623. SIMDRegister<type> a;
  624. copy (a, inArray);
  625. a = SIMDRegister<type>::truncate (a);
  626. for (size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
  627. outArray[j] = (type) (int) inArray[j];
  628. u.expect (vecEqualToArray (a, outArray));
  629. }
  630. };
  631. struct CheckBoolEquals
  632. {
  633. template <typename type>
  634. static void run (UnitTest& u, Random& random)
  635. {
  636. bool is_signed = std::is_signed<type>::value;
  637. type array [SIMDRegister<type>::SIMDNumElements];
  638. auto value = is_signed ? static_cast<type> ((random.nextFloat() * 16.0) - 8.0)
  639. : static_cast<type> (random.nextFloat() * 8.0);
  640. std::fill (array, array + SIMDRegister<type>::SIMDNumElements, value);
  641. SIMDRegister<type> a, b;
  642. copy (a, array);
  643. u.expect (a == value);
  644. u.expect (! (a != value));
  645. value += 1;
  646. u.expect (a != value);
  647. u.expect (! (a == value));
  648. SIMDRegister_test_internal::VecFiller<type>::fill (array, SIMDRegister<type>::SIMDNumElements, random);
  649. copy (a, array);
  650. copy (b, array);
  651. u.expect (a == b);
  652. u.expect (! (a != b));
  653. SIMDRegister_test_internal::VecFiller<type>::fill (array, SIMDRegister<type>::SIMDNumElements, random);
  654. copy (b, array);
  655. u.expect (a != b);
  656. u.expect (! (a == b));
  657. }
  658. };
  659. //==============================================================================
  660. template <class TheTest>
  661. void runTestFloatingPoint (const char* unitTestName)
  662. {
  663. beginTest (unitTestName);
  664. Random random = getRandom();
  665. TheTest::template run<float> (*this, random);
  666. TheTest::template run<double> (*this, random);
  667. }
  668. //==============================================================================
  669. template <class TheTest>
  670. void runTestForAllTypes (const char* unitTestName)
  671. {
  672. beginTest (unitTestName);
  673. Random random = getRandom();
  674. TheTest::template run<float> (*this, random);
  675. TheTest::template run<double> (*this, random);
  676. TheTest::template run<int8_t> (*this, random);
  677. TheTest::template run<uint8_t> (*this, random);
  678. TheTest::template run<int16_t> (*this, random);
  679. TheTest::template run<uint16_t>(*this, random);
  680. TheTest::template run<int32_t> (*this, random);
  681. TheTest::template run<uint32_t>(*this, random);
  682. TheTest::template run<int64_t> (*this, random);
  683. TheTest::template run<uint64_t>(*this, random);
  684. TheTest::template run<std::complex<float>> (*this, random);
  685. TheTest::template run<std::complex<double>> (*this, random);
  686. }
  687. template <class TheTest>
  688. void runTestNonComplex (const char* unitTestName)
  689. {
  690. beginTest (unitTestName);
  691. Random random = getRandom();
  692. TheTest::template run<float> (*this, random);
  693. TheTest::template run<double> (*this, random);
  694. TheTest::template run<int8_t> (*this, random);
  695. TheTest::template run<uint8_t> (*this, random);
  696. TheTest::template run<int16_t> (*this, random);
  697. TheTest::template run<uint16_t>(*this, random);
  698. TheTest::template run<int32_t> (*this, random);
  699. TheTest::template run<uint32_t>(*this, random);
  700. TheTest::template run<int64_t> (*this, random);
  701. TheTest::template run<uint64_t>(*this, random);
  702. }
  703. template <class TheTest>
  704. void runTestSigned (const char* unitTestName)
  705. {
  706. beginTest (unitTestName);
  707. Random random = getRandom();
  708. TheTest::template run<float> (*this, random);
  709. TheTest::template run<double> (*this, random);
  710. TheTest::template run<int8_t> (*this, random);
  711. TheTest::template run<int16_t> (*this, random);
  712. TheTest::template run<int32_t> (*this, random);
  713. TheTest::template run<int64_t> (*this, random);
  714. }
  715. void runTest()
  716. {
  717. runTestForAllTypes<InitializationTest> ("InitializationTest");
  718. runTestForAllTypes<AccessTest> ("AccessTest");
  719. runTestForAllTypes<OperatorTests<Addition>> ("AdditionOperators");
  720. runTestForAllTypes<OperatorTests<Subtraction>> ("SubtractionOperators");
  721. runTestForAllTypes<OperatorTests<Multiplication>> ("MultiplicationOperators");
  722. runTestForAllTypes<BitOperatorTests<BitAND>> ("BitANDOperators");
  723. runTestForAllTypes<BitOperatorTests<BitOR>> ("BitOROperators");
  724. runTestForAllTypes<BitOperatorTests<BitXOR>> ("BitXOROperators");
  725. runTestNonComplex<CheckComparisonOps> ("CheckComparisons");
  726. runTestNonComplex<CheckBoolEquals> ("CheckBoolEquals");
  727. runTestNonComplex<CheckMinMax> ("CheckMinMax");
  728. runTestForAllTypes<CheckMultiplyAdd> ("CheckMultiplyAdd");
  729. runTestForAllTypes<CheckSum> ("CheckSum");
  730. runTestSigned<CheckAbs> ("CheckAbs");
  731. runTestFloatingPoint<CheckTruncate> ("CheckTruncate");
  732. }
  733. };
  734. static SIMDRegisterUnitTests SIMDRegisterUnitTests;
  735. } // namespace dsp
  736. } // namespace juce