13 #include <type_traits>
15 #ifdef ALPAKA_ACC_SYCL_ENABLED
17 # include <sycl/sycl.hpp>
25 class AtomicGenericSycl
31 template<
typename THierarchy>
32 struct SyclMemoryScope
37 struct SyclMemoryScope<hierarchy::Grids>
39 static constexpr
auto value = sycl::memory_scope::device;
43 struct SyclMemoryScope<hierarchy::Blocks>
45 static constexpr
auto value = sycl::memory_scope::device;
49 struct SyclMemoryScope<hierarchy::Threads>
51 static constexpr
auto value = sycl::memory_scope::work_group;
55 inline auto get_global_ptr(T*
const addr)
57 return sycl::address_space_cast<sycl::access::address_space::global_space, sycl::access::decorated::no>(
62 inline auto get_local_ptr(T*
const addr)
64 return sycl::address_space_cast<sycl::access::address_space::local_space, sycl::access::decorated::no>(
68 template<
typename T,
typename THierarchy>
71 sycl::memory_order::relaxed,
72 SyclMemoryScope<THierarchy>::value,
73 sycl::access::address_space::global_space>;
75 template<
typename T,
typename THierarchy>
78 sycl::memory_order::relaxed,
79 SyclMemoryScope<THierarchy>::value,
80 sycl::access::address_space::local_space>;
82 template<
typename THierarchy,
typename T,
typename TOp>
83 inline auto callAtomicOp(T*
const addr, TOp&& op)
85 if(
auto ptr = get_global_ptr(addr); ptr !=
nullptr)
87 auto ref = global_ref<T, THierarchy>{*addr};
92 auto ref = local_ref<T, THierarchy>{*addr};
97 template<
typename TRef,
typename T,
typename TEval>
98 inline auto casWithCondition(T*
const addr, TEval&& eval)
100 auto ref = TRef{*addr};
101 auto old_val = ref.load();
104 while(!ref.compare_exchange_weak(old_val, eval(old_val)))
117 template<
typename T,
typename THierarchy>
118 struct AtomicOp<AtomicAdd, AtomicGenericSycl, T, THierarchy>
120 static_assert(std::is_integral_v<T> || std::is_floating_point_v<T>,
"SYCL atomics do not support this type");
122 static auto atomicOp(AtomicGenericSycl
const&, T*
const addr, T
const& value) -> T
124 return alpaka::detail::callAtomicOp<THierarchy>(
126 [&value](
auto& ref) {
return ref.fetch_add(value); });
132 template<
typename T,
typename THierarchy>
133 struct AtomicOp<AtomicSub, AtomicGenericSycl, T, THierarchy>
135 static_assert(std::is_integral_v<T> || std::is_floating_point_v<T>,
"SYCL atomics do not support this type");
137 static auto atomicOp(AtomicGenericSycl
const&, T*
const addr, T
const& value) -> T
139 return alpaka::detail::callAtomicOp<THierarchy>(
141 [&value](
auto& ref) {
return ref.fetch_sub(value); });
147 template<
typename T,
typename THierarchy>
148 struct AtomicOp<AtomicMin, AtomicGenericSycl, T, THierarchy>
150 static_assert(std::is_integral_v<T> || std::is_floating_point_v<T>,
"SYCL atomics do not support this type");
152 static auto atomicOp(AtomicGenericSycl
const&, T*
const addr, T
const& value) -> T
154 return alpaka::detail::callAtomicOp<THierarchy>(
156 [&value](
auto& ref) {
return ref.fetch_min(value); });
162 template<
typename T,
typename THierarchy>
163 struct AtomicOp<AtomicMax, AtomicGenericSycl, T, THierarchy>
165 static_assert(std::is_integral_v<T> || std::is_floating_point_v<T>,
"SYCL atomics do not support this type");
167 static auto atomicOp(AtomicGenericSycl
const&, T*
const addr, T
const& value) -> T
169 return alpaka::detail::callAtomicOp<THierarchy>(
171 [&value](
auto& ref) {
return ref.fetch_max(value); });
177 template<
typename T,
typename THierarchy>
178 struct AtomicOp<AtomicExch, AtomicGenericSycl, T, THierarchy>
181 (std::is_integral_v<T> || std::is_floating_point_v<T>) &&(
sizeof(T) == 4 ||
sizeof(T) == 8),
182 "SYCL atomics do not support this type");
184 static auto atomicOp(AtomicGenericSycl
const&, T*
const addr, T
const& value) -> T
186 return alpaka::detail::callAtomicOp<THierarchy>(addr, [&value](
auto& ref) {
return ref.exchange(value); });
192 template<
typename T,
typename THierarchy>
193 struct AtomicOp<AtomicInc, AtomicGenericSycl, T, THierarchy>
196 std::is_unsigned_v<T> && (
sizeof(T) == 4 ||
sizeof(T) == 8),
197 "SYCL atomics support only 32- and 64-bits unsigned integral types");
199 static auto atomicOp(AtomicGenericSycl
const&, T*
const addr, T
const& value) -> T
201 auto inc = [&value](
auto old_val)
202 {
return (old_val >= value) ?
static_cast<T
>(0) : (old_val +
static_cast<T
>(1)); };
203 if(
auto ptr = alpaka::detail::get_global_ptr(addr); ptr !=
nullptr)
204 return alpaka::detail::casWithCondition<alpaka::detail::global_ref<T, THierarchy>>(addr, inc);
206 return alpaka::detail::casWithCondition<alpaka::detail::local_ref<T, THierarchy>>(addr, inc);
212 template<
typename T,
typename THierarchy>
213 struct AtomicOp<AtomicDec, AtomicGenericSycl, T, THierarchy>
216 std::is_unsigned_v<T> && (
sizeof(T) == 4 ||
sizeof(T) == 8),
217 "SYCL atomics support only 32- and 64-bits unsigned integral types");
219 static auto atomicOp(AtomicGenericSycl
const&, T*
const addr, T
const& value) -> T
221 auto dec = [&value](
auto& old_val)
222 {
return ((old_val == 0) || (old_val > value)) ? value : (old_val -
static_cast<T
>(1)); };
223 if(
auto ptr = alpaka::detail::get_global_ptr(addr); ptr !=
nullptr)
224 return alpaka::detail::casWithCondition<alpaka::detail::global_ref<T, THierarchy>>(addr, dec);
226 return alpaka::detail::casWithCondition<alpaka::detail::local_ref<T, THierarchy>>(addr, dec);
232 template<
typename T,
typename THierarchy>
233 struct AtomicOp<AtomicAnd, AtomicGenericSycl, T, THierarchy>
235 static_assert(std::is_integral_v<T>,
"Bitwise operations only supported for integral types.");
237 static auto atomicOp(AtomicGenericSycl
const&, T*
const addr, T
const& value) -> T
239 return alpaka::detail::callAtomicOp<THierarchy>(
241 [&value](
auto& ref) {
return ref.fetch_and(value); });
247 template<
typename T,
typename THierarchy>
248 struct AtomicOp<AtomicOr, AtomicGenericSycl, T, THierarchy>
250 static_assert(std::is_integral_v<T>,
"Bitwise operations only supported for integral types.");
252 static auto atomicOp(AtomicGenericSycl
const&, T*
const addr, T
const& value) -> T
254 return alpaka::detail::callAtomicOp<THierarchy>(addr, [&value](
auto& ref) {
return ref.fetch_or(value); });
260 template<
typename T,
typename THierarchy>
261 struct AtomicOp<AtomicXor, AtomicGenericSycl, T, THierarchy>
263 static_assert(std::is_integral_v<T>,
"Bitwise operations only supported for integral types.");
265 static auto atomicOp(AtomicGenericSycl
const&, T*
const addr, T
const& value) -> T
267 return alpaka::detail::callAtomicOp<THierarchy>(
269 [&value](
auto& ref) {
return ref.fetch_xor(value); });
275 template<
typename T,
typename THierarchy>
276 struct AtomicOp<AtomicCas, AtomicGenericSycl, T, THierarchy>
278 static_assert(std::is_integral_v<T> || std::is_floating_point_v<T>,
"SYCL atomics do not support this type");
280 static auto atomicOp(AtomicGenericSycl
const&, T*
const addr, T
const& expected, T
const& desired) -> T
282 auto cas = [&expected, &desired](
auto& ref)
284 auto expected_ = expected;
290 ref.compare_exchange_strong(expected_, desired);
297 if(
auto ptr = alpaka::detail::get_global_ptr(addr); ptr !=
nullptr)
299 auto ref = alpaka::detail::global_ref<T, THierarchy>{*addr};
304 auto ref = alpaka::detail::local_ref<T, THierarchy>{*addr};
boost::atomic_ref< T > atomic_ref
The alpaka accelerator library.
ALPAKA_NO_HOST_ACC_WARNING ALPAKA_FN_HOST_ACC auto atomicOp(TAtomic const &atomic, T *const addr, T const &value, THierarchy const &=THierarchy()) -> T
Executes the given operation atomically.