16 #ifdef __SYCL_DEVICE_ONLY__
21 #ifndef __SYCL_DEVICE_ONLY__
24 #include <type_traits>
34 static constexpr
bool value =
35 (std::is_same<T, int>::value || std::is_same<T, unsigned int>::value ||
36 std::is_same<T, long>::value || std::is_same<T, unsigned long>::value ||
37 std::is_same<T, long long>::value ||
38 std::is_same<T, unsigned long long>::value ||
39 std::is_same<T, float>::value || std::is_same<T, double>::value ||
40 std::is_pointer<T>::value);
44 static constexpr
bool value =
45 (AS == access::address_space::global_space ||
46 AS == access::address_space::local_space ||
47 AS == access::address_space::ext_intel_global_device_space ||
48 AS == access::address_space::generic_space);
52 template <memory_order Order>
54 Order == memory_order::acq_rel ||
55 Order == memory_order::seq_cst>;
76 case memory_order::relaxed:
77 return memory_order::relaxed;
79 case memory_order::acquire:
80 case memory_order::__consume_unsupported:
81 case memory_order::acq_rel:
82 case memory_order::release:
83 return memory_order::acquire;
85 case memory_order::seq_cst:
86 return memory_order::seq_cst;
90 template <
typename T,
typename =
void>
struct bit_equal;
94 bool operator()(
const T &lhs,
const T &rhs) {
return lhs == rhs; }
99 auto LhsInt = sycl::bit_cast<uint32_t>(lhs);
100 auto RhsInt = sycl::bit_cast<uint32_t>(rhs);
101 return LhsInt == RhsInt;
107 auto LhsInt = sycl::bit_cast<uint64_t>(lhs);
108 auto RhsInt = sycl::bit_cast<uint64_t>(rhs);
109 return LhsInt == RhsInt;
119 "Invalid atomic type. Valid types are int, unsigned int, long, "
120 "unsigned long, long long, unsigned long long, float, double "
121 "and pointer types");
123 "Invalid atomic address_space. Valid address spaces are: "
124 "global_space, local_space, ext_intel_global_device_space, "
128 "Invalid default memory_order for atomics. Valid defaults are: "
129 "relaxed, acq_rel, seq_cst");
132 static_assert(DefaultOrder != sycl::memory_order::seq_cst,
133 "seq_cst memory order is not supported on AMDGPU");
139 static constexpr
size_t required_alignment =
sizeof(T);
140 static constexpr
bool is_always_lock_free =
146 static constexpr
memory_order default_read_modify_write_order = DefaultOrder;
153 #ifdef __SYCL_DEVICE_ONLY__
159 : ptr(reinterpret_cast<
std::atomic<T> *>(&ref)) {}
168 #ifdef __SYCL_DEVICE_ONLY__
169 detail::spirv::AtomicStore(ptr, scope, order, operand);
183 #ifdef __SYCL_DEVICE_ONLY__
184 return detail::spirv::AtomicLoad(ptr, scope, order);
191 operator T() const noexcept {
return load(); }
195 #ifdef __SYCL_DEVICE_ONLY__
196 return detail::spirv::AtomicExchange(ptr, scope, order, operand);
207 #ifdef __SYCL_DEVICE_ONLY__
208 T value = detail::spirv::AtomicCompareExchange(ptr, scope,
success, failure,
217 return ptr->compare_exchange_strong(expected, desired,
227 return compare_exchange_strong(expected, desired, order, order, scope);
237 #ifdef __SYCL_DEVICE_ONLY__
238 return compare_exchange_strong(expected, desired,
success, failure, scope);
241 return ptr->compare_exchange_weak(expected, desired,
251 return compare_exchange_weak(expected, desired, order, order, scope);
255 #ifdef __SYCL_DEVICE_ONLY__
263 template <
typename T,
bool IsAspectAtomic64AttrUsed,
memory_order DefaultOrder,
267 :
public atomic_ref_base<T, DefaultOrder, DefaultScope, AddressSpace> {
274 template <
typename T,
bool IsAspectAtomic64AttrUsed,
memory_order DefaultOrder,
278 typename detail::
enable_if_t<std::is_integral<T>::value>>
279 :
public atomic_ref_base<T, DefaultOrder, DefaultScope, AddressSpace> {
284 static constexpr
size_t required_alignment =
sizeof(T);
285 static constexpr
bool is_always_lock_free =
291 static constexpr
memory_order default_read_modify_write_order = DefaultOrder;
298 AddressSpace>::compare_exchange_weak;
303 #ifdef __SYCL_DEVICE_ONLY__
304 return detail::spirv::AtomicIAdd(ptr, scope, order, operand);
312 return fetch_add(operand) + operand;
322 return fetch_add(1) + 1;
327 #ifdef __SYCL_DEVICE_ONLY__
328 return detail::spirv::AtomicISub(ptr, scope, order, operand);
336 return fetch_sub(operand) - operand;
346 return fetch_sub(1) - 1;
351 #ifdef __SYCL_DEVICE_ONLY__
352 return detail::spirv::AtomicAnd(ptr, scope, order, operand);
360 return fetch_and(operand) & operand;
365 #ifdef __SYCL_DEVICE_ONLY__
366 return detail::spirv::AtomicOr(ptr, scope, order, operand);
373 T
operator|=(T operand)
const noexcept {
return fetch_or(operand) | operand; }
377 #ifdef __SYCL_DEVICE_ONLY__
378 return detail::spirv::AtomicXor(ptr, scope, order, operand);
386 return fetch_xor(operand) ^ operand;
391 #ifdef __SYCL_DEVICE_ONLY__
392 return detail::spirv::AtomicMin(ptr, scope, order, operand);
395 T old = load(load_order, scope);
396 while (operand < old &&
397 !compare_exchange_weak(old, operand, order, scope)) {
405 #ifdef __SYCL_DEVICE_ONLY__
406 return detail::spirv::AtomicMax(ptr, scope, order, operand);
409 T old = load(load_order, scope);
410 while (operand > old &&
411 !compare_exchange_weak(old, operand, order, scope)) {
422 template <
typename T,
bool IsAspectAtomic64AttrUsed,
memory_order DefaultOrder,
425 T, IsAspectAtomic64AttrUsed, DefaultOrder, DefaultScope, AddressSpace,
426 typename detail::
enable_if_t<std::is_floating_point<T>::value>>
427 :
public atomic_ref_base<T, DefaultOrder, DefaultScope, AddressSpace> {
432 static constexpr
size_t required_alignment =
sizeof(T);
433 static constexpr
bool is_always_lock_free =
439 static constexpr
memory_order default_read_modify_write_order = DefaultOrder;
446 AddressSpace>::compare_exchange_weak;
453 #if defined(__SYCL_DEVICE_ONLY__) && defined(SYCL_USE_NATIVE_FP_ATOMICS)
454 return detail::spirv::AtomicFAdd(ptr, scope, order, operand);
461 load(load_order, scope);
462 desired = expected + operand;
463 }
while (!compare_exchange_weak(expected, desired, order, scope));
469 return fetch_add(operand) + operand;
476 #if defined(__SYCL_DEVICE_ONLY__) && defined(SYCL_USE_NATIVE_FP_ATOMICS)
477 return detail::spirv::AtomicFAdd(ptr, scope, order, -operand);
480 T expected = load(load_order, scope);
483 desired = expected - operand;
484 }
while (!compare_exchange_weak(expected, desired, order, scope));
490 return fetch_sub(operand) - operand;
497 #if defined(__SYCL_DEVICE_ONLY__) && defined(SYCL_USE_NATIVE_FP_ATOMICS)
498 return detail::spirv::AtomicMin(ptr, scope, order, operand);
501 T old = load(load_order, scope);
502 while (operand < old &&
503 !compare_exchange_weak(old, operand, order, scope)) {
513 #if defined(__SYCL_DEVICE_ONLY__) && defined(SYCL_USE_NATIVE_FP_ATOMICS)
514 return detail::spirv::AtomicMax(ptr, scope, order, operand);
517 T old = load(load_order, scope);
518 while (operand > old &&
519 !compare_exchange_weak(old, operand, order, scope)) {
533 #ifndef __SYCL_DEVICE_ONLY__
536 class [[__sycl_detail__::__uses_aspects__(aspect::atomic64)]]
atomic_ref_impl<
538 T, true, DefaultOrder, DefaultScope,
539 AddressSpace, typename detail::enable_if_t<std::is_integral<T>::value>>
541 DefaultOrder, DefaultScope, AddressSpace> {
546 DefaultScope, AddressSpace>::atomic_ref_impl::operator=;
553 #ifndef __SYCL_DEVICE_ONLY__
556 class [[__sycl_detail__::__uses_aspects__(aspect::atomic64)]]
atomic_ref_impl<
558 T, true, DefaultOrder, DefaultScope,
560 typename detail::enable_if_t<std::is_floating_point<T>::value>>
562 DefaultOrder, DefaultScope, AddressSpace> {
567 DefaultScope, AddressSpace>::atomic_ref_impl::operator=;
575 class atomic_ref_impl<T *, IsAspectAtomic64AttrUsed, DefaultOrder, DefaultScope, AddressSpace>
586 static constexpr
size_t required_alignment =
sizeof(T *);
587 static constexpr
bool is_always_lock_free =
593 static constexpr
memory_order default_read_modify_write_order = DefaultOrder;
596 using base_type::is_lock_free;
599 :
base_type(reinterpret_cast<uintptr_t &>(ref)) {}
603 base_type::store(
reinterpret_cast<uintptr_t
>(operand), order, scope);
613 return reinterpret_cast<T *
>(base_type::load(order, scope));
616 operator T *()
const noexcept {
return load(); }
620 return reinterpret_cast<T *
>(base_type::exchange(
621 reinterpret_cast<uintptr_t
>(operand), order, scope));
632 expected = load(load_order, scope);
633 desired = expected + operand;
634 }
while (!compare_exchange_weak(expected, desired, order, scope));
639 return fetch_add(operand) + operand;
653 T *expected = load(load_order, scope);
656 desired = expected - operand;
657 }
while (!compare_exchange_weak(expected, desired, order, scope));
662 return fetch_sub(operand) - operand;
675 return base_type::compare_exchange_strong(
676 reinterpret_cast<uintptr_t &
>(expected),
677 reinterpret_cast<uintptr_t
>(desired),
success, failure, scope);
684 return compare_exchange_strong(expected, desired, order, order, scope);
691 return base_type::compare_exchange_weak(
692 reinterpret_cast<uintptr_t &
>(expected),
693 reinterpret_cast<uintptr_t
>(desired),
success, failure, scope);
700 return compare_exchange_weak(expected, desired, order, order, scope);
704 using base_type::ptr;
711 access::address_space::generic_space>
717 DefaultScope, AddressSpace> {
720 AddressSpace>::atomic_ref_impl;
722 AddressSpace>::
operator=;