diff options
| author | comex <comexk@gmail.com> | 2013-09-22 16:07:45 -0400 |
|---|---|---|
| committer | comex <comexk@gmail.com> | 2013-09-22 16:07:45 -0400 |
| commit | 7fe440340f73dbfd95ad9a32de88e2dd70a26fa4 (patch) | |
| tree | a1f240c2f73a7d3405bc56a4600b1b164c87a691 /Source/Core | |
| parent | 6209067daa5121e383d173f7272bbf20bc108047 (diff) | |
Improve Atomic.h:
- For GCC, use intrinsics that will work on ARM.
- Add AtomicExchangeAcquire.
- Make Atomic{Load,LoadAcquire,Store,StoreRelease} work for any suitable type.
Diffstat (limited to 'Source/Core')
| -rw-r--r-- | Source/Core/Common/Src/Atomic_GCC.h | 66 | ||||
| -rw-r--r-- | Source/Core/Common/Src/Atomic_Win32.h | 37 |
2 files changed, 66 insertions, 37 deletions
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 void AtomicOr(volatile u32& target, u32 value) { + __sync_or_and_fetch(&target, value); } -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; + +#ifdef __clang__ +template <typename T> +_Atomic(T)* ToC11Atomic(volatile T* loc) +{ + return (_Atomic(T)*) loc; } -inline void AtomicOr(volatile u32& target, u32 value) { - __sync_or_and_fetch(&target, value); +#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 <typename T> +inline T AtomicLoad(volatile T& src) { + return __atomic_load_n(&src, __ATOMIC_RELAXED); +} + +template <typename T> +inline T AtomicLoadAcquire(volatile T& src) { + return __atomic_load_n(&src, __ATOMIC_ACQUIRE); } -inline void AtomicStore(volatile u32& dest, u32 value) { - dest = value; // 32-bit writes are always atomic. +template <typename T, typename U> +inline void AtomicStore(volatile T& dest, U value) { + __atomic_store_n(&dest, value, __ATOMIC_RELAXED); } -inline void AtomicStoreRelease(volatile u32& dest, u32 value) { - __sync_lock_test_and_set(&dest, value); // TODO: Wrong! This function is has acquire semantics. + +template <typename T, typename U> +inline void AtomicStoreRelease(volatile T& dest, U value) { + __atomic_store_n(&dest, value, __ATOMIC_RELEASE); +} + +template <typename T, typename U> +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); + _InterlockedDecrement((volatile LONG*)&target); } -inline u32 AtomicLoad(volatile u32& src) { +inline void AtomicOr(volatile u32& target, u32 value) { + _InterlockedOr((volatile LONG*)&target, (LONG)value); +} + +template <typename T> +inline T AtomicLoad(volatile T& src) { return src; // 32-bit reads are always atomic. } -inline u32 AtomicLoadAcquire(volatile u32& src) { - u32 result = src; // 32-bit reads are always atomic. + +template <typename T> +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; } -inline void AtomicOr(volatile u32& target, u32 value) { - _InterlockedOr((volatile LONG*)&target, (LONG)value); +template <typename T, typename U> +inline void AtomicStore(volatile T& dest, U value) { + dest = (T) value; // 32-bit writes are always atomic. } -inline void AtomicStore(volatile u32& dest, u32 value) { - dest = value; // 32-bit writes are always atomic. -} -inline void AtomicStoreRelease(volatile u32& dest, u32 value) { +template <typename T, typename U> +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 <typename T, typename U> +inline T* AtomicExchangeAcquire(T* volatile& loc, U newval) { + return (T*) _InterlockedExchangePointer_acq((void* volatile*) &loc, (void*) newval); } } |
