3#include "native/isa_import.h"
4#include "native/config.h"
18#if NATIVE_HOST_X86 || defined(NATIVE_DOXYGEN)
19namespace native::detail::x86_memory {
22 inline void constant_offset_requires_complete_elements() noexcept { __builtin_trap(); }
23 inline void constant_offset_out_of_range() noexcept { __builtin_trap(); }
25 template<
int Scale,
class T,
class I>
26 constexpr std::ptrdiff_t element_offset(I index)
noexcept {
27 std::int64_t value = index;
28 if constexpr (Scale <
sizeof(T)) {
29 constexpr auto divisor =
static_cast<std::int64_t
>(
sizeof(T) / Scale);
30 if (value % divisor) constant_offset_requires_complete_elements();
33 constexpr auto multiplier =
static_cast<std::int64_t
>(Scale /
sizeof(T));
34 if (value > std::numeric_limits<std::ptrdiff_t>::max() / multiplier ||
35 value < std::numeric_limits<std::ptrdiff_t>::min() / multiplier) {
36 constant_offset_out_of_range();
40 if (value > std::numeric_limits<std::ptrdiff_t>::max() ||
41 value < std::numeric_limits<std::ptrdiff_t>::min()) constant_offset_out_of_range();
42 return static_cast<std::ptrdiff_t
>(value);
46 constexpr auto array(V value)
noexcept {
47 std::array<typename V::value_type, V::lanes> result{};
48 value.store(result.data());
53 constexpr bool active(M
mask, std::size_t lane)
noexcept {
54 if constexpr (std::same_as<M, std::uint64_t>)
return (
mask >> lane) & 1;
55 else return array(
mask)[lane] < 0;
58 template<
int Scale,
class V,
class I,
class M>
59 constexpr V gather(
typename V::value_type
const * base, I indices, V source, M
mask)
noexcept {
60 auto result = array(source);
61 auto offsets = array(indices);
62 constexpr auto count = V::lanes < I::lanes ? V::lanes : I::lanes;
63 for (std::size_t lane = 0; lane < count; ++lane) {
64 if (active(
mask, lane)) result[lane] = base[element_offset<Scale, typename V::value_type>(offsets[lane])];
66 for (std::size_t lane = count; lane < V::lanes; ++lane) result[lane] = {};
70 template<
int Scale,
class V,
class I>
71 constexpr void scatter(
typename V::value_type * base, I indices, V value, std::uint64_t
mask)
noexcept {
72 auto values = array(value);
73 auto offsets = array(indices);
74 constexpr auto count = V::lanes < I::lanes ? V::lanes : I::lanes;
75 for (std::size_t lane = 0; lane < count; ++lane) {
76 if (!active(
mask, lane))
continue;
77 auto offset = element_offset<Scale, typename V::value_type>(offsets[lane]);
78 base[offset] = values[lane];
99 template<
int Scale, std::
size_t N, isa<x86> Arch>
100 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 4)
107 _mm_i32gather_ps(base, indices.to_native(), Scale));
112 template<
int Scale, isa<x86> Arch>
113 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
118 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
121 _mm_mask_i32gather_ps(source.to_native(), base, indices.to_native(), __builtin_bit_cast(
typename decltype(source)::native_type,
mask.to_native()), Scale));
126 template<
int Scale, isa<x86> Arch>
127 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
132 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
135 _mm_mmask_i32gather_ps(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
140 template<
int Scale, isa<x86> Arch>
141 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
146 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
148 _mm_mask_i32scatter_ps(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
153 template<
int Scale, std::
size_t N, isa<x86> Arch>
154 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 8)
161 _mm256_i32gather_ps(base, indices.to_native(), Scale));
166 template<
int Scale, isa<x86> Arch>
167 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
172 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
175 _mm256_mask_i32gather_ps(source.to_native(), base, indices.to_native(), __builtin_bit_cast(
typename decltype(source)::native_type,
mask.to_native()), Scale));
180 template<
int Scale, isa<x86> Arch>
181 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
186 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
189 _mm256_mmask_i32gather_ps(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
194 template<
int Scale, isa<x86> Arch>
195 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
200 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
202 _mm256_mask_i32scatter_ps(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
207 template<
int Scale, isa<x86> Arch>
208 requires(Arch.has(x86_feature::avx512f) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
213 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
216 _mm512_mask_i32gather_ps(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
221 template<
int Scale, isa<x86> Arch>
222 requires(Arch.has(x86_feature::avx512f) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
227 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
229 _mm512_mask_i32scatter_ps(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
234 template<
int Scale, std::
size_t N, isa<x86> Arch,
class T>
235 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 4 && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>))
242 _mm_i32gather_epi32(
reinterpret_cast<int const *
>(base), indices.to_native(), Scale));
247 template<
int Scale, isa<x86> Arch,
class T>
248 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>))
253 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
256 _mm_mask_i32gather_epi32(source.to_native(),
reinterpret_cast<int const *
>(base), indices.to_native(),
mask.to_native(), Scale));
261 template<
int Scale, isa<x86> Arch,
class T>
262 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>))
267 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
270 _mm_mmask_i32gather_epi32(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
275 template<
int Scale, isa<x86> Arch,
class T>
276 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>))
281 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
283 _mm_mask_i32scatter_epi32(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
288 template<
int Scale, std::
size_t N, isa<x86> Arch,
class T>
289 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 8 && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>))
296 _mm256_i32gather_epi32(
reinterpret_cast<int const *
>(base), indices.to_native(), Scale));
301 template<
int Scale, isa<x86> Arch,
class T>
302 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>))
307 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
310 _mm256_mask_i32gather_epi32(source.to_native(),
reinterpret_cast<int const *
>(base), indices.to_native(),
mask.to_native(), Scale));
315 template<
int Scale, isa<x86> Arch,
class T>
316 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>))
321 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
324 _mm256_mmask_i32gather_epi32(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
329 template<
int Scale, isa<x86> Arch,
class T>
330 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>))
335 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
337 _mm256_mask_i32scatter_epi32(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
342 template<
int Scale, isa<x86> Arch,
class T>
343 requires(Arch.has(x86_feature::avx512f) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>))
348 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
351 _mm512_mask_i32gather_epi32(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
356 template<
int Scale, isa<x86> Arch,
class T>
357 requires(Arch.has(x86_feature::avx512f) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>))
362 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
364 _mm512_mask_i32scatter_epi32(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
369 template<
int Scale, std::
size_t N, isa<x86> Arch>
370 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 2)
377 _mm_i32gather_pd(base, indices.to_native(), Scale));
382 template<
int Scale, isa<x86> Arch>
383 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
388 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
391 _mm_mask_i32gather_pd(source.to_native(), base, indices.to_native(), __builtin_bit_cast(
typename decltype(source)::native_type,
mask.to_native()), Scale));
396 template<
int Scale, isa<x86> Arch>
397 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
402 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
405 _mm_mmask_i32gather_pd(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
410 template<
int Scale, isa<x86> Arch>
411 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
416 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
418 _mm_mask_i32scatter_pd(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
423 template<
int Scale, std::
size_t N, isa<x86> Arch>
424 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 4)
431 _mm256_i32gather_pd(base, indices.to_native(), Scale));
436 template<
int Scale, isa<x86> Arch>
437 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
442 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
445 _mm256_mask_i32gather_pd(source.to_native(), base, indices.to_native(), __builtin_bit_cast(
typename decltype(source)::native_type,
mask.to_native()), Scale));
450 template<
int Scale, isa<x86> Arch>
451 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
456 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
459 _mm256_mmask_i32gather_pd(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
464 template<
int Scale, isa<x86> Arch>
465 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
470 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
472 _mm256_mask_i32scatter_pd(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
477 template<
int Scale, isa<x86> Arch>
478 requires(Arch.has(x86_feature::avx512f) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
483 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
486 _mm512_mask_i32gather_pd(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
491 template<
int Scale, isa<x86> Arch>
492 requires(Arch.has(x86_feature::avx512f) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
497 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
499 _mm512_mask_i32scatter_pd(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
504 template<
int Scale, std::
size_t N, isa<x86> Arch,
class T>
505 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 2 && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>))
512 _mm_i32gather_epi64(
reinterpret_cast<long long const *
>(base), indices.to_native(), Scale));
517 template<
int Scale, isa<x86> Arch,
class T>
518 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>))
523 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
526 _mm_mask_i32gather_epi64(source.to_native(),
reinterpret_cast<long long const *
>(base), indices.to_native(),
mask.to_native(), Scale));
531 template<
int Scale, isa<x86> Arch,
class T>
532 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>))
537 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
540 _mm_mmask_i32gather_epi64(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
545 template<
int Scale, isa<x86> Arch,
class T>
546 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>))
551 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
553 _mm_mask_i32scatter_epi64(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
558 template<
int Scale, std::
size_t N, isa<x86> Arch,
class T>
559 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 4 && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>))
566 _mm256_i32gather_epi64(
reinterpret_cast<long long const *
>(base), indices.to_native(), Scale));
571 template<
int Scale, isa<x86> Arch,
class T>
572 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>))
577 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
580 _mm256_mask_i32gather_epi64(source.to_native(),
reinterpret_cast<long long const *
>(base), indices.to_native(),
mask.to_native(), Scale));
585 template<
int Scale, isa<x86> Arch,
class T>
586 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>))
591 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
594 _mm256_mmask_i32gather_epi64(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
599 template<
int Scale, isa<x86> Arch,
class T>
600 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>))
605 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
607 _mm256_mask_i32scatter_epi64(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
612 template<
int Scale, isa<x86> Arch,
class T>
613 requires(Arch.has(x86_feature::avx512f) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>))
618 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
621 _mm512_mask_i32gather_epi64(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
626 template<
int Scale, isa<x86> Arch,
class T>
627 requires(Arch.has(x86_feature::avx512f) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>))
632 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
634 _mm512_mask_i32scatter_epi64(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
639 template<
int Scale, std::
size_t N, isa<x86> Arch>
640 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 4)
647 _mm_i64gather_ps(base, indices.to_native(), Scale));
652 template<
int Scale, isa<x86> Arch>
653 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
658 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
661 _mm_mask_i64gather_ps(source.to_native(), base, indices.to_native(), __builtin_bit_cast(
typename decltype(source)::native_type,
mask.to_native()), Scale));
666 template<
int Scale, isa<x86> Arch>
667 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
672 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
675 _mm_mmask_i64gather_ps(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
680 template<
int Scale, isa<x86> Arch>
681 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
686 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
688 _mm_mask_i64scatter_ps(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
693 template<
int Scale, std::
size_t N, isa<x86> Arch>
694 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 4)
701 _mm256_i64gather_ps(base, indices.to_native(), Scale));
706 template<
int Scale, isa<x86> Arch>
707 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
712 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
715 _mm256_mask_i64gather_ps(source.to_native(), base, indices.to_native(), __builtin_bit_cast(
typename decltype(source)::native_type,
mask.to_native()), Scale));
720 template<
int Scale, isa<x86> Arch>
721 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
726 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
729 _mm256_mmask_i64gather_ps(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
734 template<
int Scale, isa<x86> Arch>
735 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
740 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
742 _mm256_mask_i64scatter_ps(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
747 template<
int Scale, isa<x86> Arch>
748 requires(Arch.has(x86_feature::avx512f) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
753 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
756 _mm512_mask_i64gather_ps(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
761 template<
int Scale, isa<x86> Arch>
762 requires(Arch.has(x86_feature::avx512f) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
767 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
769 _mm512_mask_i64scatter_ps(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
774 template<
int Scale, std::
size_t N, isa<x86> Arch,
class T>
775 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 4 && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>))
782 _mm_i64gather_epi32(
reinterpret_cast<int const *
>(base), indices.to_native(), Scale));
787 template<
int Scale, isa<x86> Arch,
class T>
788 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>))
793 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
796 _mm_mask_i64gather_epi32(source.to_native(),
reinterpret_cast<int const *
>(base), indices.to_native(),
mask.to_native(), Scale));
801 template<
int Scale, isa<x86> Arch,
class T>
802 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>))
807 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
810 _mm_mmask_i64gather_epi32(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
815 template<
int Scale, isa<x86> Arch,
class T>
816 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>))
821 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
823 _mm_mask_i64scatter_epi32(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
828 template<
int Scale, std::
size_t N, isa<x86> Arch,
class T>
829 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 4 && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>))
836 _mm256_i64gather_epi32(
reinterpret_cast<int const *
>(base), indices.to_native(), Scale));
841 template<
int Scale, isa<x86> Arch,
class T>
842 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>))
847 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
850 _mm256_mask_i64gather_epi32(source.to_native(),
reinterpret_cast<int const *
>(base), indices.to_native(),
mask.to_native(), Scale));
855 template<
int Scale, isa<x86> Arch,
class T>
856 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>))
861 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
864 _mm256_mmask_i64gather_epi32(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
869 template<
int Scale, isa<x86> Arch,
class T>
870 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>))
875 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
877 _mm256_mask_i64scatter_epi32(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
882 template<
int Scale, isa<x86> Arch,
class T>
883 requires(Arch.has(x86_feature::avx512f) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>))
888 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
891 _mm512_mask_i64gather_epi32(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
896 template<
int Scale, isa<x86> Arch,
class T>
897 requires(Arch.has(x86_feature::avx512f) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>))
902 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
904 _mm512_mask_i64scatter_epi32(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
909 template<
int Scale, std::
size_t N, isa<x86> Arch>
910 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 2)
917 _mm_i64gather_pd(base, indices.to_native(), Scale));
922 template<
int Scale, isa<x86> Arch>
923 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
928 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
931 _mm_mask_i64gather_pd(source.to_native(), base, indices.to_native(), __builtin_bit_cast(
typename decltype(source)::native_type,
mask.to_native()), Scale));
936 template<
int Scale, isa<x86> Arch>
937 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
942 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
945 _mm_mmask_i64gather_pd(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
950 template<
int Scale, isa<x86> Arch>
951 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
956 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
958 _mm_mask_i64scatter_pd(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
963 template<
int Scale, std::
size_t N, isa<x86> Arch>
964 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 4)
971 _mm256_i64gather_pd(base, indices.to_native(), Scale));
976 template<
int Scale, isa<x86> Arch>
977 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
982 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
985 _mm256_mask_i64gather_pd(source.to_native(), base, indices.to_native(), __builtin_bit_cast(
typename decltype(source)::native_type,
mask.to_native()), Scale));
990 template<
int Scale, isa<x86> Arch>
991 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
996 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
999 _mm256_mmask_i64gather_pd(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
1004 template<
int Scale, isa<x86> Arch>
1005 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
1010 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1012 _mm256_mask_i64scatter_pd(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
1017 template<
int Scale, isa<x86> Arch>
1018 requires(Arch.has(x86_feature::avx512f) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
1023 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1026 _mm512_mask_i64gather_pd(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
1031 template<
int Scale, isa<x86> Arch>
1032 requires(Arch.has(x86_feature::avx512f) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8))
1037 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1039 _mm512_mask_i64scatter_pd(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
1044 template<
int Scale, std::
size_t N, isa<x86> Arch,
class T>
1045 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 2 && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>))
1049 return detail::x86_memory::gather<Scale>(base, indices,
simd<T, 2, Arch>{},
~std::uint64_t{0});
1052 _mm_i64gather_epi64(
reinterpret_cast<long long const *
>(base), indices.to_native(), Scale));
1057 template<
int Scale, isa<x86> Arch,
class T>
1058 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>))
1063 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
1066 _mm_mask_i64gather_epi64(source.to_native(),
reinterpret_cast<long long const *
>(base), indices.to_native(),
mask.to_native(), Scale));
1071 template<
int Scale, isa<x86> Arch,
class T>
1072 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>))
1077 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1080 _mm_mmask_i64gather_epi64(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
1085 template<
int Scale, isa<x86> Arch,
class T>
1086 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>))
1091 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1093 _mm_mask_i64scatter_epi64(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
1098 template<
int Scale, std::
size_t N, isa<x86> Arch,
class T>
1099 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 4 && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>))
1103 return detail::x86_memory::gather<Scale>(base, indices,
simd<T, 4, Arch>{},
~std::uint64_t{0});
1106 _mm256_i64gather_epi64(
reinterpret_cast<long long const *
>(base), indices.to_native(), Scale));
1111 template<
int Scale, isa<x86> Arch,
class T>
1112 requires(Arch.has(x86_feature::avx2) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>))
1117 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
1120 _mm256_mask_i64gather_epi64(source.to_native(),
reinterpret_cast<long long const *
>(base), indices.to_native(),
mask.to_native(), Scale));
1125 template<
int Scale, isa<x86> Arch,
class T>
1126 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>))
1131 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1134 _mm256_mmask_i64gather_epi64(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
1139 template<
int Scale, isa<x86> Arch,
class T>
1140 requires(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>))
1145 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1147 _mm256_mask_i64scatter_epi64(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
1152 template<
int Scale, isa<x86> Arch,
class T>
1153 requires(Arch.has(x86_feature::avx512f) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>))
1158 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1161 _mm512_mask_i64gather_epi64(source.to_native(),
mask.to_bitset(), indices.to_native(), base, Scale));
1166 template<
int Scale, isa<x86> Arch,
class T>
1167 requires(Arch.has(x86_feature::avx512f) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>))
1172 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1174 _mm512_mask_i64scatter_epi64(base,
mask.to_bitset(), indices.to_native(), value.to_native(), Scale);
1179 template<
int Scale, std::
size_t N, isa<x86> Arch>
1180 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 4 &&
requires {
sizeof(simd<float, 4, Arch>);
sizeof(simd<std::int32_t, 4, Arch>); })
1185 template<
int Scale, isa<x86> Arch>
1186 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires {
sizeof(simd<float, 4, Arch>);
sizeof(simd<std::int32_t, 4, Arch>); })
1189 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
1192 template<
int Scale, isa<x86> Arch>
1193 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires { sizeof(simd<float, 4, Arch>); sizeof(simd<std::int32_t, 4, Arch>); })
1195 float const * base,
simd<
std::int32_t, 4, Arch> indices) noexcept {
1196 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1199 template<
int Scale, isa<x86> Arch>
1200 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires { sizeof(simd<float, 4, Arch>); sizeof(simd<std::int32_t, 4, Arch>); })
1202 simd<
std::int32_t, 4, Arch> indices,
simd<
float, 4, Arch> value) noexcept {
1203 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1206 template<
int Scale, std::
size_t N, isa<x86> Arch>
1207 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 8 &&
requires {
sizeof(simd<float, 8, Arch>);
sizeof(simd<std::int32_t, 8, Arch>); })
1212 template<
int Scale, isa<x86> Arch>
1213 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires {
sizeof(simd<float, 8, Arch>);
sizeof(simd<std::int32_t, 8, Arch>); })
1216 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
1219 template<
int Scale, isa<x86> Arch>
1220 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires { sizeof(simd<float, 8, Arch>); sizeof(simd<std::int32_t, 8, Arch>); })
1222 float const * base,
simd<
std::int32_t, 8, Arch> indices) noexcept {
1223 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1226 template<
int Scale, isa<x86> Arch>
1227 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires { sizeof(simd<float, 8, Arch>); sizeof(simd<std::int32_t, 8, Arch>); })
1229 simd<
std::int32_t, 8, Arch> indices,
simd<
float, 8, Arch> value) noexcept {
1230 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1233 template<
int Scale, isa<x86> Arch>
1234 requires(!(Arch.has(x86_feature::avx512f)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires {
sizeof(simd<float, 16, Arch>);
sizeof(simd<std::int32_t, 16, Arch>); })
1237 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1240 template<
int Scale, isa<x86> Arch>
1241 requires(!(Arch.has(x86_feature::avx512f)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires {
sizeof(simd<float, 16, Arch>);
sizeof(simd<std::int32_t, 16, Arch>); })
1244 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1247 template<
int Scale, std::
size_t N, isa<x86> Arch,
class T>
1248 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 4 && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>) &&
requires {
sizeof(simd<T, 4, Arch>);
sizeof(simd<std::int32_t, 4, Arch>); })
1250 return detail::x86_memory::gather<Scale>(base, indices,
simd<T, 4, Arch>{},
~std::uint64_t{0});
1253 template<
int Scale, isa<x86> Arch,
class T>
1254 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>) &&
requires {
sizeof(simd<T, 4, Arch>);
sizeof(simd<std::int32_t, 4, Arch>); })
1257 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
1260 template<
int Scale, isa<x86> Arch,
class T>
1261 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>) &&
requires { sizeof(simd<T, 4, Arch>); sizeof(simd<std::int32_t, 4, Arch>); })
1263 T const * base,
simd<
std::int32_t, 4, Arch> indices) noexcept {
1264 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1267 template<
int Scale, isa<x86> Arch,
class T>
1268 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>) &&
requires { sizeof(simd<T, 4, Arch>); sizeof(simd<std::int32_t, 4, Arch>); })
1270 simd<
std::int32_t, 4, Arch> indices,
simd<T, 4, Arch> value) noexcept {
1271 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1274 template<
int Scale, std::
size_t N, isa<x86> Arch,
class T>
1275 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 8 && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>) &&
requires {
sizeof(simd<T, 8, Arch>);
sizeof(simd<std::int32_t, 8, Arch>); })
1277 return detail::x86_memory::gather<Scale>(base, indices,
simd<T, 8, Arch>{},
~std::uint64_t{0});
1280 template<
int Scale, isa<x86> Arch,
class T>
1281 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>) &&
requires {
sizeof(simd<T, 8, Arch>);
sizeof(simd<std::int32_t, 8, Arch>); })
1284 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
1287 template<
int Scale, isa<x86> Arch,
class T>
1288 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>) &&
requires { sizeof(simd<T, 8, Arch>); sizeof(simd<std::int32_t, 8, Arch>); })
1290 T const * base,
simd<
std::int32_t, 8, Arch> indices) noexcept {
1291 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1294 template<
int Scale, isa<x86> Arch,
class T>
1295 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>) &&
requires { sizeof(simd<T, 8, Arch>); sizeof(simd<std::int32_t, 8, Arch>); })
1297 simd<
std::int32_t, 8, Arch> indices,
simd<T, 8, Arch> value) noexcept {
1298 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1301 template<
int Scale, isa<x86> Arch,
class T>
1302 requires(!(Arch.has(x86_feature::avx512f)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>) &&
requires {
sizeof(simd<T, 16, Arch>);
sizeof(simd<std::int32_t, 16, Arch>); })
1305 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1308 template<
int Scale, isa<x86> Arch,
class T>
1309 requires(!(Arch.has(x86_feature::avx512f)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>) &&
requires {
sizeof(simd<T, 16, Arch>);
sizeof(simd<std::int32_t, 16, Arch>); })
1312 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1315 template<
int Scale, std::
size_t N, isa<x86> Arch>
1316 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 2 &&
requires {
sizeof(simd<double, 2, Arch>);
sizeof(simd<std::int32_t, 4, Arch>); })
1321 template<
int Scale, isa<x86> Arch>
1322 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires {
sizeof(simd<double, 2, Arch>);
sizeof(simd<std::int32_t, 4, Arch>);
sizeof(simd<std::int64_t, 2, Arch>); })
1325 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
1328 template<
int Scale, isa<x86> Arch>
1329 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires { sizeof(simd<double, 2, Arch>); sizeof(simd<std::int32_t, 4, Arch>); })
1331 double const * base,
simd<
std::int32_t, 4, Arch> indices) noexcept {
1332 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1335 template<
int Scale, isa<x86> Arch>
1336 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires { sizeof(simd<double, 2, Arch>); sizeof(simd<std::int32_t, 4, Arch>); })
1338 simd<
std::int32_t, 4, Arch> indices,
simd<
double, 2, Arch> value) noexcept {
1339 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1342 template<
int Scale, std::
size_t N, isa<x86> Arch>
1343 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 4 &&
requires {
sizeof(simd<double, 4, Arch>);
sizeof(simd<std::int32_t, 4, Arch>); })
1348 template<
int Scale, isa<x86> Arch>
1349 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires {
sizeof(simd<double, 4, Arch>);
sizeof(simd<std::int32_t, 4, Arch>);
sizeof(simd<std::int64_t, 4, Arch>); })
1352 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
1355 template<
int Scale, isa<x86> Arch>
1356 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires { sizeof(simd<double, 4, Arch>); sizeof(simd<std::int32_t, 4, Arch>); })
1358 double const * base,
simd<
std::int32_t, 4, Arch> indices) noexcept {
1359 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1362 template<
int Scale, isa<x86> Arch>
1363 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires { sizeof(simd<double, 4, Arch>); sizeof(simd<std::int32_t, 4, Arch>); })
1365 simd<
std::int32_t, 4, Arch> indices,
simd<
double, 4, Arch> value) noexcept {
1366 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1369 template<
int Scale, isa<x86> Arch>
1370 requires(!(Arch.has(x86_feature::avx512f)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires {
sizeof(simd<double, 8, Arch>);
sizeof(simd<std::int32_t, 8, Arch>); })
1373 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1376 template<
int Scale, isa<x86> Arch>
1377 requires(!(Arch.has(x86_feature::avx512f)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires {
sizeof(simd<double, 8, Arch>);
sizeof(simd<std::int32_t, 8, Arch>); })
1380 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1383 template<
int Scale, std::
size_t N, isa<x86> Arch,
class T>
1384 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 2 && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>) &&
requires {
sizeof(simd<T, 2, Arch>);
sizeof(simd<std::int32_t, 4, Arch>); })
1386 return detail::x86_memory::gather<Scale>(base, indices,
simd<T, 2, Arch>{},
~std::uint64_t{0});
1389 template<
int Scale, isa<x86> Arch,
class T>
1390 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>) &&
requires {
sizeof(simd<T, 2, Arch>);
sizeof(simd<std::int32_t, 4, Arch>);
sizeof(simd<std::int64_t, 2, Arch>); })
1393 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
1396 template<
int Scale, isa<x86> Arch,
class T>
1397 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>) &&
requires { sizeof(simd<T, 2, Arch>); sizeof(simd<std::int32_t, 4, Arch>); })
1399 T const * base,
simd<
std::int32_t, 4, Arch> indices) noexcept {
1400 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1403 template<
int Scale, isa<x86> Arch,
class T>
1404 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>) &&
requires { sizeof(simd<T, 2, Arch>); sizeof(simd<std::int32_t, 4, Arch>); })
1406 simd<
std::int32_t, 4, Arch> indices,
simd<T, 2, Arch> value) noexcept {
1407 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1410 template<
int Scale, std::
size_t N, isa<x86> Arch,
class T>
1411 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 4 && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>) &&
requires {
sizeof(simd<T, 4, Arch>);
sizeof(simd<std::int32_t, 4, Arch>); })
1413 return detail::x86_memory::gather<Scale>(base, indices,
simd<T, 4, Arch>{},
~std::uint64_t{0});
1416 template<
int Scale, isa<x86> Arch,
class T>
1417 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>) &&
requires {
sizeof(simd<T, 4, Arch>);
sizeof(simd<std::int32_t, 4, Arch>);
sizeof(simd<std::int64_t, 4, Arch>); })
1420 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
1423 template<
int Scale, isa<x86> Arch,
class T>
1424 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>) &&
requires { sizeof(simd<T, 4, Arch>); sizeof(simd<std::int32_t, 4, Arch>); })
1426 T const * base,
simd<
std::int32_t, 4, Arch> indices) noexcept {
1427 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1430 template<
int Scale, isa<x86> Arch,
class T>
1431 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>) &&
requires { sizeof(simd<T, 4, Arch>); sizeof(simd<std::int32_t, 4, Arch>); })
1433 simd<
std::int32_t, 4, Arch> indices,
simd<T, 4, Arch> value) noexcept {
1434 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1437 template<
int Scale, isa<x86> Arch,
class T>
1438 requires(!(Arch.has(x86_feature::avx512f)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>) &&
requires {
sizeof(simd<T, 8, Arch>);
sizeof(simd<std::int32_t, 8, Arch>); })
1441 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1444 template<
int Scale, isa<x86> Arch,
class T>
1445 requires(!(Arch.has(x86_feature::avx512f)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>) &&
requires {
sizeof(simd<T, 8, Arch>);
sizeof(simd<std::int32_t, 8, Arch>); })
1448 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1451 template<
int Scale, std::
size_t N, isa<x86> Arch>
1452 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 4 &&
requires {
sizeof(simd<float, 4, Arch>);
sizeof(simd<std::int64_t, 2, Arch>); })
1457 template<
int Scale, isa<x86> Arch>
1458 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires {
sizeof(simd<float, 4, Arch>);
sizeof(simd<std::int32_t, 4, Arch>);
sizeof(simd<std::int64_t, 2, Arch>); })
1461 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
1464 template<
int Scale, isa<x86> Arch>
1465 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires { sizeof(simd<float, 4, Arch>); sizeof(simd<std::int64_t, 2, Arch>); })
1467 float const * base,
simd<
std::int64_t, 2, Arch> indices) noexcept {
1468 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1471 template<
int Scale, isa<x86> Arch>
1472 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires { sizeof(simd<float, 4, Arch>); sizeof(simd<std::int64_t, 2, Arch>); })
1474 simd<
std::int64_t, 2, Arch> indices,
simd<
float, 4, Arch> value) noexcept {
1475 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1478 template<
int Scale, std::
size_t N, isa<x86> Arch>
1479 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 4 &&
requires {
sizeof(simd<float, 4, Arch>);
sizeof(simd<std::int64_t, 4, Arch>); })
1484 template<
int Scale, isa<x86> Arch>
1485 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires {
sizeof(simd<float, 4, Arch>);
sizeof(simd<std::int32_t, 4, Arch>);
sizeof(simd<std::int64_t, 4, Arch>); })
1488 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
1491 template<
int Scale, isa<x86> Arch>
1492 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires { sizeof(simd<float, 4, Arch>); sizeof(simd<std::int64_t, 4, Arch>); })
1494 float const * base,
simd<
std::int64_t, 4, Arch> indices) noexcept {
1495 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1498 template<
int Scale, isa<x86> Arch>
1499 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires { sizeof(simd<float, 4, Arch>); sizeof(simd<std::int64_t, 4, Arch>); })
1501 simd<
std::int64_t, 4, Arch> indices,
simd<
float, 4, Arch> value) noexcept {
1502 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1505 template<
int Scale, isa<x86> Arch>
1506 requires(!(Arch.has(x86_feature::avx512f)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires {
sizeof(simd<float, 8, Arch>);
sizeof(simd<std::int64_t, 8, Arch>); })
1509 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1512 template<
int Scale, isa<x86> Arch>
1513 requires(!(Arch.has(x86_feature::avx512f)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires {
sizeof(simd<float, 8, Arch>);
sizeof(simd<std::int64_t, 8, Arch>); })
1516 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1519 template<
int Scale, std::
size_t N, isa<x86> Arch,
class T>
1520 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 4 && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>) &&
requires {
sizeof(simd<T, 4, Arch>);
sizeof(simd<std::int64_t, 2, Arch>); })
1522 return detail::x86_memory::gather<Scale>(base, indices,
simd<T, 4, Arch>{},
~std::uint64_t{0});
1525 template<
int Scale, isa<x86> Arch,
class T>
1526 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>) &&
requires {
sizeof(simd<T, 4, Arch>);
sizeof(simd<std::int32_t, 4, Arch>);
sizeof(simd<std::int64_t, 2, Arch>); })
1529 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
1532 template<
int Scale, isa<x86> Arch,
class T>
1533 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>) &&
requires { sizeof(simd<T, 4, Arch>); sizeof(simd<std::int64_t, 2, Arch>); })
1535 T const * base,
simd<
std::int64_t, 2, Arch> indices) noexcept {
1536 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1539 template<
int Scale, isa<x86> Arch,
class T>
1540 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>) &&
requires { sizeof(simd<T, 4, Arch>); sizeof(simd<std::int64_t, 2, Arch>); })
1542 simd<
std::int64_t, 2, Arch> indices,
simd<T, 4, Arch> value) noexcept {
1543 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1546 template<
int Scale, std::
size_t N, isa<x86> Arch,
class T>
1547 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 4 && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>) &&
requires {
sizeof(simd<T, 4, Arch>);
sizeof(simd<std::int64_t, 4, Arch>); })
1549 return detail::x86_memory::gather<Scale>(base, indices,
simd<T, 4, Arch>{},
~std::uint64_t{0});
1552 template<
int Scale, isa<x86> Arch,
class T>
1553 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>) &&
requires {
sizeof(simd<T, 4, Arch>);
sizeof(simd<std::int32_t, 4, Arch>);
sizeof(simd<std::int64_t, 4, Arch>); })
1556 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
1559 template<
int Scale, isa<x86> Arch,
class T>
1560 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>) &&
requires { sizeof(simd<T, 4, Arch>); sizeof(simd<std::int64_t, 4, Arch>); })
1562 T const * base,
simd<
std::int64_t, 4, Arch> indices) noexcept {
1563 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1566 template<
int Scale, isa<x86> Arch,
class T>
1567 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>) &&
requires { sizeof(simd<T, 4, Arch>); sizeof(simd<std::int64_t, 4, Arch>); })
1569 simd<
std::int64_t, 4, Arch> indices,
simd<T, 4, Arch> value) noexcept {
1570 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1573 template<
int Scale, isa<x86> Arch,
class T>
1574 requires(!(Arch.has(x86_feature::avx512f)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>) &&
requires {
sizeof(simd<T, 8, Arch>);
sizeof(simd<std::int64_t, 8, Arch>); })
1577 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1580 template<
int Scale, isa<x86> Arch,
class T>
1581 requires(!(Arch.has(x86_feature::avx512f)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int32_t> || std::same_as<T, std::uint32_t>) &&
requires {
sizeof(simd<T, 8, Arch>);
sizeof(simd<std::int64_t, 8, Arch>); })
1584 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1587 template<
int Scale, std::
size_t N, isa<x86> Arch>
1588 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 2 &&
requires {
sizeof(simd<double, 2, Arch>);
sizeof(simd<std::int64_t, 2, Arch>); })
1593 template<
int Scale, isa<x86> Arch>
1594 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires {
sizeof(simd<double, 2, Arch>);
sizeof(simd<std::int64_t, 2, Arch>); })
1597 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
1600 template<
int Scale, isa<x86> Arch>
1601 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires { sizeof(simd<double, 2, Arch>); sizeof(simd<std::int64_t, 2, Arch>); })
1603 double const * base,
simd<
std::int64_t, 2, Arch> indices) noexcept {
1604 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1607 template<
int Scale, isa<x86> Arch>
1608 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires { sizeof(simd<double, 2, Arch>); sizeof(simd<std::int64_t, 2, Arch>); })
1610 simd<
std::int64_t, 2, Arch> indices,
simd<
double, 2, Arch> value) noexcept {
1611 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1614 template<
int Scale, std::
size_t N, isa<x86> Arch>
1615 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 4 &&
requires {
sizeof(simd<double, 4, Arch>);
sizeof(simd<std::int64_t, 4, Arch>); })
1620 template<
int Scale, isa<x86> Arch>
1621 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires {
sizeof(simd<double, 4, Arch>);
sizeof(simd<std::int64_t, 4, Arch>); })
1624 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
1627 template<
int Scale, isa<x86> Arch>
1628 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires { sizeof(simd<double, 4, Arch>); sizeof(simd<std::int64_t, 4, Arch>); })
1630 double const * base,
simd<
std::int64_t, 4, Arch> indices) noexcept {
1631 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1634 template<
int Scale, isa<x86> Arch>
1635 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires { sizeof(simd<double, 4, Arch>); sizeof(simd<std::int64_t, 4, Arch>); })
1637 simd<
std::int64_t, 4, Arch> indices,
simd<
double, 4, Arch> value) noexcept {
1638 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1641 template<
int Scale, isa<x86> Arch>
1642 requires(!(Arch.has(x86_feature::avx512f)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires {
sizeof(simd<double, 8, Arch>);
sizeof(simd<std::int64_t, 8, Arch>); })
1645 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1648 template<
int Scale, isa<x86> Arch>
1649 requires(!(Arch.has(x86_feature::avx512f)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) &&
requires {
sizeof(simd<double, 8, Arch>);
sizeof(simd<std::int64_t, 8, Arch>); })
1652 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1655 template<
int Scale, std::
size_t N, isa<x86> Arch,
class T>
1656 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 2 && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>) &&
requires {
sizeof(simd<T, 2, Arch>);
sizeof(simd<std::int64_t, 2, Arch>); })
1658 return detail::x86_memory::gather<Scale>(base, indices,
simd<T, 2, Arch>{},
~std::uint64_t{0});
1661 template<
int Scale, isa<x86> Arch,
class T>
1662 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>) &&
requires {
sizeof(simd<T, 2, Arch>);
sizeof(simd<std::int64_t, 2, Arch>); })
1665 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
1668 template<
int Scale, isa<x86> Arch,
class T>
1669 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>) &&
requires { sizeof(simd<T, 2, Arch>); sizeof(simd<std::int64_t, 2, Arch>); })
1671 T const * base,
simd<
std::int64_t, 2, Arch> indices) noexcept {
1672 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1675 template<
int Scale, isa<x86> Arch,
class T>
1676 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>) &&
requires { sizeof(simd<T, 2, Arch>); sizeof(simd<std::int64_t, 2, Arch>); })
1678 simd<
std::int64_t, 2, Arch> indices,
simd<T, 2, Arch> value) noexcept {
1679 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1682 template<
int Scale, std::
size_t N, isa<x86> Arch,
class T>
1683 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && N == 4 && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>) &&
requires {
sizeof(simd<T, 4, Arch>);
sizeof(simd<std::int64_t, 4, Arch>); })
1685 return detail::x86_memory::gather<Scale>(base, indices,
simd<T, 4, Arch>{},
~std::uint64_t{0});
1688 template<
int Scale, isa<x86> Arch,
class T>
1689 requires(!(Arch.has(x86_feature::avx2)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>) &&
requires {
sizeof(simd<T, 4, Arch>);
sizeof(simd<std::int64_t, 4, Arch>); })
1692 return detail::x86_memory::gather<Scale>(base, indices, source,
mask);
1695 template<
int Scale, isa<x86> Arch,
class T>
1696 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>) &&
requires { sizeof(simd<T, 4, Arch>); sizeof(simd<std::int64_t, 4, Arch>); })
1698 T const * base,
simd<
std::int64_t, 4, Arch> indices) noexcept {
1699 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1702 template<
int Scale, isa<x86> Arch,
class T>
1703 requires(!(Arch.has(x86_feature::avx512f) && Arch.has(x86_feature::avx512vl)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>) &&
requires { sizeof(simd<T, 4, Arch>); sizeof(simd<std::int64_t, 4, Arch>); })
1705 simd<
std::int64_t, 4, Arch> indices,
simd<T, 4, Arch> value) noexcept {
1706 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1709 template<
int Scale, isa<x86> Arch,
class T>
1710 requires(!(Arch.has(x86_feature::avx512f)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>) &&
requires {
sizeof(simd<T, 8, Arch>);
sizeof(simd<std::int64_t, 8, Arch>); })
1713 return detail::x86_memory::gather<Scale>(base, indices, source,
static_cast<std::uint64_t
>(
mask.to_bitset()));
1716 template<
int Scale, isa<x86> Arch,
class T>
1717 requires(!(Arch.has(x86_feature::avx512f)) && (Scale == 1 || Scale == 2 || Scale == 4 || Scale == 8) && (std::same_as<T, std::int64_t> || std::same_as<T, std::uint64_t>) &&
requires {
sizeof(simd<T, 8, Arch>);
sizeof(simd<std::int64_t, 8, Arch>); })
1720 detail::x86_memory::scatter<Scale>(base, indices, value,
static_cast<std::uint64_t
>(
mask.to_bitset()));
Compiler attributes for host code, with shader-safe shared modifiers.
#define native_inline
inline [[always_inline]]
#define native_nodiscard
C++17 [[nodiscard]].
#define native_target(x)
this indicates a required feature set for the current multiversioned function.
typename mask_traits< std::remove_cvref_t< T > >::type mask
constexpr simd< double, 2, Arch > vgatherqpd(double const *base, simd< std::int64_t, 2, Arch > indices) noexcept
Gather all addressable lanes; N specifies the result lane count.
constexpr simd< float, 4, Arch > mask_vgatherdps(simd< float, 4, Arch > source, simd< std::int32_t, 4, Arch > mask, float const *base, simd< std::int32_t, 4, Arch > indices) noexcept
Gather lanes whose full vector mask has its sign bit set; retain source otherwise.
constexpr simd< T, 2, Arch > vpgatherdq(T const *base, simd< std::int32_t, 4, Arch > indices) noexcept
Gather all addressable lanes; N specifies the result lane count.
constexpr void mask_vpscatterdq(T *base, predicate< 2, Arch > mask, simd< std::int32_t, 4, Arch > indices, simd< T, 2, Arch > value) noexcept
Store predicate-selected lanes; inactive addresses are not accessed.
constexpr simd< float, 4, Arch > vgatherqps(float const *base, simd< std::int64_t, 2, Arch > indices) noexcept
Gather all addressable lanes; N specifies the result lane count.
constexpr simd< float, 4, Arch > mask_vgatherqps(simd< float, 4, Arch > source, simd< std::int32_t, 4, Arch > mask, float const *base, simd< std::int64_t, 2, Arch > indices) noexcept
Gather lanes whose full vector mask has its sign bit set; retain source otherwise.
constexpr simd< T, 4, Arch > mask_vpgatherqd(simd< T, 4, Arch > source, simd< std::int32_t, 4, Arch > mask, T const *base, simd< std::int64_t, 2, Arch > indices) noexcept
Gather lanes whose full vector mask has its sign bit set; retain source otherwise.
constexpr void mask_vpscatterqq(T *base, predicate< 2, Arch > mask, simd< std::int64_t, 2, Arch > indices, simd< T, 2, Arch > value) noexcept
Store predicate-selected lanes; inactive addresses are not accessed.
constexpr simd< double, 2, Arch > vgatherdpd(double const *base, simd< std::int32_t, 4, Arch > indices) noexcept
Gather all addressable lanes; N specifies the result lane count.
constexpr void mask_vscatterdps(float *base, predicate< 4, Arch > mask, simd< std::int32_t, 4, Arch > indices, simd< float, 4, Arch > value) noexcept
Store predicate-selected lanes; inactive addresses are not accessed.
constexpr simd< float, 4, Arch > vgatherdps(float const *base, simd< std::int32_t, 4, Arch > indices) noexcept
Gather all addressable lanes; N specifies the result lane count.
constexpr simd< T, 4, Arch > vpgatherdd(T const *base, simd< std::int32_t, 4, Arch > indices) noexcept
Gather all addressable lanes; N specifies the result lane count.
constexpr simd< T, 2, Arch > mask_vpgatherqq(simd< T, 2, Arch > source, simd< std::int64_t, 2, Arch > mask, T const *base, simd< std::int64_t, 2, Arch > indices) noexcept
Gather lanes whose full vector mask has its sign bit set; retain source otherwise.
constexpr simd< double, 2, Arch > mask_vgatherdpd(simd< double, 2, Arch > source, simd< std::int64_t, 2, Arch > mask, double const *base, simd< std::int32_t, 4, Arch > indices) noexcept
Gather lanes whose full vector mask has its sign bit set; retain source otherwise.
constexpr simd< T, 4, Arch > mask_vpgatherdd(simd< T, 4, Arch > source, simd< std::int32_t, 4, Arch > mask, T const *base, simd< std::int32_t, 4, Arch > indices) noexcept
Gather lanes whose full vector mask has its sign bit set; retain source otherwise.
constexpr simd< T, 2, Arch > mask_vpgatherdq(simd< T, 2, Arch > source, simd< std::int64_t, 2, Arch > mask, T const *base, simd< std::int32_t, 4, Arch > indices) noexcept
Gather lanes whose full vector mask has its sign bit set; retain source otherwise.
constexpr simd< T, 2, Arch > vpgatherqq(T const *base, simd< std::int64_t, 2, Arch > indices) noexcept
Gather all addressable lanes; N specifies the result lane count.
constexpr simd< T, 4, Arch > vpgatherqd(T const *base, simd< std::int64_t, 2, Arch > indices) noexcept
Gather all addressable lanes; N specifies the result lane count.
constexpr void mask_vpscatterqd(T *base, predicate< 4, Arch > mask, simd< std::int64_t, 2, Arch > indices, simd< T, 4, Arch > value) noexcept
Store predicate-selected lanes; inactive addresses are not accessed.
constexpr void mask_vscatterdpd(double *base, predicate< 2, Arch > mask, simd< std::int32_t, 4, Arch > indices, simd< double, 2, Arch > value) noexcept
Store predicate-selected lanes; inactive addresses are not accessed.
constexpr void mask_vpscatterdd(T *base, predicate< 4, Arch > mask, simd< std::int32_t, 4, Arch > indices, simd< T, 4, Arch > value) noexcept
Store predicate-selected lanes; inactive addresses are not accessed.
constexpr simd< double, 2, Arch > mask_vgatherqpd(simd< double, 2, Arch > source, simd< std::int64_t, 2, Arch > mask, double const *base, simd< std::int64_t, 2, Arch > indices) noexcept
Gather lanes whose full vector mask has its sign bit set; retain source otherwise.
constexpr void mask_vscatterqpd(double *base, predicate< 2, Arch > mask, simd< std::int64_t, 2, Arch > indices, simd< double, 2, Arch > value) noexcept
Store predicate-selected lanes; inactive addresses are not accessed.
constexpr void mask_vscatterqps(float *base, predicate< 4, Arch > mask, simd< std::int64_t, 2, Arch > indices, simd< float, 4, Arch > value) noexcept
Store predicate-selected lanes; inactive addresses are not accessed.
Architecture-tagged vectors, register packs and supporting value types. Native arithmetic follows its...
Standard-library adaptations documented here for SIMD value types.
Omitted architecture arguments use the native.simd provider's baseline.