Nektar++
TestSimdLibDouble.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: TestSimdLibDouble.cpp
4//
5// For more information, please see: http://www.nektar.info
6//
7// The MIT License
8//
9// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10// Department of Aeronautics, Imperial College London (UK), and Scientific
11// Computing and Imaging Institute, University of Utah (USA).
12//
13// Permission is hereby granted, free of charge, to any person obtaining a
14// copy of this software and associated documentation files (the "Software"),
15// to deal in the Software without restriction, including without limitation
16// the rights to use, copy, modify, merge, publish, distribute, sublicense,
17// and/or sell copies of the Software, and to permit persons to whom the
18// Software is furnished to do so, subject to the following conditions:
19//
20/// The above copyright notice and this permission notice shall be included
21// in all copies or substantial portions of the Software.
22//
23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29// DEALINGS IN THE SOFTWARE.
30//
31// Description:
32//
33///////////////////////////////////////////////////////////////////////////////
34
37
38#include <boost/test/tools/floating_point_comparison.hpp>
39#include <boost/test/unit_test.hpp>
40
41#include <array>
42#include <cmath>
43#include <iostream>
44
45// define types in use and number of lanes
46#define NUM_LANES_64BITS 1
47#define ALIGNMENT 8
48#define USING_SCALAR
49#if defined(__x86_64__)
50#if defined(__AVX512F__) && defined(NEKTAR_ENABLE_SIMD_AVX512)
51#define USING_AVX512
52#undef NUM_LANES_64BITS
53#define NUM_LANES_64BITS 8
54#undef ALIGNMENT
55#define ALIGNMENT 64
56#undef USING_SCALAR
57#elif defined(__AVX2__) && defined(NEKTAR_ENABLE_SIMD_AVX2)
58#define USING_AVX2
59#undef NUM_LANES_64BITS
60#define NUM_LANES_64BITS 4
61#undef ALIGNMENT
62#define ALIGNMENT 32
63#undef USING_SCALAR
64#elif defined(__SSE2__) && defined(NEKTAR_ENABLE_SIMD_SSE2)
65#define USING_SSE2
66#undef NUM_LANES_64BITS
67#define NUM_LANES_64BITS 2
68#undef ALIGNMENT
69#define ALIGNMENT 16
70#undef USING_SCALAR
71#endif
72#endif
73#if defined(__ARM_FEATURE_SVE) && defined(NEKTAR_ENABLE_SIMD_SVE)
74#define USING_SVE
75#undef NUM_LANES_64BITS
76#define NUM_LANES_64BITS __ARM_FEATURE_SVE_BITS / 64
77#undef ALIGNMENT
78#define ALIGNMENT __ARM_FEATURE_SVE_BITS / 8
79#undef USING_SCALAR
80#endif
81
83{
84using namespace tinysimd;
86
87BOOST_AUTO_TEST_CASE(SimdLibDouble_width_alignment)
88{
89 std::size_t width, alignment;
90
91#if defined(USING_SCALAR)
92 std::cout << "scalar double" << std::endl;
93#endif
94#if defined(USING_AVX2)
95 std::cout << "avx2 double" << std::endl;
96#endif
97#if defined(USING_AVX512)
98 std::cout << "avx512 double" << std::endl;
99#endif
100#if defined(USING_SVE)
101 std::cout << "sve double" << std::endl;
102#endif
103
104 // double
105 width = simd<double>::width;
106 alignment = simd<double>::alignment;
107 BOOST_CHECK_EQUAL(width, NUM_LANES_64BITS);
108 BOOST_CHECK_EQUAL(alignment, ALIGNMENT);
109 // std::int32_t index forcing # of lanes
112 BOOST_CHECK_EQUAL(width, NUM_LANES_64BITS);
113 // std::int64_t index forcing # of lanes
116 BOOST_CHECK_EQUAL(width, NUM_LANES_64BITS);
117 BOOST_CHECK_EQUAL(alignment, ALIGNMENT);
118 // std::int64_t default index
121 BOOST_CHECK_EQUAL(width, NUM_LANES_64BITS);
122 BOOST_CHECK_EQUAL(alignment, ALIGNMENT);
123}
124
125BOOST_AUTO_TEST_CASE(SimdLibDouble_type_traits)
126{
127 {
128 using namespace details;
129
130 BOOST_CHECK_EQUAL(has_width<double>::value, false);
131 BOOST_CHECK_EQUAL(has_width<vec_t>::value, true);
132
133 BOOST_CHECK_EQUAL(has_alignment<double>::value, false);
134 BOOST_CHECK_EQUAL(has_alignment<vec_t>::value, true);
135
136 BOOST_CHECK_EQUAL(has_scalarType<double>::value, false);
137 BOOST_CHECK_EQUAL(has_scalarType<vec_t>::value, true);
138 }
139
140 BOOST_CHECK_EQUAL(is_vector<double>::value, false);
141 BOOST_CHECK_EQUAL(is_vector<vec_t>::value, true);
142
143 BOOST_CHECK_EQUAL(is_vector_floating_point<double>::value, false);
144 BOOST_CHECK_EQUAL(is_vector_floating_point<simd<int>>::value, false);
145 BOOST_CHECK_EQUAL(is_vector_floating_point<vec_t>::value, true);
146}
147
148BOOST_AUTO_TEST_CASE(SimdLibDouble_mem_size)
149{
150 BOOST_CHECK_EQUAL(sizeof(vec_t), sizeof(double) * vec_t::width);
151}
152
153BOOST_AUTO_TEST_CASE(SimdLibDouble_ctors)
154{
155 [[maybe_unused]] vec_t avec1;
156
157 vec_t::scalarType ascalar = 0;
158 vec_t avec2(ascalar);
159 [[maybe_unused]] vec_t avec3{ascalar};
160 vec_t avec4 = ascalar;
161
162 [[maybe_unused]] vec_t avec5(avec2);
163 [[maybe_unused]] vec_t avec6{avec4};
164
165 [[maybe_unused]] vec_t avec7(avec2._data);
166 [[maybe_unused]] vec_t avec8{avec2._data};
167
168 vec_t::vectorType anative;
169 [[maybe_unused]] vec_t avec9(anative);
170 [[maybe_unused]] vec_t avec10{anative};
171}
172
173BOOST_AUTO_TEST_CASE(SimdLibDouble_load)
174{
175 alignas(vec_t::alignment) std::array<double, vec_t::width> ascalararr{
176 {}}; // double brace to deal with gcc 4.8.5 ...
177 vec_t avec;
178 avec.load(ascalararr.data());
179}
180
181BOOST_AUTO_TEST_CASE(SimdLibDouble_load_implicit)
182{
183 alignas(vec_t::alignment) std::array<double, vec_t::width> ascalararr{
184 {}}; // double brace to deal with gcc 4.8.5 ...
185 vec_t avec;
186 avec = *(reinterpret_cast<vec_t *>(ascalararr.data()));
187}
188
189BOOST_AUTO_TEST_CASE(SimdLibDouble_load_aligned)
190{
191 alignas(vec_t::alignment) std::array<double, vec_t::width> ascalararr{
192 {}}; // double brace to deal with gcc 4.8.5 ...
193 vec_t avec;
194 avec.load(ascalararr.data(), is_aligned);
195}
196
197BOOST_AUTO_TEST_CASE(SimdLibDouble_load_unaligned)
198{
199 std::array<double, vec_t::width> ascalararr{
200 {}}; // double brace to deal with gcc 4.8.5 ...
201 vec_t avec;
202 avec.load(ascalararr.data(), is_not_aligned);
203}
204
205BOOST_AUTO_TEST_CASE(SimdLibInt64_load)
206{
207 alignas(vec_t::alignment) std::array<std::uint64_t, vec_t::width>
208 ascalararr{{}}; // double brace to deal with gcc 4.8.5 ...
210 aindex.load(ascalararr.data());
211}
212
213BOOST_AUTO_TEST_CASE(SimdLibInt64_load_aligned)
214{
215 alignas(vec_t::alignment) std::array<std::uint64_t, vec_t::width>
216 ascalararr{{}}; // double brace to deal with gcc 4.8.5 ...
218 aindex.load(ascalararr.data(), is_aligned);
219}
220
221BOOST_AUTO_TEST_CASE(SimdLibInt64_load_unaligned)
222{
223 std::array<std::uint64_t, vec_t::width> ascalararr{
224 {}}; // double brace to deal with gcc 4.8.5 ...
226 aindex.load(ascalararr.data(), is_not_aligned);
227}
228
229BOOST_AUTO_TEST_CASE(SimdLibInt32_load)
230{
231 alignas(vec_t::alignment) std::array<std::uint32_t, vec_t::width>
232 ascalararr{{}}; // double brace to deal with gcc 4.8.5 ...
234 aindex.load(ascalararr.data());
235}
236
237BOOST_AUTO_TEST_CASE(SimdLibInt32_load_aligned)
238{
239 alignas(vec_t::alignment) std::array<std::uint32_t, vec_t::width>
240 ascalararr{{}}; // double brace to deal with gcc 4.8.5 ...
242 aindex.load(ascalararr.data(), is_aligned);
243}
244
245BOOST_AUTO_TEST_CASE(SimdLibInt32_load_unaligned)
246{
247 std::array<std::uint32_t, vec_t::width> ascalararr{
248 {}}; // double brace to deal with gcc 4.8.5 ...
250 aindex.load(ascalararr.data(), is_not_aligned);
251}
252
253BOOST_AUTO_TEST_CASE(SimdLibDouble_store)
254{
255 double val = 4.0;
256 vec_t avec(val);
257 alignas(vec_t::alignment) std::array<double, vec_t::width> ascalararr{
258 {}}; // double brace to deal with gcc 4.8.5 ...
259 avec.store(ascalararr.data());
260
261 for (size_t i = 0; i < vec_t::width; ++i)
262 {
263 BOOST_CHECK_EQUAL(ascalararr[i], val);
264 }
265}
266
267BOOST_AUTO_TEST_CASE(SimdLibDouble_store_aligned)
268{
269 double val = 4.0;
270 vec_t avec(val);
271 alignas(vec_t::alignment) std::array<double, vec_t::width> ascalararr{
272 {}}; // double brace to deal with gcc 4.8.5 ...
273 avec.store(ascalararr.data(), is_aligned);
274
275 for (size_t i = 0; i < vec_t::width; ++i)
276 {
277 BOOST_CHECK_EQUAL(ascalararr[i], val);
278 }
279}
280
281BOOST_AUTO_TEST_CASE(SimdLibDouble_store_unaligned)
282{
283 double val = 4.0;
284 vec_t avec(val);
285 std::array<double, vec_t::width> ascalararr{
286 {}}; // double brace to deal with gcc 4.8.5 ...
287 avec.store(ascalararr.data(), is_not_aligned);
288
289 for (size_t i = 0; i < vec_t::width; ++i)
290 {
291 BOOST_CHECK_EQUAL(ascalararr[i], val);
292 }
293}
294
295BOOST_AUTO_TEST_CASE(SimdLibDouble_store_non_temporal)
296{
297 double val = 4.0;
298 vec_t avec(val);
299 alignas(vec_t::alignment) std::array<double, vec_t::width> ascalararr{
300 {}}; // double brace to deal with gcc 4.8.5 ...
301 avec.store(ascalararr.data(), is_not_reused);
302
303 for (size_t i = 0; i < vec_t::width; ++i)
304 {
305 BOOST_CHECK_EQUAL(ascalararr[i], val);
306 }
307}
308
309BOOST_AUTO_TEST_CASE(SimdLibDouble_broadcast)
310{
311 vec_t::scalarType ascalar{3.333};
312 vec_t avec;
313 avec.broadcast(ascalar);
314}
315
316BOOST_AUTO_TEST_CASE(SimdLibDouble_subscript_assign_read)
317{
318 vec_t avec;
319 alignas(vec_t::alignment) std::array<double, vec_t::width> ascalararr{
320 {}}; // double brace to deal with gcc 4.8.5 ...
321
322 for (size_t i = 0; i < vec_t::width; ++i)
323 {
324 ascalararr[i] = i;
325 }
326
327 for (size_t i = 0; i < vec_t::width; ++i)
328 {
329 avec[i] = ascalararr[i];
330 }
331
332 for (size_t i = 0; i < vec_t::width; ++i)
333 {
334 BOOST_CHECK_EQUAL(ascalararr[i], avec[i]);
335 }
336}
337
338BOOST_AUTO_TEST_CASE(SimdLibDouble_gather64)
339{
340 vec_t avec;
341 using index_t = simd<size_t>;
342 index_t aindexvec;
343
344 // create and fill index
345 std::array<size_t, vec_t::width> aindex;
346 aindex[0] = 0;
347 if (vec_t::width > 2)
348 {
349 aindex[1] = 3;
350 aindex[2] = 5;
351 aindex[3] = 6;
352 }
353 if (vec_t::width > 4)
354 {
355 aindex[4] = 8;
356 aindex[5] = 15;
357 aindex[6] = 16;
358 aindex[7] = 20;
359 }
360
361 // load index
362 aindexvec.load(aindex.data(), is_not_aligned);
363
364 // create and fill scalar array
365 constexpr size_t scalarArraySize = 32;
366 std::array<double, scalarArraySize> ascalararr;
367 for (size_t i = 0; i < scalarArraySize; ++i)
368 {
369 ascalararr[i] = i;
370 }
371
372 avec.gather(ascalararr.data(), aindexvec);
373
374 // check
375 for (size_t i = 0; i < vec_t::width; ++i)
376 {
377 BOOST_CHECK_EQUAL(ascalararr[aindex[i]], avec[i]);
378 }
379}
380
381BOOST_AUTO_TEST_CASE(SimdLibDouble_gather32)
382{
383 vec_t avec;
384 using index_t = simd<std::uint32_t, vec_t::width>;
385 index_t aindexvec;
386
387 // create and fill index
388 std::array<std::uint32_t, vec_t::width> aindex;
389 aindex[0] = 0;
390 if (vec_t::width > 2)
391 {
392 aindex[1] = 3;
393 aindex[2] = 5;
394 aindex[3] = 6;
395 }
396 if (vec_t::width > 4)
397 {
398 aindex[4] = 8;
399 aindex[5] = 15;
400 aindex[6] = 16;
401 aindex[7] = 20;
402 }
403
404 // load index
405 aindexvec.load(aindex.data(), is_not_aligned);
406
407 // create and fill scalar array
408 constexpr size_t scalarArraySize = 32;
409 std::array<double, scalarArraySize> ascalararr;
410 for (size_t i = 0; i < scalarArraySize; ++i)
411 {
412 ascalararr[i] = i;
413 }
414
415 avec.gather(ascalararr.data(), aindexvec);
416
417 // check
418 for (size_t i = 0; i < vec_t::width; ++i)
419 {
420 BOOST_CHECK_EQUAL(ascalararr[aindex[i]], avec[i]);
421 }
422}
423
424BOOST_AUTO_TEST_CASE(SimdLibDouble_scatter64)
425{
426 vec_t avec;
427 using index_t = simd<size_t>;
428 index_t aindexvec;
429
430 // create and fill index
431 std::array<size_t, vec_t::width> aindex;
432 aindex[0] = 1;
433 if (vec_t::width > 1)
434 {
435 aindex[1] = 3;
436 }
437 if (vec_t::width > 2)
438 {
439 aindex[2] = 5;
440 aindex[3] = 6;
441 }
442 if (vec_t::width > 4)
443 {
444 aindex[4] = 8;
445 aindex[5] = 15;
446 aindex[6] = 20;
447 aindex[7] = 30;
448 }
449
450 // load index
451 aindexvec.load(aindex.data(), is_not_aligned);
452
453 // create scalar array
454 constexpr size_t scalarArraySize = 32;
455 std::array<double, scalarArraySize> ascalararr;
456
457 // fill vector
458 alignas(vec_t::alignment) std::array<double, vec_t::width> avecarr{{}};
459 avecarr[0] = 10;
460 if (vec_t::width > 1)
461 {
462 avecarr[1] = 9;
463 }
464
465 if (vec_t::width > 2)
466 {
467 avecarr[2] = 8;
468 avecarr[3] = 7;
469 }
470 if (vec_t::width > 4)
471 {
472 avecarr[4] = 4;
473 avecarr[5] = 3;
474 avecarr[6] = 2;
475 avecarr[7] = 1;
476 }
477 avec.load(avecarr.data());
478
479 avec.scatter(ascalararr.data(), aindexvec);
480
481 // check
482 for (size_t i = 0; i < vec_t::width; ++i)
483 {
484 BOOST_CHECK_EQUAL(avec[i], ascalararr[aindex[i]]);
485 }
486}
487
488BOOST_AUTO_TEST_CASE(SimdLibDouble_add_unary)
489{
490 double val1 = -4.0;
491 double val2 = 2.0;
492 vec_t res(val1);
493 vec_t avec(val2);
494 res += avec;
495 alignas(vec_t::alignment) std::array<double, vec_t::width> ascalararr{
496 {}}; // double brace to deal with gcc 4.8.5 ...
497 res.store(ascalararr.data());
498
499 for (size_t i = 0; i < vec_t::width; ++i)
500 {
501 BOOST_CHECK_EQUAL(ascalararr[i], val1 + val2);
502 }
503}
504
505BOOST_AUTO_TEST_CASE(SimdLibDouble_sub_unary)
506{
507 double val1 = -4.0;
508 double val2 = 2.0;
509 vec_t res(val1);
510 vec_t avec(val2);
511 res -= avec;
512 alignas(vec_t::alignment) std::array<double, vec_t::width> ascalararr{
513 {}}; // double brace to deal with gcc 4.8.5 ...
514 res.store(ascalararr.data());
515
516 for (size_t i = 0; i < vec_t::width; ++i)
517 {
518 BOOST_CHECK_EQUAL(ascalararr[i], val1 - val2);
519 }
520}
521
522BOOST_AUTO_TEST_CASE(SimdLibDouble_mul_unary)
523{
524 double val1 = -4.0;
525 double val2 = 2.0;
526 vec_t res(val1);
527 vec_t avec(val2);
528 res *= avec;
529 alignas(vec_t::alignment) std::array<double, vec_t::width> ascalararr{
530 {}}; // double brace to deal with gcc 4.8.5 ...
531 res.store(ascalararr.data());
532
533 for (size_t i = 0; i < vec_t::width; ++i)
534 {
535 BOOST_CHECK_EQUAL(ascalararr[i], val1 * val2);
536 }
537}
538
539BOOST_AUTO_TEST_CASE(SimdLibDouble_div_unary)
540{
541 double val1 = -4.0;
542 double val2 = 2.0;
543 vec_t res(val1);
544 vec_t avec(val2);
545 res /= avec;
546 alignas(vec_t::alignment) std::array<double, vec_t::width> ascalararr{
547 {}}; // double brace to deal with gcc 4.8.5 ...
548 res.store(ascalararr.data());
549
550 for (size_t i = 0; i < vec_t::width; ++i)
551 {
552 BOOST_CHECK_EQUAL(ascalararr[i], val1 / val2);
553 }
554}
555
556BOOST_AUTO_TEST_CASE(SimdLibDouble_add_binary)
557{
558 double val1 = -4.0;
559 double val2 = 2.5;
560 vec_t avec1(val1);
561 vec_t avec2(val2);
562 vec_t res = avec1 + avec2;
563 alignas(vec_t::alignment) std::array<double, vec_t::width> ascalararr{
564 {}}; // double brace to deal with gcc 4.8.5 ...
565 res.store(ascalararr.data());
566
567 for (size_t i = 0; i < vec_t::width; ++i)
568 {
569 BOOST_CHECK_EQUAL(ascalararr[i], val1 + val2);
570 }
571}
572
573BOOST_AUTO_TEST_CASE(SimdLibDouble_sub_binary)
574{
575 double val1 = -4.0;
576 double val2 = 2.5;
577 vec_t avec1(val1);
578 vec_t avec2(val2);
579 vec_t res = avec1 - avec2;
580 alignas(vec_t::alignment) std::array<double, vec_t::width> ascalararr{
581 {}}; // double brace to deal with gcc 4.8.5 ...
582 res.store(ascalararr.data());
583
584 for (size_t i = 0; i < vec_t::width; ++i)
585 {
586 BOOST_CHECK_EQUAL(ascalararr[i], val1 - val2);
587 }
588}
589
590BOOST_AUTO_TEST_CASE(SimdLibDouble_mul_binary)
591{
592 double val1 = -4.0;
593 double val2 = 2.5;
594 vec_t avec1(val1);
595 vec_t avec2(val2);
596 vec_t res = avec1 * avec2;
597 alignas(vec_t::alignment) std::array<double, vec_t::width> ascalararr{
598 {}}; // double brace to deal with gcc 4.8.5 ...
599 res.store(ascalararr.data());
600
601 for (size_t i = 0; i < vec_t::width; ++i)
602 {
603 BOOST_CHECK_EQUAL(ascalararr[i], val1 * val2);
604 }
605}
606
607BOOST_AUTO_TEST_CASE(SimdLibDouble_div_binary)
608{
609 double val1 = -4.0;
610 double val2 = 2.5;
611 vec_t avec1(val1);
612 vec_t avec2(val2);
613 vec_t res = avec1 / avec2;
614 alignas(vec_t::alignment) std::array<double, vec_t::width> ascalararr{
615 {}}; // double brace to deal with gcc 4.8.5 ...
616 res.store(ascalararr.data());
617
618 for (size_t i = 0; i < vec_t::width; ++i)
619 {
620 BOOST_CHECK_EQUAL(ascalararr[i], val1 / val2);
621 }
622}
623
624BOOST_AUTO_TEST_CASE(SimdLibDouble_add_mul)
625{
626 double val1 = -4.0;
627 double val2 = 1.5;
628 double val3 = 5.0;
629 vec_t avec1(val1);
630 vec_t avec2(val2);
631 vec_t avec3(val3);
632 vec_t res = avec1 + avec2 * avec3;
633 alignas(vec_t::alignment) std::array<double, vec_t::width> ascalararr{
634 {}}; // double brace to deal with gcc 4.8.5 ...
635 res.store(ascalararr.data());
636
637 for (size_t i = 0; i < vec_t::width; ++i)
638 {
639 BOOST_CHECK_EQUAL(ascalararr[i], val1 + val2 * val3);
640 }
641}
642
643BOOST_AUTO_TEST_CASE(SimdLibDouble_fused_add_mul)
644{
645 double val1 = -4.0;
646 double val2 = 1.5;
647 double val3 = 5.0;
648 vec_t avec1(val1);
649 vec_t avec2(val2);
650 vec_t avec3(val3);
651 avec1.fma(avec2, avec3);
652 alignas(vec_t::alignment) std::array<double, vec_t::width> ascalararr{
653 {}}; // double brace to deal with gcc 4.8.5 ...
654 avec1.store(ascalararr.data());
655
656 for (size_t i = 0; i < vec_t::width; ++i)
657 {
658 BOOST_CHECK_EQUAL(ascalararr[i], val1 + val2 * val3);
659 }
660}
661
662BOOST_AUTO_TEST_CASE(SimdLibDouble_sqrt)
663{
664 double val = 4.0;
665 vec_t avec(val);
666 vec_t asqrt = sqrt(avec);
667 alignas(vec_t::alignment) std::array<double, vec_t::width> ascalararr{
668 {}}; // double brace to deal with gcc 4.8.5 ...
669 asqrt.store(ascalararr.data());
670
671 for (size_t i = 0; i < vec_t::width; ++i)
672 {
673 BOOST_CHECK_EQUAL(ascalararr[i], std::sqrt(val));
674 }
675}
676
677BOOST_AUTO_TEST_CASE(SimdLibDouble_abs)
678{
679 double val = -4.0;
680 vec_t avec(val);
681 vec_t aabs = abs(avec);
682 alignas(vec_t::alignment) std::array<double, vec_t::width> ascalararr{
683 {}}; // double brace to deal with gcc 4.8.5 ...
684 aabs.store(ascalararr.data());
685
686 for (size_t i = 0; i < vec_t::width; ++i)
687 {
688 BOOST_CHECK_EQUAL(ascalararr[i], std::abs(val));
689 }
690}
691
692BOOST_AUTO_TEST_CASE(SimdLibDouble_log)
693{
694 double val = 4.0;
695 vec_t avec(val);
696 vec_t alog = log(avec);
697 alignas(vec_t::alignment) std::array<double, vec_t::width> ascalararr{
698 {}}; // double brace to deal with gcc 4.8.5 ...
699 alog.store(ascalararr.data());
700
701 for (size_t i = 0; i < vec_t::width; ++i)
702 {
703 BOOST_CHECK_EQUAL(ascalararr[i], std::log(val));
704 }
705}
706
707BOOST_AUTO_TEST_CASE(SimdLibDouble_greater)
708{
709 double aval = 4.0;
710 vec_t avec(aval);
711 using mask_t = simd<bool, vec_t::width>;
712 mask_t amask;
713
714 amask = avec > avec;
715 // check
716 alignas(vec_t::alignment) std::array<std::uint64_t, vec_t::width>
717 ascalararr{{}}; // double brace to deal with gcc 4.8.5 ...
718 amask.store(ascalararr.data());
719 for (size_t i = 0; i < vec_t::width; ++i)
720 {
721 // type conversion make lvalue in rvalue, needed pre-c++17
722 BOOST_CHECK_EQUAL(ascalararr[i], (std::uint64_t)mask_t::false_v);
723 }
724
725 double bval = 3.0;
726 vec_t bvec(bval);
727
728 amask = avec > bvec;
729 // check
730 amask.store(ascalararr.data());
731 for (size_t i = 0; i < vec_t::width; ++i)
732 {
733 // type conversion make lvalue in rvalue, needed pre-c++17
734 BOOST_CHECK_EQUAL(ascalararr[i], (std::uint64_t)mask_t::true_v);
735 }
736
737 double cval = 5.0;
738 vec_t cvec(cval);
739
740 amask = avec > cvec;
741 // check
742 amask.store(ascalararr.data());
743 for (size_t i = 0; i < vec_t::width; ++i)
744 {
745 // type conversion make lvalue in rvalue, needed pre-c++17
746 BOOST_CHECK_EQUAL(ascalararr[i], (std::uint64_t)mask_t::false_v);
747 }
748
749 if (vec_t::width == 4)
750 {
751 alignas(vec_t::alignment) std::array<double, 4> ascalararr2{
752 {1.0, 2.0, 3.0, 4.0}}; // double brace to deal with gcc 4.8.5 ...
753 double dval = 2.0;
754 vec_t dvec(dval);
755 vec_t evec;
756 evec.load(ascalararr2.data());
757
758 amask = dvec > evec;
759 // check
760 for (size_t i = 0; i < vec_t::width; ++i)
761 {
762 BOOST_CHECK_EQUAL(static_cast<bool>(amask[i]),
763 dval > ascalararr2[i]);
764 }
765 }
766
767 if (vec_t::width == 8)
768 {
769 alignas(vec_t::alignment) std::array<double, 8> ascalararr2{
770 {1.0, 2.0, 3.0, 4.0, 3.0, 2.0,
771 1.0}}; // double brace to deal with gcc 4.8.5 ...
772 double dval = 2.0;
773 vec_t dvec(dval);
774 vec_t evec;
775 evec.load(ascalararr2.data());
776
777 amask = dvec > evec;
778 // check
779 for (size_t i = 0; i < vec_t::width; ++i)
780 {
781 BOOST_CHECK_EQUAL(static_cast<bool>(amask[i]),
782 dval > ascalararr2[i]);
783 }
784 }
785}
786
787BOOST_AUTO_TEST_CASE(SimdLibDouble_logic_and)
788{
789 double aval = 4.0;
790 vec_t avec(aval);
791 using mask_t = simd<bool, vec_t::width>;
792 mask_t amask;
793
794 alignas(vec_t::alignment) std::array<std::uint64_t, vec_t::width>
795 ascalararr{{}}; // double brace to deal with gcc 4.8.5 ...
796 for (size_t i = 0; i < vec_t::width; ++i)
797 {
798 ascalararr[i] = mask_t::true_v;
799 }
800 amask.load(ascalararr.data());
801
802 // check
803 BOOST_CHECK_EQUAL(amask && false, false);
804 BOOST_CHECK_EQUAL(amask && true, true);
805
806 for (size_t i = 0; i < vec_t::width; ++i)
807 {
808 ascalararr[i] = mask_t::false_v;
809 }
810 amask.load(ascalararr.data());
811
812 // check
813 BOOST_CHECK_EQUAL(amask && false, false);
814 BOOST_CHECK_EQUAL(amask && true, false);
815
816 if (vec_t::width > 1)
817 {
818 ascalararr[0] = mask_t::true_v;
819 // check
820 BOOST_CHECK_EQUAL(amask && false, false);
821 BOOST_CHECK_EQUAL(amask && true, false);
822 }
823}
824
825BOOST_AUTO_TEST_CASE(SimdLibDouble_load_interleave_unload)
826{
827 constexpr size_t nDof{5};
828 // no padding in load_interleave deinterleave_store
829 constexpr size_t nEle{vec_t::width * 5};
830 constexpr size_t nDofBlock = nDof * vec_t::width;
831
832 constexpr size_t size{nDof * nEle};
833 std::array<double, size> dofScalarArr{{}};
834 for (size_t i = 0; i < size; ++i)
835 {
836 dofScalarArr[i] = i;
837 }
838
839 // number of blocks
840 size_t nBlock = nEle / vec_t::width;
841
842 // aligned vector
843 std::vector<vec_t, allocator<vec_t>> dofVectorArr(nDof);
844
845 double *dataPtr = dofScalarArr.data();
846 // loop over blocks vec_t::width elements at the time
847 for (size_t b = 0; b < nBlock; ++b)
848 {
849 // load
850 load_interleave(dataPtr, nDof, dofVectorArr);
851
852 // manipulate each block
853 for (size_t j = 0; j < nDof; ++j)
854 {
855 dofVectorArr[j] = dofVectorArr[j] + j;
856 }
857
858 // store
859 deinterleave_store(dofVectorArr, nDof, dataPtr);
860 dataPtr += nDofBlock;
861 }
862
863 // check
864 for (size_t b = 0, i = 0; b < nBlock; ++b)
865 {
866 for (size_t j = 0; j < nDof; ++j, ++i)
867 {
868 BOOST_CHECK_EQUAL(dofScalarArr[i], i + j);
869 }
870 }
871}
872
873BOOST_AUTO_TEST_CASE(SimdLibDouble_io)
874{
875 vec_t avec(3.14);
876 std::cout << avec << std::endl;
877}
878
879} // namespace Nektar::SimdLibTests
#define ALIGNMENT
#define NUM_LANES_64BITS
The above copyright notice and this permission notice shall be included.
BOOST_AUTO_TEST_CASE(SimdLibDouble_width_alignment)
void load_interleave(const T *in, size_t dataLen, std::vector< scalarT< T >, allocator< scalarT< T > > > &out)
Definition: scalar.hpp:309
scalarT< T > abs(scalarT< T > in)
Definition: scalar.hpp:298
static constexpr struct tinysimd::is_aligned_t is_aligned
static constexpr struct tinysimd::is_not_aligned_t is_not_aligned
typename abi< ScalarType, width >::type simd
Definition: tinysimd.hpp:80
scalarT< T > log(scalarT< T > in)
Definition: scalar.hpp:303
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:294
static constexpr struct tinysimd::is_not_reused_t is_not_reused
void deinterleave_store(const std::vector< scalarT< T >, allocator< scalarT< T > > > &in, size_t dataLen, T *out)
Definition: scalar.hpp:319