OpenShot Audio Library | OpenShotAudio: juce_SIMDRegister_test.cpp Source File

OpenShot Audio Library | OpenShotAudio 0.3.2

Loading...
Searching...
No Matches
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
27namespace juce
28{
29namespace dsp
30{
31
32namespace 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
136class SIMDRegisterUnitTests : public UnitTest
137{
138public:
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 {
186 if (SIMDRegister<type>::isSIMDAligned (ptr))
187 {
188 vec = SIMDRegister<type>::fromRawArray (ptr);
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;
324 type array [SIMDRegister<type>::SIMDNumElements];
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
355 type array_a [SIMDRegister<type>::SIMDNumElements];
356 type array_b [SIMDRegister<type>::SIMDNumElements];
357 type array_c [SIMDRegister<type>::SIMDNumElements];
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 {
431 type array_a [SIMDRegister<type>::SIMDNumElements];
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
467 type float_a [SIMDRegister<type>::SIMDNumElements];
468 type float_c [SIMDRegister<type>::SIMDNumElements];
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
554 type array_a [SIMDRegister<type>::SIMDNumElements];
555 type array_b [SIMDRegister<type>::SIMDNumElements];
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);
589 le = SIMDRegister<type>::lessThanOrEqual (a, b);
590 gt = SIMDRegister<type>::greaterThan (a, b);
591 ge = SIMDRegister<type>::greaterThanOrEqual (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
642 type array_a [SIMDRegister<type>::SIMDNumElements];
643 type array_b [SIMDRegister<type>::SIMDNumElements];
644 type array_c [SIMDRegister<type>::SIMDNumElements];
645 type array_d [SIMDRegister<type>::SIMDNumElements];
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 {
675 type array_a [SIMDRegister<type>::SIMDNumElements];
676 type array_b [SIMDRegister<type>::SIMDNumElements];
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 {
723 type array [SIMDRegister<type>::SIMDNumElements];
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 {
745 type inArray[SIMDRegister<type>::SIMDNumElements];
746 type outArray[SIMDRegister<type>::SIMDNumElements];
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 {
768 type inArray[SIMDRegister<type>::SIMDNumElements];
769 type outArray[SIMDRegister<type>::SIMDNumElements];
770
771 SIMDRegister_test_internal::VecFiller<type>::fill (inArray, SIMDRegister<type>::SIMDNumElements, random);
772
773 SIMDRegister<type> a;
774 copy (a, inArray);
775 a = SIMDRegister<type>::truncate (a);
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;
790 type array [SIMDRegister<type>::SIMDNumElements];
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
916static SIMDRegisterUnitTests SIMDRegisterUnitTests;
917
918} // namespace dsp
919} // namespace juce
juce::UnitTest::UnitTest
UnitTest(const String &name, const String &category=String())
Definition: juce_UnitTest.cpp:26
juce::UnitTest::beginTest
void beginTest(const String &testName)
Definition: juce_UnitTest.cpp:89
juce::UnitTest::getRandom
Random getRandom() const
Definition: juce_UnitTest.cpp:108
juce::dsp::SIMDRegister::truncate
static SIMDRegister JUCE_VECTOR_CALLTYPE truncate(SIMDRegister a) noexcept
Definition: juce_SIMDRegister.h:334
juce::dsp::SIMDRegister::expand
static SIMDRegister JUCE_VECTOR_CALLTYPE expand(ElementType s) noexcept
Definition: juce_SIMDRegister.h:130
juce::dsp::SIMDRegister::max
static SIMDRegister JUCE_VECTOR_CALLTYPE max(SIMDRegister a, SIMDRegister b) noexcept
Definition: juce_SIMDRegister.h:318
juce::dsp::SIMDRegister::getNextSIMDAlignedPtr
static ElementType * getNextSIMDAlignedPtr(ElementType *ptr) noexcept
Definition: juce_SIMDRegister.h:356
juce::dsp::SIMDRegister::greaterThanOrEqual
static vMaskType JUCE_VECTOR_CALLTYPE greaterThanOrEqual(SIMDRegister a, SIMDRegister b) noexcept
Definition: juce_SIMDRegister.h:311
juce::dsp::SIMDRegister::greaterThan
static vMaskType JUCE_VECTOR_CALLTYPE greaterThan(SIMDRegister a, SIMDRegister b) noexcept
Definition: juce_SIMDRegister.h:306
juce::dsp::SIMDRegister::isSIMDAligned
static bool isSIMDAligned(const ElementType *ptr) noexcept
Definition: juce_SIMDRegister.h:345
juce::dsp::SIMDRegister::abs
static SIMDRegister JUCE_VECTOR_CALLTYPE abs(SIMDRegister a) noexcept
Definition: juce_SIMDRegister.h:338
juce::dsp::SIMDRegister::vMaskType
SIMDRegister< MaskType > vMaskType
Definition: juce_SIMDRegister.h:89
juce::dsp::SIMDRegister::equal
static vMaskType JUCE_VECTOR_CALLTYPE equal(SIMDRegister a, SIMDRegister b) noexcept
Definition: juce_SIMDRegister.h:286
juce::dsp::SIMDRegister::multiplyAdd
static SIMDRegister JUCE_VECTOR_CALLTYPE multiplyAdd(SIMDRegister a, const SIMDRegister b, SIMDRegister c) noexcept
Definition: juce_SIMDRegister.h:322
juce::dsp::SIMDRegister::lessThan
static vMaskType JUCE_VECTOR_CALLTYPE lessThan(SIMDRegister a, SIMDRegister b) noexcept
Definition: juce_SIMDRegister.h:296
juce::dsp::SIMDRegister::min
static SIMDRegister JUCE_VECTOR_CALLTYPE min(SIMDRegister a, SIMDRegister b) noexcept
Definition: juce_SIMDRegister.h:315
juce::dsp::SIMDRegister::SIMDNumElements
static constexpr size_t SIMDNumElements
Definition: juce_SIMDRegister.h:107
juce::dsp::SIMDRegister::lessThanOrEqual
static vMaskType JUCE_VECTOR_CALLTYPE lessThanOrEqual(SIMDRegister a, SIMDRegister b) noexcept
Definition: juce_SIMDRegister.h:301
juce::dsp::SIMDRegister::MaskType
typename SIMDInternal::MaskTypeFor< ElementType >::type MaskType
Definition: juce_SIMDRegister.h:74
juce::dsp::SIMDRegister::fromRawArray
static SIMDRegister JUCE_VECTOR_CALLTYPE fromRawArray(const ElementType *a) noexcept
Definition: juce_SIMDRegister.h:137
juce::dsp::SIMDRegister::notEqual
static vMaskType JUCE_VECTOR_CALLTYPE notEqual(SIMDRegister a, SIMDRegister b) noexcept
Definition: juce_SIMDRegister.h:291