OpenShot Library | OpenShotAudio  0.2.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 
137 {
138 public:
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 
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
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
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
325 
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>
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 
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 
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
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>
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));
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 
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);
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);
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 
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 
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  {
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 
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 
637  {
638  template <typename type>
639  static void run (UnitTest& u, Random& random)
640  {
641  // set-up
646 
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 
727 
728  for (size_t j = 0; j < SIMDRegister<type>::SIMDNumElements; ++j)
729  {
730  sumCheck += array[j];
731  }
732 
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 
749 
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 
764  {
765  template <typename type>
766  static void run (UnitTest& u, Random& random)
767  {
770 
772 
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 
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 
807  copy (a, array);
808  copy (b, array);
809 
810  u.expect (a == b);
811  u.expect (! (a != b));
812 
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 
917 
918 } // namespace dsp
919 } // namespace juce
static vMaskType JUCE_VECTOR_CALLTYPE greaterThanOrEqual(SIMDRegister a, SIMDRegister b) noexcept
Returns a SIMDRegister of the corresponding integral type where each element has each bit set if the ...
typename SIMDInternal::MaskTypeFor< ElementType >::type MaskType
The corresponding primitive integer type, for example, this will be int32_t if type is a float...
static SIMDRegister JUCE_VECTOR_CALLTYPE abs(SIMDRegister a) noexcept
Returns the absolute value of each element.
ElementType * getData() const noexcept
Returns a raw pointer to the allocated data.
static vMaskType JUCE_VECTOR_CALLTYPE lessThan(SIMDRegister a, SIMDRegister b) noexcept
Returns a SIMDRegister of the corresponding integral type where each element has each bit set if the ...
int nextInt() noexcept
Returns the next random 32 bit integer.
Definition: juce_Random.cpp:78
ElementType sum() const noexcept
Returns a scalar which is the sum of all elements of the receiver.
static SIMDRegister JUCE_VECTOR_CALLTYPE min(SIMDRegister a, SIMDRegister b) noexcept
Returns a new vector where each element is the minimum of the corresponding element of a and b...
Very simple container class to hold a pointer to some data on the heap.
STL namespace.
static SIMDRegister JUCE_VECTOR_CALLTYPE truncate(SIMDRegister a) noexcept
Truncates each element to its integer part.
A wrapper around the platform&#39;s native SIMD register type.
static SIMDRegister JUCE_VECTOR_CALLTYPE multiplyAdd(SIMDRegister a, const SIMDRegister b, SIMDRegister c) noexcept
Multiplies b and c and adds the result to a.
static SIMDRegister JUCE_VECTOR_CALLTYPE expand(ElementType s) noexcept
Creates a new SIMDRegister from the corresponding scalar primitive.
int64 nextInt64() noexcept
Returns the next 64-bit random number.
Definition: juce_Random.cpp:96
This is a base class for classes that perform a unit test.
Definition: juce_UnitTest.h:73
static vMaskType JUCE_VECTOR_CALLTYPE notEqual(SIMDRegister a, SIMDRegister b) noexcept
Returns a SIMDRegister of the corresponding integral type where each element has each bit set if the ...
static vMaskType JUCE_VECTOR_CALLTYPE greaterThan(SIMDRegister a, SIMDRegister b) noexcept
Returns a SIMDRegister of the corresponding integral type where each element has each bit set if the ...
void JUCE_VECTOR_CALLTYPE copyToRawArray(ElementType *a) const noexcept
Copies the elements of the SIMDRegister to a scalar array in memory.
static SIMDRegister JUCE_VECTOR_CALLTYPE fromRawArray(const ElementType *a) noexcept
Creates a new SIMDRegister from the first SIMDNumElements of a scalar array.
static vMaskType JUCE_VECTOR_CALLTYPE equal(SIMDRegister a, SIMDRegister b) noexcept
Returns a SIMDRegister of the corresponding integral type where each element has each bit set if the ...
void expect(bool testResult, const String &failureMessage=String())
Checks that the result of a test is true, and logs this result.
static ElementType * getNextSIMDAlignedPtr(ElementType *ptr) noexcept
Returns the next position in memory where isSIMDAligned returns true.
float nextFloat() noexcept
Returns the next random floating-point number.
A random number generator.
Definition: juce_Random.h:38
static vMaskType JUCE_VECTOR_CALLTYPE lessThanOrEqual(SIMDRegister a, SIMDRegister b) noexcept
Returns a SIMDRegister of the corresponding integral type where each element has each bit set if the ...
void runTest()
Implement this method in your subclass to actually run your tests.
static SIMDRegister JUCE_VECTOR_CALLTYPE max(SIMDRegister a, SIMDRegister b) noexcept
Returns a new vector where each element is the maximum of the corresponding element of a and b...