35#ifndef NEKTAR_LIB_LIBUTILITES_SIMDLIB_AVX512_H
36#define NEKTAR_LIB_LIBUTILITES_SIMDLIB_AVX512_H
38#if defined(__x86_64__)
40#if defined(__INTEL_COMPILER) && !defined(TINYSIMD_HAS_SVML)
41#define TINYSIMD_HAS_SVML
52template <
typename scalarType,
int w
idth = 0>
struct avx512
59#if defined(__AVX512F__) && defined(NEKTAR_ENABLE_SIMD_AVX512)
65template <
typename T>
struct avx512Long8;
66template <
typename T>
struct avx512Int16;
75template <>
struct avx512<double>
77 using type = avx512Double8;
79template <>
struct avx512<float>
81 using type = avx512Float16;
87 using type = avx512Long8<std::int64_t>;
91 using type = avx512Long8<std::uint64_t>;
94template <>
struct avx512<
std::size_t>
96 using type = avx512Long8<std::size_t>;
101 using type = avx512Int16<std::int32_t>;
105 using type = avx512Int16<std::uint32_t>;
110 using type = avx512Long8<std::int64_t>;
114 using type = avx512Long8<std::uint64_t>;
116#if defined(__APPLE__)
117template <>
struct avx512<
std::size_t, 8>
119 using type = avx512Long8<std::size_t>;
124 using type = avx2Int8<std::int32_t>;
128 using type = avx2Int8<std::uint32_t>;
132 using type = avx512Int16<std::int32_t>;
136 using type = avx512Int16<std::uint32_t>;
139template <>
struct avx512<bool, 8>
141 using type = avx512Mask8;
143template <>
struct avx512<bool, 16>
145 using type = avx512Mask16;
153template <
typename T>
struct avx512Int16
155 static_assert(std::is_integral_v<T> &&
sizeof(T) == 4,
156 "4 bytes Integral required.");
158 static constexpr unsigned int width = 16;
159 static constexpr unsigned int alignment = 64;
161 using scalarType = T;
162 using vectorType = __m512i;
163 using scalarArray = scalarType[width];
169 inline avx512Int16() =
default;
170 inline avx512Int16(
const avx512Int16 &rhs) =
default;
171 inline avx512Int16(
const vectorType &rhs) : _data(rhs)
174 inline avx512Int16(
const scalarType rhs)
176 _data = _mm512_set1_epi32(rhs);
178 explicit inline avx512Int16(scalarArray &rhs)
180 _data = _mm512_load_epi32(rhs);
184 inline avx512Int16 &operator=(
const avx512Int16 &) =
default;
187 inline void store(scalarType *p)
const
189 _mm512_store_epi32(p, _data);
192 template <
class flag,
193 typename std::enable_if<is_requiring_alignment_v<flag> &&
194 !is_streaming_v<flag>,
196 inline void store(scalarType *p, flag)
const
198 _mm512_store_epi32(p, _data);
201 template <
class flag,
typename std::enable_if<
202 !is_requiring_alignment_v<flag>,
bool>::type = 0>
203 inline void store(scalarType *p, flag)
const
205 _mm512_storeu_epi32(p, _data);
208 inline void load(
const scalarType *p)
210 _data = _mm512_load_epi32(p);
213 template <
class flag,
214 typename std::enable_if<is_requiring_alignment_v<flag> &&
215 !is_streaming_v<flag>,
217 inline void load(
const scalarType *p, flag)
219 _data = _mm512_load_epi32(p);
222 template <
class flag,
typename std::enable_if<
223 !is_requiring_alignment_v<flag>,
bool>::type = 0>
224 inline void load(
const scalarType *p, flag)
231 _data = _mm512_loadu_si512(p);
234 inline void broadcast(
const scalarType rhs)
236 _data = _mm512_set1_epi32(rhs);
242 inline scalarType operator[](
size_t i)
const
244 alignas(alignment) scalarArray tmp;
245 store(tmp, is_aligned);
249 inline scalarType &operator[](
size_t i)
251 scalarType *tmp =
reinterpret_cast<scalarType *
>(&_data);
257inline avx512Int16<T>
operator+(avx512Int16<T> lhs, avx512Int16<T> rhs)
259 return _mm512_add_epi32(lhs._data, rhs._data);
262template <
typename T,
typename U,
263 typename =
typename std::enable_if<std::is_arithmetic_v<U>>::type>
264inline avx512Int16<T>
operator+(avx512Int16<T> lhs, U rhs)
266 return _mm512_add_epi32(lhs._data, _mm512_set1_epi32(rhs));
271template <
typename T>
struct avx512Long8
273 static_assert(std::is_integral_v<T> &&
sizeof(T) == 8,
274 "8 bytes Integral required.");
276 static constexpr unsigned int width = 8;
277 static constexpr unsigned int alignment = 64;
279 using scalarType = T;
280 using vectorType = __m512i;
281 using scalarArray = scalarType[width];
287 inline avx512Long8() =
default;
288 inline avx512Long8(
const avx512Long8 &rhs) =
default;
289 inline avx512Long8(
const vectorType &rhs) : _data(rhs)
292 inline avx512Long8(
const scalarType rhs)
294 _data = _mm512_set1_epi64(rhs);
296 explicit inline avx512Long8(scalarArray &rhs)
298 _data = _mm512_load_epi64(rhs);
302 inline avx512Long8 &operator=(
const avx512Long8 &) =
default;
305 inline void store(scalarType *p)
const
307 _mm512_store_epi64(p, _data);
310 template <
class flag,
311 typename std::enable_if<is_requiring_alignment_v<flag> &&
312 !is_streaming_v<flag>,
314 inline void store(scalarType *p, flag)
const
316 _mm512_store_epi64(p, _data);
319 template <
class flag,
typename std::enable_if<
320 !is_requiring_alignment_v<flag>,
bool>::type = 0>
321 inline void store(scalarType *p, flag)
const
323 _mm512_storeu_epi64(p, _data);
326 inline void load(
const scalarType *p)
328 _data = _mm512_load_epi64(p);
331 template <
class flag,
332 typename std::enable_if<is_requiring_alignment_v<flag> &&
333 !is_streaming_v<flag>,
335 inline void load(
const scalarType *p, flag)
337 _data = _mm512_load_epi64(p);
340 template <
class flag,
typename std::enable_if<
341 !is_requiring_alignment_v<flag>,
bool>::type = 0>
342 inline void load(
const scalarType *p, flag)
349 _data = _mm512_loadu_si512(p);
352 inline void broadcast(
const scalarType rhs)
354 _data = _mm512_set1_epi64(rhs);
360 inline scalarType operator[](
size_t i)
const
362 alignas(alignment) scalarArray tmp;
363 store(tmp, is_aligned);
367 inline scalarType &operator[](
size_t i)
369 scalarType *tmp =
reinterpret_cast<scalarType *
>(&_data);
375inline avx512Long8<T>
operator+(avx512Long8<T> lhs, avx512Long8<T> rhs)
377 return _mm512_add_epi64(lhs._data, rhs._data);
380template <
typename T,
typename U,
381 typename =
typename std::enable_if<std::is_arithmetic_v<U>>::type>
382inline avx512Long8<T>
operator+(avx512Long8<T> lhs, U rhs)
384 return _mm512_add_epi64(lhs._data, _mm512_set1_epi64(rhs));
391 static constexpr unsigned int width = 8;
392 static constexpr unsigned int alignment = 64;
394 using scalarType = double;
395 using scalarIndexType = std::uint64_t;
396 using vectorType = __m512d;
397 using scalarArray = scalarType[width];
403 inline avx512Double8() =
default;
404 inline avx512Double8(
const avx512Double8 &rhs) =
default;
405 inline avx512Double8(
const vectorType &rhs) : _data(rhs)
408 inline avx512Double8(
const scalarType rhs)
410 _data = _mm512_set1_pd(rhs);
414 inline avx512Double8 &operator=(
const avx512Double8 &) =
default;
417 inline void store(scalarType *p)
const
419 _mm512_store_pd(p, _data);
422 template <
class flag,
423 typename std::enable_if<is_requiring_alignment_v<flag> &&
424 !is_streaming_v<flag>,
426 inline void store(scalarType *p, flag)
const
428 _mm512_store_pd(p, _data);
431 template <
class flag,
typename std::enable_if<
432 !is_requiring_alignment_v<flag>,
bool>::type = 0>
433 inline void store(scalarType *p, flag)
const
435 _mm512_storeu_pd(p, _data);
438 template <
class flag,
439 typename std::enable_if<is_streaming_v<flag>,
bool>::type = 0>
440 inline void store(scalarType *p, flag)
const
442 _mm512_stream_pd(p, _data);
446 inline void load(
const scalarType *p)
448 _data = _mm512_load_pd(p);
451 template <
class flag,
typename std::enable_if<
452 is_requiring_alignment_v<flag>,
bool>::type = 0>
453 inline void load(
const scalarType *p, flag)
455 _data = _mm512_load_pd(p);
458 template <
class flag,
typename std::enable_if<
459 !is_requiring_alignment_v<flag>,
bool>::type = 0>
460 inline void load(
const scalarType *p, flag)
462 _data = _mm512_loadu_pd(p);
466 inline void broadcast(
const scalarType rhs)
468 _data = _mm512_set1_pd(rhs);
472 template <
typename T>
473 inline void gather(scalarType
const *p,
const avx2Int8<T> &indices)
475 _data = _mm512_i32gather_pd(indices._data, p, 8);
478 template <
typename T>
479 inline void scatter(scalarType *out,
const avx2Int8<T> &indices)
const
481 _mm512_i32scatter_pd(out, indices._data, _data, 8);
484 template <
typename T>
485 inline void gather(scalarType
const *p,
const avx512Long8<T> &indices)
487 _data = _mm512_i64gather_pd(indices._data, p, 8);
490 template <
typename T>
491 inline void scatter(scalarType *out,
const avx512Long8<T> &indices)
const
493 _mm512_i64scatter_pd(out, indices._data, _data, 8);
498 inline void fma(
const avx512Double8 &a,
const avx512Double8 &b)
500 _data = _mm512_fmadd_pd(a._data, b._data, _data);
506 inline scalarType operator[](
size_t i)
const
508 alignas(alignment) scalarArray tmp;
509 store(tmp, is_aligned);
513 inline scalarType &operator[](
size_t i)
515 scalarType *tmp =
reinterpret_cast<scalarType *
>(&_data);
520 inline void operator+=(avx512Double8 rhs)
522 _data = _mm512_add_pd(_data, rhs._data);
525 inline void operator-=(avx512Double8 rhs)
527 _data = _mm512_sub_pd(_data, rhs._data);
530 inline void operator*=(avx512Double8 rhs)
532 _data = _mm512_mul_pd(_data, rhs._data);
535 inline void operator/=(avx512Double8 rhs)
537 _data = _mm512_div_pd(_data, rhs._data);
541inline avx512Double8
operator+(avx512Double8 lhs, avx512Double8 rhs)
543 return _mm512_add_pd(lhs._data, rhs._data);
546inline avx512Double8
operator-(avx512Double8 lhs, avx512Double8 rhs)
548 return _mm512_sub_pd(lhs._data, rhs._data);
551inline avx512Double8
operator-(avx512Double8 in)
553 return _mm512_sub_pd(_mm512_set1_pd(-0.0), in._data);
557inline avx512Double8
operator*(avx512Double8 lhs, avx512Double8 rhs)
559 return _mm512_mul_pd(lhs._data, rhs._data);
562inline avx512Double8
operator/(avx512Double8 lhs, avx512Double8 rhs)
564 return _mm512_div_pd(lhs._data, rhs._data);
567inline avx512Double8
sqrt(avx512Double8 in)
569 return _mm512_sqrt_pd(in._data);
572inline avx512Double8
abs(avx512Double8 in)
574 return _mm512_abs_pd(in._data);
577inline avx512Double8
min(avx512Double8 lhs, avx512Double8 rhs)
579 return _mm512_min_pd(lhs._data, rhs._data);
582inline avx512Double8
max(avx512Double8 lhs, avx512Double8 rhs)
584 return _mm512_max_pd(lhs._data, rhs._data);
587inline avx512Double8
log(avx512Double8 in)
589#if defined(TINYSIMD_HAS_SVML)
590 return _mm512_log_pd(in._data);
594 alignas(avx512Double8::alignment) avx512Double8::scalarArray tmp;
596 tmp[0] = std::log(tmp[0]);
597 tmp[1] = std::log(tmp[1]);
598 tmp[2] = std::log(tmp[2]);
599 tmp[3] = std::log(tmp[3]);
600 tmp[4] = std::log(tmp[4]);
601 tmp[5] = std::log(tmp[5]);
602 tmp[6] = std::log(tmp[6]);
603 tmp[7] = std::log(tmp[7]);
611 const double *in,
const std::uint32_t dataLen,
612 std::vector<avx512Double8, allocator<avx512Double8>> &out)
614 alignas(avx512Double8::alignment) avx512Double8::scalarArray tmp;
615 for (
size_t i = 0; i < dataLen; ++i)
618 tmp[1] = in[i + dataLen];
619 tmp[2] = in[i + 2 * dataLen];
620 tmp[3] = in[i + 3 * dataLen];
621 tmp[4] = in[i + 4 * dataLen];
622 tmp[5] = in[i + 5 * dataLen];
623 tmp[6] = in[i + 6 * dataLen];
624 tmp[7] = in[i + 7 * dataLen];
630 const double *in,
const std::uint32_t dataLen,
const std::uint32_t skipPads,
631 std::vector<avx512Double8, allocator<avx512Double8>> &out)
633 alignas(avx512Double8::alignment) avx512Double8::scalarArray tmp;
634 alignas(avx512Double8::alignment) avx512Double8::scalarArray tmp1;
635 alignas(avx512Double8::alignment) avx512Double8::scalarArray tmp2;
636 alignas(avx512Double8::alignment) avx512Double8::scalarArray tmp3;
638 size_t nBlocks = dataLen / 4;
639 const avx512Double8 zero{0.0};
641 for (
size_t i = 0; i < nBlocks; ++i)
647 for (
size_t j = 0; j < avx512Double8::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 < avx512Double8::width - skipPads; ++j)
665 tmp[j] = in[i + j * dataLen];
672 const double *in, std::uint32_t dataLen,
673 std::vector<avx512Double8, allocator<avx512Double8>> &out)
676 alignas(avx512Double8::alignment)
677 avx512Double8::scalarIndexType tmp[avx512Double8::width] = {
678 0, dataLen, 2 * dataLen, 3 * dataLen,
679 4 * dataLen, 5 * dataLen, 6 * dataLen, 7 * dataLen};
681 using index_t = avx512Long8<avx512Double8::scalarIndexType>;
683 index_t index1 = index0 + 1;
684 index_t index2 = index0 + 2;
685 index_t index3 = index0 + 3;
688 constexpr uint16_t unrl = 4;
689 size_t nBlocks = dataLen / unrl;
690 for (
size_t i = 0; i < nBlocks; ++i)
692 out[unrl * i + 0].gather(in, index0);
693 out[unrl * i + 1].gather(in, index1);
694 out[unrl * i + 2].gather(in, index2);
695 out[unrl * i + 3].gather(in, index3);
696 index0 = index0 + unrl;
697 index1 = index1 + unrl;
698 index2 = index2 + unrl;
699 index3 = index3 + unrl;
703 for (
size_t i = unrl * nBlocks; i < dataLen; ++i)
705 out[i].gather(in, index0);
711 const std::vector<avx512Double8, allocator<avx512Double8>> &in,
712 const std::uint32_t dataLen,
double *out)
714 alignas(avx512Double8::alignment) avx512Double8::scalarArray tmp;
715 for (
size_t i = 0; i < dataLen; ++i)
719 out[i + dataLen] = tmp[1];
720 out[i + 2 * dataLen] = tmp[2];
721 out[i + 3 * dataLen] = tmp[3];
722 out[i + 4 * dataLen] = tmp[4];
723 out[i + 5 * dataLen] = tmp[5];
724 out[i + 6 * dataLen] = tmp[6];
725 out[i + 7 * dataLen] = tmp[7];
730 const std::vector<avx512Double8, allocator<avx512Double8>> &in,
731 const std::uint32_t dataLen,
const std::uint32_t skipPads,
double *out)
733 alignas(avx512Double8::alignment) avx512Double8::scalarArray tmp;
734 alignas(avx512Double8::alignment) avx512Double8::scalarArray tmp1;
735 alignas(avx512Double8::alignment) avx512Double8::scalarArray tmp2;
736 alignas(avx512Double8::alignment) avx512Double8::scalarArray tmp3;
739 size_t nBlocks = dataLen / 4;
741 for (
size_t i = 0; i < nBlocks; ++i)
743 in[4 * i].store(tmp);
744 in[4 * i + 1].store(tmp1);
745 in[4 * i + 2].store(tmp2);
746 in[4 * i + 3].store(tmp3);
747 for (
size_t j = 0; j < avx512Double8::width - skipPads; ++j)
749 out[j * dataLen + 4 * i] = tmp[j];
750 out[j * dataLen + 4 * i + 1] = tmp1[j];
751 out[j * dataLen + 4 * i + 2] = tmp2[j];
752 out[j * dataLen + 4 * i + 3] = tmp3[j];
757 for (
size_t i = nBlocks * 4; i < dataLen; ++i)
760 for (
size_t j = 0; j < avx512Double8::width - skipPads; ++j)
762 out[j * dataLen + i] = tmp[j];
768 const std::vector<avx512Double8, allocator<avx512Double8>> &in,
769 std::uint32_t dataLen,
double *out)
773 alignas(avx512Double8::alignment)
774 avx512Double8::scalarIndexType tmp[avx512Double8::width] = {
775 0, dataLen, 2 * dataLen, 3 * dataLen,
776 4 * dataLen, 5 * dataLen, 6 * dataLen, 7 * dataLen};
777 using index_t = avx512Long8<avx512Double8::scalarIndexType>;
779 for (
size_t i = 0; i < dataLen; ++i)
781 in[i].scatter(out, index0);
788 static constexpr unsigned int width = 16;
789 static constexpr unsigned int alignment = 64;
791 using scalarType = float;
792 using scalarIndexType = std::uint32_t;
793 using vectorType = __m512;
794 using scalarArray = scalarType[width];
800 inline avx512Float16() =
default;
801 inline avx512Float16(
const avx512Float16 &rhs) =
default;
802 inline avx512Float16(
const vectorType &rhs) : _data(rhs)
805 inline avx512Float16(
const scalarType rhs)
807 _data = _mm512_set1_ps(rhs);
811 inline avx512Float16 &operator=(
const avx512Float16 &) =
default;
814 inline void store(scalarType *p)
const
816 _mm512_store_ps(p, _data);
819 template <
class flag,
820 typename std::enable_if<is_requiring_alignment_v<flag> &&
821 !is_streaming_v<flag>,
823 inline void store(scalarType *p, flag)
const
825 _mm512_store_ps(p, _data);
828 template <
class flag,
typename std::enable_if<
829 !is_requiring_alignment_v<flag>,
bool>::type = 0>
830 inline void store(scalarType *p, flag)
const
832 _mm512_storeu_ps(p, _data);
835 template <
class flag,
836 typename std::enable_if<is_streaming_v<flag>,
bool>::type = 0>
837 inline void store(scalarType *p, flag)
const
839 _mm512_stream_ps(p, _data);
843 inline void load(
const scalarType *p)
845 _data = _mm512_load_ps(p);
848 template <
class flag,
typename std::enable_if<
849 is_requiring_alignment_v<flag>,
bool>::type = 0>
850 inline void load(
const scalarType *p, flag)
852 _data = _mm512_load_ps(p);
855 template <
class flag,
typename std::enable_if<
856 !is_requiring_alignment_v<flag>,
bool>::type = 0>
857 inline void load(
const scalarType *p, flag)
859 _data = _mm512_loadu_ps(p);
863 inline void broadcast(
const scalarType rhs)
865 _data = _mm512_set1_ps(rhs);
869 template <
typename T>
870 inline void gather(scalarType
const *p,
const avx512Int16<T> &indices)
872 _data = _mm512_i32gather_ps(indices._data, p,
sizeof(scalarType));
875 template <
typename T>
876 inline void scatter(scalarType *out,
const avx512Int16<T> &indices)
const
878 _mm512_i32scatter_ps(out, indices._data, _data,
sizeof(scalarType));
883 inline void fma(
const avx512Float16 &a,
const avx512Float16 &b)
885 _data = _mm512_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+=(avx512Float16 rhs)
906 _data = _mm512_add_ps(_data, rhs._data);
909 inline void operator-=(avx512Float16 rhs)
911 _data = _mm512_sub_ps(_data, rhs._data);
914 inline void operator*=(avx512Float16 rhs)
916 _data = _mm512_mul_ps(_data, rhs._data);
919 inline void operator/=(avx512Float16 rhs)
921 _data = _mm512_div_ps(_data, rhs._data);
925inline avx512Float16
operator+(avx512Float16 lhs, avx512Float16 rhs)
927 return _mm512_add_ps(lhs._data, rhs._data);
930inline avx512Float16
operator-(avx512Float16 lhs, avx512Float16 rhs)
932 return _mm512_sub_ps(lhs._data, rhs._data);
935inline avx512Float16
operator-(avx512Float16 in)
937 return _mm512_sub_ps(_mm512_set1_ps(-0.0), in._data);
941inline avx512Float16
operator*(avx512Float16 lhs, avx512Float16 rhs)
943 return _mm512_mul_ps(lhs._data, rhs._data);
946inline avx512Float16
operator/(avx512Float16 lhs, avx512Float16 rhs)
948 return _mm512_div_ps(lhs._data, rhs._data);
951inline avx512Float16
sqrt(avx512Float16 in)
953 return _mm512_sqrt_ps(in._data);
956inline avx512Float16
abs(avx512Float16 in)
958 return _mm512_abs_ps(in._data);
961inline avx512Float16
min(avx512Float16 lhs, avx512Float16 rhs)
963 return _mm512_min_ps(lhs._data, rhs._data);
966inline avx512Float16
max(avx512Float16 lhs, avx512Float16 rhs)
968 return _mm512_max_ps(lhs._data, rhs._data);
971inline avx512Float16
log(avx512Float16 in)
973#if defined(TINYSIMD_HAS_SVML)
974 return _mm512_log_ps(in._data);
978 alignas(avx512Float16::alignment) avx512Float16::scalarArray tmp;
980 tmp[0] = std::log(tmp[0]);
981 tmp[1] = std::log(tmp[1]);
982 tmp[2] = std::log(tmp[2]);
983 tmp[3] = std::log(tmp[3]);
984 tmp[4] = std::log(tmp[4]);
985 tmp[5] = std::log(tmp[5]);
986 tmp[6] = std::log(tmp[6]);
987 tmp[7] = std::log(tmp[7]);
988 tmp[8] = std::log(tmp[8]);
989 tmp[9] = std::log(tmp[9]);
990 tmp[10] = std::log(tmp[10]);
991 tmp[11] = std::log(tmp[11]);
992 tmp[12] = std::log(tmp[12]);
993 tmp[13] = std::log(tmp[13]);
994 tmp[14] = std::log(tmp[14]);
995 tmp[15] = std::log(tmp[15]);
1003 const double *in,
const std::uint32_t dataLen,
1004 std::vector<avx512Float16, allocator<avx512Float16>> &out)
1006 alignas(avx512Float16::alignment) avx512Float16::scalarArray tmp;
1007 for (
size_t i = 0; i < dataLen; ++i)
1010 tmp[1] = in[i + dataLen];
1011 tmp[2] = in[i + 2 * dataLen];
1012 tmp[3] = in[i + 3 * dataLen];
1013 tmp[4] = in[i + 4 * dataLen];
1014 tmp[5] = in[i + 5 * dataLen];
1015 tmp[6] = in[i + 6 * dataLen];
1016 tmp[7] = in[i + 7 * dataLen];
1017 tmp[8] = in[i + 8 * dataLen];
1018 tmp[9] = in[i + 9 * dataLen];
1019 tmp[10] = in[i + 10 * dataLen];
1020 tmp[11] = in[i + 11 * dataLen];
1021 tmp[12] = in[i + 12 * dataLen];
1022 tmp[13] = in[i + 13 * dataLen];
1023 tmp[14] = in[i + 14 * dataLen];
1024 tmp[15] = in[i + 15 * dataLen];
1030 const double *in,
const std::uint32_t dataLen,
const std::uint32_t skipPads,
1031 std::vector<avx512Float16, allocator<avx512Float16>> &out)
1033 alignas(avx512Float16::alignment) avx512Float16::scalarArray tmp;
1034 alignas(avx512Float16::alignment) avx512Float16::scalarArray tmp1;
1035 alignas(avx512Float16::alignment) avx512Float16::scalarArray tmp2;
1036 alignas(avx512Float16::alignment) avx512Float16::scalarArray tmp3;
1038 size_t nBlocks = dataLen / 4;
1039 const avx512Float16 zero{0.0};
1041 for (
size_t i = 0; i < nBlocks; ++i)
1047 for (
size_t j = 0; j < avx512Float16::width - skipPads; ++j)
1049 tmp[j] = in[j * dataLen + 4 * i];
1050 tmp1[j] = in[j * dataLen + 4 * i + 1];
1051 tmp2[j] = in[j * dataLen + 4 * i + 2];
1052 tmp3[j] = in[j * dataLen + 4 * i + 3];
1054 out[4 * i].load(tmp);
1055 out[4 * i + 1].load(tmp1);
1056 out[4 * i + 2].load(tmp2);
1057 out[4 * i + 3].load(tmp3);
1060 for (
size_t i = nBlocks * 4; i < dataLen; ++i)
1063 for (
size_t j = 0; j < avx512Float16::width - skipPads; ++j)
1065 tmp[j] = in[i + j * dataLen];
1072 const float *in, std::uint32_t dataLen,
1073 std::vector<avx512Float16, allocator<avx512Float16>> &out)
1076 alignas(avx512Float16::alignment)
1077 avx512Float16::scalarIndexType tmp[avx512Float16::width] = {
1095 using index_t = avx512Int16<avx512Float16::scalarIndexType>;
1096 index_t index0(tmp);
1097 index_t index1 = index0 + 1;
1098 index_t index2 = index0 + 2;
1099 index_t index3 = index0 + 3;
1102 constexpr uint16_t unrl = 4;
1103 size_t nBlocks = dataLen / unrl;
1104 for (
size_t i = 0; i < nBlocks; ++i)
1106 out[unrl * i + 0].gather(in, index0);
1107 out[unrl * i + 1].gather(in, index1);
1108 out[unrl * i + 2].gather(in, index2);
1109 out[unrl * i + 3].gather(in, index3);
1110 index0 = index0 + unrl;
1111 index1 = index1 + unrl;
1112 index2 = index2 + unrl;
1113 index3 = index3 + unrl;
1117 for (
size_t i = unrl * nBlocks; i < dataLen; ++i)
1119 out[i].gather(in, index0);
1120 index0 = index0 + 1;
1125 const std::vector<avx512Float16, allocator<avx512Float16>> &in,
1126 const std::uint32_t dataLen,
double *out)
1128 alignas(avx512Float16::alignment) avx512Float16::scalarArray tmp;
1129 for (
size_t i = 0; i < dataLen; ++i)
1133 out[i + dataLen] = tmp[1];
1134 out[i + 2 * dataLen] = tmp[2];
1135 out[i + 3 * dataLen] = tmp[3];
1136 out[i + 4 * dataLen] = tmp[4];
1137 out[i + 5 * dataLen] = tmp[5];
1138 out[i + 6 * dataLen] = tmp[6];
1139 out[i + 7 * dataLen] = tmp[7];
1140 out[i + 8 * dataLen] = tmp[8];
1141 out[i + 9 * dataLen] = tmp[9];
1142 out[i + 10 * dataLen] = tmp[10];
1143 out[i + 11 * dataLen] = tmp[11];
1144 out[i + 12 * dataLen] = tmp[12];
1145 out[i + 13 * dataLen] = tmp[13];
1146 out[i + 14 * dataLen] = tmp[14];
1147 out[i + 15 * dataLen] = tmp[15];
1152 const std::vector<avx512Float16, allocator<avx512Float16>> &in,
1153 const std::uint32_t dataLen,
const std::uint32_t skipPads,
double *out)
1155 alignas(avx512Float16::alignment) avx512Float16::scalarArray tmp;
1156 alignas(avx512Float16::alignment) avx512Float16::scalarArray tmp1;
1157 alignas(avx512Float16::alignment) avx512Float16::scalarArray tmp2;
1158 alignas(avx512Float16::alignment) avx512Float16::scalarArray tmp3;
1161 size_t nBlocks = dataLen / 4;
1163 for (
size_t i = 0; i < nBlocks; ++i)
1165 in[4 * i].store(tmp);
1166 in[4 * i + 1].store(tmp1);
1167 in[4 * i + 2].store(tmp2);
1168 in[4 * i + 3].store(tmp3);
1169 for (
size_t j = 0; j < avx512Float16::width - skipPads; ++j)
1171 out[j * dataLen + 4 * i] = tmp[j];
1172 out[j * dataLen + 4 * i + 1] = tmp1[j];
1173 out[j * dataLen + 4 * i + 2] = tmp2[j];
1174 out[j * dataLen + 4 * i + 3] = tmp3[j];
1179 for (
size_t i = nBlocks * 4; i < dataLen; ++i)
1182 for (
size_t j = 0; j < avx512Float16::width - skipPads; ++j)
1184 out[j * dataLen + i] = tmp[j];
1190 const std::vector<avx512Float16, allocator<avx512Float16>> &in,
1191 std::uint32_t dataLen,
float *out)
1195 alignas(avx512Float16::alignment)
1196 avx512Float16::scalarIndexType tmp[avx512Float16::width] = {
1213 using index_t = avx512Int16<avx512Float16::scalarIndexType>;
1215 index_t index0(tmp);
1216 for (
size_t i = 0; i < dataLen; ++i)
1218 in[i].scatter(out, index0);
1219 index0 = index0 + 1;
1232struct avx512Mask8 : avx512Long8<std::uint64_t>
1235 using avx512Long8::avx512Long8;
1237 static constexpr scalarType true_v = -1;
1238 static constexpr scalarType false_v = 0;
1241inline avx512Mask8
operator>(avx512Double8 lhs, avx512Double8 rhs)
1243 __mmask8 mask = _mm512_cmp_pd_mask(lhs._data, rhs._data, _CMP_GT_OQ);
1244 return _mm512_maskz_set1_epi64(mask, avx512Mask8::true_v);
1247inline bool operator&&(avx512Mask8 lhs,
bool rhs)
1249 __m512i val_true = _mm512_set1_epi64(avx512Mask8::true_v);
1250 __mmask8 mask = _mm512_test_epi64_mask(lhs._data, val_true);
1251 unsigned int tmp = _cvtmask16_u32(mask);
1255struct avx512Mask16 : avx512Int16<std::uint32_t>
1258 using avx512Int16::avx512Int16;
1260 static constexpr scalarType true_v = -1;
1261 static constexpr scalarType false_v = 0;
1264inline avx512Mask16
operator>(avx512Float16 lhs, avx512Float16 rhs)
1266 __mmask16 mask = _mm512_cmp_ps_mask(lhs._data, rhs._data, _CMP_GT_OQ);
1267 return _mm512_maskz_set1_epi32(mask, avx512Mask16::true_v);
1270inline bool operator&&(avx512Mask16 lhs,
bool rhs)
1272 __m512i val_true = _mm512_set1_epi32(avx512Mask16::true_v);
1273 __mmask16 mask = _mm512_test_epi32_mask(lhs._data, val_true);
1274 unsigned int tmp = _cvtmask16_u32(mask);
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)