Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion include/xsimd/arch/xsimd_avx2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <class A>
XSIMD_INLINE batch<float, A> swizzle(batch<float, A> const& self, batch<uint32_t, A> indices, requires_arch<avx2>) noexcept
{
return _mm256_permutevar8x32_ps(self, indices);
}

template <class A, typename T, detail::enable_sized_integral_t<T, 4> = 0>
XSIMD_INLINE batch<T, A> swizzle(batch<T, A> const& self, batch<uint32_t, A> const& indices, requires_arch<avx2>) noexcept
{
return _mm256_permutevar8x32_epi32(self, indices);
}

template <class A, typename T, detail::enable_sized_integral_t<T, 8> = 0>
XSIMD_INLINE batch<T, A> swizzle(batch<T, A> const& self, batch<uint64_t, A> const& indices, requires_arch<avx2>) noexcept
{
// A 64 bits index i selects the 32 bits pair (2i, 2i + 1).
Comment thread
DiamonDinoia marked this conversation as resolved.
Resolved
__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 <class A>
XSIMD_INLINE batch<double, A> swizzle(batch<double, A> const& self, batch<uint64_t, A> indices, requires_arch<avx2> req) noexcept
{
return bitwise_cast<double>(swizzle(bitwise_cast<uint64_t>(self), indices, req));
}

// swizzle (dynamic mask) on 8 and 16 bits
template <class A>
XSIMD_INLINE batch<uint8_t, A> swizzle(batch<uint8_t, A> const& self, batch<uint8_t, A> mask, requires_arch<avx2>) noexcept
{
Expand Down
38 changes: 38 additions & 0 deletions test/test_batch_manip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@

#include "test_utils.hpp"

#include <algorithm>
#include <random>

// Compile time tests for include/xsimd/arch/common/xsimd_common_swizzle.hpp
namespace xsimd
{
Expand Down Expand Up @@ -297,6 +300,40 @@ struct swizzle_test
b_expect);
}

void dynamic_duplicates()
{
using idx_t = typename xsimd::as_index<value_type>::type;
using idx_batch_type = xsimd::batch<idx_t, arch_type>;
const vec_t lhs = make_lhs();
const auto b_lhs = batch_type::load_unaligned(lhs.data());
std::array<idx_t, N> 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<idx_t>(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<idx_t>(generator() % N); });
check();
}
}
Comment thread
DiamonDinoia marked this conversation as resolved.
Resolved

void rotate_right()
{
vec_t lhs = make_lhs(), expect;
Expand Down Expand Up @@ -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<B>().dynamic_duplicates(); }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use the macro above for consistency

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Emm this is a subcase and didn't calls xsimd::fill_pattern 🤔, so should we just leave subcase? This just verify the case for duplicate, which is mentioned eariler

// Rotation checks:
SUBCASE("rotate_left") { swizzle_test<B>().rotate_left(); }
SUBCASE("rotate_left_inv") { swizzle_test<B>().rotate_left_inv(); }
Expand Down
Loading