From 6fac6da45f9ce4f2c92f65443ee6b7d27801c5c5 Mon Sep 17 00:00:00 2001 From: Joel Falcou Date: Fri, 19 Jan 2024 18:05:08 +0100 Subject: [PATCH] #1520 - scatter emulation --- include/eve/module/core/regular/core.hpp | 1 + .../eve/module/core/regular/impl/scatter.hpp | 42 +++++++++++ include/eve/module/core/regular/scatter.hpp | 74 +++++++++++++++++++ include/eve/traits/overload/supports.hpp | 17 +++++ test/doc/core/regular/scatter.cpp | 17 +++++ test/unit/module/core/scatter.cpp | 55 ++++++++++++++ 6 files changed, 206 insertions(+) create mode 100644 include/eve/module/core/regular/impl/scatter.hpp create mode 100644 include/eve/module/core/regular/scatter.hpp create mode 100644 test/doc/core/regular/scatter.cpp create mode 100644 test/unit/module/core/scatter.cpp diff --git a/include/eve/module/core/regular/core.hpp b/include/eve/module/core/regular/core.hpp index 43f101b9c9..1ed1d1782c 100644 --- a/include/eve/module/core/regular/core.hpp +++ b/include/eve/module/core/regular/core.hpp @@ -197,6 +197,7 @@ #include #include #include +#include #include #include #include diff --git a/include/eve/module/core/regular/impl/scatter.hpp b/include/eve/module/core/regular/impl/scatter.hpp new file mode 100644 index 0000000000..b043ff2578 --- /dev/null +++ b/include/eve/module/core/regular/impl/scatter.hpp @@ -0,0 +1,42 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include +#include + +namespace eve::detail +{ + template + EVE_FORCEINLINE void scatter_(EVE_REQUIRES(cpu_), O const& o, T const& v, Ptr p, Idx const& idx) + { + // Retrieve element to scatter + auto se = store_equivalent(o[condition_key],v,p); + + // Extract the pointer from a potential aligned_ptr + auto base = unalign(get<2>(se)); + + // Single-value scatter + auto sc = [&](auto n, auto c, auto v) + { + // We only write if mask is set + if constexpr(match_option) write(v.get(n),base+idx.get(n)); + else + { + auto m = c.mask( as>{} ); + if(m.get(n)) write(v.get(n),base+idx.get(n)); + } + }; + + // Scatter all (clang doesn't like capturing structured bindings) + eve::detail::for_<0, 1, T::size()>([&](auto... I) { ( sc(I,get<0>(se),get<1>(se)), ...); }); + } +} diff --git a/include/eve/module/core/regular/scatter.hpp b/include/eve/module/core/regular/scatter.hpp new file mode 100644 index 0000000000..9ffcf4c1ec --- /dev/null +++ b/include/eve/module/core/regular/scatter.hpp @@ -0,0 +1,74 @@ +//====================================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//====================================================================================================================== +#pragma once + +#include +#include +#include +#include +#include + +namespace eve +{ +template +struct scatter_t : callable +{ + template Ptr> + EVE_FORCEINLINE void operator()(T const& v, Ptr ptr, Idx const& idx) const noexcept { EVE_DISPATCH_CALL(v,ptr,idx); } + + EVE_CALLABLE_OBJECT(scatter_t, scatter_); +}; + +//====================================================================================================================== +//! @addtogroup core_arithmetic +//! @{ +//! @var scatter +//! @brief Store a SIMD register to memory using scattered indexes +//! +//! Store each element of a given [SIMD value](@ref eve::simd_value) `v`in different memory address computed form a base +//! SIMD compatible iterator `ptr` and a [SIMD integral value](@ref eve::integral_simd_value) `idx` used as indexes. +//! +//! A call to `eve::scatter(v,ptr,idx)` is semantically equivalent to: +//! +//! ``` +//! for(std::size_t i=0;i +//! @endcode +//! +//! @groupheader{Callable Signatures} +//! +//! @code +//! namespace eve +//! { +//! template Ptr> +//! void scatter(T const& v, Ptr ptr, Idx const& idx) noexcept; +//! } +//! @endcode +//! +//! **Parameters** +//! +//! * `v` : [SIMD value](@ref eve::simd_value) to scatter +//! * `ptr` : Base pointer to scatter to. +//! * `idx` : [Integral SIMD value](@ref eve::integral_simd_value) containing the index to scatter to. +//! +//! @groupheader{Example} +//! +//! @godbolt{doc/core/regular/scatter.cpp} +//! +//! @} +//====================================================================================================================== +inline constexpr auto scatter = functor; +} + +#include diff --git a/include/eve/traits/overload/supports.hpp b/include/eve/traits/overload/supports.hpp index 43309f44a8..32591e166c 100644 --- a/include/eve/traits/overload/supports.hpp +++ b/include/eve/traits/overload/supports.hpp @@ -260,6 +260,23 @@ namespace eve return options{new_opts}; } }; + + struct relative_conditional_no_alternative_option + { + template + EVE_FORCEINLINE constexpr auto process(auto const& base, Opt opt) const + requires( !Opt::has_alternative ) + { + auto new_opts = rbr::merge(options{condition_key = opt}, base); + return options{new_opts}; + } + + EVE_FORCEINLINE constexpr auto default_to(auto const& base) const + { + auto new_opts = rbr::merge(base, options{condition_key = ignore_none}); + return options{new_opts}; + } + }; } namespace eve::detail diff --git a/test/doc/core/regular/scatter.cpp b/test/doc/core/regular/scatter.cpp new file mode 100644 index 0000000000..558718a481 --- /dev/null +++ b/test/doc/core/regular/scatter.cpp @@ -0,0 +1,17 @@ +#include +#include + +int main() +{ + float data[2*eve::wide::size()] = {}; + + eve::wide indexes = [](auto i, auto) { return 2*i; }; + eve::wide values = [](auto i, auto) { return 1.5f * (1+i); }; + + eve::scatter(values, data, indexes); + + for(auto e : data) + std::cout << e << " "; + std::cout << "\n"; +} + diff --git a/test/unit/module/core/scatter.cpp b/test/unit/module/core/scatter.cpp new file mode 100644 index 0000000000..e88095163d --- /dev/null +++ b/test/unit/module/core/scatter.cpp @@ -0,0 +1,55 @@ +//================================================================================================== +/* + EVE - Expressive Vector Engine + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "test.hpp" + +#include +#include + +template +void test_scatter(T const& values, auto ptr) +{ + using e_t = eve::element_type_t; + eve::wide> indexes = [](auto i, auto) { return 2*i; }; + + e_t ref [2*T::size()]; + auto base = eve::unalign(ptr); + std::copy(base,base+2*T::size(),&ref[0]); + for( std::size_t i = 0; i < T::size(); ++i ) ref[indexes.get(i)] = values.get(i); + + eve::scatter(values, ptr, indexes); + + TTS_EXPECT(std::equal(&ref[0],&ref[0]+2*T::size(),base)); +} + +TTS_CASE_TPL("Check eve::scatter behavior with pointer", eve::test::simd::all_types) +(tts::type) +{ + using e_t = eve::element_type_t; + e_t data[2*T::size()]; + for( std::size_t i = 0; i < 2*T::size(); ++i ) data[i] = e_t(99); + T values = [](auto i, auto) { return 2*i+1; }; + + test_scatter(values,&data[0]); + test_scatter(values,&data[0]); + test_scatter(values,&data[0]); + test_scatter(values,&data[0]); +}; + +TTS_CASE_TPL("Check eve::scatter behavior with aligned_ptr", eve::test::simd::all_types) +(tts::type) +{ + using e_t = eve::element_type_t; + alignas(T::alignment()) e_t data[2*T::size()]; + for( std::size_t i = 0; i < 2*T::size(); ++i ) data[i] = e_t(99); + T values = [](auto i, auto) { return 2*i+1; }; + + test_scatter(values,eve::as_aligned(&data[0],typename T::cardinal_type{})); + test_scatter(values,eve::as_aligned(&data[0],typename T::cardinal_type{})); + test_scatter(values,eve::as_aligned(&data[0],typename T::cardinal_type{})); + test_scatter(values,eve::as_aligned(&data[0],typename T::cardinal_type{})); +};