35#ifndef NEKTAR_LIB_LIBUTILITES_SIMDLIB_SSE2_H
36#define NEKTAR_LIB_LIBUTILITES_SIMDLIB_SSE2_H
38#if defined(__x86_64__)
40#if defined(__INTEL_COMPILER) && !defined(TINYSIMD_HAS_SVML)
41#define TINYSIMD_HAS_SVML
53template <
typename scalarType>
struct simd64
60#if defined(__SSE2__) && defined(NEKTAR_ENABLE_SIMD_SSE2)
66template <
typename T>
struct simd64Int2;
71template <>
struct simd64<
std::int32_t>
73 using type = simd64Int2<std::int32_t>;
75template <>
struct simd64<
std::uint32_t>
77 using type = simd64Int2<std::uint32_t>;
83template <
typename T>
struct simd64Int2
85 static_assert(std::is_integral_v<T> &&
sizeof(T) == 4,
86 "4 bytes Integral required.");
88 static constexpr unsigned int width = 2;
89 static constexpr unsigned int alignment = 8;
92 using vectorType = scalarType[width];
93 using scalarArray = scalarType[width];
99 inline simd64Int2() =
default;
100 inline simd64Int2(
const simd64Int2 &rhs) =
default;
101 inline simd64Int2(
const vectorType &rhs) : _data(rhs)
104 inline simd64Int2(
const scalarType rhs)
111 inline void store(scalarType *p)
const
117 template <
class flag,
118 typename std::enable_if<is_requiring_alignment_v<flag> &&
119 !is_streaming_v<flag>,
121 inline void store(scalarType *p, flag)
const
127 template <
class flag,
typename std::enable_if<
128 !is_requiring_alignment_v<flag>,
bool>::type = 0>
129 inline void store(scalarType *p, flag)
const
135 inline void load(
const scalarType *p)
141 template <
class flag,
142 typename std::enable_if<is_requiring_alignment_v<flag> &&
143 !is_streaming_v<flag>,
145 inline void load(
const scalarType *p, flag)
151 template <
class flag,
typename std::enable_if<
152 !is_requiring_alignment_v<flag>,
bool>::type = 0>
153 inline void load(
const scalarType *p, flag)
160 inline void gather(scalarType
const *p,
const simd64Int2<T> &indices)
162 _data[0] =
p[indices[0]];
163 _data[1] =
p[indices[1]];
166 inline void scatter(scalarType *out,
const simd64Int2<T> &indices)
const
168 out[indices[0]] = _data[0];
169 out[indices[1]] = _data[1];
172 inline void broadcast(
const scalarType rhs)
181 inline scalarType operator[](
size_t i)
const
193template <
typename scalarType,
int w
idth = 0>
struct sse2
200#if defined(__SSE2__) && defined(NEKTAR_ENABLE_SIMD_SSE2)
206template <
typename T>
struct sse2Long2;
207template <
typename T>
struct sse2Int4;
217template <>
struct sse2<double>
219 using type = sse2Double2;
221template <>
struct sse2<float>
223 using type = sse2Float4;
229 using type = sse2Long2<std::int64_t>;
233 using type = sse2Long2<std::uint64_t>;
235#if defined(__APPLE__)
236template <>
struct sse2<
std::size_t>
238 using type = sse2Long2<std::size_t>;
243 using type = sse2Int4<std::int32_t>;
247 using type = sse2Int4<std::uint32_t>;
252 using type = sse2Long2<std::int64_t>;
256 using type = sse2Long2<std::uint64_t>;
258#if defined(__APPLE__)
259template <>
struct sse2<
std::size_t, 2>
261 using type = sse2Long2<std::size_t>;
266 using type = simd64Int2<std::int32_t>;
270 using type = simd64Int2<std::uint32_t>;
274 using type = sse2Int4<std::int32_t>;
278 using type = sse2Int4<std::uint32_t>;
281template <>
struct sse2<bool, 2>
283 using type = sse2Mask2;
285template <>
struct sse2<bool, 4>
287 using type = sse2Mask4;
293template <
typename T>
struct sse2Int4
295 static_assert(std::is_integral_v<T> &&
sizeof(T) == 4,
296 "4 bytes Integral required.");
298 static constexpr unsigned int width = 4;
299 static constexpr unsigned int alignment = 16;
301 using scalarType = T;
302 using vectorType = __m128i;
303 using scalarArray = scalarType[width];
309 inline sse2Int4() =
default;
310 inline sse2Int4(
const sse2Int4 &rhs) =
default;
311 inline sse2Int4(
const vectorType &rhs) : _data(rhs)
314 inline sse2Int4(
const scalarType rhs)
316 _data = _mm_set1_epi32(rhs);
318 explicit inline sse2Int4(scalarArray &rhs)
320 _data = _mm_load_si128(
reinterpret_cast<vectorType *
>(rhs));
324 inline sse2Int4 &operator=(
const sse2Int4 &) =
default;
327 inline void store(scalarType *p)
const
329 _mm_store_si128(
reinterpret_cast<vectorType *
>(p), _data);
332 template <
class flag,
333 typename std::enable_if<is_requiring_alignment_v<flag> &&
334 !is_streaming_v<flag>,
336 inline void store(scalarType *p, flag)
const
338 _mm_store_si128(
reinterpret_cast<vectorType *
>(p), _data);
341 template <
class flag,
typename std::enable_if<
342 !is_requiring_alignment_v<flag>,
bool>::type = 0>
343 inline void store(scalarType *p, flag)
const
345 _mm_storeu_si128(
reinterpret_cast<vectorType *
>(p), _data);
348 inline void load(
const scalarType *p)
350 _data = _mm_load_si128(
reinterpret_cast<const vectorType *
>(p));
353 template <
class flag,
354 typename std::enable_if<is_requiring_alignment_v<flag> &&
355 !is_streaming_v<flag>,
357 inline void load(
const scalarType *p, flag)
359 _data = _mm_load_si128(
reinterpret_cast<const vectorType *
>(p));
362 template <
class flag,
typename std::enable_if<
363 !is_requiring_alignment_v<flag>,
bool>::type = 0>
364 inline void load(
const scalarType *p, flag)
366 _data = _mm_loadu_si128(
reinterpret_cast<const vectorType *
>(p));
369 inline void broadcast(
const scalarType rhs)
371 _data = _mm_set1_epi32(rhs);
393 inline scalarType operator[](
size_t i)
const
395 alignas(alignment) scalarArray tmp;
396 store(tmp, is_aligned);
400 inline scalarType &operator[](
size_t i)
402 scalarType *tmp =
reinterpret_cast<scalarType *
>(&_data);
408inline sse2Int4<T>
operator+(sse2Int4<T> lhs, sse2Int4<T> rhs)
410 return _mm_add_epi32(lhs._data, rhs._data);
413template <
typename T,
typename U,
414 typename =
typename std::enable_if<std::is_arithmetic_v<U>>::type>
415inline sse2Int4<T>
operator+(sse2Int4<T> lhs, U rhs)
417 return _mm_add_epi32(lhs._data, _mm_set1_epi32(rhs));
422template <
typename T>
struct sse2Long2
424 static_assert(std::is_integral_v<T> &&
sizeof(T) == 8,
425 "8 bytes Integral required.");
427 static constexpr unsigned int width = 2;
428 static constexpr unsigned int alignment = 16;
430 using scalarType = T;
431 using vectorType = __m128i;
432 using scalarArray = scalarType[width];
438 inline sse2Long2() =
default;
439 inline sse2Long2(
const sse2Long2 &rhs) =
default;
440 inline sse2Long2(
const vectorType &rhs) : _data(rhs)
443 inline sse2Long2(
const scalarType rhs)
445 _data = _mm_set1_epi64x(rhs);
447 explicit inline sse2Long2(scalarArray &rhs)
449 _data = _mm_load_si128(
reinterpret_cast<vectorType *
>(rhs));
453 inline sse2Long2 &operator=(
const sse2Long2 &) =
default;
456 inline void store(scalarType *p)
const
458 _mm_store_si128(
reinterpret_cast<vectorType *
>(p), _data);
461 template <
class flag,
462 typename std::enable_if<is_requiring_alignment_v<flag> &&
463 !is_streaming_v<flag>,
465 inline void store(scalarType *p, flag)
const
467 _mm_store_si128(
reinterpret_cast<vectorType *
>(p), _data);
470 template <
class flag,
typename std::enable_if<
471 !is_requiring_alignment_v<flag>,
bool>::type = 0>
472 inline void store(scalarType *p, flag)
const
474 _mm_storeu_si128(
reinterpret_cast<vectorType *
>(p), _data);
477 inline void load(
const scalarType *p)
479 _data = _mm_load_si128(
reinterpret_cast<const vectorType *
>(p));
482 template <
class flag,
483 typename std::enable_if<is_requiring_alignment_v<flag> &&
484 !is_streaming_v<flag>,
486 inline void load(
const scalarType *p, flag)
488 _data = _mm_load_si128(
reinterpret_cast<const vectorType *
>(p));
491 template <
class flag,
typename std::enable_if<
492 !is_requiring_alignment_v<flag>,
bool>::type = 0>
493 inline void load(
const scalarType *p, flag)
495 _data = _mm_loadu_si128(
reinterpret_cast<const vectorType *
>(p));
498 inline void broadcast(
const scalarType rhs)
500 _data = _mm_set1_epi64x(rhs);
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);
521inline sse2Long2<T>
operator+(sse2Long2<T> lhs, sse2Long2<T> rhs)
523 return _mm_add_epi64(lhs._data, rhs._data);
526template <
typename T,
typename U,
527 typename =
typename std::enable_if<std::is_arithmetic_v<U>>::type>
528inline sse2Long2<T>
operator+(sse2Long2<T> lhs, U rhs)
530 return _mm_add_epi64(lhs._data, _mm_set1_epi64x(rhs));
537 static constexpr unsigned width = 2;
538 static constexpr unsigned alignment = 16;
540 using scalarType = double;
541 using scalarIndexType = std::uint64_t;
542 using vectorType = __m128d;
543 using scalarArray = scalarType[width];
549 inline sse2Double2() =
default;
550 inline sse2Double2(
const sse2Double2 &rhs) =
default;
551 inline sse2Double2(
const vectorType &rhs) : _data(rhs)
554 inline sse2Double2(
const scalarType rhs)
556 _data = _mm_set1_pd(rhs);
560 inline sse2Double2 &operator=(
const sse2Double2 &) =
default;
563 inline void store(scalarType *p)
const
565 _mm_store_pd(p, _data);
568 template <
class flag,
569 typename std::enable_if<is_requiring_alignment_v<flag> &&
570 !is_streaming_v<flag>,
572 inline void store(scalarType *p, flag)
const
574 _mm_store_pd(p, _data);
577 template <
class flag,
typename std::enable_if<
578 !is_requiring_alignment_v<flag>,
bool>::type = 0>
579 inline void store(scalarType *p, flag)
const
581 _mm_storeu_pd(p, _data);
584 template <
class flag,
585 typename std::enable_if<is_streaming_v<flag>,
bool>::type = 0>
586 inline void store(scalarType *p, flag)
const
588 _mm_stream_pd(p, _data);
592 inline void load(
const scalarType *p)
594 _data = _mm_load_pd(p);
597 template <
class flag,
typename std::enable_if<
598 is_requiring_alignment_v<flag>,
bool>::type = 0>
599 inline void load(
const scalarType *p, flag)
601 _data = _mm_load_pd(p);
604 template <
class flag,
typename std::enable_if<
605 !is_requiring_alignment_v<flag>,
bool>::type = 0>
606 inline void load(
const scalarType *p, flag)
608 _data = _mm_loadu_pd(p);
612 inline void broadcast(
const scalarType rhs)
614 _data = _mm_set1_pd(rhs);
618 template <
typename T>
619 inline void gather(scalarType
const *p,
const simd64Int2<T> &indices)
622 alignas(alignment) scalarArray tmp;
623 tmp[0] =
p[indices[0]];
624 tmp[1] =
p[indices[1]];
625 _data = _mm_load_pd(&tmp[0]);
628 template <
typename T>
629 inline void scatter(scalarType *out,
const simd64Int2<T> &indices)
const
632 alignas(alignment) scalarArray tmp;
633 _mm_store_pd(tmp, _data);
635 out[indices[0]] = tmp[0];
636 out[indices[1]] = tmp[1];
639 template <
typename T>
640 inline void gather(scalarType
const *p,
const sse2Long2<T> &indices)
643 alignas(alignment) scalarArray tmp;
644 tmp[0] =
p[_mm_extract_epi64(indices._data, 0)];
645 tmp[1] =
p[_mm_extract_epi64(indices._data, 1)];
646 _data = _mm_load_pd(&tmp[0]);
649 template <
typename T>
650 inline void scatter(scalarType *out,
const sse2Long2<T> &indices)
const
653 alignas(alignment) scalarArray tmp;
654 _mm_store_pd(tmp, _data);
656 out[_mm_extract_epi64(indices._data, 0)] = tmp[0];
657 out[_mm_extract_epi64(indices._data, 1)] = tmp[1];
662 inline void fma(
const sse2Double2 &a,
const sse2Double2 &b)
664 _data = _mm_fmadd_pd(a._data, b._data, _data);
670 inline scalarType operator[](
size_t i)
const
672 alignas(alignment) scalarArray tmp;
673 store(tmp, is_aligned);
677 inline scalarType &operator[](
size_t i)
679 scalarType *tmp =
reinterpret_cast<scalarType *
>(&_data);
684 inline void operator+=(sse2Double2 rhs)
686 _data = _mm_add_pd(_data, rhs._data);
689 inline void operator-=(sse2Double2 rhs)
691 _data = _mm_sub_pd(_data, rhs._data);
694 inline void operator*=(sse2Double2 rhs)
696 _data = _mm_mul_pd(_data, rhs._data);
699 inline void operator/=(sse2Double2 rhs)
701 _data = _mm_div_pd(_data, rhs._data);
705inline sse2Double2
operator+(sse2Double2 lhs, sse2Double2 rhs)
707 return _mm_add_pd(lhs._data, rhs._data);
710inline sse2Double2
operator-(sse2Double2 lhs, sse2Double2 rhs)
712 return _mm_sub_pd(lhs._data, rhs._data);
715inline sse2Double2
operator-(sse2Double2 in)
717 return _mm_xor_pd(in._data, _mm_set1_pd(-0.0));
720inline sse2Double2
operator*(sse2Double2 lhs, sse2Double2 rhs)
722 return _mm_mul_pd(lhs._data, rhs._data);
725inline sse2Double2
operator/(sse2Double2 lhs, sse2Double2 rhs)
727 return _mm_div_pd(lhs._data, rhs._data);
730inline sse2Double2
sqrt(sse2Double2 in)
732 return _mm_sqrt_pd(in._data);
735inline sse2Double2
abs(sse2Double2 in)
738 static const __m128d sign_mask = _mm_set1_pd(-0.);
739 return _mm_andnot_pd(sign_mask, in._data);
742inline sse2Double2
min(sse2Double2 lhs, sse2Double2 rhs)
744 return _mm_min_pd(lhs._data, rhs._data);
747inline sse2Double2
max(sse2Double2 lhs, sse2Double2 rhs)
749 return _mm_max_pd(lhs._data, rhs._data);
752inline sse2Double2
log(sse2Double2 in)
754#if defined(TINYSIMD_HAS_SVML)
755 return _mm_log_pd(in._data);
759 alignas(sse2Double2::alignment) sse2Double2::scalarArray tmp;
761 tmp[0] = std::log(tmp[0]);
762 tmp[1] = std::log(tmp[1]);
770 const double *in,
const std::uint32_t dataLen,
771 std::vector<sse2Double2, allocator<sse2Double2>> &out)
773 alignas(sse2Double2::alignment) sse2Double2::scalarArray tmp;
774 for (
size_t i = 0; i < dataLen; ++i)
777 tmp[1] = in[i + dataLen];
783 const double *in, std::uint32_t dataLen,
784 std::vector<sse2Double2, allocator<sse2Double2>> &out)
786 alignas(sse2Double2::alignment)
787 size_t tmp[sse2Double2::width] = {0, dataLen};
788 using index_t = sse2Long2<size_t>;
790 index_t index1 = index0 + 1;
793 constexpr uint16_t unrl = 2;
794 size_t nBlocks = dataLen / unrl;
795 for (
size_t i = 0; i < nBlocks; ++i)
797 out[unrl * i + 0].gather(in, index0);
798 out[unrl * i + 1].gather(in, index1);
799 index0 = index0 + unrl;
800 index1 = index1 + unrl;
804 for (
size_t i = unrl * nBlocks; i < dataLen; ++i)
806 out[i].gather(in, index0);
812 const std::vector<sse2Double2, allocator<sse2Double2>> &in,
813 const std::uint32_t dataLen,
double *out)
815 alignas(sse2Double2::alignment) sse2Double2::scalarArray tmp;
816 for (
size_t i = 0; i < dataLen; ++i)
820 out[i + dataLen] = tmp[1];
825 const std::vector<sse2Double2, allocator<sse2Double2>> &in,
826 std::uint32_t dataLen,
double *out)
828 alignas(sse2Double2::alignment)
829 size_t tmp[sse2Double2::width] = {0, dataLen};
830 using index_t = sse2Long2<size_t>;
833 for (
size_t i = 0; i < dataLen; ++i)
835 in[i].scatter(out, index0);
844 static constexpr unsigned width = 4;
845 static constexpr unsigned alignment = 16;
847 using scalarType = float;
848 using scalarIndexType = std::uint32_t;
849 using vectorType = __m128;
850 using scalarArray = scalarType[width];
856 inline sse2Float4() =
default;
857 inline sse2Float4(
const sse2Float4 &rhs) =
default;
858 inline sse2Float4(
const vectorType &rhs) : _data(rhs)
861 inline sse2Float4(
const scalarType rhs)
863 _data = _mm_set1_ps(rhs);
867 inline sse2Float4 &operator=(
const sse2Float4 &) =
default;
870 inline void store(scalarType *p)
const
872 _mm_store_ps(p, _data);
875 template <
class flag,
876 typename std::enable_if<is_requiring_alignment_v<flag> &&
877 !is_streaming_v<flag>,
879 inline void store(scalarType *p, flag)
const
881 _mm_store_ps(p, _data);
884 template <
class flag,
typename std::enable_if<
885 !is_requiring_alignment_v<flag>,
bool>::type = 0>
886 inline void store(scalarType *p, flag)
const
888 _mm_storeu_ps(p, _data);
891 template <
class flag,
892 typename std::enable_if<is_streaming_v<flag>,
bool>::type = 0>
893 inline void store(scalarType *p, flag)
const
895 _mm_stream_ps(p, _data);
899 inline void load(
const scalarType *p)
901 _data = _mm_load_ps(p);
904 template <
class flag,
typename std::enable_if<
905 is_requiring_alignment_v<flag>,
bool>::type = 0>
906 inline void load(
const scalarType *p, flag)
908 _data = _mm_load_ps(p);
911 template <
class flag,
typename std::enable_if<
912 !is_requiring_alignment_v<flag>,
bool>::type = 0>
913 inline void load(
const scalarType *p, flag)
915 _data = _mm_loadu_ps(p);
919 inline void broadcast(
const scalarType rhs)
921 _data = _mm_set1_ps(rhs);
925 template <
typename T>
926 inline void gather(scalarType
const *p,
const sse2Int4<T> &indices)
929 alignas(alignment) scalarArray tmp;
930 tmp[0] =
p[_mm_extract_epi32(indices._data, 0)];
931 tmp[1] =
p[_mm_extract_epi32(indices._data, 1)];
932 tmp[2] =
p[_mm_extract_epi32(indices._data, 2)];
933 tmp[3] =
p[_mm_extract_epi32(indices._data, 3)];
934 _data = _mm_load_ps(&tmp[0]);
937 template <
typename T>
938 inline void scatter(scalarType *out,
const sse2Int4<T> &indices)
const
941 alignas(alignment) scalarArray tmp;
942 _mm_store_ps(tmp, _data);
944 out[_mm_extract_epi32(indices._data, 0)] = tmp[0];
945 out[_mm_extract_epi32(indices._data, 1)] = tmp[1];
946 out[_mm_extract_epi32(indices._data, 2)] = tmp[2];
947 out[_mm_extract_epi32(indices._data, 3)] = tmp[3];
952 inline void fma(
const sse2Float4 &a,
const sse2Float4 &b)
954 _data = _mm_fmadd_ps(a._data, b._data, _data);
960 inline scalarType operator[](
size_t i)
const
962 alignas(alignment) scalarArray tmp;
963 store(tmp, is_aligned);
967 inline scalarType &operator[](
size_t i)
969 scalarType *tmp =
reinterpret_cast<scalarType *
>(&_data);
973 inline void operator+=(sse2Float4 rhs)
975 _data = _mm_add_ps(_data, rhs._data);
978 inline void operator-=(sse2Float4 rhs)
980 _data = _mm_sub_ps(_data, rhs._data);
983 inline void operator*=(sse2Float4 rhs)
985 _data = _mm_mul_ps(_data, rhs._data);
988 inline void operator/=(sse2Float4 rhs)
990 _data = _mm_div_ps(_data, rhs._data);
994inline sse2Float4
operator+(sse2Float4 lhs, sse2Float4 rhs)
996 return _mm_add_ps(lhs._data, rhs._data);
999inline sse2Float4
operator-(sse2Float4 lhs, sse2Float4 rhs)
1001 return _mm_sub_ps(lhs._data, rhs._data);
1004inline sse2Float4
operator-(sse2Float4 in)
1006 return _mm_xor_ps(in._data, _mm_set1_ps(-0.0));
1009inline sse2Float4
operator*(sse2Float4 lhs, sse2Float4 rhs)
1011 return _mm_mul_ps(lhs._data, rhs._data);
1014inline sse2Float4
operator/(sse2Float4 lhs, sse2Float4 rhs)
1016 return _mm_div_ps(lhs._data, rhs._data);
1019inline sse2Float4
sqrt(sse2Float4 in)
1021 return _mm_sqrt_ps(in._data);
1024inline sse2Float4
abs(sse2Float4 in)
1027 static const __m128 sign_mask = _mm_set1_ps(-0.);
1028 return _mm_andnot_ps(sign_mask, in._data);
1031inline sse2Float4
min(sse2Float4 lhs, sse2Float4 rhs)
1033 return _mm_min_ps(lhs._data, rhs._data);
1036inline sse2Float4
max(sse2Float4 lhs, sse2Float4 rhs)
1038 return _mm_max_ps(lhs._data, rhs._data);
1041inline sse2Float4
log(sse2Float4 in)
1045 alignas(sse2Float4::alignment) sse2Float4::scalarArray tmp;
1047 tmp[0] = std::log(tmp[0]);
1048 tmp[1] = std::log(tmp[1]);
1049 tmp[2] = std::log(tmp[2]);
1050 tmp[3] = std::log(tmp[3]);
1057 const double *in,
const std::uint32_t dataLen,
1058 std::vector<sse2Float4, allocator<sse2Float4>> &out)
1060 alignas(sse2Float4::alignment) sse2Float4::scalarArray tmp;
1061 for (
size_t i = 0; i < dataLen; ++i)
1064 tmp[1] = in[i + dataLen];
1065 tmp[2] = in[i + 2 * dataLen];
1066 tmp[3] = in[i + 3 * dataLen];
1072 std::vector<sse2Float4, allocator<sse2Float4>> &out)
1075 alignas(sse2Float4::alignment) sse2Float4::scalarIndexType tmp[4] = {
1076 0, dataLen, 2 * dataLen, 3 * dataLen};
1078 using index_t = sse2Int4<sse2Float4::scalarIndexType>;
1079 index_t index0(tmp);
1080 index_t index1 = index0 + 1;
1083 size_t nBlocks = dataLen / 2;
1084 for (
size_t i = 0; i < nBlocks; ++i)
1086 out[2 * i + 0].gather(in, index0);
1087 out[2 * i + 1].gather(in, index1);
1088 index0 = index0 + 2;
1089 index1 = index1 + 2;
1093 for (
size_t i = 2 * nBlocks; i < dataLen; ++i)
1095 out[i].gather(in, index0);
1096 index0 = index0 + 1;
1101 const std::vector<sse2Float4, allocator<sse2Float4>> &in,
1102 const std::uint32_t dataLen,
double *out)
1104 alignas(sse2Float4::alignment) sse2Float4::scalarArray tmp;
1105 for (
size_t i = 0; i < dataLen; ++i)
1109 out[i + dataLen] = tmp[1];
1110 out[i + 2 * dataLen] = tmp[2];
1111 out[i + 3 * dataLen] = tmp[3];
1116 const std::vector<sse2Float4, allocator<sse2Float4>> &in,
1117 std::uint32_t dataLen,
float *out)
1119 alignas(sse2Float4::alignment) sse2Float4::scalarIndexType tmp[4] = {
1120 0, dataLen, 2 * dataLen, 3 * dataLen};
1121 using index_t = sse2Int4<sse2Float4::scalarIndexType>;
1122 index_t index0(tmp);
1124 for (
size_t i = 0; i < dataLen; ++i)
1126 in[i].scatter(out, index0);
1127 index0 = index0 + 1;
1140struct sse2Mask2 : sse2Long2<std::uint64_t>
1143 using sse2Long2::sse2Long2;
1145 static constexpr scalarType true_v = -1;
1146 static constexpr scalarType false_v = 0;
1149inline sse2Mask2
operator>(sse2Double2 lhs, sse2Double2 rhs)
1151 return reinterpret_cast<__m128i
>(
1152 _mm_cmp_pd(lhs._data, rhs._data, _CMP_GT_OQ));
1155inline bool operator&&(sse2Mask2 lhs,
bool rhs)
1157 bool tmp = _mm_testc_si128(lhs._data, _mm_set1_epi64x(sse2Mask2::true_v));
1162struct sse2Mask4 : sse2Int4<std::uint32_t>
1165 using sse2Int4::sse2Int4;
1167 static constexpr scalarType true_v = -1;
1168 static constexpr scalarType false_v = 0;
1171inline sse2Mask4
operator>(sse2Float4 lhs, sse2Float4 rhs)
1173 return reinterpret_cast<__m128i
>(_mm_cmp_ps(rhs._data, lhs._data, 1));
1176inline bool operator&&(sse2Mask4 lhs,
bool rhs)
1178 bool tmp = _mm_testc_si128(lhs._data, _mm_set1_epi64x(sse2Mask4::true_v));
std::vector< double > p(NPUPPER)
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)
scalarT< T > sqrt(scalarT< T > in)
scalarT< T > operator+(scalarT< T > lhs, scalarT< T > rhs)