19#if ALPAKA_LANG_CUDA || ALPAKA_LANG_HIP
21namespace alpaka::onAcc::internalCompute
27 template<
typename T_Type>
28 using AtomicCasType = std::conditional_t<
31 std::conditional_t<
sizeof(T_Type) == 8u,
unsigned long long int,
void>>;
33 template<
typename T_Type>
34 static __device__
auto reinterpretAddress(T_Type* address)
35 -> AtomicCasType<T_Type>*
requires(
sizeof(T_Type) == 4u ||
sizeof(T_Type) == 8u) {
36 return reinterpret_cast<AtomicCasType<T_Type>*
>(address);
39 template<
typename T_Type>
40 static __device__
auto reinterpretValue(T_Type value)
41 -> AtomicCasType<T_Type>
requires(
sizeof(T_Type) == 4u ||
sizeof(T_Type) == 8u)
43 return std::bit_cast<AtomicCasType<T_Type>>(value);
55 typename TSfinae = void,
56 typename TDefer =
void>
57 struct EmulateAtomic :
private EmulationBase
60 static __device__
auto atomic(internal::CudaHipAtomic
const ctx, T*
const addr, T
const& value) -> T
62 auto*
const addressAsIntegralType = reinterpretAddress(addr);
63 using EmulatedType = std::decay_t<
decltype(*addressAsIntegralType)>;
68# if __has_builtin(__hip_atomic_load)
69 EmulatedType old{__hip_atomic_load(addressAsIntegralType, __ATOMIC_RELAXED, __HIP_MEMORY_SCOPE_AGENT)};
71 EmulatedType old{__atomic_load_n(addressAsIntegralType, __ATOMIC_RELAXED)};
74 EmulatedType old{*addressAsIntegralType};
80 T v = std::bit_cast<T>(assumed);
82 using Cas = Atomic::Op<alpaka::operation::Cas, internal::CudaHipAtomic, EmulatedType, T_Scope>;
83 old = Cas::atomicOp(ctx, addressAsIntegralType, assumed, reinterpretValue(v));
85 }
while(assumed != old);
86 return std::bit_cast<T>(old);
91 template<
typename T,
typename T_Scope>
92 struct EmulateAtomic<
alpaka::operation::Cas, internal::CudaHipAtomic, T, T_Scope> :
private EmulationBase
94 static __device__
auto atomic(
95 internal::CudaHipAtomic
const ctx,
100 auto*
const addressAsIntegralType = reinterpretAddress(addr);
101 using EmulatedType = std::decay_t<
decltype(*addressAsIntegralType)>;
102 EmulatedType reinterpretedCompare = reinterpretValue(compare);
103 EmulatedType reinterpretedValue = reinterpretValue(value);
106 = Atomic::Op<alpaka::operation::Cas, internal::CudaHipAtomic, EmulatedType, T_Scope>::atomicOp(
108 addressAsIntegralType,
109 reinterpretedCompare,
112 return std::bit_cast<T>(old);
117 template<
typename T,
typename T_Scope>
118 struct EmulateAtomic<
alpaka::operation::Sub, internal::CudaHipAtomic, T, T_Scope>
120 static __device__
auto atomic(internal::CudaHipAtomic
const ctx, T*
const addr, T
const& value) -> T
122 return Atomic::Op<alpaka::operation::Add, internal::CudaHipAtomic, T, T_Scope>::atomicOp(
130 template<
typename T,
typename T_Scope>
131 struct EmulateAtomic<
133 internal::CudaHipAtomic,
136 std::enable_if_t<std::is_floating_point_v<T>>>
138 static __device__
auto atomic(internal::CudaHipAtomic
const&, T*
const, T
const&) -> T
142 "EmulateAtomic<alpaka::operation::Dec> is not supported for floating point data types!");
148 template<
typename T,
typename T_Scope>
149 struct EmulateAtomic<
151 internal::CudaHipAtomic,
154 std::enable_if_t<std::is_floating_point_v<T>>>
156 static __device__
auto atomic(internal::CudaHipAtomic
const&, T*
const, T
const&) -> T
160 "EmulateAtomic<alpaka::operation::Inc> is not supported for floating point data types!");
166 template<
typename T,
typename T_Scope>
167 struct EmulateAtomic<
169 internal::CudaHipAtomic,
172 std::enable_if_t<std::is_floating_point_v<T>>>
174 static __device__
auto atomic(internal::CudaHipAtomic
const&, T*
const, T
const&) -> T
178 "EmulateAtomic<alpaka::operation::And> is not supported for floating point data types!");
184 template<
typename T,
typename T_Scope>
185 struct EmulateAtomic<
187 internal::CudaHipAtomic,
190 std::enable_if_t<std::is_floating_point_v<T>>>
192 static __device__
auto atomic(internal::CudaHipAtomic
const&, T*
const, T
const&) -> T
196 "EmulateAtomic<alpaka::operation::Or> is not supported for floating point data types!");
202 template<
typename T,
typename T_Scope>
203 struct EmulateAtomic<
205 internal::CudaHipAtomic,
208 std::enable_if_t<std::is_floating_point_v<T>>>
210 static __device__
auto atomic(internal::CudaHipAtomic
const&, T*
const, T
const&) -> T
214 "EmulateAtomic<alpaka::operation::Xor> is not supported for floating point data types!");
226 template<
typename TOp,
typename T,
typename T_Scope>
227 struct Atomic::Op<TOp, internal::CudaHipAtomic, T, T_Scope>
230 internal::CudaHipAtomic
const ctx,
231 [[maybe_unused]] T*
const addr,
232 [[maybe_unused]] T
const& value) -> T
235 sizeof(T) == 4u ||
sizeof(T) == 8u,
236 "atomicOp<TOp, internal::CudaHipAtomic, T>(atomic, addr, value) is not supported! Only 64 and "
237 "32bit atomics are supported.");
239 if constexpr(::AlpakaBuiltInAtomic<TOp, T, T_Scope>::value)
240 return ::AlpakaBuiltInAtomic<TOp, T, T_Scope>::atomic(addr, value);
242 else if constexpr(std::is_same_v<unsigned long int, T>)
244 if constexpr(
sizeof(T) == 4u && ::AlpakaBuiltInAtomic<TOp, unsigned int, T_Scope>::value)
245 return ::AlpakaBuiltInAtomic<TOp, unsigned int, T_Scope>::atomic(
246 reinterpret_cast<unsigned int*
>(addr),
247 static_cast<unsigned int>(value));
249 sizeof(T) == 8u && ::AlpakaBuiltInAtomic<TOp, unsigned long long int, T_Scope>::value)
251 return ::AlpakaBuiltInAtomic<TOp, unsigned long long int, T_Scope>::atomic(
252 reinterpret_cast<unsigned long long int*
>(addr),
253 static_cast<unsigned long long int>(value));
257 return detail::EmulateAtomic<TOp, internal::CudaHipAtomic, T, T_Scope>::atomic(ctx, addr, value);
261 template<
typename T,
typename T_Scope>
262 struct Atomic::Op<
alpaka::operation::Cas, internal::CudaHipAtomic, T, T_Scope>
265 [[maybe_unused]] internal::CudaHipAtomic
const ctx,
266 [[maybe_unused]] T*
const addr,
267 [[maybe_unused]] T
const& compare,
268 [[maybe_unused]] T
const& value) -> T
271 sizeof(T) == 4u ||
sizeof(T) == 8u,
272 "atomicOp<alpaka::operation::Cas, internal::CudaHipAtomic, T>(atomic, addr, compare, value) is not "
273 "supported! Only 64 and "
274 "32bit atomics are supported.");
276 if constexpr(::AlpakaBuiltInAtomic<alpaka::operation::Cas, T, T_Scope>::value)
277 return ::AlpakaBuiltInAtomic<alpaka::operation::Cas, T, T_Scope>::atomic(addr, compare, value);
279 else if constexpr(std::is_same_v<unsigned long int, T>)
282 sizeof(T) == 4u && ::AlpakaBuiltInAtomic<alpaka::operation::Cas, unsigned int, T_Scope>::value)
283 return ::AlpakaBuiltInAtomic<alpaka::operation::Cas, unsigned int, T_Scope>::atomic(
284 reinterpret_cast<unsigned int*
>(addr),
285 static_cast<unsigned int>(compare),
286 static_cast<unsigned int>(value));
289 && ::AlpakaBuiltInAtomic<alpaka::operation::Cas, unsigned long long int, T_Scope>::value)
291 return ::AlpakaBuiltInAtomic<alpaka::operation::Cas, unsigned long long int, T_Scope>::atomic(
292 reinterpret_cast<unsigned long long int*
>(addr),
293 static_cast<unsigned long long int>(compare),
294 static_cast<unsigned long long int>(value));
298 return detail::EmulateAtomic<alpaka::operation::Cas, internal::CudaHipAtomic, T, T_Scope>::atomic(
constexpr auto atomicOp(auto const &acc, T *const addr, T const &value, T_Scope const scope=T_Scope()) -> T
Executes the given operation atomically.