Skip to content

Commit fb39929

Browse files
Improve generic version of complex masked load
Use the usual kernel mechanism which allows for specialization. Implement specialization for avx. Follow-up to #1391
1 parent bbfc648 commit fb39929

4 files changed

Lines changed: 59 additions & 5 deletions

File tree

include/xsimd/arch/common/xsimd_common_memory.hpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,29 @@ namespace xsimd
450450
return batch<T, A>::load_aligned(buffer.data());
451451
}
452452

453+
template <class A, class T, class Mode>
454+
XSIMD_INLINE batch<std::complex<T>, A>
455+
load_complex_masked(std::complex<T> const* mem, batch_bool<T, A> mask, Mode, requires_arch<common>) noexcept
456+
{
457+
// Scalar fallback: only active lanes are touched. Arches with
458+
// hardware predicated loads should override this.
459+
constexpr std::size_t size = batch<T, A>::size;
460+
alignas(A::alignment()) std::array<T, size> buffer_real;
461+
alignas(A::alignment()) std::array<T, size> buffer_imag;
462+
for (std::size_t i = 0; i < size; ++i)
463+
if (mask.get(i))
464+
{
465+
buffer_real[i] = mem[i].real();
466+
buffer_imag[i] = mem[i].imag();
467+
}
468+
else
469+
{
470+
buffer_real[i] = T(0);
471+
buffer_imag[i] = T(0);
472+
}
473+
return batch<std::complex<T>, A>::load_aligned(buffer_real.data(), buffer_imag.data());
474+
}
475+
453476
template <class A, class T_in, class T_out, bool... Values, class alignment>
454477
XSIMD_INLINE void
455478
store_masked(T_out* mem, batch<T_in, A> const& src, batch_bool_constant<T_in, A, Values...> mask, alignment mode, requires_arch<common>) noexcept

include/xsimd/arch/xsimd_avx.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,19 @@ namespace xsimd
10251025
return _mm256_maskload_pd(mem, _mm256_castpd_si256(mask));
10261026
}
10271027

1028+
template <class A, class T, class Mode>
1029+
XSIMD_INLINE batch<std::complex<T>, A>
1030+
load_complex_masked(std::complex<T> const* mem, batch_bool<T, A> mask, Mode mode, requires_arch<avx>) noexcept
1031+
{
1032+
using mask_register_type = typename batch_bool<T, A>::register_type;
1033+
mask_register_type nmask = mask.to_native();
1034+
batch_bool<T, A> lo_mask = zip_lo(batch<T, A>(nmask), batch<T, A>(nmask)).to_native();
1035+
batch_bool<T, A> hi_mask = zip_hi(batch<T, A>(nmask), batch<T, A>(nmask)).to_native();
1036+
batch<T, A> res_lo = batch<T, A>::load(reinterpret_cast<T const*>(mem), lo_mask, mode);
1037+
batch<T, A> res_hi = batch<T, A>::load(reinterpret_cast<T const*>(mem) + mask.size, hi_mask, mode);
1038+
return detail::load_complex(res_lo, res_hi, A{});
1039+
}
1040+
10281041
// 4/8-byte ints: bitcast to same-width float, reuse the vmaskmov path.
10291042
template <class A, class T, class Mode>
10301043
XSIMD_INLINE std::enable_if_t<std::is_integral_v<T> && (sizeof(T) == 4 || sizeof(T) == 8), batch<T, A>>

include/xsimd/arch/xsimd_avx512f.hpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1655,6 +1655,27 @@ namespace xsimd
16551655
}
16561656
}
16571657

1658+
template <class A, class T, class Mode>
1659+
XSIMD_INLINE batch<std::complex<T>, A>
1660+
load_complex_masked(std::complex<T> const* mem, batch_bool<T, A> mask, Mode mode, requires_arch<avx512f>) noexcept
1661+
{
1662+
using mask_register_type = typename batch_bool<T, A>::register_type;
1663+
mask_register_type nmask = mask.to_native();
1664+
1665+
// manually zip mask
1666+
constexpr mask_register_type lo_bitmask = xsimd::utils::make_low_mask<mask_register_type>(mask.size / 2);
1667+
mask_register_type lo_mask = nmask & lo_bitmask;
1668+
lo_mask |= lo_mask << (mask.size / 2);
1669+
1670+
constexpr mask_register_type hi_bitmask = lo_bitmask << (mask.size / 2);
1671+
mask_register_type hi_mask = nmask & hi_bitmask;
1672+
hi_mask |= hi_mask >> (mask.size / 2);
1673+
1674+
batch<T, A> res_lo = batch<T, A>::load(reinterpret_cast<T const*>(mem), lo_mask, mode);
1675+
batch<T, A> res_hi = batch<T, A>::load(reinterpret_cast<T const*>(mem) + mask.size, hi_mask, mode);
1676+
return detail::load_complex(res_lo, res_hi, A{});
1677+
}
1678+
16581679
// load_unaligned
16591680
template <class A, class T, class = std::enable_if_t<std::is_integral_v<T>>>
16601681
XSIMD_INLINE batch<T, A> load_unaligned(T const* mem, convert<T>, requires_arch<avx512f>) noexcept

include/xsimd/types/xsimd_batch.hpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1557,12 +1557,9 @@ namespace xsimd
15571557

15581558
template <class T, class A>
15591559
template <class Mode>
1560-
XSIMD_INLINE batch<std::complex<T>, A> batch<std::complex<T>, A>::load(value_type const* mem, batch_bool<T, A> mask, Mode) noexcept
1560+
XSIMD_INLINE batch<std::complex<T>, A> batch<std::complex<T>, A>::load(value_type const* mem, batch_bool<T, A> mask, Mode mode) noexcept
15611561
{
1562-
alignas(A::alignment()) std::array<value_type, size> buffer {};
1563-
for (std::size_t i = 0; i < size; ++i)
1564-
buffer[i] = mask.get(i) ? mem[i] : value_type(0);
1565-
return load_aligned(buffer.data());
1562+
return kernel::load_complex_masked<A>(mem, mask, mode, A {});
15661563
}
15671564

15681565
template <class T, class A>

0 commit comments

Comments
 (0)