diff --git a/include/eve/module/core/detail/simd/x86/basic_shuffle.hpp b/include/eve/module/core/detail/simd/x86/basic_shuffle.hpp index a079c60e0a..1015dd71b3 100644 --- a/include/eve/module/core/detail/simd/x86/basic_shuffle.hpp +++ b/include/eve/module/core/detail/simd/x86/basic_shuffle.hpp @@ -251,7 +251,7 @@ basic_shuffle_(EVE_SUPPORTS(avx_), [](auto i, auto c) { Pattern r; - return (i < c / 2 ? r(i, c) : r(i - c / 2, c)) << 1; + return (r(i,c) % 2) << 1; }); auto const m = as_indexes>(fixed_pattern); diff --git a/include/eve/module/core/regular/bit_shr.hpp b/include/eve/module/core/regular/bit_shr.hpp index 814b5925a3..10316fa80d 100644 --- a/include/eve/module/core/regular/bit_shr.hpp +++ b/include/eve/module/core/regular/bit_shr.hpp @@ -15,13 +15,13 @@ namespace eve template struct bit_shr_t : strict_elementwise_callable { - template - constexpr EVE_FORCEINLINE as_wide_as_t operator()(T v, S s) const + template + constexpr EVE_FORCEINLINE as_wide_as_t operator()(T v, S s) const { return EVE_DISPATCH_CALL(v, s); } - template + template constexpr EVE_FORCEINLINE T operator()(T v, index_t s) const { constexpr std::ptrdiff_t l = sizeof(element_type_t) * 8; diff --git a/include/eve/module/core/regular/bit_swap_pairs.hpp b/include/eve/module/core/regular/bit_swap_pairs.hpp index f101f9bb87..3449d29622 100644 --- a/include/eve/module/core/regular/bit_swap_pairs.hpp +++ b/include/eve/module/core/regular/bit_swap_pairs.hpp @@ -14,7 +14,9 @@ #include #include #include +#include #include +#include namespace eve { @@ -22,11 +24,24 @@ namespace eve template struct bit_swap_pairs_t : strict_elementwise_callable { - template - constexpr EVE_FORCEINLINE T operator()(T v, I0 i0, I1 i1) const noexcept + template + struct result + { + using type = std::conditional_t && scalar_value && scalar_value, T, as_wide_t>>; + }; + + template + EVE_FORCEINLINE constexpr typename result::type operator()(T v, I0 i0, I1 i1) const noexcept + requires same_lanes_or_scalar { return EVE_DISPATCH_CALL(v, i0, i1); } + + template + EVE_FORCEINLINE constexpr T operator()(T a, index_t i0, index_t i1) const noexcept + { + return EVE_DISPATCH_CALL(a, i0, i1); + } EVE_CALLABLE_OBJECT(bit_swap_pairs_t, bit_swap_pairs_); }; @@ -83,16 +98,24 @@ namespace eve namespace detail { template - constexpr T bit_swap_pairs_(EVE_REQUIRES(cpu_), C const& cx, O const&, T a, I0 i0, I1 i1) noexcept + constexpr auto bit_swap_pairs_(EVE_REQUIRES(cpu_), C const& cx, O const&, T a, I0 i0, I1 i1) noexcept { - auto i0m = if_else(cx, i0, zero); - auto i1m = if_else(cx, i1, zero); + if constexpr (scalar_value && scalar_value && scalar_value) + { + return bit_swap_pairs(a, cx ? i0 : 0, cx ? i1 : 0); + } + else + { + using MC = max_lanes_t; - return bit_swap_pairs(a, i0m, i1m); + auto i0m = if_else(cx, as_wide_t{i0}, zero); + auto i1m = if_else(cx, as_wide_t{i1}, zero); + return bit_swap_pairs(as_wide_t{a}, i0m, i1m); + } } template - constexpr T bit_swap_pairs_(EVE_REQUIRES(cpu_), O const&, T a, I0 i0, I1 i1) noexcept + constexpr auto bit_swap_pairs_(EVE_REQUIRES(cpu_), O const&, T a, I0 i0, I1 i1) noexcept { // 1 if the bits of a at i0 and i1 are different, 0 otherwise auto x = bit_and( @@ -106,5 +129,13 @@ namespace eve // if the bits are different, swap them by toggling both return bit_xor(a, bit_shl(x, i1), bit_shl(x, i0)); } + + template + EVE_FORCEINLINE T bit_swap_pairs_(EVE_REQUIRES(cpu_), O const& o, T x, index_t, index_t) noexcept + { + constexpr std::ptrdiff_t C = sizeof(element_type_t) * 8; + static_assert((I0 >= 0) && (I1 >= 0) && (I0 < C) && (I1 < C), "some index(es) are out or range"); + return bit_swap_pairs[o](x, I0, I1); + } } } diff --git a/include/eve/module/core/regular/byte_swap_pairs.hpp b/include/eve/module/core/regular/byte_swap_pairs.hpp index 8df2ab2293..ce535e50bb 100644 --- a/include/eve/module/core/regular/byte_swap_pairs.hpp +++ b/include/eve/module/core/regular/byte_swap_pairs.hpp @@ -16,8 +16,10 @@ namespace eve struct byte_swap_pairs_t : strict_elementwise_callable { template - EVE_FORCEINLINE T operator()(T a, index_t const & i0, index_t const & i1) const noexcept - { return EVE_DISPATCH_CALL(a, i0, i1); } + EVE_FORCEINLINE T operator()(T a, index_t i0, index_t i1) const noexcept + { + return EVE_DISPATCH_CALL(a, i0, i1); + } EVE_CALLABLE_OBJECT(byte_swap_pairs_t, byte_swap_pairs_); }; diff --git a/include/eve/module/core/regular/impl/byte_swap_pairs.hpp b/include/eve/module/core/regular/impl/byte_swap_pairs.hpp index 822a62b763..e124231c47 100644 --- a/include/eve/module/core/regular/impl/byte_swap_pairs.hpp +++ b/include/eve/module/core/regular/impl/byte_swap_pairs.hpp @@ -20,11 +20,7 @@ namespace eve::detail { template - EVE_FORCEINLINE T byte_swap_pairs_(EVE_REQUIRES(cpu_), - O const &, - T x , - index_t const & , - index_t const &) noexcept + EVE_FORCEINLINE T byte_swap_pairs_(EVE_REQUIRES(cpu_), O const &, T x, index_t, index_t) noexcept { if constexpr(simd_value) { @@ -54,12 +50,7 @@ namespace eve::detail // Masked case template - EVE_FORCEINLINE T byte_swap_pairs_(EVE_REQUIRES(cpu_), - C const& cond, - O const &, - T t, - index_t const & i0, - index_t const & i1) noexcept + EVE_FORCEINLINE T byte_swap_pairs_(EVE_REQUIRES(cpu_), C const& cond, O const&, T t, index_t i0, index_t i1) noexcept { return mask_op(cond, eve::byte_swap_pairs, t, i0, i1); } diff --git a/include/eve/module/core/regular/impl/swap_pairs.hpp b/include/eve/module/core/regular/impl/swap_pairs.hpp index abc27554f8..1292aec1f4 100644 --- a/include/eve/module/core/regular/impl/swap_pairs.hpp +++ b/include/eve/module/core/regular/impl/swap_pairs.hpp @@ -13,24 +13,16 @@ namespace eve::detail { - template - EVE_FORCEINLINE T - swap_pairs_(EVE_SUPPORTS(cpu_), T x - , index_t const & - , index_t const & ) noexcept + template + EVE_FORCEINLINE constexpr T swap_pairs_(EVE_REQUIRES(cpu_), O const&, T x, index_t, index_t) noexcept { - [[maybe_unused]] constexpr std::ptrdiff_t C = scalar_value ? 1 : cardinal_v; - EVE_ASSERT((I0 >= 0) && (I1 >= 0) && (I0 < C) && (I1 < C), "some index(es) are out or range"); - if constexpr(simd_value) - { - auto p = [](auto i, auto){ - return (i == I0) ? I1 :(i == I1 ? I0 : i) ; - }; - return eve::shuffle(x, eve::as_pattern(p)); - } - else if constexpr(scalar_value) - { - return x; - } + constexpr std::ptrdiff_t C = cardinal_v; + static_assert((I0 >= 0) && (I1 >= 0) && (I0 < C) && (I1 < C), "some index(es) are out or range"); + + auto p = [](auto i, auto){ + return (i == I0) ? I1 :(i == I1 ? I0 : i) ; + }; + + return eve::shuffle(x, eve::as_pattern(p)); } } diff --git a/include/eve/module/core/regular/swap_pairs.hpp b/include/eve/module/core/regular/swap_pairs.hpp index 84b8aab770..2f78108534 100644 --- a/include/eve/module/core/regular/swap_pairs.hpp +++ b/include/eve/module/core/regular/swap_pairs.hpp @@ -11,47 +11,57 @@ namespace eve { -//TODO DOC -//================================================================================================ -//! @addtogroup core_bitops -//! @{ -//! @var swap_pairs -//! @brief swap chosen pair of elements. -//! -//! @groupheader{Header file} -//! -//! @code -//! #include -//! @endcode -//! -//! @groupheader{Callable Signatures} -//! -//! @code -//! namespace eve -//! { -//! template -//! T swap_pairs(T x, index_t const & i0, index_t const & i1); -//! @endcode -//! -//! **Parameters** -//! -//! * `x` : [argument](@ref eve::value). -//! * `i0` : first index -//! * `i1` : second index -//! -//! **Return value** -//! -//! Return x with element i0 and i1 swapped. Action on scalar is identity. -//! Assert if i0 or i1 are out of range. -//! -//! @groupheader{Example} -//! -//! @godbolt{doc/core/swap_pairs.cpp} -//================================================================================================ -EVE_MAKE_CALLABLE(swap_pairs_, swap_pairs); -//================================================================================================ -//! @} -//================================================================================================ + template + struct swap_pairs_t : callable + { + template + EVE_FORCEINLINE T operator()(T x, index_t i0, index_t i1) const noexcept + { + return EVE_DISPATCH_CALL(x, i0, i1); + } + + EVE_CALLABLE_OBJECT(swap_pairs_t, swap_pairs_); + }; + + //================================================================================================ + //! @addtogroup core_bitops + //! @{ + //! @var swap_pairs + //! @brief swap chosen pair of elements. + //! + //! @groupheader{Header file} + //! + //! @code + //! #include + //! @endcode + //! + //! @groupheader{Callable Signatures} + //! + //! @code + //! namespace eve + //! { + //! template + //! T swap_pairs(T x, index_t i0, index_t i1); + //! @endcode + //! + //! **Parameters** + //! + //! * `x` : [argument](@ref eve::simd_value). + //! * `i0` : first index + //! * `i1` : second index + //! + //! **Return value** + //! + //! Return x with element i0 and i1 swapped. + //! + //! @groupheader{Example} + //! + //! @godbolt{doc/core/swap_pairs.cpp} + //================================================================================================ + inline constexpr auto swap_pairs = functor; + //================================================================================================ + //! @} + //================================================================================================ } #include diff --git a/include/eve/traits/max_lanes.hpp b/include/eve/traits/max_lanes.hpp new file mode 100644 index 0000000000..6566e65c84 --- /dev/null +++ b/include/eve/traits/max_lanes.hpp @@ -0,0 +1,51 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +namespace eve +{ + namespace detail + { + template + consteval auto compute_max_lanes() + { + std::ptrdiff_t cards[] = { cardinal_v... }; + + auto max_card = cards[0]; + for(auto c : cards) max_card = max_card < c ? c : max_card; + + return max_card; + } + } + + //================================================================================================ + //! @addtogroup traits + //! @{ + //! @var max_lanes + //! + //! @tparam Ts Types to process + //! + //! @brief A meta function for getting a maximum lane count of given wide or scalar types. + //! @} + //================================================================================================ + template + inline constexpr auto max_lanes_v = detail::compute_max_lanes(); + + //================================================================================================ + //! @addtogroup traits + //! @{ + //! @var max_lanes + //! + //! @tparam Ts Types to process + //! + //! @brief The cardinal type of the maximum lane count of given wide or scalar types. + //! @} + //================================================================================================ + template + using max_lanes_t = fixed>; +} diff --git a/test/doc/core/bit_swap_pairs.cpp b/test/doc/core/bit_swap_pairs.cpp index dca51044cb..15cb98e399 100644 --- a/test/doc/core/bit_swap_pairs.cpp +++ b/test/doc/core/bit_swap_pairs.cpp @@ -12,9 +12,19 @@ int main() std::cout << std::showbase << std::hex; std::cout << "<- wi0 = " << wi0 << "\n"; std::cout << "<- wi1 = " << wi1 << "\n"; - std::cout << "<- wi2 = " << wi2 << "\n"; + std::cout << "<- wi2 = " << wi2 << "\n\n"; std::cout << "-> bit_swap_pairs(wi0, wi1, wi2) = " << eve::bit_swap_pairs(wi0, wi1, wi2) << "\n"; std::cout << "-> bit_swap_pairs[ignore_last(2)](wi0, wi1, wi2) = " << eve::bit_swap_pairs[eve::ignore_last(2)](wi0, wi1, wi2) << "\n"; - std::cout << "-> bit_swap_pairs[wi3 > 0](wi0, wi1, wi3) = " << eve::bit_swap_pairs[wi3 >= 0](wi0, wi1, wi3) << "\n"; + std::cout << "-> bit_swap_pairs[wi3 > 0](wi0, wi1, wi3) = " << eve::bit_swap_pairs[wi3 >= 0](wi0, wi1, wi3) << "\n\n"; + + std::cout << "-> bit_swap_pairs(wi0, 3, 2) = " << eve::bit_swap_pairs(wi0, 3, 2) << "\n"; + std::cout << "-> bit_swap_pairs[ignore_last(2)](wi0, 3, 2) = " << eve::bit_swap_pairs[eve::ignore_last(2)](wi0, 3, 2) << "\n"; + std::cout << "-> bit_swap_pairs[wi3 > 0](wi0, 3, 2) = " << eve::bit_swap_pairs[wi3 >= 0](wi0, 3, 2) << "\n\n"; + + auto i3 = eve::index_t<3>{}; + auto i2 = eve::index_t<2>{}; + std::cout << "-> bit_swap_pairs(wi0, i3, i2) = " << eve::bit_swap_pairs(wi0, i3, i2) << "\n"; + std::cout << "-> bit_swap_pairs[ignore_last(2)](wi0, i3, i2) = " << eve::bit_swap_pairs[eve::ignore_last(2)](wi0, i3, i2) << "\n"; + std::cout << "-> bit_swap_pairs[wi3 > 0](wi0, i3, i2) = " << eve::bit_swap_pairs[wi3 >= 0](wi0, i3, i2) << "\n\n"; } diff --git a/test/unit/module/core/bit_swap_pairs.cpp b/test/unit/module/core/bit_swap_pairs.cpp index 49c3d52729..4663466ae2 100644 --- a/test/unit/module/core/bit_swap_pairs.cpp +++ b/test/unit/module/core/bit_swap_pairs.cpp @@ -20,8 +20,21 @@ TTS_CASE_WITH("Check behavior of bit_swap_pairs(simd) on integral types", using v_t = eve::element_type_t; using eve::bit_swap_pairs; - TTS_EQUAL(bit_swap_pairs(a0, 0u, 7u), tts::map([](auto e) -> v_t { return eve::bit_swap_pairs(e, 0u, 7u); }, a0)) << a0 << '\n'; - TTS_EQUAL(eve::bit_swap_pairs[t](a0, 0u, 7u), eve::if_else(t, eve::bit_swap_pairs(a0, 0u, 7u), a0)); + // full scalar + TTS_EQUAL(eve::bit_swap_pairs(0b01010101, 0, 7), 0b11010100); + TTS_EQUAL(eve::bit_swap_pairs(0b01010101, eve::index<0>, eve::index<7>), 0b11010100); + + // scalar into wide + using wt = eve::wide>; + TTS_EQUAL(eve::bit_swap_pairs(0b01010101, wt{0}, wt{7}), wt{0b11010100}); + + // wide + TTS_EQUAL(bit_swap_pairs(a0, 0u, 7), tts::map([](auto e) -> v_t { return eve::bit_swap_pairs(e, 0, 7u); }, a0)) << a0 << '\n'; + TTS_EQUAL(bit_swap_pairs(a0, eve::index<0>, eve::index<7>), tts::map([](auto e) -> v_t { return eve::bit_swap_pairs(e, eve::index<0>, eve::index<7>); }, a0)) << a0 << '\n'; + + // wide masked + TTS_EQUAL(eve::bit_swap_pairs[t](a0, 0u, 7), eve::if_else(t, eve::bit_swap_pairs(a0, 0, 7u), a0)); + TTS_EQUAL(eve::bit_swap_pairs[t](a0, eve::index<0>, eve::index<7>), eve::if_else(t, eve::bit_swap_pairs(a0, eve::index<0>, eve::index<7>), a0)); eve::wide wn{[](auto i, auto) { return -i; }}; TTS_EQUAL(eve::bit_swap_pairs[wn > 0](a0, wn, 7), a0); diff --git a/test/unit/module/core/swap_pairs.cpp b/test/unit/module/core/swap_pairs.cpp index 7057be5ce8..80a8b116cc 100644 --- a/test/unit/module/core/swap_pairs.cpp +++ b/test/unit/module/core/swap_pairs.cpp @@ -13,17 +13,19 @@ //================================================================================================== TTS_CASE_WITH("Check behavior of swap_pairs(simd) on all types", eve::test::simd::all_types, - tts::generate(tts::randoms(eve::valmin, eve::valmax) - ) + tts::generate(tts::randoms(eve::valmin, eve::valmax)) ) (T const& a0) { - using v_t = eve::element_type_t; using eve::swap_pairs; - constexpr size_t S = eve::cardinal_v-1; + constexpr size_t S = eve::cardinal_v - 1; constexpr auto _0 = eve::index_t<0>(); constexpr auto _S = eve::index_t(); constexpr auto _H = eve::index_t(); - TTS_EQUAL(swap_pairs(a0, _0, _S), tts::map([_0, _S](auto e) -> v_t { return swap_pairs(e, _0, _S); }, a0)); - TTS_EQUAL(swap_pairs(a0, _0, _H), tts::map([_0, _H](auto e) -> v_t { return swap_pairs(e, _0, _H); }, a0)); + + T refS = [&](auto i, auto) { return i == 0 ? a0.get(S) : (i == S ? a0.get(0) : a0.get(i)); }; + T refH = [&](auto i, auto) { return i == 0 ? a0.get(S/2) : (i == S/2 ? a0.get(0) : a0.get(i)); }; + + TTS_EQUAL(swap_pairs(a0, _0, _S), refS); + TTS_EQUAL(swap_pairs(a0, _0, _H), refH); };