diff --git a/include/xsimd/arch/xsimd_neon.hpp b/include/xsimd/arch/xsimd_neon.hpp index 8ea2756f7..48be9b88e 100644 --- a/include/xsimd/arch/xsimd_neon.hpp +++ b/include/xsimd/arch/xsimd_neon.hpp @@ -3308,7 +3308,9 @@ namespace xsimd requires_arch) noexcept { static_assert(batch::size == sizeof...(idx), "valid swizzle indices"); - std::array::size> data; + // std::array is only aligned to alignof(T), while store_aligned requires + // the full batch alignment + alignas(A::alignment()) std::array::size> data; self.store_aligned(data.data()); return set(batch(), A(), data[idx]...); } diff --git a/test/test_batch_manip.cpp b/test/test_batch_manip.cpp index 93d0e2a46..8fdc3cfd2 100644 --- a/test/test_batch_manip.cpp +++ b/test/test_batch_manip.cpp @@ -330,6 +330,44 @@ TEST_CASE_TEMPLATE("[swizzle]", B, BATCH_SWIZZLE_TYPES) SUBCASE("rotate_right") { swizzle_test().rotate_right(); } } +// Regression test for https://github.com/xtensor-stack/xsimd/issues/1260: the generic +// swizzle kernel stored to an std::array aligned only to alignof(T), tripping the +// alignment assertion in store_aligned for the 8- and 16-bit batches that use it. +// Run on every supported architecture, not just the default one, so the generic +// kernels of the narrower archs are exercised too +struct check_narrow_swizzle_and_reduce +{ + template + void operator()(Arch) const + { + if (!Arch::available()) + { + return; + } + check_for(); + check_for(); + check_for(); + check_for(); + } + + template + void check_for() const + { + using B = xsimd::batch; + swizzle_test().template run(); + swizzle_test().template run(); + swizzle_test().template run(); + auto lhs = swizzle_test::make_lhs(); + auto b = B::load_unaligned(lhs.data()); + CHECK_EQ(xsimd::reduce_max(b), lhs[B::size - 1]); + } +}; + +TEST_CASE("[narrow swizzle and reduce_max on every supported architecture]") +{ + xsimd::supported_architectures::for_each(check_narrow_swizzle_and_reduce {}); +} + #undef XSIMD_SWIZZLE_PATTERN_CASE #endif /* XSIMD_NO_SUPPORTED_ARCHITECTURE */