OpenShot Audio Library | OpenShotAudio  0.3.2
juce_SIMDRegister_test.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2017 - ROLI Ltd.
6 
7  JUCE is an open source library subject to commercial or open-source
8  licensing.
9 
10  By using JUCE, you agree to the terms of both the JUCE 5 End-User License
11  Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
12  27th April 2017).
13 
14  End User License Agreement: www.juce.com/juce-5-licence
15  Privacy Policy: www.juce.com/juce-5-privacy-policy
16 
17  Or: You may also use this code under the terms of the GPL v3 (see
18  www.gnu.org/licenses).
19 
20  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22  DISCLAIMED.
23 
24  ==============================================================================
25 */
26 
27 namespace juce
28 {
29 namespace dsp
30 {
31 
32 namespace SIMDRegister_test_internal
33 {
34  template <typename type, typename = void> struct RandomPrimitive {};
35 
36  template <typename type>
37  struct RandomPrimitive<type, typename std::enable_if<std::is_floating_point<type>::value>::type>
38  {
39  static type next (Random& random)
40  {
41  return static_cast<type> (std::is_signed<type>::value ? (random.nextFloat() * 16.0) - 8.0
42  : (random.nextFloat() * 8.0));
43 
44  }
45  };
46 
47  template <typename type>
48  struct RandomPrimitive<type, typename std::enable_if<std::is_integral<type>::value>::type>
49  {
50  static type next (Random& random)
51  {
52  return static_cast<type> (random.nextInt64());
53 
54  }
55  };
56 
57  template <typename type> struct RandomValue { static type next (Random& random) { return RandomPrimitive<type>::next (random); } };
58  template <typename type>
59  struct RandomValue<std::complex<type>>
60  {
61  static std::complex<type> next (Random& random)
62  {
63  return {RandomPrimitive<type>::next (random), RandomPrimitive<type>::next (random)};
64  }
65  };
66 
67 
68  template <typename type>
69  struct VecFiller
70  {
71  static void fill (type* dst, const int size, Random& random)
72  {
73  for (int i = 0; i < size; ++i)
74  dst[i] = RandomValue<type>::next (random);
75  }
76  };
77 
78  // We need to specialise for complex types: otherwise GCC 6 gives
79  // us an ICE internal compiler error after which the compiler seg faults.
80  template <typename type>
81  struct VecFiller<std::complex<type>>
82  {
83  static void fill (std::complex<type>* dst, const int size, Random& random)
84  {
85  for (int i = 0; i < size; ++i)
86  dst[i] = std::complex<type> (RandomValue<type>::next (random), RandomValue<type>::next (random));
87  }
88  };
89 
90  template <typename type>
91  struct VecFiller<SIMDRegister<type>>
92  {
93  static SIMDRegister<type> fill (Random& random)
94  {
95  constexpr int size = (int) SIMDRegister<type>::SIMDNumElements;
96  #ifdef _MSC_VER
97  __declspec(align(sizeof (SIMDRegister<type>))) type elements[size];
98  #else
99  type elements[(size_t) size] __attribute__((aligned(sizeof (SIMDRegister<type>))));
100  #endif
101 
102  VecFiller<type>::fill (elements, size, random);
103  return SIMDRegister<type>::fromRawArray (elements);
104  }
105  };
106 
107  // Avoid visual studio warning
108  template <typename type>
109  static type safeAbs (type a)
110  {
111  return static_cast<type> (std::abs (static_cast<double> (a)));
112  }
113 
114  template <typename type>
115  static type safeAbs (std::complex<type> a)
116  {
117  return std::abs (a);
118  }
119 
120  template <typename type>
121  static double difference (type a)
122  {
123  return static_cast<double> (safeAbs (a));
124  }
125 
126  template <typename type>
127  static double difference (type a, type b)
128  {
129  return difference (a - b);
130  }
131 }
132 
133 // These tests need to be strictly run on all platforms supported by JUCE as the
134 // SIMD code is highly platform dependent.
135 
136 class SIMDRegisterUnitTests : public UnitTest
137 {
138 public:
139  SIMDRegisterUnitTests()
140  : UnitTest ("SIMDRegister UnitTests", UnitTestCategories::dsp)
141  {}
142 
143  //==============================================================================
144  // Some helper classes
145  template <typename type>
146  static bool allValuesEqualTo (const SIMDRegister<type>& vec, const type scalar)
147  {
148  #ifdef _MSC_VER
149  __declspec(align(sizeof (SIMDRegister<type>))) type elements[SIMDRegister<type>::SIMDNumElements];
150  #else
151  type elements[SIMDRegister<type>::SIMDNumElements] __attribute__((aligned(sizeof (SIMDRegister<type>))));
152  #endif
153 
154  vec.copyToRawArray (elements);
155 
156  // as we do not want to rely on the access operator we cast this to a primitive pointer
157  for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
158  if (elements[i] != scalar) return false;
159 
160  return true;
161  }
162 
163  template <typename type>
164  static bool vecEqualToArray (const SIMDRegister<type>& vec, const type* array)
165  {
166  HeapBlock<type> vecElementsStorage (SIMDRegister<type>::SIMDNumElements * 2);
167  auto* ptr = SIMDRegister<type>::getNextSIMDAlignedPtr (vecElementsStorage.getData());
168  vec.copyToRawArray (ptr);
169 
170  for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
171  {
172  double delta = SIMDRegister_test_internal::difference (ptr[i], array[i]);
173  if (delta > 1e-4)
174  {
175  DBG ("a: " << SIMDRegister_test_internal::difference (ptr[i]) << " b: " << SIMDRegister_test_internal::difference (array[i]) << " difference: " << delta);
176  return false;
177  }
178  }
179 
180  return true;
181  }
182 
183  template <typename type>
184  static void copy (SIMDRegister<type>& vec, const type* ptr)
185  {
187  {
189  }
190  else
191  {
192  for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
193  vec[i] = ptr[i];
194  }
195  }
196 
197  //==============================================================================
198  // Some useful operations to test
199  struct Addition
200  {
201  template <typename typeOne, typename typeTwo>
202  static void inplace (typeOne& a, const typeTwo& b)
203  {
204  a += b;
205  }
206 
207  template <typename typeOne, typename typeTwo>
208  static typeOne outofplace (const typeOne& a, const typeTwo& b)
209  {
210  return a + b;
211  }
212  };
213 
214  struct Subtraction
215  {
216  template <typename typeOne, typename typeTwo>
217  static void inplace (typeOne& a, const typeTwo& b)
218  {
219  a -= b;
220  }
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 
229  struct Multiplication
230  {
231  template <typename typeOne, typename typeTwo>
232  static void inplace (typeOne& a, const typeTwo& b)
233  {
234  a *= b;
235  }
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  struct BitAND
245  {
246  template <typename typeOne, typename typeTwo>
247  static void inplace (typeOne& a, const typeTwo& b)
248  {
249  a &= b;
250  }
251 
252  template <typename typeOne, typename typeTwo>
253  static typeOne outofplace (const typeOne& a, const typeTwo& b)
254  {
255  return a & b;
256  }
257  };
258 
259  struct BitOR
260  {
261  template <typename typeOne, typename typeTwo>
262  static void inplace (typeOne& a, const typeTwo& b)
263  {
264  a |= b;
265  }
266 
267  template <typename typeOne, typename typeTwo>
268  static typeOne outofplace (const typeOne& a, const typeTwo& b)
269  {
270  return a | b;
271  }
272  };
273 
274  struct BitXOR
275  {
276  template <typename typeOne, typename typeTwo>
277  static void inplace (typeOne& a, const typeTwo& b)
278  {
279  a ^= b;
280  }
281 
282  template <typename typeOne, typename typeTwo>
283  static typeOne outofplace (const typeOne& a, const typeTwo& b)
284  {
285  return a ^ b;
286  }
287  };
288 
289  //==============================================================================
290  // the individual tests
291  struct InitializationTest
292  {
293  template <typename type>
294  static void run (UnitTest& u, Random& random)
295  {
296  u.expect (allValuesEqualTo<type> (SIMDRegister<type>::expand (static_cast<type> (23)), 23));
297 
298  {
299  #ifdef _MSC_VER
300  __declspec(align(sizeof (SIMDRegister<type>))) type elements[SIMDRegister<type>::SIMDNumElements];
301  #else
302  type elements[SIMDRegister<type>::SIMDNumElements] __attribute__((aligned(sizeof (SIMDRegister<type>))));
303  #endif
304  SIMDRegister_test_internal::VecFiller<type>::fill (elements, SIMDRegister<type>::SIMDNumElements, random);
305  SIMDRegister<type> a (SIMDRegister<type>::fromRawArray (elements));
306 
307  u.expect (vecEqualToArray (a, elements));
308 
309  SIMDRegister<type> b (a);
310  a *= static_cast<type> (2);
311 
312  u.expect (vecEqualToArray (b, elements));
313  }
314  }
315  };
316 
317  struct AccessTest
318  {
319  template <typename type>
320  static void run (UnitTest& u, Random& random)
321  {
322  // set-up
323  SIMDRegister<type> a;
325 
326  SIMDRegister_test_internal::VecFiller<type>::fill (array, SIMDRegister<type>::SIMDNumElements, random);
327 
328  // Test non-const access operator
329  for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
330  a[i] = array[i];
331 
332  u.expect (vecEqualToArray (a, array));
333 
334  // Test const access operator
335  const SIMDRegister<type>& b = a;
336 
337  for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
338  u.expect (b[i] == array[i]);
339  }
340  };
341 
342  template <class Operation>
343  struct OperatorTests
344  {
345  template <typename type>
346  static void run (UnitTest& u, Random& random)
347  {
348  for (int n = 0; n < 100; ++n)
349  {
350  // set-up
351  SIMDRegister<type> a (static_cast<type> (0));
352  SIMDRegister<type> b (static_cast<type> (0));
353  SIMDRegister<type> c (static_cast<type> (0));
354 
358 
359  SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
360  SIMDRegister_test_internal::VecFiller<type>::fill (array_b, SIMDRegister<type>::SIMDNumElements, random);
361  SIMDRegister_test_internal::VecFiller<type>::fill (array_c, SIMDRegister<type>::SIMDNumElements, random);
362 
363  copy (a, array_a); copy (b, array_b); copy (c, array_c);
364 
365  // test in-place with both params being vectors
366  for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
367  Operation::template inplace<type, type> (array_a[i], array_b[i]);
368 
369  Operation::template inplace<SIMDRegister<type>, SIMDRegister<type>> (a, b);
370 
371  u.expect (vecEqualToArray (a, array_a));
372  u.expect (vecEqualToArray (b, array_b));
373 
374  SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
375  SIMDRegister_test_internal::VecFiller<type>::fill (array_b, SIMDRegister<type>::SIMDNumElements, random);
376  SIMDRegister_test_internal::VecFiller<type>::fill (array_c, SIMDRegister<type>::SIMDNumElements, random);
377 
378  copy (a, array_a); copy (b, array_b); copy (c, array_c);
379 
380  // test in-place with one param being scalar
381  for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
382  Operation::template inplace<type, type> (array_b[i], static_cast<type> (2));
383 
384  Operation::template inplace<SIMDRegister<type>, type> (b, 2);
385 
386  u.expect (vecEqualToArray (a, array_a));
387  u.expect (vecEqualToArray (b, array_b));
388 
389  // set-up again
390  SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
391  SIMDRegister_test_internal::VecFiller<type>::fill (array_b, SIMDRegister<type>::SIMDNumElements, random);
392  SIMDRegister_test_internal::VecFiller<type>::fill (array_c, SIMDRegister<type>::SIMDNumElements, random);
393  copy (a, array_a); copy (b, array_b); copy (c, array_c);
394 
395  // test out-of-place with both params being vectors
396  for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
397  array_c[i] = Operation::template outofplace<type, type> (array_a[i], array_b[i]);
398 
399  c = Operation::template outofplace<SIMDRegister<type>, SIMDRegister<type>> (a, b);
400 
401  u.expect (vecEqualToArray (a, array_a));
402  u.expect (vecEqualToArray (b, array_b));
403  u.expect (vecEqualToArray (c, array_c));
404 
405  // test out-of-place with one param being scalar
406  for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
407  array_c[i] = Operation::template outofplace<type, type> (array_b[i], static_cast<type> (2));
408 
409  c = Operation::template outofplace<SIMDRegister<type>, type> (b, 2);
410 
411  u.expect (vecEqualToArray (a, array_a));
412  u.expect (vecEqualToArray (b, array_b));
413  u.expect (vecEqualToArray (c, array_c));
414  }
415  }
416  };
417 
418  template <class Operation>
419  struct BitOperatorTests
420  {
421  template <typename type>
422  static void run (UnitTest& u, Random& random)
423  {
424  typedef typename SIMDRegister<type>::vMaskType vMaskType;
425  typedef typename SIMDRegister<type>::MaskType MaskType;
426 
427  for (int n = 0; n < 100; ++n)
428  {
429  // Check flip sign bit and using as a union
430  {
432 
433  union ConversionUnion
434  {
435  inline ConversionUnion() : floatVersion (static_cast<type> (0)) {}
436  inline ~ConversionUnion() {}
437  SIMDRegister<type> floatVersion;
438  vMaskType intVersion;
439  } a, b;
440 
441  vMaskType bitmask = vMaskType::expand (static_cast<MaskType> (1) << (sizeof (MaskType) - 1));
442  SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
443  copy (a.floatVersion, array_a);
444  copy (b.floatVersion, array_a);
445 
446  Operation::template inplace<SIMDRegister<type>, vMaskType> (a.floatVersion, bitmask);
447  Operation::template inplace<vMaskType, vMaskType> (b.intVersion, bitmask);
448 
449  #ifdef _MSC_VER
450  __declspec(align(sizeof (SIMDRegister<type>))) type elements[SIMDRegister<type>::SIMDNumElements];
451  #else
452  type elements[SIMDRegister<type>::SIMDNumElements] __attribute__((aligned(sizeof (SIMDRegister<type>))));
453  #endif
454  b.floatVersion.copyToRawArray (elements);
455 
456  u.expect (vecEqualToArray (a.floatVersion, elements));
457  }
458 
459  // set-up
460  SIMDRegister<type> a, c;
461  vMaskType b;
462 
463  MaskType array_a [SIMDRegister<MaskType>::SIMDNumElements];
464  MaskType array_b [SIMDRegister<MaskType>::SIMDNumElements];
465  MaskType array_c [SIMDRegister<MaskType>::SIMDNumElements];
466 
469 
470  SIMDRegister_test_internal::VecFiller<type>::fill (float_a, SIMDRegister<type>::SIMDNumElements, random);
471  SIMDRegister_test_internal::VecFiller<MaskType>::fill (array_b, SIMDRegister<MaskType>::SIMDNumElements, random);
472  SIMDRegister_test_internal::VecFiller<type>::fill (float_c, SIMDRegister<type>::SIMDNumElements, random);
473 
474  memcpy (array_a, float_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
475  memcpy (array_c, float_c, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
476  copy (a, float_a); copy (b, array_b); copy (c, float_c);
477 
478  // test in-place with both params being vectors
479  for (size_t i = 0; i < SIMDRegister<MaskType>::SIMDNumElements; ++i)
480  Operation::template inplace<MaskType, MaskType> (array_a[i], array_b[i]);
481  memcpy (float_a, array_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
482 
483  Operation::template inplace<SIMDRegister<type>, vMaskType> (a, b);
484 
485  u.expect (vecEqualToArray (a, float_a));
486  u.expect (vecEqualToArray (b, array_b));
487 
488  SIMDRegister_test_internal::VecFiller<type>::fill (float_a, SIMDRegister<type>::SIMDNumElements, random);
489  SIMDRegister_test_internal::VecFiller<MaskType>::fill (array_b, SIMDRegister<MaskType>::SIMDNumElements, random);
490  SIMDRegister_test_internal::VecFiller<type>::fill (float_c, SIMDRegister<type>::SIMDNumElements, random);
491  memcpy (array_a, float_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
492  memcpy (array_c, float_c, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
493  copy (a, float_a); copy (b, array_b); copy (c, float_c);
494 
495  // test in-place with one param being scalar
496  for (size_t i = 0; i < SIMDRegister<MaskType>::SIMDNumElements; ++i)
497  Operation::template inplace<MaskType, MaskType> (array_a[i], static_cast<MaskType> (9));
498  memcpy (float_a, array_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
499 
500  Operation::template inplace<SIMDRegister<type>, MaskType> (a, static_cast<MaskType> (9));
501 
502  u.expect (vecEqualToArray (a, float_a));
503  u.expect (vecEqualToArray (b, array_b));
504 
505  // set-up again
506  SIMDRegister_test_internal::VecFiller<type>::fill (float_a, SIMDRegister<type>::SIMDNumElements, random);
507  SIMDRegister_test_internal::VecFiller<MaskType>::fill (array_b, SIMDRegister<MaskType>::SIMDNumElements, random);
508  SIMDRegister_test_internal::VecFiller<type>::fill (float_c, SIMDRegister<type>::SIMDNumElements, random);
509  memcpy (array_a, float_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
510  memcpy (array_c, float_c, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
511  copy (a, float_a); copy (b, array_b); copy (c, float_c);
512 
513  // test out-of-place with both params being vectors
514  for (size_t i = 0; i < SIMDRegister<MaskType>::SIMDNumElements; ++i)
515  {
516  array_c[i] =
517  Operation::template outofplace<MaskType, MaskType> (array_a[i], array_b[i]);
518  }
519  memcpy (float_a, array_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
520  memcpy (float_c, array_c, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
521 
522  c = Operation::template outofplace<SIMDRegister<type>, vMaskType> (a, b);
523 
524  u.expect (vecEqualToArray (a, float_a));
525  u.expect (vecEqualToArray (b, array_b));
526  u.expect (vecEqualToArray (c, float_c));
527 
528  // test out-of-place with one param being scalar
529  for (size_t i = 0; i < SIMDRegister<MaskType>::SIMDNumElements; ++i)
530  array_c[i] = Operation::template outofplace<MaskType, MaskType> (array_a[i], static_cast<MaskType> (9));
531  memcpy (float_a, array_a, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
532  memcpy (float_c, array_c, sizeof (type) * SIMDRegister<type>::SIMDNumElements);
533 
534  c = Operation::template outofplace<SIMDRegister<type>, MaskType> (a, static_cast<MaskType> (9));
535 
536  u.expect (vecEqualToArray (a, float_a));
537  u.expect (vecEqualToArray (b, array_b));
538  u.expect (vecEqualToArray (c, float_c));
539  }
540  }
541  };
542 
543  struct CheckComparisonOps
544  {
545  template <typename type>
546  static void run (UnitTest& u, Random& random)
547  {
548  typedef typename SIMDRegister<type>::vMaskType vMaskType;
549  typedef typename SIMDRegister<type>::MaskType MaskType;
550 
551  for (int i = 0; i < 100; ++i)
552  {
553  // set-up
556  MaskType array_eq [SIMDRegister<type>::SIMDNumElements];
557  MaskType array_neq [SIMDRegister<type>::SIMDNumElements];
558  MaskType array_lt [SIMDRegister<type>::SIMDNumElements];
559  MaskType array_le [SIMDRegister<type>::SIMDNumElements];
560  MaskType array_gt [SIMDRegister<type>::SIMDNumElements];
561  MaskType array_ge [SIMDRegister<type>::SIMDNumElements];
562 
563 
564  SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
565  SIMDRegister_test_internal::VecFiller<type>::fill (array_b, SIMDRegister<type>::SIMDNumElements, random);
566 
567  // do check
568  for (size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
569  {
570  array_eq [j] = (array_a[j] == array_b[j]) ? static_cast<MaskType> (-1) : 0;
571  array_neq [j] = (array_a[j] != array_b[j]) ? static_cast<MaskType> (-1) : 0;
572  array_lt [j] = (array_a[j] < array_b[j]) ? static_cast<MaskType> (-1) : 0;
573  array_le [j] = (array_a[j] <= array_b[j]) ? static_cast<MaskType> (-1) : 0;
574  array_gt [j] = (array_a[j] > array_b[j]) ? static_cast<MaskType> (-1) : 0;
575  array_ge [j] = (array_a[j] >= array_b[j]) ? static_cast<MaskType> (-1) : 0;
576  }
577 
578  SIMDRegister<type> a (static_cast<type> (0));
579  SIMDRegister<type> b (static_cast<type> (0));
580 
581  vMaskType eq, neq, lt, le, gt, ge;
582 
583  copy (a, array_a);
584  copy (b, array_b);
585 
586  eq = SIMDRegister<type>::equal (a, b);
587  neq = SIMDRegister<type>::notEqual (a, b);
588  lt = SIMDRegister<type>::lessThan (a, b);
592 
593  u.expect (vecEqualToArray (eq, array_eq ));
594  u.expect (vecEqualToArray (neq, array_neq));
595  u.expect (vecEqualToArray (lt, array_lt ));
596  u.expect (vecEqualToArray (le, array_le ));
597  u.expect (vecEqualToArray (gt, array_gt ));
598  u.expect (vecEqualToArray (ge, array_ge ));
599 
600  do
601  {
602  SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
603  SIMDRegister_test_internal::VecFiller<type>::fill (array_b, SIMDRegister<type>::SIMDNumElements, random);
604  } while (std::equal (array_a, array_a + SIMDRegister<type>::SIMDNumElements, array_b));
605 
606  copy (a, array_a);
607  copy (b, array_b);
608  u.expect (a != b);
609  u.expect (b != a);
610  u.expect (! (a == b));
611  u.expect (! (b == a));
612 
613  SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
614  copy (a, array_a);
615  copy (b, array_a);
616 
617  u.expect (a == b);
618  u.expect (b == a);
619  u.expect (! (a != b));
620  u.expect (! (b != a));
621 
622  type scalar = a[0];
623  a = SIMDRegister<type>::expand (scalar);
624 
625  u.expect (a == scalar);
626  u.expect (! (a != scalar));
627 
628  scalar--;
629 
630  u.expect (a != scalar);
631  u.expect (! (a == scalar));
632  }
633  }
634  };
635 
636  struct CheckMultiplyAdd
637  {
638  template <typename type>
639  static void run (UnitTest& u, Random& random)
640  {
641  // set-up
646 
647  SIMDRegister_test_internal::VecFiller<type>::fill (array_a, SIMDRegister<type>::SIMDNumElements, random);
648  SIMDRegister_test_internal::VecFiller<type>::fill (array_b, SIMDRegister<type>::SIMDNumElements, random);
649  SIMDRegister_test_internal::VecFiller<type>::fill (array_c, SIMDRegister<type>::SIMDNumElements, random);
650  SIMDRegister_test_internal::VecFiller<type>::fill (array_d, SIMDRegister<type>::SIMDNumElements, random);
651 
652  // check
653  for (size_t i = 0; i < SIMDRegister<type>::SIMDNumElements; ++i)
654  array_d[i] = array_a[i] + (array_b[i] * array_c[i]);
655 
656  SIMDRegister<type> a, b, c, d;
657 
658  copy (a, array_a);
659  copy (b, array_b);
660  copy (c, array_c);
661 
662  d = SIMDRegister<type>::multiplyAdd (a, b, c);
663 
664  u.expect (vecEqualToArray (d, array_d));
665  }
666  };
667 
668  struct CheckMinMax
669  {
670  template <typename type>
671  static void run (UnitTest& u, Random& random)
672  {
673  for (int i = 0; i < 100; ++i)
674  {
677  type array_min [SIMDRegister<type>::SIMDNumElements];
678  type array_max [SIMDRegister<type>::SIMDNumElements];
679 
680  for (size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
681  {
682  array_a[j] = static_cast<type> (random.nextInt (127));
683  array_b[j] = static_cast<type> (random.nextInt (127));
684  }
685 
686  for (size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
687  {
688  array_min[j] = (array_a[j] < array_b[j]) ? array_a[j] : array_b[j];
689  array_max[j] = (array_a[j] > array_b[j]) ? array_a[j] : array_b[j];
690  }
691 
692  SIMDRegister<type> a (static_cast<type> (0));
693  SIMDRegister<type> b (static_cast<type> (0));
694  SIMDRegister<type> vMin (static_cast<type> (0));
695  SIMDRegister<type> vMax (static_cast<type> (0));
696 
697  copy (a, array_a);
698  copy (b, array_b);
699 
700  vMin = jmin (a, b);
701  vMax = jmax (a, b);
702 
703  u.expect (vecEqualToArray (vMin, array_min));
704  u.expect (vecEqualToArray (vMax, array_max));
705 
706  copy (vMin, array_a);
707  copy (vMax, array_a);
708 
709  vMin = SIMDRegister<type>::min (a, b);
710  vMax = SIMDRegister<type>::max (a, b);
711 
712  u.expect (vecEqualToArray (vMin, array_min));
713  u.expect (vecEqualToArray (vMax, array_max));
714  }
715  }
716  };
717 
718  struct CheckSum
719  {
720  template <typename type>
721  static void run (UnitTest& u, Random& random)
722  {
724  type sumCheck = 0;
725 
726  SIMDRegister_test_internal::VecFiller<type>::fill (array, SIMDRegister<type>::SIMDNumElements, random);
727 
728  for (size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
729  {
730  sumCheck += array[j];
731  }
732 
733  SIMDRegister<type> a;
734  copy (a, array);
735 
736  u.expect (SIMDRegister_test_internal::difference (sumCheck, a.sum()) < 1e-4);
737  }
738  };
739 
740  struct CheckAbs
741  {
742  template <typename type>
743  static void run (UnitTest& u, Random& random)
744  {
747 
748  SIMDRegister_test_internal::VecFiller<type>::fill (inArray, SIMDRegister<type>::SIMDNumElements, random);
749 
750  SIMDRegister<type> a;
751  copy (a, inArray);
752  a = SIMDRegister<type>::abs (a);
753 
754  auto calcAbs = [] (type x) -> type { return x >= type (0) ? x : -x; };
755 
756  for (size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
757  outArray[j] = calcAbs (inArray[j]);
758 
759  u.expect (vecEqualToArray (a, outArray));
760  }
761  };
762 
763  struct CheckTruncate
764  {
765  template <typename type>
766  static void run (UnitTest& u, Random& random)
767  {
770 
771  SIMDRegister_test_internal::VecFiller<type>::fill (inArray, SIMDRegister<type>::SIMDNumElements, random);
772 
773  SIMDRegister<type> a;
774  copy (a, inArray);
776 
777  for (size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
778  outArray[j] = (type) (int) inArray[j];
779 
780  u.expect (vecEqualToArray (a, outArray));
781  }
782  };
783 
784  struct CheckBoolEquals
785  {
786  template <typename type>
787  static void run (UnitTest& u, Random& random)
788  {
789  bool is_signed = std::is_signed<type>::value;
791 
792  auto value = is_signed ? static_cast<type> ((random.nextFloat() * 16.0) - 8.0)
793  : static_cast<type> (random.nextFloat() * 8.0);
794 
795  std::fill (array, array + SIMDRegister<type>::SIMDNumElements, value);
796  SIMDRegister<type> a, b;
797  copy (a, array);
798 
799  u.expect (a == value);
800  u.expect (! (a != value));
801  value += 1;
802 
803  u.expect (a != value);
804  u.expect (! (a == value));
805 
806  SIMDRegister_test_internal::VecFiller<type>::fill (array, SIMDRegister<type>::SIMDNumElements, random);
807  copy (a, array);
808  copy (b, array);
809 
810  u.expect (a == b);
811  u.expect (! (a != b));
812 
813  SIMDRegister_test_internal::VecFiller<type>::fill (array, SIMDRegister<type>::SIMDNumElements, random);
814  copy (b, array);
815 
816  u.expect (a != b);
817  u.expect (! (a == b));
818  }
819  };
820 
821  //==============================================================================
822  template <class TheTest>
823  void runTestFloatingPoint (const char* unitTestName)
824  {
825  beginTest (unitTestName);
826 
827  Random random = getRandom();
828 
829  TheTest::template run<float> (*this, random);
830  TheTest::template run<double> (*this, random);
831  }
832 
833  //==============================================================================
834  template <class TheTest>
835  void runTestForAllTypes (const char* unitTestName)
836  {
837  beginTest (unitTestName);
838 
839  Random random = getRandom();
840 
841  TheTest::template run<float> (*this, random);
842  TheTest::template run<double> (*this, random);
843  TheTest::template run<int8_t> (*this, random);
844  TheTest::template run<uint8_t> (*this, random);
845  TheTest::template run<int16_t> (*this, random);
846  TheTest::template run<uint16_t>(*this, random);
847  TheTest::template run<int32_t> (*this, random);
848  TheTest::template run<uint32_t>(*this, random);
849  TheTest::template run<int64_t> (*this, random);
850  TheTest::template run<uint64_t>(*this, random);
851  TheTest::template run<std::complex<float>> (*this, random);
852  TheTest::template run<std::complex<double>> (*this, random);
853  }
854 
855  template <class TheTest>
856  void runTestNonComplex (const char* unitTestName)
857  {
858  beginTest (unitTestName);
859 
860  Random random = getRandom();
861 
862  TheTest::template run<float> (*this, random);
863  TheTest::template run<double> (*this, random);
864  TheTest::template run<int8_t> (*this, random);
865  TheTest::template run<uint8_t> (*this, random);
866  TheTest::template run<int16_t> (*this, random);
867  TheTest::template run<uint16_t>(*this, random);
868  TheTest::template run<int32_t> (*this, random);
869  TheTest::template run<uint32_t>(*this, random);
870  TheTest::template run<int64_t> (*this, random);
871  TheTest::template run<uint64_t>(*this, random);
872  }
873 
874  template <class TheTest>
875  void runTestSigned (const char* unitTestName)
876  {
877  beginTest (unitTestName);
878 
879  Random random = getRandom();
880 
881  TheTest::template run<float> (*this, random);
882  TheTest::template run<double> (*this, random);
883  TheTest::template run<int8_t> (*this, random);
884  TheTest::template run<int16_t> (*this, random);
885  TheTest::template run<int32_t> (*this, random);
886  TheTest::template run<int64_t> (*this, random);
887  }
888 
889  void runTest()
890  {
891  runTestForAllTypes<InitializationTest> ("InitializationTest");
892 
893  runTestForAllTypes<AccessTest> ("AccessTest");
894 
895  runTestForAllTypes<OperatorTests<Addition>> ("AdditionOperators");
896  runTestForAllTypes<OperatorTests<Subtraction>> ("SubtractionOperators");
897  runTestForAllTypes<OperatorTests<Multiplication>> ("MultiplicationOperators");
898 
899  runTestForAllTypes<BitOperatorTests<BitAND>> ("BitANDOperators");
900  runTestForAllTypes<BitOperatorTests<BitOR>> ("BitOROperators");
901  runTestForAllTypes<BitOperatorTests<BitXOR>> ("BitXOROperators");
902 
903  runTestNonComplex<CheckComparisonOps> ("CheckComparisons");
904  runTestNonComplex<CheckBoolEquals> ("CheckBoolEquals");
905  runTestNonComplex<CheckMinMax> ("CheckMinMax");
906 
907  runTestForAllTypes<CheckMultiplyAdd> ("CheckMultiplyAdd");
908  runTestForAllTypes<CheckSum> ("CheckSum");
909 
910  runTestSigned<CheckAbs> ("CheckAbs");
911 
912  runTestFloatingPoint<CheckTruncate> ("CheckTruncate");
913  }
914 };
915 
916 static SIMDRegisterUnitTests SIMDRegisterUnitTests;
917 
918 } // namespace dsp
919 } // namespace juce
UnitTest(const String &name, const String &category=String())
void beginTest(const String &testName)
Random getRandom() const
static SIMDRegister JUCE_VECTOR_CALLTYPE truncate(SIMDRegister a) noexcept
static SIMDRegister JUCE_VECTOR_CALLTYPE expand(ElementType s) noexcept
static SIMDRegister JUCE_VECTOR_CALLTYPE max(SIMDRegister a, SIMDRegister b) noexcept
static vMaskType JUCE_VECTOR_CALLTYPE greaterThanOrEqual(SIMDRegister a, SIMDRegister b) noexcept
static vMaskType JUCE_VECTOR_CALLTYPE greaterThan(SIMDRegister a, SIMDRegister b) noexcept
static bool isSIMDAligned(const ElementType *ptr) noexcept
static SIMDRegister JUCE_VECTOR_CALLTYPE abs(SIMDRegister a) noexcept
SIMDRegister< MaskType > vMaskType
static vMaskType JUCE_VECTOR_CALLTYPE equal(SIMDRegister a, SIMDRegister b) noexcept
static SIMDRegister JUCE_VECTOR_CALLTYPE multiplyAdd(SIMDRegister a, const SIMDRegister b, SIMDRegister c) noexcept
static vMaskType JUCE_VECTOR_CALLTYPE lessThan(SIMDRegister a, SIMDRegister b) noexcept
static SIMDRegister JUCE_VECTOR_CALLTYPE min(SIMDRegister a, SIMDRegister b) noexcept
static constexpr size_t SIMDNumElements
static vMaskType JUCE_VECTOR_CALLTYPE lessThanOrEqual(SIMDRegister a, SIMDRegister b) noexcept
static ElementType * getNextSIMDAlignedPtr(ElementType *ptr) noexcept
typename SIMDInternal::MaskTypeFor< ElementType >::type MaskType
static SIMDRegister JUCE_VECTOR_CALLTYPE fromRawArray(const ElementType *a) noexcept
static vMaskType JUCE_VECTOR_CALLTYPE notEqual(SIMDRegister a, SIMDRegister b) noexcept