summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorcomex <comexk@gmail.com>2013-09-22 16:07:45 -0400
committercomex <comexk@gmail.com>2013-09-22 16:07:45 -0400
commit7fe440340f73dbfd95ad9a32de88e2dd70a26fa4 (patch)
treea1f240c2f73a7d3405bc56a4600b1b164c87a691 /Source/Core
parent6209067daa5121e383d173f7272bbf20bc108047 (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.h66
-rw-r--r--Source/Core/Common/Src/Atomic_Win32.h37
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);
}
}