Nektar++
Loading...
Searching...
No Matches
tinysimd.hpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File: tinysimd.hpp
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: Light wrapper for automatic selection of available SIMD type.
32//
33///////////////////////////////////////////////////////////////////////////////
34
35#ifndef NEKTAR_LIB_LIBUTILITES_SIMDLIB_TINYSIMD_H
36#define NEKTAR_LIB_LIBUTILITES_SIMDLIB_TINYSIMD_H
37
38#include "avx2.hpp"
39#include "avx512.hpp"
40#include "scalar.hpp"
41#include "sse2.hpp"
42#include "sve.hpp"
43#include <array>
44#include <cstdint>
45#include <vector>
46
47namespace tinysimd
48{
49
50template <typename...> struct first_not_void_of
51{
52 using type = void;
53};
54
55template <typename... Rest> struct first_not_void_of<void, Rest...>
56{
57 using type = typename first_not_void_of<Rest...>::type;
58};
59
60template <typename T, typename... Rest> struct first_not_void_of<T, Rest...>
61{
62 using type = T;
63};
64
65template <unsigned int Width> struct width_tag
66{
67 static constexpr unsigned int width = Width;
68};
69
70template <typename T, typename = void>
71struct width_or_zero : std::integral_constant<unsigned int, 0>
72{
73};
74
75template <typename T>
76struct width_or_zero<T, std::void_t<decltype(T::width)>>
77 : std::integral_constant<unsigned int, T::width>
78{
79};
80
81namespace abi
82{
83
84// pick the most specialiazed available match out of available ABIs.
85template <typename T, int width> struct default_abi
86{
87 using type = typename first_not_void_of<
90 typename simd64<T>::type, typename scalar<T>::type>::type;
91
92 static_assert(!std::is_void_v<type>, "unsupported SIMD type");
93};
94
95} // namespace abi
96
97// Global long-SIMD scaling knob. PACKSIZE is derived from this multiplier,
98// the selected architecture, and the scalar type.
99static constexpr unsigned int PACKMULTIPLIER = 1;
100
101namespace abi
102{
103
104template <typename T> struct default_longsimd_width
105{
106private:
108
109public:
110 static constexpr unsigned int value = native_type::width * PACKMULTIPLIER;
111
112 static_assert(value > 0, "unsupported SIMD type");
113};
114
115} // namespace abi
116
117// Global long-SIMD width used by library code for NekDouble packs.
118static constexpr unsigned int PACKSIZE =
120
121#if defined(__clang__)
122#define TINYSIMD_PRAGMA_UNROLL _Pragma("clang loop unroll(full)")
123#elif defined(__GNUC__)
124#define TINYSIMD_PRAGMA_UNROLL _Pragma("GCC unroll 16")
125#else
126#define TINYSIMD_PRAGMA_UNROLL
127#endif
128
129// light wrapper for default types
130template <typename ScalarType, int width = 0,
131 template <typename, int> class abi = abi::default_abi>
132using simd = typename abi<ScalarType, width>::type;
133
134namespace details
135{
136
137template <typename T, typename = void> struct scalar_index_type
138{
139 using type = std::conditional_t<(sizeof(typename T::scalarType) <= 4),
140 std::uint32_t, std::uint64_t>;
141};
142
143template <typename T>
144struct scalar_index_type<T, std::enable_if_t<has_scalarIndexType<T>::value>>
145{
146 using type = typename T::scalarIndexType;
147};
148
149template <typename T>
151
152template <typename SimdType, unsigned int Width> struct long_simd
153{
154 static_assert(is_vector_floating_point_v<SimdType>,
155 "longsimd requires a floating-point SIMD chunk type");
156
157 static constexpr unsigned int width = Width;
158 static constexpr unsigned int alignment = SimdType::alignment;
159 static constexpr unsigned int chunkWidth = SimdType::width;
160 static constexpr unsigned int numChunks = width / chunkWidth;
161
162 static_assert(width >= chunkWidth,
163 "longsimd width must be at least one native SIMD chunk");
164 static_assert(width % chunkWidth == 0,
165 "longsimd width must be a multiple of the chunk width");
166
167 using scalarType = typename SimdType::scalarType;
169 using chunkType = SimdType;
171 using vectorType = std::array<chunkType, numChunks>;
173
174 static_assert(sizeof(chunkType) == sizeof(scalarType) * chunkWidth,
175 "longsimd requires tightly packed SIMD chunk storage");
176
178
179 inline long_simd() = default;
180 inline long_simd(const long_simd &rhs) = default;
181
182 inline void broadcast(const chunkType &rhs)
183 {
184 _data[0] = rhs;
185
187 for (size_t i = 1; i < numChunks; ++i)
188 {
189 _data[i] = _data[0];
190 }
191 }
192
193 inline long_simd(const vectorType &rhs)
194 {
196 for (size_t i = 0; i < numChunks; ++i)
197 {
198 _data[i] = rhs[i];
199 }
200 }
201
202 inline long_simd(const chunkType *rhs)
203 {
205 for (size_t i = 0; i < numChunks; ++i)
206 {
207 _data[i] = rhs[i];
208 }
209 }
210
211 inline long_simd(const scalarType rhs)
212 {
213 broadcast(chunkType(rhs));
214 }
215
216 inline long_simd &operator=(const long_simd &) = default;
217
218 inline void store(scalarType *p) const
219 {
221 for (size_t i = 0; i < numChunks; ++i)
222 {
223 _data[i].store(p + i * chunkWidth);
224 }
225 }
226
227 template <class flag,
228 typename std::enable_if<is_load_tag_v<flag>, bool>::type = 0>
229 inline void store(scalarType *p, flag f) const
230 {
232 for (size_t i = 0; i < numChunks; ++i)
233 {
234 _data[i].store(p + i * chunkWidth, f);
235 }
236 }
237
238 inline void load(const scalarType *p)
239 {
241 for (size_t i = 0; i < numChunks; ++i)
242 {
243 _data[i].load(p + i * chunkWidth);
244 }
245 }
246
247 template <class flag,
248 typename std::enable_if<is_load_tag_v<flag>, bool>::type = 0>
249 inline void load(const scalarType *p, flag f)
250 {
252 for (size_t i = 0; i < numChunks; ++i)
253 {
254 _data[i].load(p + i * chunkWidth, f);
255 }
256 }
257
258 inline void broadcast(const scalarType rhs)
259 {
260 broadcast(chunkType(rhs));
261 }
262
263 template <typename IndexType>
264 inline void gather(const scalarType *p, const IndexType *indices)
265 {
267 for (size_t i = 0; i < numChunks; ++i)
268 {
269 _data[i].gather(p, indices[i]);
270 }
271 }
272
273 template <typename IndexType>
274 inline void scatter(scalarType *out, const IndexType *indices) const
275 {
277 for (size_t i = 0; i < numChunks; ++i)
278 {
279 _data[i].scatter(out, indices[i]);
280 }
281 }
282
283 inline void fma(const long_simd &a, const long_simd &b)
284 {
286 for (size_t i = 0; i < numChunks; ++i)
287 {
288 _data[i].fma(a._data[i], b._data[i]);
289 }
290 }
291
292 inline void fma(const long_simd &a, const chunkType &b)
293 {
295 for (size_t i = 0; i < numChunks; ++i)
296 {
297 _data[i].fma(a._data[i], b);
298 }
299 }
300
301 inline void fma(const chunkType &a, const long_simd &b)
302 {
304 for (size_t i = 0; i < numChunks; ++i)
305 {
306 _data[i].fma(a, b._data[i]);
307 }
308 }
309
310 inline void fma(const chunkType &a, const chunkType &b)
311 {
312 const chunkType ab = a * b;
313 *this += ab;
314 }
315
316 template <typename U,
317 typename std::enable_if<std::is_arithmetic_v<U>, bool>::type = 0>
318 inline void fma(const long_simd &a, U b)
319 {
320 fma(a, chunkType(static_cast<scalarType>(b)));
321 }
322
323 template <typename U,
324 typename std::enable_if<std::is_arithmetic_v<U>, bool>::type = 0>
325 inline void fma(U a, const long_simd &b)
326 {
327 fma(chunkType(static_cast<scalarType>(a)), b);
328 }
329
330 template <
331 typename U, typename V,
332 typename std::enable_if<
333 std::is_arithmetic_v<U> && std::is_arithmetic_v<V>, bool>::type = 0>
334 inline void fma(U a, V b)
335 {
336 fma(chunkType(static_cast<scalarType>(a)),
337 chunkType(static_cast<scalarType>(b)));
338 }
339
340 inline scalarType operator[](size_t i) const
341 {
342 alignas(alignment) scalarArray tmp;
343 store(tmp, is_aligned);
344 return tmp[i];
345 }
346
347 inline scalarType &operator[](size_t i)
348 {
349 scalarType *tmp = reinterpret_cast<scalarType *>(_data);
350 return tmp[i];
351 }
352
353 inline void operator+=(const long_simd &rhs)
354 {
356 for (size_t i = 0; i < numChunks; ++i)
357 {
358 _data[i] += rhs._data[i];
359 }
360 }
361
362 inline void operator+=(const chunkType &rhs)
363 {
365 for (size_t i = 0; i < numChunks; ++i)
366 {
367 _data[i] += rhs;
368 }
369 }
370
371 template <typename U,
372 typename std::enable_if<std::is_arithmetic_v<U>, bool>::type = 0>
373 inline void operator+=(U rhs)
374 {
375 *this += chunkType(static_cast<scalarType>(rhs));
376 }
377
378 inline void operator-=(const long_simd &rhs)
379 {
381 for (size_t i = 0; i < numChunks; ++i)
382 {
383 _data[i] -= rhs._data[i];
384 }
385 }
386
387 inline void operator-=(const chunkType &rhs)
388 {
390 for (size_t i = 0; i < numChunks; ++i)
391 {
392 _data[i] -= rhs;
393 }
394 }
395
396 template <typename U,
397 typename std::enable_if<std::is_arithmetic_v<U>, bool>::type = 0>
398 inline void operator-=(U rhs)
399 {
400 *this -= chunkType(static_cast<scalarType>(rhs));
401 }
402
403 inline void operator*=(const long_simd &rhs)
404 {
406 for (size_t i = 0; i < numChunks; ++i)
407 {
408 _data[i] *= rhs._data[i];
409 }
410 }
411
412 inline void operator*=(const chunkType &rhs)
413 {
415 for (size_t i = 0; i < numChunks; ++i)
416 {
417 _data[i] *= rhs;
418 }
419 }
420
421 template <typename U,
422 typename std::enable_if<std::is_arithmetic_v<U>, bool>::type = 0>
423 inline void operator*=(U rhs)
424 {
425 *this *= chunkType(static_cast<scalarType>(rhs));
426 }
427
428 inline void operator/=(const long_simd &rhs)
429 {
431 for (size_t i = 0; i < numChunks; ++i)
432 {
433 _data[i] /= rhs._data[i];
434 }
435 }
436
437 inline void operator/=(const chunkType &rhs)
438 {
440 for (size_t i = 0; i < numChunks; ++i)
441 {
442 _data[i] /= rhs;
443 }
444 }
445
446 template <typename U,
447 typename std::enable_if<std::is_arithmetic_v<U>, bool>::type = 0>
448 inline void operator/=(U rhs)
449 {
450 *this /= chunkType(static_cast<scalarType>(rhs));
451 }
452};
453
454template <typename ScalarType, int width,
455 template <typename, int> class abi_policy>
457{
458private:
460
461 static constexpr int default_width =
463
464public:
465 static constexpr int requested_width = width == 0 ? default_width : width;
466
467 static_assert(requested_width > 0, "longsimd width must be positive");
468 static_assert(
469 requested_width >= static_cast<int>(native_type::width),
470 "longsimd width must be at least the native SIMD width; use simd<> "
471 "for narrower types");
472 static_assert(requested_width % static_cast<int>(native_type::width) == 0,
473 "longsimd width must be a multiple of the native SIMD width");
474
475 using type = std::conditional_t<
476 requested_width == static_cast<int>(native_type::width), native_type,
477 long_simd<native_type, static_cast<unsigned int>(requested_width)>>;
478};
479
480} // namespace details
481
482template <typename ScalarType, int width = 0,
483 template <typename, int> class abi = abi::default_abi>
484using longsimd =
486
487#if defined(__AVX2__) && defined(NEKTAR_ENABLE_SIMD_AVX2)
488using avx2Double8 = details::long_simd<avx2Double4, 8>;
489#endif
490
491#if defined(__AVX512F__) && defined(NEKTAR_ENABLE_SIMD_AVX512)
492using avx512Double16 = details::long_simd<avx512Double8, 16>;
493#endif
494
495template <typename SimdType, unsigned int Width>
499{
500 lhs += rhs;
501 return lhs;
502}
503
504template <typename SimdType, unsigned int Width>
508{
509 lhs += rhs;
510 return lhs;
511}
512
513template <typename SimdType, unsigned int Width>
517{
518 rhs += lhs;
519 return rhs;
520}
521
522template <typename SimdType, unsigned int Width, typename U,
523 typename std::enable_if<std::is_arithmetic_v<U>, bool>::type = 0>
526{
527 lhs += rhs;
528 return lhs;
529}
530
531template <typename SimdType, unsigned int Width, typename U,
532 typename std::enable_if<std::is_arithmetic_v<U>, bool>::type = 0>
535{
537 return typename vec_t::chunkType(
538 static_cast<typename vec_t::scalarType>(lhs)) +
539 rhs;
540}
541
542template <typename SimdType, unsigned int Width>
546{
547 lhs -= rhs;
548 return lhs;
549}
550
551template <typename SimdType, unsigned int Width>
555{
556 lhs -= rhs;
557 return lhs;
558}
559
560template <typename SimdType, unsigned int Width>
564{
566 for (size_t i = 0; i < rhs.numChunks; ++i)
567 {
568 rhs._data[i] = lhs - rhs._data[i];
569 }
570 return rhs;
571}
572
573template <typename SimdType, unsigned int Width, typename U,
574 typename std::enable_if<std::is_arithmetic_v<U>, bool>::type = 0>
577{
578 lhs -= rhs;
579 return lhs;
580}
581
582template <typename SimdType, unsigned int Width, typename U,
583 typename std::enable_if<std::is_arithmetic_v<U>, bool>::type = 0>
586{
588 return typename vec_t::chunkType(
589 static_cast<typename vec_t::scalarType>(lhs)) -
590 rhs;
591}
592
593template <typename SimdType, unsigned int Width>
596{
598 for (size_t i = 0; i < in.numChunks; ++i)
599 {
600 in._data[i] = -in._data[i];
601 }
602 return in;
603}
604
605template <typename SimdType, unsigned int Width>
609{
610 lhs *= rhs;
611 return lhs;
612}
613
614template <typename SimdType, unsigned int Width>
618{
619 lhs *= rhs;
620 return lhs;
621}
622
623template <typename SimdType, unsigned int Width>
627{
628 rhs *= lhs;
629 return rhs;
630}
631
632template <typename SimdType, unsigned int Width, typename U,
633 typename std::enable_if<std::is_arithmetic_v<U>, bool>::type = 0>
636{
637 lhs *= rhs;
638 return lhs;
639}
640
641template <typename SimdType, unsigned int Width, typename U,
642 typename std::enable_if<std::is_arithmetic_v<U>, bool>::type = 0>
645{
647 return typename vec_t::chunkType(
648 static_cast<typename vec_t::scalarType>(lhs)) *
649 rhs;
650}
651
652template <typename SimdType, unsigned int Width>
656{
657 lhs /= rhs;
658 return lhs;
659}
660
661template <typename SimdType, unsigned int Width>
665{
666 lhs /= rhs;
667 return lhs;
668}
669
670template <typename SimdType, unsigned int Width>
674{
676 for (size_t i = 0; i < rhs.numChunks; ++i)
677 {
678 rhs._data[i] = lhs / rhs._data[i];
679 }
680 return rhs;
681}
682
683template <typename SimdType, unsigned int Width, typename U,
684 typename std::enable_if<std::is_arithmetic_v<U>, bool>::type = 0>
687{
688 lhs /= rhs;
689 return lhs;
690}
691
692template <typename SimdType, unsigned int Width, typename U,
693 typename std::enable_if<std::is_arithmetic_v<U>, bool>::type = 0>
696{
698 return typename vec_t::chunkType(
699 static_cast<typename vec_t::scalarType>(lhs)) /
700 rhs;
701}
702
703template <typename SimdType, unsigned int Width>
706{
708 for (size_t i = 0; i < in.numChunks; ++i)
709 {
710 in._data[i] = sqrt(in._data[i]);
711 }
712 return in;
713}
714
715template <typename SimdType, unsigned int Width>
718{
720 for (size_t i = 0; i < in.numChunks; ++i)
721 {
722 in._data[i] = abs(in._data[i]);
723 }
724 return in;
725}
726
727template <typename SimdType, unsigned int Width>
731{
733 for (size_t i = 0; i < lhs.numChunks; ++i)
734 {
735 lhs._data[i] = min(lhs._data[i], rhs._data[i]);
736 }
737 return lhs;
738}
739
740template <typename SimdType, unsigned int Width>
744{
746 for (size_t i = 0; i < lhs.numChunks; ++i)
747 {
748 lhs._data[i] = max(lhs._data[i], rhs._data[i]);
749 }
750 return lhs;
751}
752
753template <typename SimdType, unsigned int Width>
756{
758 for (size_t i = 0; i < in.numChunks; ++i)
759 {
760 in._data[i] = log(in._data[i]);
761 }
762 return in;
763}
764
765template <typename SimdType, unsigned int Width>
768 const std::uint32_t dataLen,
771{
773
774 alignas(vec_t::alignment) typename vec_t::scalarArray tmp;
775 for (size_t i = 0; i < dataLen; ++i)
776 {
777 for (size_t j = 0; j < vec_t::width; ++j)
778 {
779 tmp[j] = in[i + j * dataLen];
780 }
781 out[i].load(tmp);
782 }
783}
784
785template <typename SimdType, unsigned int Width>
788 const std::uint32_t dataLen, const std::uint32_t skipPads,
791{
793
794 alignas(vec_t::alignment) typename vec_t::scalarArray tmp;
795 alignas(vec_t::alignment) typename vec_t::scalarArray tmp1;
796 alignas(vec_t::alignment) typename vec_t::scalarArray tmp2;
797 alignas(vec_t::alignment) typename vec_t::scalarArray tmp3;
798
799 size_t nBlocks = dataLen / 4;
800 const vec_t zero{static_cast<typename vec_t::scalarType>(0)};
801
802 for (size_t i = 0; i < nBlocks; ++i)
803 {
804 zero.store(tmp);
805 zero.store(tmp1);
806 zero.store(tmp2);
807 zero.store(tmp3);
808
809 for (size_t j = 0; j < vec_t::width - skipPads; ++j)
810 {
811 tmp[j] = in[j * dataLen + 4 * i];
812 tmp1[j] = in[j * dataLen + 4 * i + 1];
813 tmp2[j] = in[j * dataLen + 4 * i + 2];
814 tmp3[j] = in[j * dataLen + 4 * i + 3];
815 }
816
817 out[4 * i].load(tmp);
818 out[4 * i + 1].load(tmp1);
819 out[4 * i + 2].load(tmp2);
820 out[4 * i + 3].load(tmp3);
821 }
822
823 for (size_t i = nBlocks * 4; i < dataLen; ++i)
824 {
825 zero.store(tmp);
826 for (size_t j = 0; j < vec_t::width - skipPads; ++j)
827 {
828 tmp[j] = in[i + j * dataLen];
829 }
830 out[i].load(tmp);
831 }
832}
833
834template <typename SimdType, unsigned int Width>
835inline void load_interleave(
837 std::uint32_t dataLen,
840{
842 using index_t = typename vec_t::chunkIndexType;
843
844 alignas(index_t::alignment) typename index_t::scalarArray tmp;
845 index_t index[vec_t::numChunks];
846
847 for (size_t chunk = 0; chunk < vec_t::numChunks; ++chunk)
848 {
849 for (size_t lane = 0; lane < index_t::width; ++lane)
850 {
851 tmp[lane] = static_cast<typename vec_t::scalarIndexType>(
852 (chunk * index_t::width + lane) * dataLen);
853 }
854 index[chunk].load(tmp);
855 }
856
857 for (size_t i = 0; i < dataLen; ++i)
858 {
859 out[i].gather(in, index);
860 for (auto &idx : index)
861 {
862 idx = idx + index_t(1);
863 }
864 }
865}
866
867template <typename SimdType, unsigned int Width>
869 const std::vector<details::long_simd<SimdType, Width>,
871 const std::uint32_t dataLen,
873{
875
876 alignas(vec_t::alignment) typename vec_t::scalarArray tmp;
877 for (size_t i = 0; i < dataLen; ++i)
878 {
879 in[i].store(tmp);
880 for (size_t j = 0; j < vec_t::width; ++j)
881 {
882 out[i + j * dataLen] = tmp[j];
883 }
884 }
885}
886
887template <typename SimdType, unsigned int Width>
889 const std::vector<details::long_simd<SimdType, Width>,
891 const std::uint32_t dataLen, const std::uint32_t skipPads,
893{
895
896 alignas(vec_t::alignment) typename vec_t::scalarArray tmp;
897 alignas(vec_t::alignment) typename vec_t::scalarArray tmp1;
898 alignas(vec_t::alignment) typename vec_t::scalarArray tmp2;
899 alignas(vec_t::alignment) typename vec_t::scalarArray tmp3;
900
901 size_t nBlocks = dataLen / 4;
902
903 for (size_t i = 0; i < nBlocks; ++i)
904 {
905 in[4 * i].store(tmp);
906 in[4 * i + 1].store(tmp1);
907 in[4 * i + 2].store(tmp2);
908 in[4 * i + 3].store(tmp3);
909
910 for (size_t j = 0; j < vec_t::width - skipPads; ++j)
911 {
912 out[j * dataLen + 4 * i] = tmp[j];
913 out[j * dataLen + 4 * i + 1] = tmp1[j];
914 out[j * dataLen + 4 * i + 2] = tmp2[j];
915 out[j * dataLen + 4 * i + 3] = tmp3[j];
916 }
917 }
918
919 for (size_t i = nBlocks * 4; i < dataLen; ++i)
920 {
921 in[i].store(tmp);
922 for (size_t j = 0; j < vec_t::width - skipPads; ++j)
923 {
924 out[j * dataLen + i] = tmp[j];
925 }
926 }
927}
928
929template <typename SimdType, unsigned int Width>
931 const std::vector<details::long_simd<SimdType, Width>,
933 std::uint32_t dataLen,
935{
937 using index_t = typename vec_t::chunkIndexType;
938
939 alignas(index_t::alignment) typename index_t::scalarArray tmp;
940 index_t index[vec_t::numChunks];
941
942 for (size_t chunk = 0; chunk < vec_t::numChunks; ++chunk)
943 {
944 for (size_t lane = 0; lane < index_t::width; ++lane)
945 {
946 tmp[lane] = static_cast<typename vec_t::scalarIndexType>(
947 (chunk * index_t::width + lane) * dataLen);
948 }
949 index[chunk].load(tmp);
950 }
951
952 for (size_t i = 0; i < dataLen; ++i)
953 {
954 in[i].scatter(out, index);
955 for (auto &idx : index)
956 {
957 idx = idx + index_t(1);
958 }
959 }
960}
961
962#undef TINYSIMD_PRAGMA_UNROLL
963
964} // namespace tinysimd
965#endif
STL namespace.
typename scalar_index_type< T >::type scalar_index_type_t
Definition tinysimd.hpp:150
void load_interleave(const T *in, const size_t dataLen, std::vector< scalarT< T >, allocator< scalarT< T > > > &out)
Definition scalar.hpp:338
scalarT< T > abs(scalarT< T > in)
Definition scalar.hpp:295
static constexpr unsigned int PACKMULTIPLIER
Definition tinysimd.hpp:99
void deinterleave_unalign_store(const std::vector< scalarT< T >, allocator< scalarT< T > > > &in, const size_t dataLen, T *out)
Definition scalar.hpp:348
static constexpr struct tinysimd::is_aligned_t is_aligned
scalarT< T > operator-(scalarT< T > lhs, scalarT< T > rhs)
Definition scalar.hpp:232
scalarT< T > operator/(scalarT< T > lhs, scalarT< T > rhs)
Definition scalar.hpp:273
scalarT< T > max(scalarT< T > lhs, scalarT< T > rhs)
Definition scalar.hpp:305
typename abi< ScalarType, width >::type simd
Definition tinysimd.hpp:132
boost::alignment::aligned_allocator< T, T::alignment > allocator
Definition allocator.hpp:48
scalarT< T > log(scalarT< T > in)
Definition scalar.hpp:310
scalarT< T > operator*(scalarT< T > lhs, scalarT< T > rhs)
Definition scalar.hpp:255
void load_unalign_interleave(const T *in, const size_t dataLen, std::vector< scalarT< T >, allocator< scalarT< T > > > &out)
Definition scalar.hpp:316
void deinterleave_store(const std::vector< scalarT< T >, allocator< scalarT< T > > > &in, const size_t dataLen, T *out)
Definition scalar.hpp:370
scalarT< T > min(scalarT< T > lhs, scalarT< T > rhs)
Definition scalar.hpp:300
void deinterleave_unalign_store_skipPads(const std::vector< scalarT< T >, allocator< scalarT< T > > > &in, const size_t dataLen, const size_t skipPads, T *out)
Definition scalar.hpp:359
static constexpr unsigned int PACKSIZE
Definition tinysimd.hpp:118
scalarT< T > sqrt(scalarT< T > in)
Definition scalar.hpp:290
void load_unalign_interleave_skipPads(const T *in, const size_t dataLen, const size_t skipPads, std::vector< scalarT< T >, allocator< scalarT< T > > > &out)
Definition scalar.hpp:327
scalarT< T > operator+(scalarT< T > lhs, scalarT< T > rhs)
Definition scalar.hpp:214
typename details::longsimd_selector< ScalarType, width, abi >::type longsimd
Definition tinysimd.hpp:485
typename first_not_void_of< typename sve< T, width >::type, typename avx512< T, width >::type, typename avx2< T, width >::type, typename sse2< T, width >::type, typename simd64< T >::type, typename scalar< T >::type >::type type
Definition tinysimd.hpp:90
static constexpr unsigned int value
Definition tinysimd.hpp:110
typename default_abi< T, 0 >::type native_type
Definition tinysimd.hpp:107
void gather(const scalarType *p, const IndexType *indices)
Definition tinysimd.hpp:264
void fma(const long_simd &a, const chunkType &b)
Definition tinysimd.hpp:292
void operator*=(const chunkType &rhs)
Definition tinysimd.hpp:412
void load(const scalarType *p)
Definition tinysimd.hpp:238
long_simd(const chunkType *rhs)
Definition tinysimd.hpp:202
void broadcast(const chunkType &rhs)
Definition tinysimd.hpp:182
scalarType[width] scalarArray
Definition tinysimd.hpp:172
void operator/=(const chunkType &rhs)
Definition tinysimd.hpp:437
void fma(U a, const long_simd &b)
Definition tinysimd.hpp:325
static constexpr unsigned int chunkWidth
Definition tinysimd.hpp:159
std::array< chunkType, numChunks > vectorType
Definition tinysimd.hpp:171
void fma(const chunkType &a, const long_simd &b)
Definition tinysimd.hpp:301
void load(const scalarType *p, flag f)
Definition tinysimd.hpp:249
void broadcast(const scalarType rhs)
Definition tinysimd.hpp:258
long_simd(const scalarType rhs)
Definition tinysimd.hpp:211
scalar_index_type_t< SimdType > scalarIndexType
Definition tinysimd.hpp:168
void fma(const long_simd &a, U b)
Definition tinysimd.hpp:318
void operator*=(const long_simd &rhs)
Definition tinysimd.hpp:403
void fma(const chunkType &a, const chunkType &b)
Definition tinysimd.hpp:310
long_simd(const long_simd &rhs)=default
scalarType & operator[](size_t i)
Definition tinysimd.hpp:347
void fma(const long_simd &a, const long_simd &b)
Definition tinysimd.hpp:283
scalarType operator[](size_t i) const
Definition tinysimd.hpp:340
long_simd(const vectorType &rhs)
Definition tinysimd.hpp:193
void store(scalarType *p) const
Definition tinysimd.hpp:218
void store(scalarType *p, flag f) const
Definition tinysimd.hpp:229
chunkType _data[numChunks]
Definition tinysimd.hpp:177
static constexpr unsigned int numChunks
Definition tinysimd.hpp:160
simd< scalarIndexType, chunkWidth > chunkIndexType
Definition tinysimd.hpp:170
void operator-=(const chunkType &rhs)
Definition tinysimd.hpp:387
void operator+=(const chunkType &rhs)
Definition tinysimd.hpp:362
static constexpr unsigned int width
Definition tinysimd.hpp:157
void scatter(scalarType *out, const IndexType *indices) const
Definition tinysimd.hpp:274
long_simd & operator=(const long_simd &)=default
void operator+=(const long_simd &rhs)
Definition tinysimd.hpp:353
void operator/=(const long_simd &rhs)
Definition tinysimd.hpp:428
void operator-=(const long_simd &rhs)
Definition tinysimd.hpp:378
static constexpr unsigned int alignment
Definition tinysimd.hpp:158
typename SimdType::scalarType scalarType
Definition tinysimd.hpp:167
static constexpr int requested_width
Definition tinysimd.hpp:465
static constexpr int default_width
Definition tinysimd.hpp:461
std::conditional_t< requested_width==static_cast< int >(native_type::width), native_type, long_simd< native_type, static_cast< unsigned int >(requested_width)> > type
Definition tinysimd.hpp:477
simd< ScalarType, 0, abi_policy > native_type
Definition tinysimd.hpp:459
std::conditional_t<(sizeof(typename T::scalarType)<=4), std::uint32_t, std::uint64_t > type
Definition tinysimd.hpp:140
typename first_not_void_of< Rest... >::type type
Definition tinysimd.hpp:57
static constexpr unsigned int width
Definition tinysimd.hpp:67
#define TINYSIMD_PRAGMA_UNROLL
Definition tinysimd.hpp:126