diff --git a/Source/Core/Common/Src/Atomic_GCC.h b/Source/Core/Common/Src/Atomic_GCC.h index f923ba8b5e..d255c72bc1 100644 --- a/Source/Core/Common/Src/Atomic_GCC.h +++ b/Source/Core/Common/Src/Atomic_GCC.h @@ -40,27 +40,45 @@ inline void AtomicIncrement(volatile u32& target) { __sync_add_and_fetch(&target, 1); } -inline u32 AtomicLoad(volatile u32& src) { - return src; // 32-bit reads are always atomic. -} -inline u32 AtomicLoadAcquire(volatile u32& src) { - //keep the compiler from caching any memory references - u32 result = src; // 32-bit reads are always atomic. - //__sync_synchronize(); // TODO: May not be necessary. - // Compiler instruction only. x86 loads always have acquire semantics. - __asm__ __volatile__ ( "":::"memory" ); - return result; -} - inline void AtomicOr(volatile u32& target, u32 value) { __sync_or_and_fetch(&target, value); } -inline void AtomicStore(volatile u32& dest, u32 value) { - dest = value; // 32-bit writes are always atomic. +#ifdef __clang__ +template +_Atomic(T)* ToC11Atomic(volatile T* loc) +{ + return (_Atomic(T)*) loc; } -inline void AtomicStoreRelease(volatile u32& dest, u32 value) { - __sync_lock_test_and_set(&dest, value); // TODO: Wrong! This function is has acquire semantics. + +#define __atomic_load_n(p, m) __c11_atomic_load(ToC11Atomic(p), m) +#define __atomic_store_n(p, v, m) __c11_atomic_store(ToC11Atomic(p), v, m) +#define __atomic_exchange_n(p, v, m) __c11_atomic_exchange(ToC11Atomic(p), v, m) +#endif + +template +inline T AtomicLoad(volatile T& src) { + return __atomic_load_n(&src, __ATOMIC_RELAXED); +} + +template +inline T AtomicLoadAcquire(volatile T& src) { + return __atomic_load_n(&src, __ATOMIC_ACQUIRE); +} + +template +inline void AtomicStore(volatile T& dest, U value) { + __atomic_store_n(&dest, value, __ATOMIC_RELAXED); +} + +template +inline void AtomicStoreRelease(volatile T& dest, U value) { + __atomic_store_n(&dest, value, __ATOMIC_RELEASE); +} + +template +inline T* AtomicExchangeAcquire(T* volatile& loc, U newval) { + return __atomic_exchange_n(&loc, newval, __ATOMIC_ACQ_REL); } } @@ -74,9 +92,9 @@ LONG SyncInterlockedIncrement(LONG *Dest) #else register int result; __asm__ __volatile__("lock; xadd %0,%1" - : "=r" (result), "=m" (*Dest) - : "0" (1), "m" (*Dest) - : "memory"); + : "=r" (result), "=m" (*Dest) + : "0" (1), "m" (*Dest) + : "memory"); return result; #endif } @@ -88,9 +106,9 @@ LONG SyncInterlockedExchangeAdd(LONG *Dest, LONG Val) #else register int result; __asm__ __volatile__("lock; xadd %0,%1" - : "=r" (result), "=m" (*Dest) - : "0" (Val), "m" (*Dest) - : "memory"); + : "=r" (result), "=m" (*Dest) + : "0" (Val), "m" (*Dest) + : "memory"); return result; #endif } @@ -102,9 +120,9 @@ LONG SyncInterlockedExchange(LONG *Dest, LONG Val) #else register int result; __asm__ __volatile__("lock; xchg %0,%1" - : "=r" (result), "=m" (*Dest) - : "0" (Val), "m" (*Dest) - : "memory"); + : "=r" (result), "=m" (*Dest) + : "0" (Val), "m" (*Dest) + : "memory"); return result; #endif } diff --git a/Source/Core/Common/Src/Atomic_Win32.h b/Source/Core/Common/Src/Atomic_Win32.h index 1b05f8e777..7ce1381938 100644 --- a/Source/Core/Common/Src/Atomic_Win32.h +++ b/Source/Core/Common/Src/Atomic_Win32.h @@ -31,7 +31,7 @@ namespace Common { inline void AtomicAdd(volatile u32& target, u32 value) { - InterlockedExchangeAdd((volatile LONG*)&target, (LONG)value); + _InterlockedExchangeAdd((volatile LONG*)&target, (LONG)value); } inline void AtomicAnd(volatile u32& target, u32 value) { @@ -39,32 +39,43 @@ inline void AtomicAnd(volatile u32& target, u32 value) { } inline void AtomicIncrement(volatile u32& target) { - InterlockedIncrement((volatile LONG*)&target); + _InterlockedIncrement((volatile LONG*)&target); } inline void AtomicDecrement(volatile u32& target) { - InterlockedDecrement((volatile LONG*)&target); -} - -inline u32 AtomicLoad(volatile u32& src) { - return src; // 32-bit reads are always atomic. -} -inline u32 AtomicLoadAcquire(volatile u32& src) { - u32 result = src; // 32-bit reads are always atomic. - _ReadBarrier(); // Compiler instruction only. x86 loads always have acquire semantics. - return result; + _InterlockedDecrement((volatile LONG*)&target); } inline void AtomicOr(volatile u32& target, u32 value) { _InterlockedOr((volatile LONG*)&target, (LONG)value); } -inline void AtomicStore(volatile u32& dest, u32 value) { - dest = value; // 32-bit writes are always atomic. +template +inline T AtomicLoad(volatile T& src) { + return src; // 32-bit reads are always atomic. } -inline void AtomicStoreRelease(volatile u32& dest, u32 value) { + +template +inline T AtomicLoadAcquire(volatile T& src) { + T result = src; // 32-bit reads are always atomic. + _ReadBarrier(); // Compiler instruction only. x86 loads always have acquire semantics. + return result; +} + +template +inline void AtomicStore(volatile T& dest, U value) { + dest = (T) value; // 32-bit writes are always atomic. +} + +template +inline void AtomicStoreRelease(volatile T& dest, U value) { _WriteBarrier(); // Compiler instruction only. x86 stores always have release semantics. - dest = value; // 32-bit writes are always atomic. + dest = (T) value; // 32-bit writes are always atomic. +} + +template +inline T* AtomicExchangeAcquire(T* volatile& loc, U newval) { + return (T*) _InterlockedExchangePointer_acq((void* volatile*) &loc, (void*) newval); } }