Skip to content

Commit

Permalink
Use std::atomic_ref instead of std::atomic pointer casting
Browse files Browse the repository at this point in the history
  • Loading branch information
capitalistspz committed Sep 5, 2024
1 parent 00a34f0 commit 94a9992
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 58 deletions.
9 changes: 5 additions & 4 deletions src/Cafe/HW/Espresso/Interpreter/PPCInterpreterLoadStore.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,19 @@ static void PPCInterpreter_STWCX(PPCInterpreter_t* hCPU, uint32 Opcode)
if (hCPU->reservedMemAddr == ea)
{
uint32be reservedValue = hCPU->reservedMemValue; // this is the value we expect in memory (if it does not match, STWCX fails)
std::atomic<uint32be>* wordPtr;
uint32be* wordPtr;
if constexpr(ppcItpCtrl::allowSupervisorMode)
{
wordPtr = _rawPtrToAtomic((uint32be*)(memory_base + ppcItpCtrl::ppcMem_translateVirtualDataToPhysicalAddr(hCPU, ea)));
wordPtr = reinterpret_cast<uint32be*>(memory_base + ppcItpCtrl::ppcMem_translateVirtualDataToPhysicalAddr(hCPU, ea));
DSI_EXIT();
}
else
{
wordPtr = _rawPtrToAtomic((uint32be*)memory_getPointerFromVirtualOffset(ea));
wordPtr = reinterpret_cast<uint32be*>(memory_getPointerFromVirtualOffset(ea));
}
auto word = rawPtrToAtomicRef(wordPtr);
uint32be newValue = hCPU->gpr[rS];
if (!wordPtr->compare_exchange_strong(reservedValue, newValue))
if (!word.compare_exchange_strong(reservedValue, newValue))
{
// failed
ppc_setCRBit(hCPU, CR_BIT_LT, 0);
Expand Down
9 changes: 4 additions & 5 deletions src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -583,29 +583,28 @@ LatteCMDPtr LatteCP_itMemSemaphore(LatteCMDPtr cmd, uint32 nWords)
uint32 semaphoreControl = LatteReadCMD();
uint8 SEM_SIGNAL = (semaphoreControl >> 29) & 7;

std::atomic<uint64le>* semaphoreData = _rawPtrToAtomic((uint64le*)memory_getPointerFromPhysicalOffset(semaphorePhysicalAddress));
static_assert(sizeof(std::atomic<uint64le>) == sizeof(uint64le));
auto semaphoreData = rawPtrToAtomicRef(reinterpret_cast<uint64le*>(memory_getPointerFromPhysicalOffset(semaphorePhysicalAddress)));

if (SEM_SIGNAL == 6)
{
// signal
semaphoreData->fetch_add(1);
semaphoreData.fetch_add(1);
}
else if(SEM_SIGNAL == 7)
{
// wait
size_t loopCount = 0;
while (true)
{
uint64le oldVal = semaphoreData->load();
uint64le oldVal = semaphoreData.load();
if (oldVal == 0)
{
loopCount++;
if (loopCount > 2000)
std::this_thread::yield();
continue;
}
if (semaphoreData->compare_exchange_strong(oldVal, oldVal - 1))
if (semaphoreData.compare_exchange_strong(oldVal, oldVal - 1))
break;
}
}
Expand Down
64 changes: 37 additions & 27 deletions src/Cafe/OS/libs/coreinit/coreinit_Atomic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,115 +6,125 @@ namespace coreinit
{
/* 32bit atomic operations */

uint32 OSSwapAtomic(std::atomic<uint32be>* mem, uint32 newValue)
uint32 OSSwapAtomic(uint32be* mem, uint32 newValue)
{
const auto ref = rawPtrToAtomicRef(mem);
uint32be _newValue = newValue;
uint32be previousValue = mem->exchange(_newValue);
uint32be previousValue = ref.exchange(_newValue);
return previousValue;
}

bool OSCompareAndSwapAtomic(std::atomic<uint32be>* mem, uint32 compareValue, uint32 swapValue)
bool OSCompareAndSwapAtomic(uint32be* mem, uint32 compareValue, uint32 swapValue)
{
// seen in GTA3 homebrew port
const auto ref = rawPtrToAtomicRef(mem);
uint32be _compareValue = compareValue;
uint32be _swapValue = swapValue;
return mem->compare_exchange_strong(_compareValue, _swapValue);
return ref.compare_exchange_strong(_compareValue, _swapValue);
}

bool OSCompareAndSwapAtomicEx(std::atomic<uint32be>* mem, uint32 compareValue, uint32 swapValue, uint32be* previousValue)
bool OSCompareAndSwapAtomicEx(uint32be* mem, uint32 compareValue, uint32 swapValue, uint32be* previousValue)
{
// seen in GTA3 homebrew port
const auto ref = rawPtrToAtomicRef(mem);
uint32be _compareValue = compareValue;
uint32be _swapValue = swapValue;
bool r = mem->compare_exchange_strong(_compareValue, _swapValue);
bool r = ref.compare_exchange_strong(_compareValue, _swapValue);
*previousValue = _compareValue;
return r;
}

uint32 OSAddAtomic(std::atomic<uint32be>* mem, uint32 adder)
uint32 OSAddAtomic(uint32be* mem, uint32 adder)
{
// used by SDL Wii U port
const auto ref = rawPtrToAtomicRef(mem);
uint32be knownValue;
while (true)
{
knownValue = mem->load();
knownValue = ref.load();
uint32be newValue = knownValue + adder;
if (mem->compare_exchange_strong(knownValue, newValue))
if (ref.compare_exchange_strong(knownValue, newValue))
break;
}
return knownValue;
}

/* 64bit atomic operations */

uint64 OSSwapAtomic64(std::atomic<uint64be>* mem, uint64 newValue)
uint64 OSSwapAtomic64(uint64be* mem, uint64 newValue)
{
const auto ref = rawPtrToAtomicRef(mem);
uint64be _newValue = newValue;
uint64be previousValue = mem->exchange(_newValue);
uint64be previousValue = ref.exchange(_newValue);
return previousValue;
}

uint64 OSSetAtomic64(std::atomic<uint64be>* mem, uint64 newValue)
uint64 OSSetAtomic64(uint64be* mem, uint64 newValue)
{
return OSSwapAtomic64(mem, newValue);
}

uint64 OSGetAtomic64(std::atomic<uint64be>* mem)
uint64 OSGetAtomic64(uint64be* mem)
{
return mem->load();
return rawPtrToAtomicRef(mem).load();
}

uint64 OSAddAtomic64(std::atomic<uint64be>* mem, uint64 adder)
uint64 OSAddAtomic64(uint64be* mem, uint64 adder)
{
const auto ref = rawPtrToAtomicRef(mem);
uint64be knownValue;
while (true)
{
knownValue = mem->load();
knownValue = ref.load();
uint64be newValue = knownValue + adder;
if (mem->compare_exchange_strong(knownValue, newValue))
if (ref.compare_exchange_strong(knownValue, newValue))
break;
}
return knownValue;
}

uint64 OSAndAtomic64(std::atomic<uint64be>* mem, uint64 val)
uint64 OSAndAtomic64(uint64be* mem, uint64 val)
{
const auto ref = rawPtrToAtomicRef(mem);
uint64be knownValue;
while (true)
{
knownValue = mem->load();
knownValue = ref.load();
uint64be newValue = knownValue & val;
if (mem->compare_exchange_strong(knownValue, newValue))
if (ref.compare_exchange_strong(knownValue, newValue))
break;
}
return knownValue;
}

uint64 OSOrAtomic64(std::atomic<uint64be>* mem, uint64 val)
uint64 OSOrAtomic64(uint64be* mem, uint64 val)
{
const auto ref = rawPtrToAtomicRef(mem);
uint64be knownValue;
while (true)
{
knownValue = mem->load();
knownValue = ref.load();
uint64be newValue = knownValue | val;
if (mem->compare_exchange_strong(knownValue, newValue))
if (ref.compare_exchange_strong(knownValue, newValue))
break;
}
return knownValue;
}

bool OSCompareAndSwapAtomic64(std::atomic<uint64be>* mem, uint64 compareValue, uint64 swapValue)
bool OSCompareAndSwapAtomic64(uint64be* mem, uint64 compareValue, uint64 swapValue)
{
const auto ref = rawPtrToAtomicRef(mem);
uint64be _compareValue = compareValue;
uint64be _swapValue = swapValue;
return mem->compare_exchange_strong(_compareValue, _swapValue);
return ref.compare_exchange_strong(_compareValue, _swapValue);
}

bool OSCompareAndSwapAtomicEx64(std::atomic<uint64be>* mem, uint64 compareValue, uint64 swapValue, uint64be* previousValue)
bool OSCompareAndSwapAtomicEx64(uint64be* mem, uint64 compareValue, uint64 swapValue, uint64be* previousValue)
{
const auto ref = rawPtrToAtomicRef(mem);
uint64be _compareValue = compareValue;
uint64be _swapValue = swapValue;
bool r = mem->compare_exchange_strong(_compareValue, _swapValue);
bool r = ref.compare_exchange_strong(_compareValue, _swapValue);
*previousValue = _compareValue;
return r;
}
Expand Down
24 changes: 12 additions & 12 deletions src/Cafe/OS/libs/coreinit/coreinit_Atomic.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@

namespace coreinit
{
uint32 OSSwapAtomic(std::atomic<uint32be>* mem, uint32 newValue);
bool OSCompareAndSwapAtomic(std::atomic<uint32be>* mem, uint32 compareValue, uint32 swapValue);
bool OSCompareAndSwapAtomicEx(std::atomic<uint32be>* mem, uint32 compareValue, uint32 swapValue, uint32be* previousValue);
uint32 OSAddAtomic(std::atomic<uint32be>* mem, uint32 adder);
uint32 OSSwapAtomic(uint32be* mem, uint32 newValue);
bool OSCompareAndSwapAtomic(uint32be* mem, uint32 compareValue, uint32 swapValue);
bool OSCompareAndSwapAtomicEx(uint32be* mem, uint32 compareValue, uint32 swapValue, uint32be* previousValue);
uint32 OSAddAtomic(uint32be* mem, uint32 adder);

uint64 OSSwapAtomic64(std::atomic<uint64be>* mem, uint64 newValue);
uint64 OSSetAtomic64(std::atomic<uint64be>* mem, uint64 newValue);
uint64 OSGetAtomic64(std::atomic<uint64be>* mem);
uint64 OSAddAtomic64(std::atomic<uint64be>* mem, uint64 adder);
uint64 OSAndAtomic64(std::atomic<uint64be>* mem, uint64 val);
uint64 OSOrAtomic64(std::atomic<uint64be>* mem, uint64 val);
bool OSCompareAndSwapAtomic64(std::atomic<uint64be>* mem, uint64 compareValue, uint64 swapValue);
bool OSCompareAndSwapAtomicEx64(std::atomic<uint64be>* mem, uint64 compareValue, uint64 swapValue, uint64be* previousValue);
uint64 OSSwapAtomic64(uint64be* mem, uint64 newValue);
uint64 OSSetAtomic64(uint64be* mem, uint64 newValue);
uint64 OSGetAtomic64(uint64be* mem);
uint64 OSAddAtomic64(uint64be* mem, uint64 adder);
uint64 OSAndAtomic64(uint64be* mem, uint64 val);
uint64 OSOrAtomic64(uint64be* mem, uint64 val);
bool OSCompareAndSwapAtomic64(uint64be* mem, uint64 compareValue, uint64 swapValue);
bool OSCompareAndSwapAtomicEx64(uint64be* mem, uint64 compareValue, uint64 swapValue, uint64be* previousValue);

void InitializeAtomic();
}
6 changes: 3 additions & 3 deletions src/Cafe/OS/libs/dmae/dmae.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,17 +79,17 @@ void dmaeExport_DMAESemaphore(PPCInterpreter_t* hCPU)

uint32 actionType = hCPU->gpr[4];

std::atomic<uint64le>* semaphore = _rawPtrToAtomic((uint64le*)memory_getPointerFromVirtualOffset(hCPU->gpr[3]));
auto semaphore = rawPtrToAtomicRef(reinterpret_cast<uint64le*>(memory_getPointerFromVirtualOffset(hCPU->gpr[3])));

if( actionType == 1 )
{
// Signal Semaphore
semaphore->fetch_add(1);
++semaphore;
}
else if (actionType == 0) // wait
{
cemuLog_logDebug(LogType::Force, "DMAESemaphore: Unsupported wait operation");
semaphore->fetch_sub(1);
--semaphore;
}
else
{
Expand Down
4 changes: 2 additions & 2 deletions src/Common/MemPtr.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ class MEMPTR : MEMPTRBase
{
MEMPTR<T> mp_compare = comparePtr;
MEMPTR<T> mp_new = newPtr;
auto* thisValueAtomic = reinterpret_cast<std::atomic<uint32be>*>(&m_value);
return thisValueAtomic->compare_exchange_strong(mp_compare.m_value, mp_new.m_value);
std::atomic_ref thisValueAtomic(m_value);
return thisValueAtomic.compare_exchange_strong(mp_compare.m_value, mp_new.m_value);
}

explicit constexpr operator bool() const noexcept
Expand Down
10 changes: 5 additions & 5 deletions src/Common/precompiled.h
Original file line number Diff line number Diff line change
Expand Up @@ -509,13 +509,13 @@ struct scope_exit
~scope_exit() { if (f_) f_(); }
};

// helper function to cast raw pointers to std::atomic
// this is technically not legal but works on most platforms as long as alignment restrictions are met and the implementation of atomic doesnt come with additional members

// helper function to convert raw pointers to std::atomic_ref
// this is only legal as long as alignment restrictions are met
template<typename T>
std::atomic<T>* _rawPtrToAtomic(T* ptr)
std::atomic_ref<T> rawPtrToAtomicRef(T* ptr)
{
return reinterpret_cast<std::atomic<T>*>(ptr);
cemu_assert_debug(reinterpret_cast<std::uintptr_t>(ptr) % std::atomic_ref<T>::required_alignment);
return std::atomic_ref<T>(*ptr);
}

#if defined(__GNUC__)
Expand Down

0 comments on commit 94a9992

Please sign in to comment.