diff --git a/include/xsimd/arch/xsimd_avx2.hpp b/include/xsimd/arch/xsimd_avx2.hpp index be226c314..8bec0390c 100644 --- a/include/xsimd/arch/xsimd_avx2.hpp +++ b/include/xsimd/arch/xsimd_avx2.hpp @@ -1297,7 +1297,35 @@ namespace xsimd } } - // swizzle (dynamic mask) on 8 and 16 bits; see avx for 32 and 64 bits versions + // swizzle (dynamic indices) + template + XSIMD_INLINE batch swizzle(batch const& self, batch indices, requires_arch) noexcept + { + return _mm256_permutevar8x32_ps(self, indices); + } + + template = 0> + XSIMD_INLINE batch swizzle(batch const& self, batch const& indices, requires_arch) noexcept + { + return _mm256_permutevar8x32_epi32(self, indices); + } + + template = 0> + XSIMD_INLINE batch swizzle(batch const& self, batch const& indices, requires_arch) noexcept + { + // A 64 bits index i selects the 32 bits pair (2i, 2i + 1). + __m256i lo = _mm256_shuffle_epi32(indices, _MM_SHUFFLE(2, 2, 0, 0)); + __m256i expanded_indices = _mm256_add_epi32(_mm256_add_epi32(lo, lo), _mm256_setr_epi32(0, 1, 0, 1, 0, 1, 0, 1)); + return _mm256_permutevar8x32_epi32(self, expanded_indices); + } + + template + XSIMD_INLINE batch swizzle(batch const& self, batch indices, requires_arch req) noexcept + { + return bitwise_cast(swizzle(bitwise_cast(self), indices, req)); + } + + // swizzle (dynamic mask) on 8 and 16 bits template XSIMD_INLINE batch swizzle(batch const& self, batch mask, requires_arch) noexcept { diff --git a/test/test_batch_manip.cpp b/test/test_batch_manip.cpp index 1391749e5..53493fa44 100644 --- a/test/test_batch_manip.cpp +++ b/test/test_batch_manip.cpp @@ -15,6 +15,9 @@ #include "test_utils.hpp" +#include +#include + // Compile time tests for include/xsimd/arch/common/xsimd_common_swizzle.hpp namespace xsimd { @@ -297,6 +300,40 @@ struct swizzle_test b_expect); } + void dynamic_duplicates() + { + using idx_t = typename xsimd::as_index::type; + using idx_batch_type = xsimd::batch; + const vec_t lhs = make_lhs(); + const auto b_lhs = batch_type::load_unaligned(lhs.data()); + std::array idx; + vec_t expect; + auto check = [&]() + { + std::transform(idx.cbegin(), idx.cend(), expect.begin(), [&](idx_t i) + { return lhs[i]; }); + auto idx_batch = idx_batch_type::load_unaligned(idx.data()); + CAPTURE(idx_batch); + CHECK_BATCH_EQ(xsimd::swizzle(b_lhs, idx_batch), batch_type::load_unaligned(expect.data())); + }; + + for (std::size_t s = 0; s < N; ++s) + { + idx.fill(static_cast(s)); + check(); + } + + // The standard fixes the mt19937 output, so every platform tests the same cases. + // For N <= 4, 2048 draws cover all N^N index vectors. + std::mt19937 generator; + for (int r = 0; r < 2048; ++r) + { + std::generate(idx.begin(), idx.end(), [&]() + { return static_cast(generator() % N); }); + check(); + } + } + void rotate_right() { vec_t lhs = make_lhs(), expect; @@ -341,6 +378,7 @@ TEST_CASE_TEMPLATE("[swizzle]", B, BATCH_SWIZZLE_TYPES) XSIMD_SWIZZLE_PATTERN_CASE(EvenThenOdd); XSIMD_SWIZZLE_PATTERN_CASE(OddThenEven); XSIMD_SWIZZLE_PATTERN_CASE(InterleavePairs); + SUBCASE("dynamic_duplicates") { swizzle_test().dynamic_duplicates(); } // Rotation checks: SUBCASE("rotate_left") { swizzle_test().rotate_left(); } SUBCASE("rotate_left_inv") { swizzle_test().rotate_left_inv(); }