@@ -489,6 +489,25 @@ GPUhdi() constexpr int32_t GPUCommonMath::Abs<int32_t>(int32_t x)
489489 return GPUCA_CHOICE (abs (x), abs (x), abs (x));
490490}
491491
492+ #ifdef __METAL__
493+ // The counters these operate on are plain integers in the transferred structures,
494+ // as they are for CUDA and HIP. MSL's atomic operations want metal::atomic, which
495+ // has the same size and alignment. The overload is picked by address space, and a
496+ // threadgroup pointer has to keep its own: casting one to a device atomic is an
497+ // error while the qualifier is visible, but a generic pointer resolves here to
498+ // device and the cast then goes through silently.
499+ template <class T >
500+ GPUdi () threadgroup metal::atomic<T>* GPUCommonMathMetalAtomic(threadgroup T* p)
501+ {
502+ return reinterpret_cast <threadgroup metal::atomic<T>*>(p);
503+ }
504+ template <class T >
505+ GPUdi () device metal::atomic<T>* GPUCommonMathMetalAtomic(T* p)
506+ {
507+ return (device metal::atomic<T>*)p;
508+ }
509+ #endif
510+
492511template <class S , class T >
493512GPUdi () uint32_t GPUCommonMath::AtomicExchInternal (S* addr, T val)
494513{
@@ -499,7 +518,7 @@ GPUdi() uint32_t GPUCommonMath::AtomicExchInternal(S* addr, T val)
499518#elif defined(GPUCA_GPUCODE) && (defined(__CUDACC__) || defined(__HIPCC__))
500519 return ::atomicExch (addr, val);
501520#elif defined(GPUCA_GPUCODE) && defined(__METAL__)
502- return atomic_exchange_explicit (addr, val, memory_order_relaxed);
521+ return atomic_exchange_explicit (GPUCommonMathMetalAtomic ( addr) , val, memory_order_relaxed);
503522#elif defined(WITH_OPENMP)
504523 uint32_t old;
505524 __atomic_exchange (addr, &val, &old, __ATOMIC_SEQ_CST);
@@ -519,7 +538,7 @@ GPUdi() bool GPUCommonMath::AtomicCASInternal(S* addr, T cmp, T val)
519538#elif defined(GPUCA_GPUCODE) && (defined(__CUDACC__) || defined(__HIPCC__))
520539 return ::atomicCAS (addr, cmp, val) == cmp;
521540#elif defined(GPUCA_GPUCODE) && defined(__METAL__)
522- return atomic_compare_exchange_weak_explicit (addr, &cmp, val, memory_order_relaxed, memory_order_relaxed);
541+ return atomic_compare_exchange_weak_explicit (GPUCommonMathMetalAtomic ( addr) , &cmp, val, memory_order_relaxed, memory_order_relaxed);
523542#elif defined(WITH_OPENMP)
524543 return __atomic_compare_exchange (addr, &cmp, &val, true , __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
525544#else
@@ -537,7 +556,7 @@ GPUdi() uint32_t GPUCommonMath::AtomicAddInternal(S* addr, T val)
537556#elif defined(GPUCA_GPUCODE) && (defined(__CUDACC__) || defined(__HIPCC__))
538557 return ::atomicAdd (addr, val);
539558#elif defined(GPUCA_GPUCODE) && defined(__METAL__)
540- return atomic_fetch_add_explicit (addr, val, memory_order_relaxed);
559+ return atomic_fetch_add_explicit (GPUCommonMathMetalAtomic ( addr) , val, memory_order_relaxed);
541560#elif defined(WITH_OPENMP)
542561 return __atomic_add_fetch (addr, val, __ATOMIC_SEQ_CST) - val;
543562#else
@@ -555,7 +574,7 @@ GPUdi() void GPUCommonMath::AtomicMaxInternal(S* addr, T val)
555574#elif defined(GPUCA_GPUCODE) && (defined(__CUDACC__) || defined(__HIPCC__))
556575 ::atomicMax (addr, val);
557576#elif defined(GPUCA_GPUCODE) && defined(__METAL__)
558- atomic_fetch_max_explicit (addr, val, memory_order_relaxed);
577+ atomic_fetch_max_explicit (GPUCommonMathMetalAtomic ( addr) , val, memory_order_relaxed);
559578#else
560579 S current;
561580 while ((current = *(volatile S*)addr) < val && !AtomicCASInternal (addr, current, val)) {
@@ -573,7 +592,7 @@ GPUdi() void GPUCommonMath::AtomicMinInternal(S* addr, T val)
573592#elif defined(GPUCA_GPUCODE) && (defined(__CUDACC__) || defined(__HIPCC__))
574593 ::atomicMin (addr, val);
575594#elif defined(GPUCA_GPUCODE) && defined(__METAL__)
576- atomic_fetch_min_explicit (addr, val, memory_order_relaxed);
595+ atomic_fetch_min_explicit (GPUCommonMathMetalAtomic ( addr) , val, memory_order_relaxed);
577596#else
578597 S current;
579598 while ((current = *(volatile S*)addr) > val && !AtomicCASInternal (addr, current, val)) {
0 commit comments