1#ifndef AMREX_REDUCE_SIMD_H_
2#define AMREX_REDUCE_SIMD_H_
3#include <AMReX_Config.H>
18namespace Reduce::detail {
22 inline constexpr bool is_simd_reduce_op =
23 std::is_same_v<P, ReduceOpSum> ||
24 std::is_same_v<P, ReduceOpMin> ||
25 std::is_same_v<P, ReduceOpMax>;
27#if defined(AMREX_USE_SIMD) && !defined(AMREX_USE_GPU)
30 template <
int W,
typename T>
33 template <
int W,
typename... Ts>
34 struct MakeSIMDTuple<W, GpuTuple<Ts...>>
36 using type = GpuTuple<amrex::simd::stdx::fixed_size_simd<Ts, W>...>;
40 template <
typename P,
typename T>
44 using E =
typename T::value_type;
45 if constexpr (std::is_same_v<P, ReduceOpSum>) {
47 }
else if constexpr (std::is_same_v<P, ReduceOpMin>) {
48 t = T(std::numeric_limits<E>::max());
49 }
else if constexpr (std::is_same_v<P, ReduceOpMax>) {
50 t = T(std::numeric_limits<E>::lowest());
52 static_assert(is_simd_reduce_op<P>,
53 "SIMD reductions support only ReduceOpSum, ReduceOpMin and ReduceOpMax");
58 template <
typename P,
typename T>
60 void simd_local_update (T& d, T
const& s)
63 if constexpr (std::is_same_v<P, ReduceOpSum>) {
65 }
else if constexpr (std::is_same_v<P, ReduceOpMin>) {
67 }
else if constexpr (std::is_same_v<P, ReduceOpMax>) {
70 static_assert(is_simd_reduce_op<P>,
71 "SIMD reductions support only ReduceOpSum, ReduceOpMin and ReduceOpMax");
76 template <
typename P,
typename T,
typename S>
78 void simd_horizontal_update (T& d, S
const& s)
81 if constexpr (std::is_same_v<P, ReduceOpSum>) {
83 }
else if constexpr (std::is_same_v<P, ReduceOpMin>) {
85 }
else if constexpr (std::is_same_v<P, ReduceOpMax>) {
88 static_assert(is_simd_reduce_op<P>,
89 "SIMD reductions support only ReduceOpSum, ReduceOpMin and ReduceOpMax");
95 template <std::
size_t I,
typename T,
typename P>
97 void for_each_simd_init (T& t)
99 simd_init<P>(amrex::get<I>(t));
102 template <std::size_t I,
typename T,
typename P,
typename P1,
typename... Ps>
104 void for_each_simd_init (T& t)
106 simd_init<P>(amrex::get<I>(t));
107 for_each_simd_init<I+1,T,P1,Ps...>(t);
110 template <std::
size_t I,
typename T,
typename P>
112 void for_each_simd_local (T& d, T
const& s)
114 simd_local_update<P>(amrex::get<I>(d), amrex::get<I>(s));
117 template <std::size_t I,
typename T,
typename P,
typename P1,
typename... Ps>
119 void for_each_simd_local (T& d, T
const& s)
121 simd_local_update<P>(amrex::get<I>(d), amrex::get<I>(s));
122 for_each_simd_local<I+1,T,P1,Ps...>(d, s);
125 template <std::
size_t I,
typename TD,
typename TS,
typename P>
127 void for_each_horizontal (TD& d, TS
const& s)
129 simd_horizontal_update<P>(amrex::get<I>(d), amrex::get<I>(s));
132 template <std::size_t I,
typename TD,
typename TS,
typename P,
typename P1,
typename... Ps>
134 void for_each_horizontal (TD& d, TS
const& s)
136 simd_horizontal_update<P>(amrex::get<I>(d), amrex::get<I>(s));
137 for_each_horizontal<I+1,TD,TS,P1,Ps...>(d, s);
180template <
int WIDTH, std::integral N,
typename D,
typename F,
typename... Ps>
182void evalReduceSIMD (N n, D& reduce_data,
F const& f, ReduceOps<Ps...>& )
184 static_assert(WIDTH >= 1,
"evalReduceSIMD: WIDTH must be at least 1");
185 static_assert((Reduce::detail::is_simd_reduce_op<Ps> && ...),
186 "evalReduceSIMD supports only ReduceOpSum, ReduceOpMin and ReduceOpMax");
188 using ReduceTuple =
typename D::Type;
190 Reduce::detail::for_each_init<0, ReduceTuple, Ps...>(rr);
193 if constexpr (WIDTH > 1) {
194 using SimdTuple =
typename Reduce::detail::MakeSIMDTuple<WIDTH, ReduceTuple>::type;
195 static_assert(std::is_same_v<SimdTuple,
196 std::decay_t<
decltype(f(SIMDindex<WIDTH, N>{0}))>>,
197 "evalReduceSIMD: for SIMDindex<WIDTH> the callable must return the "
198 "SIMD-widened ReduceData tuple (fixed_size_simd of each component type). "
199 "Load particle/array data with amrex::simd::load_1d to get matching types.");
201 Reduce::detail::for_each_simd_init<0, SimdTuple, Ps...>(sr);
203 for (; i + WIDTH <= n; i += WIDTH) {
204 Reduce::detail::for_each_simd_local<0, SimdTuple, Ps...>(sr, f(SIMDindex<WIDTH, N>{i}));
206 Reduce::detail::for_each_horizontal<0, ReduceTuple, SimdTuple, Ps...>(rr, sr);
211 Reduce::detail::for_each_local<0, ReduceTuple, Ps...>(rr, f(SIMDindex<1, N>{i}));
213 Reduce::detail::for_each_local<0, ReduceTuple, Ps...>(
Compiler- and backend-specific extension macros (e.g., restrict, SIMD, inline).
#define AMREX_FORCE_INLINE
Definition AMReX_Extension.H:124
#define AMREX_ATTRIBUTE_FLATTEN_FOR
Definition AMReX_Extension.H:156
__host__ __device__ constexpr const T & min(const T &a, const T &b) noexcept
Definition AMReX_Algorithm.H:31
__host__ __device__ constexpr const T & max(const T &a, const T &b) noexcept
Definition AMReX_Algorithm.H:53
constexpr int get_thread_num()
Definition AMReX_OpenMP.H:37
Definition AMReX_SIMD.H:25
Definition AMReX_Amr.cpp:50