49select(
const bool a_mask,
const T a_ifTrue,
const T a_ifFalse)
noexcept
51 return a_mask ? a_ifTrue : a_ifFalse;
62both(
const bool a_lhs,
const bool a_rhs)
noexcept
64 return a_lhs && a_rhs;
74sqrt(
const float a_x)
noexcept
76 return std::sqrt(a_x);
86sqrt(
const double a_x)
noexcept
88 return std::sqrt(a_x);
98abs(
const float a_x)
noexcept
100 return std::abs(a_x);
110abs(
const double a_x)
noexcept
112 return std::abs(a_x);
127 static_assert(std::is_same_v<T, float> || std::is_same_v<T, double>,
"SIMD: T must be float or double");
129#if defined(EBGEOMETRY_DEVICE_COMPILE)
131#elif defined(__AVX512F__)
132 return 64 /
sizeof(T);
133#elif defined(__AVX__)
134 return 32 /
sizeof(T);
135#elif defined(__SSE4_1__)
136 return 16 /
sizeof(T);
149template <
class T,
size_t W>
155 for (
size_t n = WidestPack<T>(); n *
sizeof(T) >= 16; n /= 2) {
164template <
class T,
size_t N>
185template <
class T,
size_t N>
205template <
class T,
size_t N>
208#if !defined(EBGEOMETRY_DEVICE_COMPILE)
210#if defined(__SSE4_1__)
224 both(
const MaskF4 a_lhs,
const MaskF4 a_rhs)
noexcept
226 return MaskF4{_mm_and_ps(a_lhs.m, a_rhs.m)};
243 both(
const MaskD2 a_lhs,
const MaskD2 a_rhs)
noexcept
245 return MaskD2{_mm_and_pd(a_lhs.m, a_rhs.m)};
264 Pack() noexcept = default;
270 explicit Pack(const __m128 a_v) noexcept : v(a_v)
277 explicit Pack(
const float a_x) noexcept : v(_mm_set1_ps(a_x))
286 load(
const float* a_p)
noexcept
288 return Pack(_mm_load_ps(a_p));
296 store(
float* a_p)
const noexcept
298 _mm_store_ps(a_p, v);
303 friend Pack operator+(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm_add_ps(a_lhs.v, a_rhs.v)); }
304 friend Pack operator-(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm_sub_ps(a_lhs.v, a_rhs.v)); }
305 friend Pack
operator*(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm_mul_ps(a_lhs.v, a_rhs.v)); }
306 friend Pack
operator/(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm_div_ps(a_lhs.v, a_rhs.v)); }
307 friend MaskF4 operator<(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return MaskF4{_mm_cmplt_ps(a_lhs.v, a_rhs.v)}; }
308 friend MaskF4 operator>(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return MaskF4{_mm_cmpgt_ps(a_lhs.v, a_rhs.v)}; }
309 friend MaskF4 operator>=(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return MaskF4{_mm_cmpge_ps(a_lhs.v, a_rhs.v)}; }
310 friend Pack
select(
const MaskF4 a_mask,
const Pack a_ifTrue,
const Pack a_ifFalse)
noexcept {
return Pack(_mm_blendv_ps(a_ifFalse.v, a_ifTrue.v, a_mask.m)); }
311 friend Pack
sqrt(
const Pack a_x)
noexcept {
return Pack(_mm_sqrt_ps(a_x.v)); }
312 friend Pack
abs(
const Pack a_x)
noexcept {
return Pack(_mm_andnot_ps(_mm_set1_ps(-0.0F), a_x.v)); }
321struct Pack<double, 2>
331 Pack() noexcept = default;
337 explicit Pack(const __m128d a_v) noexcept : v(a_v)
344 explicit Pack(
const double a_x) noexcept : v(_mm_set1_pd(a_x))
353 load(
const double* a_p)
noexcept
355 return Pack(_mm_load_pd(a_p));
363 store(
double* a_p)
const noexcept
365 _mm_store_pd(a_p, v);
370 friend Pack operator+(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm_add_pd(a_lhs.v, a_rhs.v)); }
371 friend Pack operator-(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm_sub_pd(a_lhs.v, a_rhs.v)); }
372 friend Pack
operator*(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm_mul_pd(a_lhs.v, a_rhs.v)); }
373 friend Pack
operator/(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm_div_pd(a_lhs.v, a_rhs.v)); }
374 friend MaskD2 operator<(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return MaskD2{_mm_cmplt_pd(a_lhs.v, a_rhs.v)}; }
375 friend MaskD2 operator>(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return MaskD2{_mm_cmpgt_pd(a_lhs.v, a_rhs.v)}; }
376 friend MaskD2 operator>=(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return MaskD2{_mm_cmpge_pd(a_lhs.v, a_rhs.v)}; }
377 friend Pack
select(
const MaskD2 a_mask,
const Pack a_ifTrue,
const Pack a_ifFalse)
noexcept {
return Pack(_mm_blendv_pd(a_ifFalse.v, a_ifTrue.v, a_mask.m)); }
378 friend Pack
sqrt(
const Pack a_x)
noexcept {
return Pack(_mm_sqrt_pd(a_x.v)); }
379 friend Pack
abs(
const Pack a_x)
noexcept {
return Pack(_mm_andnot_pd(_mm_set1_pd(-0.0), a_x.v)); }
400 both(
const MaskF8 a_lhs,
const MaskF8 a_rhs)
noexcept
402 return MaskF8{_mm256_and_ps(a_lhs.m, a_rhs.m)};
419 both(
const MaskD4 a_lhs,
const MaskD4 a_rhs)
noexcept
421 return MaskD4{_mm256_and_pd(a_lhs.m, a_rhs.m)};
440 Pack() noexcept = default;
446 explicit Pack(const __m256 a_v) noexcept : v(a_v)
453 explicit Pack(
const float a_x) noexcept : v(_mm256_set1_ps(a_x))
462 load(
const float* a_p)
noexcept
464 return Pack(_mm256_load_ps(a_p));
472 store(
float* a_p)
const noexcept
474 _mm256_store_ps(a_p, v);
479 friend Pack operator+(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm256_add_ps(a_lhs.v, a_rhs.v)); }
480 friend Pack operator-(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm256_sub_ps(a_lhs.v, a_rhs.v)); }
481 friend Pack
operator*(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm256_mul_ps(a_lhs.v, a_rhs.v)); }
482 friend Pack
operator/(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm256_div_ps(a_lhs.v, a_rhs.v)); }
483 friend MaskF8 operator<(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return MaskF8{_mm256_cmp_ps(a_lhs.v, a_rhs.v, _CMP_LT_OQ)}; }
484 friend MaskF8 operator>(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return MaskF8{_mm256_cmp_ps(a_lhs.v, a_rhs.v, _CMP_GT_OQ)}; }
485 friend MaskF8 operator>=(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return MaskF8{_mm256_cmp_ps(a_lhs.v, a_rhs.v, _CMP_GE_OQ)}; }
486 friend Pack
select(
const MaskF8 a_mask,
const Pack a_ifTrue,
const Pack a_ifFalse)
noexcept {
return Pack(_mm256_blendv_ps(a_ifFalse.v, a_ifTrue.v, a_mask.m)); }
487 friend Pack
sqrt(
const Pack a_x)
noexcept {
return Pack(_mm256_sqrt_ps(a_x.v)); }
488 friend Pack
abs(
const Pack a_x)
noexcept {
return Pack(_mm256_andnot_ps(_mm256_set1_ps(-0.0F), a_x.v)); }
497struct Pack<double, 4>
507 Pack() noexcept = default;
513 explicit Pack(const __m256d a_v) noexcept : v(a_v)
520 explicit Pack(
const double a_x) noexcept : v(_mm256_set1_pd(a_x))
529 load(
const double* a_p)
noexcept
531 return Pack(_mm256_load_pd(a_p));
539 store(
double* a_p)
const noexcept
541 _mm256_store_pd(a_p, v);
546 friend Pack operator+(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm256_add_pd(a_lhs.v, a_rhs.v)); }
547 friend Pack operator-(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm256_sub_pd(a_lhs.v, a_rhs.v)); }
548 friend Pack
operator*(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm256_mul_pd(a_lhs.v, a_rhs.v)); }
549 friend Pack
operator/(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm256_div_pd(a_lhs.v, a_rhs.v)); }
550 friend MaskD4 operator<(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return MaskD4{_mm256_cmp_pd(a_lhs.v, a_rhs.v, _CMP_LT_OQ)}; }
551 friend MaskD4 operator>(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return MaskD4{_mm256_cmp_pd(a_lhs.v, a_rhs.v, _CMP_GT_OQ)}; }
552 friend MaskD4 operator>=(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return MaskD4{_mm256_cmp_pd(a_lhs.v, a_rhs.v, _CMP_GE_OQ)}; }
553 friend Pack
select(
const MaskD4 a_mask,
const Pack a_ifTrue,
const Pack a_ifFalse)
noexcept {
return Pack(_mm256_blendv_pd(a_ifFalse.v, a_ifTrue.v, a_mask.m)); }
554 friend Pack
sqrt(
const Pack a_x)
noexcept {
return Pack(_mm256_sqrt_pd(a_x.v)); }
555 friend Pack
abs(
const Pack a_x)
noexcept {
return Pack(_mm256_andnot_pd(_mm256_set1_pd(-0.0), a_x.v)); }
562#if defined(__AVX512F__)
575 friend inline MaskF16
576 both(
const MaskF16 a_lhs,
const MaskF16 a_rhs)
noexcept
578 return MaskF16{
static_cast<__mmask16
>(a_lhs.m & a_rhs.m)};
595 both(
const MaskD8 a_lhs,
const MaskD8 a_rhs)
noexcept
597 return MaskD8{
static_cast<__mmask8
>(a_lhs.m & a_rhs.m)};
608struct Pack<float, 16>
618 Pack() noexcept = default;
624 explicit Pack(const __m512 a_v) noexcept : v(a_v)
631 explicit Pack(
const float a_x) noexcept : v(_mm512_set1_ps(a_x))
640 load(
const float* a_p)
noexcept
642 return Pack(_mm512_load_ps(a_p));
650 store(
float* a_p)
const noexcept
652 _mm512_store_ps(a_p, v);
657 friend Pack operator+(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm512_add_ps(a_lhs.v, a_rhs.v)); }
658 friend Pack operator-(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm512_sub_ps(a_lhs.v, a_rhs.v)); }
659 friend Pack
operator*(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm512_mul_ps(a_lhs.v, a_rhs.v)); }
660 friend Pack
operator/(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm512_div_ps(a_lhs.v, a_rhs.v)); }
661 friend MaskF16 operator<(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return MaskF16{_mm512_cmp_ps_mask(a_lhs.v, a_rhs.v, _CMP_LT_OQ)}; }
662 friend MaskF16 operator>(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return MaskF16{_mm512_cmp_ps_mask(a_lhs.v, a_rhs.v, _CMP_GT_OQ)}; }
663 friend MaskF16 operator>=(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return MaskF16{_mm512_cmp_ps_mask(a_lhs.v, a_rhs.v, _CMP_GE_OQ)}; }
664 friend Pack
select(
const MaskF16 a_mask,
const Pack a_ifTrue,
const Pack a_ifFalse)
noexcept {
return Pack(_mm512_mask_blend_ps(a_mask.m, a_ifFalse.v, a_ifTrue.v)); }
665 friend Pack
sqrt(
const Pack a_x)
noexcept {
return Pack(_mm512_sqrt_ps(a_x.v)); }
666 friend Pack
abs(
const Pack a_x)
noexcept
668 return Pack(_mm512_castsi512_ps(_mm512_andnot_si512(_mm512_castps_si512(_mm512_set1_ps(-0.0F)), _mm512_castps_si512(a_x.v))));
679struct Pack<double, 8>
689 Pack() noexcept = default;
695 explicit Pack(const __m512d a_v) noexcept : v(a_v)
702 explicit Pack(
const double a_x) noexcept : v(_mm512_set1_pd(a_x))
711 load(
const double* a_p)
noexcept
713 return Pack(_mm512_load_pd(a_p));
721 store(
double* a_p)
const noexcept
723 _mm512_store_pd(a_p, v);
728 friend Pack operator+(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm512_add_pd(a_lhs.v, a_rhs.v)); }
729 friend Pack operator-(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm512_sub_pd(a_lhs.v, a_rhs.v)); }
730 friend Pack
operator*(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm512_mul_pd(a_lhs.v, a_rhs.v)); }
731 friend Pack
operator/(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return Pack(_mm512_div_pd(a_lhs.v, a_rhs.v)); }
732 friend MaskD8 operator<(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return MaskD8{_mm512_cmp_pd_mask(a_lhs.v, a_rhs.v, _CMP_LT_OQ)}; }
733 friend MaskD8 operator>(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return MaskD8{_mm512_cmp_pd_mask(a_lhs.v, a_rhs.v, _CMP_GT_OQ)}; }
734 friend MaskD8 operator>=(
const Pack a_lhs,
const Pack a_rhs)
noexcept {
return MaskD8{_mm512_cmp_pd_mask(a_lhs.v, a_rhs.v, _CMP_GE_OQ)}; }
735 friend Pack
select(
const MaskD8 a_mask,
const Pack a_ifTrue,
const Pack a_ifFalse)
noexcept {
return Pack(_mm512_mask_blend_pd(a_mask.m, a_ifFalse.v, a_ifTrue.v)); }
736 friend Pack
sqrt(
const Pack a_x)
noexcept {
return Pack(_mm512_sqrt_pd(a_x.v)); }
737 friend Pack
abs(
const Pack a_x)
noexcept
739 return Pack(_mm512_castsi512_pd(_mm512_andnot_si512(_mm512_castpd_si512(_mm512_set1_pd(-0.0)), _mm512_castpd_si512(a_x.v))));