diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 106322d5bc..166f8aeb00 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -2228,7 +2228,7 @@ void thread_ctrl::_wait_for(u64 usec, bool alert /* true */) } #endif - if (_this->m_sync.btr(2)) + if (_this->m_sync.bit_test_reset(2)) { return; } diff --git a/Utilities/bit_set.h b/Utilities/bit_set.h index e9015c4a33..d70668114c 100644 --- a/Utilities/bit_set.h +++ b/Utilities/bit_set.h @@ -205,7 +205,7 @@ constexpr bs_t operator ^(T lhs, T rhs) // Atomic bitset specialization with optimized operations template -class atomic_bs_t : public atomic_t<::bs_t> // TODO: true specialization +class atomic_bs_t : public atomic_t<::bs_t> { // Corresponding bitset type using bs_t = ::bs_t; @@ -379,11 +379,6 @@ public: return lhs.m_data != rhs.load().m_data; } - bool test(const bs_t& rhs) - { - return base::load().test(rhs); - } - bool test_and_set(T rhs) { return atomic_storage::bts(m_data.m_data, static_cast(static_cast(rhs))); @@ -394,10 +389,14 @@ public: return atomic_storage::btr(m_data.m_data, static_cast(static_cast(rhs))); } - bool test_and_complement(T rhs) + bool test_and_invert(T rhs) { return atomic_storage::btc(m_data.m_data, static_cast(static_cast(rhs))); } + + bool bit_test_set(uint bit) = delete; + bool bit_test_reset(uint bit) = delete; + bool bit_test_invert(uint bit) = delete; }; template diff --git a/rpcs3/Emu/Cell/Modules/cellSpurs.cpp b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp index abca9012e9..c9e8bf9b21 100644 --- a/rpcs3/Emu/Cell/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSpurs.cpp @@ -604,7 +604,7 @@ s32 _spurs::detach_lv2_eq(vm::ptr spurs, u8 spuPort, bool spursCreate if (!spursCreated) { - if (!spurs->spuPortBits.btr(spuPort) && _spurs::get_sdk_version() >= 0x180000) + if (!spurs->spuPortBits.bit_test_reset(spuPort) && _spurs::get_sdk_version() >= 0x180000) { return CELL_SPURS_CORE_ERROR_SRCH; } @@ -1831,8 +1831,8 @@ s32 cellSpursSetPriority(vm::ptr spurs, u32 wid, u32 spuId, u32 prior return CELL_SPURS_CORE_ERROR_STAT; vm::light_op(spurs->wklInfo(wid).priority[spuId], [&](u8& v){ atomic_storage::release(v, priority); }); - vm::light_op(spurs->sysSrvMsgUpdateWorkload, [&](atomic_t& v){ v.bts(spuId); }); - vm::light_op(spurs->sysSrvMessage, [&](atomic_t& v){ v.bts(spuId); }); + vm::light_op(spurs->sysSrvMsgUpdateWorkload, [&](atomic_t& v){ v.bit_test_set(spuId); }); + vm::light_op(spurs->sysSrvMessage, [&](atomic_t& v){ v.bit_test_set(spuId); }); return CELL_OK; } diff --git a/rpcs3/util/atomic.hpp b/rpcs3/util/atomic.hpp index 32e1a52b2b..a13e0d502f 100644 --- a/rpcs3/util/atomic.hpp +++ b/rpcs3/util/atomic.hpp @@ -416,34 +416,77 @@ struct atomic_storage return atomic_storage::sub_fetch(dest, 1); } - static inline bool test_and_set(T& dest, T mask) - { - return (atomic_storage::fetch_or(dest, mask) & mask) != 0; - } - - static inline bool test_and_reset(T& dest, T mask) - { - return (atomic_storage::fetch_and(dest, ~mask) & mask) != 0; - } - - static inline bool test_and_complement(T& dest, T mask) - { - return (atomic_storage::fetch_xor(dest, mask) & mask) != 0; - } - static inline bool bts(T& dest, uint bit) { - return atomic_storage::test_and_set(dest, static_cast(1) << bit); + uchar* dst = reinterpret_cast(&dest); + + if constexpr (sizeof(T) < 4) + { + const uptr ptr = reinterpret_cast(dst); + + // Align the bit up and pointer down + bit = bit + (ptr & 3) * 8; + dst = reinterpret_cast(ptr & -4); + } + +#ifdef _MSC_VER + return _interlockedbittestandset((long*)dst, bit) != 0; +#else + bool result; + __asm__ volatile ("lock btsl %2, 0(%1)\n" : "=@ccc" (result) : "r" (dst), "Ir" (bit) : "cc", "memory"); + return result; +#endif } static inline bool btr(T& dest, uint bit) { - return atomic_storage::test_and_reset(dest, static_cast(1) << bit); + uchar* dst = reinterpret_cast(&dest); + + if constexpr (sizeof(T) < 4) + { + const uptr ptr = reinterpret_cast(dst); + + // Align the bit up and pointer down + bit = bit + (ptr & 3) * 8; + dst = reinterpret_cast(ptr & -4); + } + +#ifdef _MSC_VER + return _interlockedbittestandreset((long*)dst, bit) != 0; +#else + bool result; + __asm__ volatile ("lock btrl %2, 0(%1)\n" : "=@ccc" (result) : "r" (dst), "Ir" (bit) : "cc", "memory"); + return result; +#endif } static inline bool btc(T& dest, uint bit) { - return atomic_storage::test_and_complement(dest, static_cast(1) << bit); + uchar* dst = reinterpret_cast(&dest); + + if constexpr (sizeof(T) < 4) + { + const uptr ptr = reinterpret_cast(dst); + + // Align the bit up and pointer down + bit = bit + (ptr & 3) * 8; + dst = reinterpret_cast(ptr & -4); + } + +#ifdef _MSC_VER + while (true) + { + // Keep trying until we actually invert desired bit + if (!_bittest((long*)dst, bit) && !_interlockedbittestandset((long*)dst, bit)) + return false; + if (_interlockedbittestandreset((long*)dst, bit)) + return true; + } +#else + bool result; + __asm__ volatile ("lock btcl %2, 0(%1)\n" : "=@ccc" (result) : "r" (dst), "Ir" (bit) : "cc", "memory"); + return result; +#endif } }; @@ -586,30 +629,6 @@ struct atomic_storage : atomic_storage const short r = _InterlockedDecrement16(reinterpret_cast(&dest)); return std::bit_cast(r); } -#else - static inline bool bts(T& dest, uint bit) - { - bool result; - ushort _bit = static_cast(bit); - __asm__("lock btsw %2, %0\n" : "+m" (dest), "=@ccc" (result) : "Ir" (_bit) : "cc"); - return result; - } - - static inline bool btr(T& dest, uint bit) - { - bool result; - ushort _bit = static_cast(bit); - __asm__("lock btrw %2, %0\n": "+m" (dest), "=@ccc" (result) : "Ir" (_bit) : "cc"); - return result; - } - - static inline bool btc(T& dest, uint bit) - { - bool result; - ushort _bit = static_cast(bit); - __asm__("lock btcw %2, %0\n": "+m" (dest), "=@ccc" (result) : "Ir" (_bit) : "cc"); - return result; - } #endif }; @@ -700,37 +719,6 @@ struct atomic_storage : atomic_storage const long r = _InterlockedDecrement(reinterpret_cast(&dest)); return std::bit_cast(r); } - - static inline bool bts(T& dest, uint bit) - { - return _interlockedbittestandset(reinterpret_cast(&dest), bit) != 0; - } - - static inline bool btr(T& dest, uint bit) - { - return _interlockedbittestandreset(reinterpret_cast(&dest), bit) != 0; - } -#else - static inline bool bts(T& dest, uint bit) - { - bool result; - __asm__("lock btsl %2, %0\n" : "+m" (dest), "=@ccc" (result) : "Ir" (bit) : "cc"); - return result; - } - - static inline bool btr(T& dest, uint bit) - { - bool result; - __asm__("lock btrl %2, %0\n" : "+m" (dest), "=@ccc" (result) : "Ir" (bit) : "cc"); - return result; - } - - static inline bool btc(T& dest, uint bit) - { - bool result; - __asm__("lock btcl %2, %0\n" : "+m" (dest), "=@ccc" (result) : "Ir" (bit) : "cc"); - return result; - } #endif }; @@ -821,40 +809,6 @@ struct atomic_storage : atomic_storage const llong r = _InterlockedDecrement64(reinterpret_cast(&dest)); return std::bit_cast(r); } - - static inline bool bts(T& dest, uint bit) - { - return _interlockedbittestandset64(reinterpret_cast(&dest), bit) != 0; - } - - static inline bool btr(T& dest, uint bit) - { - return _interlockedbittestandreset64(reinterpret_cast(&dest), bit) != 0; - } -#else - static inline bool bts(T& dest, uint bit) - { - bool result; - ullong _bit = bit; - __asm__("lock btsq %2, %0\n" : "+m" (dest), "=@ccc" (result) : "Ir" (_bit) : "cc"); - return result; - } - - static inline bool btr(T& dest, uint bit) - { - bool result; - ullong _bit = bit; - __asm__("lock btrq %2, %0\n" : "+m" (dest), "=@ccc" (result) : "Ir" (_bit) : "cc"); - return result; - } - - static inline bool btc(T& dest, uint bit) - { - bool result; - ullong _bit = bit; - __asm__("lock btcq %2, %0\n" : "+m" (dest), "=@ccc" (result) : "Ir" (_bit) : "cc"); - return result; - } #endif }; @@ -1431,14 +1385,19 @@ public: } } - bool bts(uint bit) + bool bit_test_set(uint bit) { - return atomic_storage::bts(m_data, bit); + return atomic_storage::bts(m_data, bit & (sizeof(T) * 8 - 1)); } - bool btr(uint bit) + bool bit_test_reset(uint bit) { - return atomic_storage::btr(m_data, bit); + return atomic_storage::btr(m_data, bit & (sizeof(T) * 8 - 1)); + } + + bool bit_test_invert(uint bit) + { + return atomic_storage::btc(m_data, bit & (sizeof(T) * 8 - 1)); } // Timeout is discouraged