35#ifndef NEKTAR_LIB_LIBUTILITES_SIMDLIB_AVX2_H
36#define NEKTAR_LIB_LIBUTILITES_SIMDLIB_AVX2_H
38#if defined(__x86_64__)
40#if defined(__INTEL_COMPILER) && !defined(TINYSIMD_HAS_SVML)
41#define TINYSIMD_HAS_SVML
53template <
typename scalarType,
int w
idth = 0>
struct avx2
60#if defined(__AVX2__) && defined(NEKTAR_ENABLE_SIMD_AVX2)
66template <
typename T>
struct avx2Long4;
67template <
typename T>
struct avx2Int8;
77template <>
struct avx2<double>
79 using type = avx2Double4;
81template <>
struct avx2<float>
83 using type = avx2Float8;
89 using type = avx2Long4<std::int64_t>;
93 using type = avx2Long4<std::uint64_t>;
96template <>
struct avx2<
std::size_t>
98 using type = avx2Long4<std::size_t>;
103 using type = avx2Int8<std::int32_t>;
107 using type = avx2Int8<std::uint32_t>;
112 using type = avx2Long4<std::int64_t>;
116 using type = avx2Long4<std::uint64_t>;
118#if defined(__APPLE__)
119template <>
struct avx2<
std::size_t, 4>
121 using type = avx2Long4<std::size_t>;
126 using type = sse2Int4<std::int32_t>;
130 using type = sse2Int4<std::uint32_t>;
134 using type = avx2Int8<std::int32_t>;
138 using type = avx2Int8<std::uint32_t>;
141template <>
struct avx2<bool, 4>
143 using type = avx2Mask4;
145template <>
struct avx2<bool, 8>
147 using type = avx2Mask8;
155template <
typename T>
struct avx2Int8
157 static_assert(std::is_integral_v<T> &&
sizeof(T) == 4,
158 "4 bytes Integral required.");
160 static constexpr unsigned int width = 8;
161 static constexpr unsigned int alignment = 32;
163 using scalarType = T;
164 using vectorType = __m256i;
165 using scalarArray = scalarType[width];
171 inline avx2Int8() =
default;
172 inline avx2Int8(
const avx2Int8 &rhs) =
default;
173 inline avx2Int8(
const vectorType &rhs) : _data(rhs)
176 inline avx2Int8(
const scalarType rhs)
178 _data = _mm256_set1_epi32(rhs);
180 explicit inline avx2Int8(scalarArray &rhs)
182 _data = _mm256_load_si256(
reinterpret_cast<vectorType *
>(rhs));
186 inline avx2Int8 &operator=(
const avx2Int8 &) =
default;
189 inline void store(scalarType *p)
const
191 _mm256_store_si256(
reinterpret_cast<vectorType *
>(p), _data);
194 template <
class flag,
195 typename std::enable_if<is_requiring_alignment_v<flag> &&
196 !is_streaming_v<flag>,
198 inline void store(scalarType *p, flag)
const
200 _mm256_store_si256(
reinterpret_cast<vectorType *
>(p), _data);
203 template <
class flag,
typename std::enable_if<
204 !is_requiring_alignment_v<flag>,
bool>::type = 0>
205 inline void store(scalarType *p, flag)
const
207 _mm256_storeu_si256(
reinterpret_cast<vectorType *
>(p), _data);
210 inline void load(
const scalarType *p)
212 _data = _mm256_load_si256(
reinterpret_cast<const vectorType *
>(p));
215 template <
class flag,
216 typename std::enable_if<is_requiring_alignment_v<flag> &&
217 !is_streaming_v<flag>,
219 inline void load(
const scalarType *p, flag)
221 _data = _mm256_load_si256(
reinterpret_cast<const vectorType *
>(p));
224 template <
class flag,
typename std::enable_if<
225 !is_requiring_alignment_v<flag>,
bool>::type = 0>
226 inline void load(
const scalarType *p, flag)
228 _data = _mm256_loadu_si256(
reinterpret_cast<const vectorType *
>(p));
231 inline void broadcast(
const scalarType rhs)
233 _data = _mm256_set1_epi32(rhs);
239 inline scalarType operator[](
size_t i)
const
241 alignas(alignment) scalarArray tmp;
242 store(tmp, is_aligned);
246 inline scalarType &operator[](
size_t i)
248 scalarType *tmp =
reinterpret_cast<scalarType *
>(&_data);
254inline avx2Int8<T>
operator+(avx2Int8<T> lhs, avx2Int8<T> rhs)
256 return _mm256_add_epi32(lhs._data, rhs._data);
259template <
typename T,
typename U,
260 typename =
typename std::enable_if<std::is_arithmetic_v<U>>::type>
261inline avx2Int8<T>
operator+(avx2Int8<T> lhs, U rhs)
263 return _mm256_add_epi32(lhs._data, _mm256_set1_epi32(rhs));
268template <
typename T>
struct avx2Long4
270 static_assert(std::is_integral_v<T> &&
sizeof(T) == 8,
271 "8 bytes Integral required.");
273 static constexpr unsigned int width = 4;
274 static constexpr unsigned int alignment = 32;
276 using scalarType = T;
277 using vectorType = __m256i;
278 using scalarArray = scalarType[width];
284 inline avx2Long4() =
default;
285 inline avx2Long4(
const avx2Long4 &rhs) =
default;
286 inline avx2Long4(
const vectorType &rhs) : _data(rhs)
289 inline avx2Long4(
const scalarType rhs)
291 _data = _mm256_set1_epi64x(rhs);
293 explicit inline avx2Long4(scalarArray &rhs)
295 _data = _mm256_load_si256(
reinterpret_cast<vectorType *
>(rhs));
299 inline avx2Long4 &operator=(
const avx2Long4 &) =
default;
302 inline void store(scalarType *p)
const
304 _mm256_store_si256(
reinterpret_cast<vectorType *
>(p), _data);
307 template <
class flag,
308 typename std::enable_if<is_requiring_alignment_v<flag> &&
309 !is_streaming_v<flag>,
311 inline void store(scalarType *p, flag)
const
313 _mm256_store_si256(
reinterpret_cast<vectorType *
>(p), _data);
316 template <
class flag,
typename std::enable_if<
317 !is_requiring_alignment_v<flag>,
bool>::type = 0>
318 inline void store(scalarType *p, flag)
const
320 _mm256_storeu_si256(
reinterpret_cast<vectorType *
>(p), _data);
323 inline void load(
const scalarType *p)
325 _data = _mm256_load_si256(
reinterpret_cast<const vectorType *
>(p));
328 template <
class flag,
329 typename std::enable_if<is_requiring_alignment_v<flag> &&
330 !is_streaming_v<flag>,
332 inline void load(
const scalarType *p, flag)
334 _data = _mm256_load_si256(
reinterpret_cast<const vectorType *
>(p));
337 template <
class flag,
typename std::enable_if<
338 !is_requiring_alignment_v<flag>,
bool>::type = 0>
339 inline void load(
const scalarType *p, flag)
341 _data = _mm256_loadu_si256(
reinterpret_cast<const vectorType *
>(p));
344 inline void broadcast(
const scalarType rhs)
346 _data = _mm256_set1_epi64x(rhs);
352 inline scalarType operator[](
size_t i)
const
354 alignas(alignment) scalarArray tmp;
355 store(tmp, is_aligned);
359 inline scalarType &operator[](
size_t i)
361 scalarType *tmp =
reinterpret_cast<scalarType *
>(&_data);
367inline avx2Long4<T>
operator+(avx2Long4<T> lhs, avx2Long4<T> rhs)
369 return _mm256_add_epi64(lhs._data, rhs._data);
372template <
typename T,
typename U,
373 typename =
typename std::enable_if<std::is_arithmetic_v<U>>::type>
374inline avx2Long4<T>
operator+(avx2Long4<T> lhs, U rhs)
376 return _mm256_add_epi64(lhs._data, _mm256_set1_epi64x(rhs));
383 static constexpr unsigned width = 4;
384 static constexpr unsigned alignment = 32;
386 using scalarType = double;
387 using scalarIndexType = std::uint64_t;
388 using vectorType = __m256d;
389 using scalarArray = scalarType[width];
395 inline avx2Double4() =
default;
396 inline avx2Double4(
const avx2Double4 &rhs) =
default;
397 inline avx2Double4(
const vectorType &rhs) : _data(rhs)
400 inline avx2Double4(
const scalarType rhs)
402 _data = _mm256_set1_pd(rhs);
406 inline avx2Double4 &operator=(
const avx2Double4 &) =
default;
409 inline void store(scalarType *p)
const
411 _mm256_store_pd(p, _data);
414 template <
class flag,
415 typename std::enable_if<is_requiring_alignment_v<flag> &&
416 !is_streaming_v<flag>,
418 inline void store(scalarType *p, flag)
const
420 _mm256_store_pd(p, _data);
423 template <
class flag,
typename std::enable_if<
424 !is_requiring_alignment_v<flag>,
bool>::type = 0>
425 inline void store(scalarType *p, flag)
const
427 _mm256_storeu_pd(p, _data);
430 template <
class flag,
431 typename std::enable_if<is_streaming_v<flag>,
bool>::type = 0>
432 inline void store(scalarType *p, flag)
const
434 _mm256_stream_pd(p, _data);
438 inline void load(
const scalarType *p)
440 _data = _mm256_load_pd(p);
443 template <
class flag,
typename std::enable_if<
444 is_requiring_alignment_v<flag>,
bool>::type = 0>
445 inline void load(
const scalarType *p, flag)
447 _data = _mm256_load_pd(p);
450 template <
class flag,
typename std::enable_if<
451 !is_requiring_alignment_v<flag>,
bool>::type = 0>
452 inline void load(
const scalarType *p, flag)
454 _data = _mm256_loadu_pd(p);
458 inline void broadcast(
const scalarType rhs)
460 _data = _mm256_set1_pd(rhs);
464 template <
typename T>
465 inline void gather(scalarType
const *p,
const sse2Int4<T> &indices)
467 _data = _mm256_i32gather_pd(p, indices._data, 8);
470 template <
typename T>
471 inline void scatter(scalarType *out,
const sse2Int4<T> &indices)
const
474 alignas(alignment) scalarArray tmp;
475 _mm256_store_pd(tmp, _data);
477 out[_mm_extract_epi32(indices._data, 0)] = tmp[0];
478 out[_mm_extract_epi32(indices._data, 1)] = tmp[1];
479 out[_mm_extract_epi32(indices._data, 2)] = tmp[2];
480 out[_mm_extract_epi32(indices._data, 3)] = tmp[3];
484 template <
typename T>
485 inline void gather(scalarType
const *p,
const avx2Long4<T> &indices)
487 _data = _mm256_i64gather_pd(p, indices._data, 8);
490 template <
typename T>
491 inline void scatter(scalarType *out,
const avx2Long4<T> &indices)
const
494 alignas(alignment) scalarArray tmp;
495 _mm256_store_pd(tmp, _data);
497 out[_mm256_extract_epi64(indices._data, 0)] = tmp[0];
498 out[_mm256_extract_epi64(indices._data, 1)] = tmp[1];
499 out[_mm256_extract_epi64(indices._data, 2)] = tmp[2];
500 out[_mm256_extract_epi64(indices._data, 3)] = tmp[3];
505 inline void fma(
const avx2Double4 &a,
const avx2Double4 &b)
507 _data = _mm256_fmadd_pd(a._data, b._data, _data);
513 inline scalarType operator[](
size_t i)
const
515 alignas(alignment) scalarArray tmp;
516 store(tmp, is_aligned);
520 inline scalarType &operator[](
size_t i)
522 scalarType *tmp =
reinterpret_cast<scalarType *
>(&_data);
527 inline void operator+=(avx2Double4 rhs)
529 _data = _mm256_add_pd(_data, rhs._data);
532 inline void operator-=(avx2Double4 rhs)
534 _data = _mm256_sub_pd(_data, rhs._data);
537 inline void operator*=(avx2Double4 rhs)
539 _data = _mm256_mul_pd(_data, rhs._data);
542 inline void operator/=(avx2Double4 rhs)
544 _data = _mm256_div_pd(_data, rhs._data);
548inline avx2Double4
operator+(avx2Double4 lhs, avx2Double4 rhs)
550 return _mm256_add_pd(lhs._data, rhs._data);
553inline avx2Double4
operator-(avx2Double4 lhs, avx2Double4 rhs)
555 return _mm256_sub_pd(lhs._data, rhs._data);
558inline avx2Double4
operator-(avx2Double4 in)
560 return _mm256_xor_pd(in._data, _mm256_set1_pd(-0.0));
563inline avx2Double4
operator*(avx2Double4 lhs, avx2Double4 rhs)
565 return _mm256_mul_pd(lhs._data, rhs._data);
568inline avx2Double4
operator/(avx2Double4 lhs, avx2Double4 rhs)
570 return _mm256_div_pd(lhs._data, rhs._data);
573inline avx2Double4
sqrt(avx2Double4 in)
575 return _mm256_sqrt_pd(in._data);
578inline avx2Double4
abs(avx2Double4 in)
581 static const __m256d sign_mask = _mm256_set1_pd(-0.);
582 return _mm256_andnot_pd(sign_mask, in._data);
585inline avx2Double4
min(avx2Double4 lhs, avx2Double4 rhs)
587 return _mm256_min_pd(lhs._data, rhs._data);
590inline avx2Double4
max(avx2Double4 lhs, avx2Double4 rhs)
592 return _mm256_max_pd(lhs._data, rhs._data);
595inline avx2Double4
log(avx2Double4 in)
597#if defined(TINYSIMD_HAS_SVML)
598 return _mm256_log_pd(in._data);
602 alignas(avx2Double4::alignment) avx2Double4::scalarArray tmp;
604 tmp[0] = std::log(tmp[0]);
605 tmp[1] = std::log(tmp[1]);
606 tmp[2] = std::log(tmp[2]);
607 tmp[3] = std::log(tmp[3]);
615 const double *in,
const std::uint32_t dataLen,
616 std::vector<avx2Double4, allocator<avx2Double4>> &out)
618 alignas(avx2Double4::alignment) avx2Double4::scalarArray tmp;
619 for (
size_t i = 0; i < dataLen; ++i)
622 tmp[1] = in[i + dataLen];
623 tmp[2] = in[i + 2 * dataLen];
624 tmp[3] = in[i + 3 * dataLen];
630 const double *in,
const std::uint32_t dataLen,
const std::uint32_t skipPads,
631 std::vector<avx2Double4, allocator<avx2Double4>> &out)
633 alignas(avx2Double4::alignment) avx2Double4::scalarArray tmp;
634 alignas(avx2Double4::alignment) avx2Double4::scalarArray tmp1;
635 alignas(avx2Double4::alignment) avx2Double4::scalarArray tmp2;
636 alignas(avx2Double4::alignment) avx2Double4::scalarArray tmp3;
638 size_t nBlocks = dataLen / 4;
639 const avx2Double4 zero{0.0};
641 for (
size_t i = 0; i < nBlocks; ++i)
647 for (
size_t j = 0; j < avx2Double4::width - skipPads; ++j)
649 tmp[j] = in[j * dataLen + 4 * i];
650 tmp1[j] = in[j * dataLen + 4 * i + 1];
651 tmp2[j] = in[j * dataLen + 4 * i + 2];
652 tmp3[j] = in[j * dataLen + 4 * i + 3];
654 out[4 * i].load(tmp);
655 out[4 * i + 1].load(tmp1);
656 out[4 * i + 2].load(tmp2);
657 out[4 * i + 3].load(tmp3);
660 for (
size_t i = nBlocks * 4; i < dataLen; ++i)
663 for (
size_t j = 0; j < avx2Double4::width - skipPads; ++j)
665 tmp[j] = in[i + j * dataLen];
672 const double *in, std::uint32_t dataLen,
673 std::vector<avx2Double4, allocator<avx2Double4>> &out)
675 alignas(avx2Double4::alignment)
676 size_t tmp[avx2Double4::width] = {0, dataLen, 2 * dataLen, 3 * dataLen};
677 using index_t = avx2Long4<size_t>;
679 index_t index1 = index0 + 1;
680 index_t index2 = index0 + 2;
681 index_t index3 = index0 + 3;
684 constexpr uint16_t unrl = 4;
685 size_t nBlocks = dataLen / unrl;
686 for (
size_t i = 0; i < nBlocks; ++i)
688 out[unrl * i + 0].gather(in, index0);
689 out[unrl * i + 1].gather(in, index1);
690 out[unrl * i + 2].gather(in, index2);
691 out[unrl * i + 3].gather(in, index3);
692 index0 = index0 + unrl;
693 index1 = index1 + unrl;
694 index2 = index2 + unrl;
695 index3 = index3 + unrl;
699 for (
size_t i = unrl * nBlocks; i < dataLen; ++i)
701 out[i].gather(in, index0);
707 const std::vector<avx2Double4, allocator<avx2Double4>> &in,
708 const std::uint32_t dataLen,
double *out)
710 alignas(avx2Double4::alignment) avx2Double4::scalarArray tmp;
711 for (
size_t i = 0; i < dataLen; ++i)
715 out[i + dataLen] = tmp[1];
716 out[i + 2 * dataLen] = tmp[2];
717 out[i + 3 * dataLen] = tmp[3];
722 const std::vector<avx2Double4, allocator<avx2Double4>> &in,
723 const std::uint32_t dataLen,
const std::uint32_t skipPads,
double *out)
725 alignas(avx2Double4::alignment) avx2Double4::scalarArray tmp;
726 alignas(avx2Double4::alignment) avx2Double4::scalarArray tmp1;
727 alignas(avx2Double4::alignment) avx2Double4::scalarArray tmp2;
728 alignas(avx2Double4::alignment) avx2Double4::scalarArray tmp3;
731 size_t nBlocks = dataLen / 4;
733 for (
size_t i = 0; i < nBlocks; ++i)
735 in[4 * i].store(tmp);
736 in[4 * i + 1].store(tmp1);
737 in[4 * i + 2].store(tmp2);
738 in[4 * i + 3].store(tmp3);
739 for (
size_t j = 0; j < avx2Double4::width - skipPads; ++j)
741 out[j * dataLen + 4 * i] = tmp[j];
742 out[j * dataLen + 4 * i + 1] = tmp1[j];
743 out[j * dataLen + 4 * i + 2] = tmp2[j];
744 out[j * dataLen + 4 * i + 3] = tmp3[j];
749 for (
size_t i = nBlocks * 4; i < dataLen; ++i)
752 for (
size_t j = 0; j < avx2Double4::width - skipPads; ++j)
754 out[j * dataLen + i] = tmp[j];
760 const std::vector<avx2Double4, allocator<avx2Double4>> &in,
761 std::uint32_t dataLen,
double *out)
763 alignas(avx2Double4::alignment)
764 size_t tmp[avx2Double4::width] = {0, dataLen, 2 * dataLen, 3 * dataLen};
765 using index_t = avx2Long4<size_t>;
768 for (
size_t i = 0; i < dataLen; ++i)
770 in[i].scatter(out, index0);
777 static constexpr unsigned width = 8;
778 static constexpr unsigned alignment = 32;
780 using scalarType = float;
781 using scalarIndexType = std::uint32_t;
782 using vectorType = __m256;
783 using scalarArray = scalarType[width];
789 inline avx2Float8() =
default;
790 inline avx2Float8(
const avx2Float8 &rhs) =
default;
791 inline avx2Float8(
const vectorType &rhs) : _data(rhs)
794 inline avx2Float8(
const scalarType rhs)
796 _data = _mm256_set1_ps(rhs);
800 inline avx2Float8 &operator=(
const avx2Float8 &) =
default;
803 inline void store(scalarType *p)
const
805 _mm256_store_ps(p, _data);
808 template <
class flag,
809 typename std::enable_if<is_requiring_alignment_v<flag> &&
810 !is_streaming_v<flag>,
812 inline void store(scalarType *p, flag)
const
814 _mm256_store_ps(p, _data);
817 template <
class flag,
typename std::enable_if<
818 !is_requiring_alignment_v<flag>,
bool>::type = 0>
819 inline void store(scalarType *p, flag)
const
821 _mm256_storeu_ps(p, _data);
824 template <
class flag,
825 typename std::enable_if<is_streaming_v<flag>,
bool>::type = 0>
826 inline void store(scalarType *p, flag)
const
828 _mm256_stream_ps(p, _data);
832 inline void load(
const scalarType *p)
834 _data = _mm256_load_ps(p);
837 template <
class flag,
typename std::enable_if<
838 is_requiring_alignment_v<flag>,
bool>::type = 0>
839 inline void load(
const scalarType *p, flag)
841 _data = _mm256_load_ps(p);
844 template <
class flag,
typename std::enable_if<
845 !is_requiring_alignment_v<flag>,
bool>::type = 0>
846 inline void load(
const scalarType *p, flag)
848 _data = _mm256_loadu_ps(p);
852 inline void broadcast(
const scalarType rhs)
854 _data = _mm256_set1_ps(rhs);
858 template <
typename T>
859 inline void gather(scalarType
const *p,
const avx2Int8<T> &indices)
861 _data = _mm256_i32gather_ps(p, indices._data, 4);
864 template <
typename T>
865 inline void scatter(scalarType *out,
const avx2Int8<T> &indices)
const
868 alignas(alignment) scalarArray tmp;
869 _mm256_store_ps(tmp, _data);
871 out[_mm256_extract_epi32(indices._data, 0)] = tmp[0];
872 out[_mm256_extract_epi32(indices._data, 1)] = tmp[1];
873 out[_mm256_extract_epi32(indices._data, 2)] = tmp[2];
874 out[_mm256_extract_epi32(indices._data, 3)] = tmp[3];
875 out[_mm256_extract_epi32(indices._data, 4)] = tmp[4];
876 out[_mm256_extract_epi32(indices._data, 5)] = tmp[5];
877 out[_mm256_extract_epi32(indices._data, 6)] = tmp[6];
878 out[_mm256_extract_epi32(indices._data, 7)] = tmp[7];
883 inline void fma(
const avx2Float8 &a,
const avx2Float8 &b)
885 _data = _mm256_fmadd_ps(a._data, b._data, _data);
891 inline scalarType operator[](
size_t i)
const
893 alignas(alignment) scalarArray tmp;
894 store(tmp, is_aligned);
898 inline scalarType &operator[](
size_t i)
900 scalarType *tmp =
reinterpret_cast<scalarType *
>(&_data);
904 inline void operator+=(avx2Float8 rhs)
906 _data = _mm256_add_ps(_data, rhs._data);
909 inline void operator-=(avx2Float8 rhs)
911 _data = _mm256_sub_ps(_data, rhs._data);
914 inline void operator*=(avx2Float8 rhs)
916 _data = _mm256_mul_ps(_data, rhs._data);
919 inline void operator/=(avx2Float8 rhs)
921 _data = _mm256_div_ps(_data, rhs._data);
925inline avx2Float8
operator+(avx2Float8 lhs, avx2Float8 rhs)
927 return _mm256_add_ps(lhs._data, rhs._data);
930inline avx2Float8
operator-(avx2Float8 lhs, avx2Float8 rhs)
932 return _mm256_sub_ps(lhs._data, rhs._data);
935inline avx2Float8
operator-(avx2Float8 in)
937 return _mm256_xor_ps(in._data, _mm256_set1_ps(-0.0));
940inline avx2Float8
operator*(avx2Float8 lhs, avx2Float8 rhs)
942 return _mm256_mul_ps(lhs._data, rhs._data);
945inline avx2Float8
operator/(avx2Float8 lhs, avx2Float8 rhs)
947 return _mm256_div_ps(lhs._data, rhs._data);
950inline avx2Float8
sqrt(avx2Float8 in)
952 return _mm256_sqrt_ps(in._data);
955inline avx2Float8
abs(avx2Float8 in)
958 static const __m256 sign_mask = _mm256_set1_ps(-0.);
959 return _mm256_andnot_ps(sign_mask, in._data);
962inline avx2Float8
min(avx2Float8 lhs, avx2Float8 rhs)
964 return _mm256_min_ps(lhs._data, rhs._data);
967inline avx2Float8
max(avx2Float8 lhs, avx2Float8 rhs)
969 return _mm256_max_ps(lhs._data, rhs._data);
972inline avx2Float8
log(avx2Float8 in)
976 alignas(avx2Float8::alignment) avx2Float8::scalarArray tmp;
978 tmp[0] = std::log(tmp[0]);
979 tmp[1] = std::log(tmp[1]);
980 tmp[2] = std::log(tmp[2]);
981 tmp[3] = std::log(tmp[3]);
982 tmp[4] = std::log(tmp[4]);
983 tmp[5] = std::log(tmp[5]);
984 tmp[6] = std::log(tmp[6]);
985 tmp[7] = std::log(tmp[7]);
992 const double *in,
const std::uint32_t dataLen,
993 std::vector<avx2Float8, allocator<avx2Float8>> &out)
995 alignas(avx2Float8::alignment) avx2Float8::scalarArray tmp;
996 for (
size_t i = 0; i < dataLen; ++i)
999 tmp[1] = in[i + dataLen];
1000 tmp[2] = in[i + 2 * dataLen];
1001 tmp[3] = in[i + 3 * dataLen];
1002 tmp[4] = in[i + 4 * dataLen];
1003 tmp[5] = in[i + 5 * dataLen];
1004 tmp[6] = in[i + 6 * dataLen];
1005 tmp[7] = in[i + 7 * dataLen];
1011 const double *in,
const std::uint32_t dataLen,
const std::uint32_t skipPads,
1012 std::vector<avx2Float8, allocator<avx2Float8>> &out)
1014 alignas(avx2Float8::alignment) avx2Float8::scalarArray tmp;
1015 alignas(avx2Float8::alignment) avx2Float8::scalarArray tmp1;
1016 alignas(avx2Float8::alignment) avx2Float8::scalarArray tmp2;
1017 alignas(avx2Float8::alignment) avx2Float8::scalarArray tmp3;
1019 size_t nBlocks = dataLen / 4;
1020 const avx2Float8 zero{0.0};
1022 for (
size_t i = 0; i < nBlocks; ++i)
1028 for (
size_t j = 0; j < avx2Float8::width - skipPads; ++j)
1030 tmp[j] = in[j * dataLen + 4 * i];
1031 tmp1[j] = in[j * dataLen + 4 * i + 1];
1032 tmp2[j] = in[j * dataLen + 4 * i + 2];
1033 tmp3[j] = in[j * dataLen + 4 * i + 3];
1035 out[4 * i].load(tmp);
1036 out[4 * i + 1].load(tmp1);
1037 out[4 * i + 2].load(tmp2);
1038 out[4 * i + 3].load(tmp3);
1041 for (
size_t i = nBlocks * 4; i < dataLen; ++i)
1044 for (
size_t j = 0; j < avx2Float8::width - skipPads; ++j)
1046 tmp[j] = in[i + j * dataLen];
1053 std::vector<avx2Float8, allocator<avx2Float8>> &out)
1056 alignas(avx2Float8::alignment) avx2Float8::scalarIndexType tmp[8] = {
1057 0, dataLen, 2 * dataLen, 3 * dataLen,
1058 4 * dataLen, 5 * dataLen, 6 * dataLen, 7 * dataLen};
1060 using index_t = avx2Int8<avx2Float8::scalarIndexType>;
1061 index_t index0(tmp);
1062 index_t index1 = index0 + 1;
1063 index_t index2 = index0 + 2;
1064 index_t index3 = index0 + 3;
1067 size_t nBlocks = dataLen / 4;
1068 for (
size_t i = 0; i < nBlocks; ++i)
1070 out[4 * i + 0].gather(in, index0);
1071 out[4 * i + 1].gather(in, index1);
1072 out[4 * i + 2].gather(in, index2);
1073 out[4 * i + 3].gather(in, index3);
1074 index0 = index0 + 4;
1075 index1 = index1 + 4;
1076 index2 = index2 + 4;
1077 index3 = index3 + 4;
1081 for (
size_t i = 4 * nBlocks; i < dataLen; ++i)
1083 out[i].gather(in, index0);
1084 index0 = index0 + 1;
1089 const std::vector<avx2Float8, allocator<avx2Float8>> &in,
1090 const std::uint32_t dataLen,
double *out)
1092 alignas(avx2Float8::alignment) avx2Float8::scalarArray tmp;
1093 for (
size_t i = 0; i < dataLen; ++i)
1097 out[i + dataLen] = tmp[1];
1098 out[i + 2 * dataLen] = tmp[2];
1099 out[i + 3 * dataLen] = tmp[3];
1100 out[i + 4 * dataLen] = tmp[4];
1101 out[i + 5 * dataLen] = tmp[5];
1102 out[i + 6 * dataLen] = tmp[6];
1103 out[i + 7 * dataLen] = tmp[7];
1108 const std::vector<avx2Float8, allocator<avx2Float8>> &in,
1109 const std::uint32_t dataLen,
const std::uint32_t skipPads,
double *out)
1111 alignas(avx2Float8::alignment) avx2Float8::scalarArray tmp;
1112 alignas(avx2Float8::alignment) avx2Float8::scalarArray tmp1;
1113 alignas(avx2Float8::alignment) avx2Float8::scalarArray tmp2;
1114 alignas(avx2Float8::alignment) avx2Float8::scalarArray tmp3;
1117 size_t nBlocks = dataLen / 4;
1119 for (
size_t i = 0; i < nBlocks; ++i)
1121 in[4 * i].store(tmp);
1122 in[4 * i + 1].store(tmp1);
1123 in[4 * i + 2].store(tmp2);
1124 in[4 * i + 3].store(tmp3);
1125 for (
size_t j = 0; j < avx2Float8::width - skipPads; ++j)
1127 out[j * dataLen + 4 * i] = tmp[j];
1128 out[j * dataLen + 4 * i + 1] = tmp1[j];
1129 out[j * dataLen + 4 * i + 2] = tmp2[j];
1130 out[j * dataLen + 4 * i + 3] = tmp3[j];
1135 for (
size_t i = nBlocks * 4; i < dataLen; ++i)
1138 for (
size_t j = 0; j < avx2Float8::width - skipPads; ++j)
1140 out[j * dataLen + i] = tmp[j];
1146 const std::vector<avx2Float8, allocator<avx2Float8>> &in,
1147 std::uint32_t dataLen,
float *out)
1149 alignas(avx2Float8::alignment) avx2Float8::scalarIndexType tmp[8] = {
1150 0, dataLen, 2 * dataLen, 3 * dataLen,
1151 4 * dataLen, 5 * dataLen, 6 * dataLen, 7 * dataLen};
1152 using index_t = avx2Int8<avx2Float8::scalarIndexType>;
1153 index_t index0(tmp);
1155 for (
size_t i = 0; i < dataLen; ++i)
1157 in[i].scatter(out, index0);
1158 index0 = index0 + 1;
1171struct avx2Mask4 : avx2Long4<std::uint64_t>
1174 using avx2Long4::avx2Long4;
1176 static constexpr scalarType true_v = -1;
1177 static constexpr scalarType false_v = 0;
1180inline avx2Mask4
operator>(avx2Double4 lhs, avx2Double4 rhs)
1182 return reinterpret_cast<__m256i
>(
1183 _mm256_cmp_pd(lhs._data, rhs._data, _CMP_GT_OQ));
1186inline bool operator&&(avx2Mask4 lhs,
bool rhs)
1189 _mm256_testc_si256(lhs._data, _mm256_set1_epi64x(avx2Mask4::true_v));
1194struct avx2Mask8 : avx2Int8<std::uint32_t>
1197 using avx2Int8::avx2Int8;
1199 static constexpr scalarType true_v = -1;
1200 static constexpr scalarType false_v = 0;
1203inline avx2Mask8
operator>(avx2Float8 lhs, avx2Float8 rhs)
1205 return reinterpret_cast<__m256i
>(_mm256_cmp_ps(rhs._data, lhs._data, 1));
1208inline bool operator&&(avx2Mask8 lhs,
bool rhs)
1211 _mm256_testc_si256(lhs._data, _mm256_set1_epi64x(avx2Mask8::true_v));
void load_interleave(const T *in, const size_t dataLen, std::vector< scalarT< T >, allocator< scalarT< T > > > &out)
scalarT< T > abs(scalarT< T > in)
void deinterleave_unalign_store(const std::vector< scalarT< T >, allocator< scalarT< T > > > &in, const size_t dataLen, T *out)
scalarT< T > operator-(scalarT< T > lhs, scalarT< T > rhs)
scalarT< T > operator/(scalarT< T > lhs, scalarT< T > rhs)
scalarT< T > max(scalarT< T > lhs, scalarT< T > rhs)
scalarT< T > log(scalarT< T > in)
scalarT< T > operator*(scalarT< T > lhs, scalarT< T > rhs)
scalarMask operator>(scalarT< double > lhs, scalarT< double > rhs)
bool operator&&(scalarMask lhs, bool rhs)
void load_unalign_interleave(const T *in, const size_t dataLen, std::vector< scalarT< T >, allocator< scalarT< T > > > &out)
void deinterleave_store(const std::vector< scalarT< T >, allocator< scalarT< T > > > &in, const size_t dataLen, T *out)
scalarT< T > min(scalarT< T > lhs, scalarT< T > rhs)
void deinterleave_unalign_store_skipPads(const std::vector< scalarT< T >, allocator< scalarT< T > > > &in, const size_t dataLen, const size_t skipPads, T *out)
scalarT< T > sqrt(scalarT< T > in)
void load_unalign_interleave_skipPads(const T *in, const size_t dataLen, const size_t skipPads, std::vector< scalarT< T >, allocator< scalarT< T > > > &out)
scalarT< T > operator+(scalarT< T > lhs, scalarT< T > rhs)