16#include <batchlas/backend_config.h>
18#include <sycl/sycl.hpp>
28#if BATCHLAS_SYCL_IMPL_ACPP || defined(BATCHLAS_DOXYGEN)
35inline constexpr bool kSplitWords =
sizeof(T) > 8 || (
sizeof(T) & (
sizeof(T) - 1)) != 0;
42template <
typename T,
typename Op>
46template <
typename T,
typename F>
48 static_assert(std::is_trivially_copyable_v<T>,
"group collectives need a trivially copyable T");
49 using W = std::conditional_t<
sizeof(T) % 8 == 0, std::uint64_t, std::uint32_t>;
50 constexpr std::size_t kN = (
sizeof(T) +
sizeof(W) - 1) /
sizeof(W);
52 std::memcpy(w, &v,
sizeof(T));
53#pragma clang loop unroll(full)
54 for (std::size_t i = 0; i < kN; ++i) w[i] = f(w[i]);
56 std::memcpy(&out, w,
sizeof(T));
66inline constexpr bool kFloating = std::is_floating_point_v<T> || std::is_same_v<T, sycl::half>;
70template <
typename R,
int N>
71struct sycl_vec<sycl::vec<R, N>> : std::true_type {
73 static constexpr int size = N;
77template <
typename Op,
typename R>
79template <
template <
typename>
class OpT,
typename V,
typename R>
91 __acpp_if_target_sscp(
92 r =
static_cast<int>(sycl::AdaptiveCpp_jit::reflect<
93 sycl::AdaptiveCpp_jit::reflection_query::compiler_backend>()) == 4;)
101 __acpp_if_target_sscp(
static __attribute__((loader_uninitialized))
111template <
typename Group,
typename T,
typename Op>
114 __acpp_if_target_host(
return sycl::reduce_over_group(g, x, op);)
116 if (on_metal())
return sycl::reduce_over_group(g, x, op);
117 const sycl::sub_group sg{};
118 const T s = sycl::reduce_over_group(sg, x, op);
119 const std::uint32_t width = sg.get_max_local_range()[0];
120 const std::uint32_t nsg = (
static_cast<std::uint32_t
>(g.get_local_linear_range()) + width - 1) / width;
121 if (nsg == 1)
return s;
122 const std::uint32_t lid =
static_cast<std::uint32_t
>(g.get_local_linear_id());
123 const std::uint32_t sgid = lid / width;
124 const bool leader = sg.get_local_linear_id() == 0;
126 if (leader && sgid < 32) buf[sgid] = s;
127 sycl::group_barrier(g);
128 for (std::uint32_t i = 32; i < nsg; i += 32) {
129 if (leader && sgid >= i && sgid < i + 32) buf[sgid % 32] = op(T(buf[sgid % 32]), s);
130 sycl::group_barrier(g);
134 for (std::uint32_t k = 1; k < (nsg < 32 ? nsg : 32); ++k) acc = op(acc, T(buf[k]));
137 sycl::group_barrier(g);
138 const T r = T(buf[0]);
139 sycl::group_barrier(g);
149template <
typename Group,
typename T,
typename... Id>
150 requires sycl::is_group_v<Group>
153 return detail::map_words(x, [&](
auto w) {
return sycl::group_broadcast(g, w,
id...); });
155 return sycl::group_broadcast(g, x,
id...);
160template <
typename Group,
typename T,
typename Id>
161 requires sycl::is_group_v<Group>
164 return detail::map_words(x, [&](
auto w) {
return sycl::select_from_group(g, w,
id); });
166 return sycl::select_from_group(g, x,
id);
171template <
typename Group,
typename T,
typename... Delta>
172 requires sycl::is_group_v<Group>
175 return detail::map_words(x, [&](
auto w) {
return sycl::shift_group_left(g, w, delta...); });
177 return sycl::shift_group_left(g, x, delta...);
182template <
typename Group,
typename T,
typename... Delta>
183 requires sycl::is_group_v<Group>
186 return detail::map_words(x, [&](
auto w) {
return sycl::shift_group_right(g, w, delta...); });
188 return sycl::shift_group_right(g, x, delta...);
193template <
typename Group,
typename T,
typename Mask>
194 requires sycl::is_group_v<Group>
197 return detail::map_words(x, [&](
auto w) {
return sycl::permute_group_by_xor(g, w, mask); });
199 return sycl::permute_group_by_xor(g, x, mask);
205template <
typename Group,
typename T,
typename Op>
206 requires sycl::is_group_v<Group>
209 using R =
typename T::value_type;
220 for (
int i = 0; i < detail::sycl_vec<T>::size; ++i)
224 return sycl::reduce_over_group(g, x, op);
230template <
typename Group,
typename Ptr,
typename T,
typename Op>
231 requires sycl::is_group_v<Group>
235 for (Ptr p = first + g.get_local_linear_id(); p < last; p += g.get_local_linear_range()) part += *p;
240 T part = sycl::known_identity_v<Op, T>;
241 for (Ptr p = first + g.get_local_linear_id(); p < last; p += g.get_local_linear_range())
242 part = op(part,
static_cast<T
>(*p));
245 return sycl::joint_reduce(g, first, last, init, op);
251template <
typename Group,
typename Ptr,
typename Op>
252 requires sycl::is_group_v<Group>
254 using T = std::remove_cv_t<std::remove_reference_t<
decltype(*first)>>;
257 if (first == last)
return T{};
263 return sycl::joint_reduce(g, first, last, op);
269template <
typename Group,
typename InPtr,
typename OutPtr,
typename T,
typename Op>
270 requires sycl::is_group_v<Group>
273 static_assert(std::is_integral_v<T>,
"portable::joint_exclusive_scan: integral T only");
276 const std::ptrdiff_t n = last - first;
277 const std::ptrdiff_t lid =
static_cast<std::ptrdiff_t
>(g.get_local_linear_id());
278 const std::ptrdiff_t width =
static_cast<std::ptrdiff_t
>(g.get_local_linear_range());
280 for (std::ptrdiff_t chunk = 0; chunk < n; chunk += width) {
281 const std::ptrdiff_t i = chunk + lid;
282 const T x = i < n ? static_cast<T>(first[i]) : carry;
283 const T out = sycl::exclusive_scan_over_group(g, x, carry, op);
284 if (i < n) result[i] = out;
287 sycl::group_barrier(g);
295using sycl::group_broadcast;
296using sycl::joint_exclusive_scan;
297using sycl::joint_reduce;
298using sycl::permute_group_by_xor;
299using sycl::reduce_over_group;
300using sycl::select_from_group;
301using sycl::shift_group_left;
302using sycl::shift_group_right;
T reduce_over_group(Group g, T x, Op op)
sycl::reduce_over_group, also for a std::complex sum; a work-group floating result is exact (see deta...
T shift_group_right(Group g, T x, Delta... delta)
sycl::shift_group_right for any trivially copyable T. Collective.
T shift_group_left(Group g, T x, Delta... delta)
sycl::shift_group_left for any trivially copyable T. Collective.
T select_from_group(Group g, T x, Id id)
sycl::select_from_group for any trivially copyable T. Collective.
T permute_group_by_xor(Group g, T x, Mask mask)
sycl::permute_group_by_xor for any trivially copyable T. Collective.
T group_broadcast(Group g, T x, Id... id)
sycl::group_broadcast for any trivially copyable T. Collective.
OutPtr joint_exclusive_scan(Group g, InPtr first, InPtr last, OutPtr result, T init, Op op)
sycl::joint_exclusive_scan with an initial value; result may equal first.
T joint_reduce(Group g, Ptr first, Ptr last, T init, Op op)
sycl::joint_reduce with an initial value, also for a std::complex sum.
constexpr bool kSplitWords
constexpr bool kWorkGroup
T map_words(const T &v, F &&f)
T wg_reduce_floating(Group g, T x, Op op)
__attribute__((always_inline)) inline bool on_metal()
constexpr bool kSplitComplexSum
__attribute__((address_space(3))) T * local_ptr
static constexpr int size