From 09fbda603c82a63d27f8c5ccdb428f278d9a3b23 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Fri, 10 Oct 2014 22:19:14 +0400 Subject: [PATCH] Atomic intrinsics refactoring --- Utilities/BEType.h | 23 ++++++ Utilities/GNU.h | 130 ++++++++++++++++++++++++++++----- rpcs3/Emu/Memory/atomic_type.h | 2 +- 3 files changed, 137 insertions(+), 18 deletions(-) diff --git a/Utilities/BEType.h b/Utilities/BEType.h index 86f47f0815..1a7756347c 100644 --- a/Utilities/BEType.h +++ b/Utilities/BEType.h @@ -303,6 +303,29 @@ union u128 } }; +#ifndef InterlockedCompareExchange +static __forceinline u128 InterlockedCompareExchange(volatile u128* dest, u128 exch, u128 comp) +{ +#if defined(__GNUG__) + auto res = __sync_val_compare_and_swap((volatile __int128_t*)dest, (__int128_t&)comp, (__int128_t&)exch); + return (u128&)res; +#else + u128 cmp = comp; + _InterlockedCompareExchange128((volatile long long*)dest, exch._u64[1], exch._u64[0], (long long*)&cmp); + return cmp; +#endif +} +#endif + +static __forceinline bool InterlockedCompareExchangeTest(volatile u128* dest, u128 exch, u128 comp) +{ +#if defined(__GNUG__) + return __sync_bool_compare_and_swap((volatile __int128_t*)dest, (__int128_t&)comp, (__int128_t&)exch); +#else + return _InterlockedCompareExchange128((volatile long long*)dest, exch._u64[1], exch._u64[0], (long long*)&comp) != 0; +#endif +} + #define re16(val) _byteswap_ushort(val) #define re32(val) _byteswap_ulong(val) #define re64(val) _byteswap_uint64(val) diff --git a/Utilities/GNU.h b/Utilities/GNU.h index e0dd758e2c..14eef264f6 100644 --- a/Utilities/GNU.h +++ b/Utilities/GNU.h @@ -46,23 +46,6 @@ void strcpy_trunc(char(&dst)[size], const char(&src)[rsize]) #define _byteswap_uint64(x) __builtin_bswap64(x) #define INFINITE 0xFFFFFFFF #define _CRT_ALIGN(x) __attribute__((aligned(x))) -#define InterlockedCompareExchange(ptr,new_val,old_val) __sync_val_compare_and_swap(ptr,old_val,new_val) -#define InterlockedExchange(ptr, value) __sync_lock_test_and_set(ptr, value) -#define InterlockedOr(ptr, value) __sync_fetch_and_or(ptr, value) -#define InterlockedAnd(ptr, value) __sync_fetch_and_and(ptr, value) -#define InterlockedXor(ptr, value) __sync_fetch_and_xor(ptr, value) - -//inline int64_t InterlockedOr64(volatile int64_t *dest, int64_t val) -//{ -// int64_t olderval; -// int64_t oldval = *dest; -// do -// { -// olderval = oldval; -// oldval = __sync_val_compare_and_swap(dest, olderval | val, olderval); -// } while (olderval != oldval); -// return oldval; -//} inline uint64_t __umulh(uint64_t a, uint64_t b) { @@ -99,95 +82,208 @@ int clock_gettime(int foo, struct timespec *ts); #ifndef InterlockedCompareExchange static __forceinline uint8_t InterlockedCompareExchange(volatile uint8_t* dest, uint8_t exch, uint8_t comp) { +#if defined(__GNUG__) + return __sync_val_compare_and_swap(dest, comp, exch); +#else return _InterlockedCompareExchange8((volatile char*)dest, exch, comp); +#endif } static __forceinline uint16_t InterlockedCompareExchange(volatile uint16_t* dest, uint16_t exch, uint16_t comp) { +#if defined(__GNUG__) + return __sync_val_compare_and_swap(dest, comp, exch); +#else return _InterlockedCompareExchange16((volatile short*)dest, exch, comp); +#endif } static __forceinline uint32_t InterlockedCompareExchange(volatile uint32_t* dest, uint32_t exch, uint32_t comp) { +#if defined(__GNUG__) + return __sync_val_compare_and_swap(dest, comp, exch); +#else return _InterlockedCompareExchange((volatile long*)dest, exch, comp); +#endif } static __forceinline uint64_t InterlockedCompareExchange(volatile uint64_t* dest, uint64_t exch, uint64_t comp) { +#if defined(__GNUG__) + return __sync_val_compare_and_swap(dest, comp, exch); +#else return _InterlockedCompareExchange64((volatile long long*)dest, exch, comp); +#endif } #endif +static __forceinline bool InterlockedCompareExchangeTest(volatile uint8_t* dest, uint8_t exch, uint8_t comp) +{ +#if defined(__GNUG__) + return __sync_bool_compare_and_swap(dest, comp, exch); +#else + return _InterlockedCompareExchange8((volatile char*)dest, exch, comp) == comp; +#endif +} +static __forceinline bool InterlockedCompareExchangeTest(volatile uint16_t* dest, uint16_t exch, uint16_t comp) +{ +#if defined(__GNUG__) + return __sync_bool_compare_and_swap(dest, comp, exch); +#else + return _InterlockedCompareExchange16((volatile short*)dest, exch, comp) == comp; +#endif +} +static __forceinline bool InterlockedCompareExchangeTest(volatile uint32_t* dest, uint32_t exch, uint32_t comp) +{ +#if defined(__GNUG__) + return __sync_bool_compare_and_swap(dest, comp, exch); +#else + return _InterlockedCompareExchange((volatile long*)dest, exch, comp) == comp; +#endif +} +static __forceinline bool InterlockedCompareExchangeTest(volatile uint64_t* dest, uint64_t exch, uint64_t comp) +{ +#if defined(__GNUG__) + return __sync_bool_compare_and_swap(dest, comp, exch); +#else + return _InterlockedCompareExchange64((volatile long long*)dest, exch, comp) == comp; +#endif +} + #ifndef InterlockedExchange static __forceinline uint8_t InterlockedExchange(volatile uint8_t* dest, uint8_t value) { +#if defined(__GNUG__) + return __sync_lock_test_and_set(dest, value); +#else return _InterlockedExchange8((volatile char*)dest, value); +#endif } static __forceinline uint16_t InterlockedExchange(volatile uint16_t* dest, uint16_t value) { +#if defined(__GNUG__) + return __sync_lock_test_and_set(dest, value); +#else return _InterlockedExchange16((volatile short*)dest, value); +#endif } static __forceinline uint32_t InterlockedExchange(volatile uint32_t* dest, uint32_t value) { +#if defined(__GNUG__) + return __sync_lock_test_and_set(dest, value); +#else return _InterlockedExchange((volatile long*)dest, value); +#endif } static __forceinline uint64_t InterlockedExchange(volatile uint64_t* dest, uint64_t value) { +#if defined(__GNUG__) + return __sync_lock_test_and_set(dest, value); +#else return _InterlockedExchange64((volatile long long*)dest, value); +#endif } #endif #ifndef InterlockedOr static __forceinline uint8_t InterlockedOr(volatile uint8_t* dest, uint8_t value) { +#if defined(__GNUG__) + return __sync_fetch_and_or(dest, value); +#else return _InterlockedOr8((volatile char*)dest, value); +#endif } static __forceinline uint16_t InterlockedOr(volatile uint16_t* dest, uint16_t value) { +#if defined(__GNUG__) + return __sync_fetch_and_or(dest, value); +#else return _InterlockedOr16((volatile short*)dest, value); +#endif } static __forceinline uint32_t InterlockedOr(volatile uint32_t* dest, uint32_t value) { +#if defined(__GNUG__) + return __sync_fetch_and_or(dest, value); +#else return _InterlockedOr((volatile long*)dest, value); +#endif } static __forceinline uint64_t InterlockedOr(volatile uint64_t* dest, uint64_t value) { +#if defined(__GNUG__) + return __sync_fetch_and_or(dest, value); +#else return _InterlockedOr64((volatile long long*)dest, value); +#endif } #endif #ifndef InterlockedAnd static __forceinline uint8_t InterlockedAnd(volatile uint8_t* dest, uint8_t value) { +#if defined(__GNUG__) + return __sync_fetch_and_and(dest, value); +#else return _InterlockedAnd8((volatile char*)dest, value); +#endif } static __forceinline uint16_t InterlockedAnd(volatile uint16_t* dest, uint16_t value) { +#if defined(__GNUG__) + return __sync_fetch_and_and(dest, value); +#else return _InterlockedAnd16((volatile short*)dest, value); +#endif } static __forceinline uint32_t InterlockedAnd(volatile uint32_t* dest, uint32_t value) { +#if defined(__GNUG__) + return __sync_fetch_and_and(dest, value); +#else return _InterlockedAnd((volatile long*)dest, value); +#endif } static __forceinline uint64_t InterlockedAnd(volatile uint64_t* dest, uint64_t value) { +#if defined(__GNUG__) + return __sync_fetch_and_and(dest, value); +#else return _InterlockedAnd64((volatile long long*)dest, value); +#endif } #endif #ifndef InterlockedXor static __forceinline uint8_t InterlockedXor(volatile uint8_t* dest, uint8_t value) { +#if defined(__GNUG__) + return __sync_fetch_and_xor(dest, value); +#else return _InterlockedXor8((volatile char*)dest, value); +#endif } static __forceinline uint16_t InterlockedXor(volatile uint16_t* dest, uint16_t value) { +#if defined(__GNUG__) + return __sync_fetch_and_xor(dest, value); +#else return _InterlockedXor16((volatile short*)dest, value); +#endif } static __forceinline uint32_t InterlockedXor(volatile uint32_t* dest, uint32_t value) { +#if defined(__GNUG__) + return __sync_fetch_and_xor(dest, value); +#else return _InterlockedXor((volatile long*)dest, value); +#endif } static __forceinline uint64_t InterlockedXor(volatile uint64_t* dest, uint64_t value) { +#if defined(__GNUG__) + return __sync_fetch_and_xor(dest, value); +#else return _InterlockedXor64((volatile long long*)dest, value); +#endif } #endif diff --git a/rpcs3/Emu/Memory/atomic_type.h b/rpcs3/Emu/Memory/atomic_type.h index 35ebf639bd..7309f9cd2b 100644 --- a/rpcs3/Emu/Memory/atomic_type.h +++ b/rpcs3/Emu/Memory/atomic_type.h @@ -49,7 +49,7 @@ public: // atomically compare data with cmp, replace with exch if equal, return true if data was replaced __forceinline bool compare_and_swap_test(const T& cmp, const T& exch) volatile { - return InterlockedCompareExchange(&data, (atomic_type&)(exch), (atomic_type&)(cmp)) == (atomic_type&)(cmp); + return InterlockedCompareExchangeTest(&data, (atomic_type&)(exch), (atomic_type&)(cmp)); } // read data with memory barrier