diff --git a/FEXCore/Source/Utils/ArchHelpers/Arm64.cpp b/FEXCore/Source/Utils/ArchHelpers/Arm64.cpp index 56cc934ad..5b22ac844 100644 --- a/FEXCore/Source/Utils/ArchHelpers/Arm64.cpp +++ b/FEXCore/Source/Utils/ArchHelpers/Arm64.cpp @@ -1953,7 +1953,7 @@ static uint64_t HandleAtomicLoadstoreExclusive(uintptr_t ProgramCounter, uint64_ } [[nodiscard]] -std::pair +std::optional HandleUnalignedAccess(FEXCore::Core::InternalThreadState* Thread, UnalignedHandlerType HandleType, uintptr_t ProgramCounter, uint64_t* GPRs) { #ifdef _M_ARM_64 constexpr bool is_arm64 = true; @@ -1961,9 +1961,8 @@ HandleUnalignedAccess(FEXCore::Core::InternalThreadState* Thread, UnalignedHandl constexpr bool is_arm64 = false; #endif - constexpr auto NotHandled = std::make_pair(false, 0); if constexpr (!is_arm64) { - return NotHandled; + return std::nullopt; } uint32_t* PC = (uint32_t*)ProgramCounter; @@ -1985,38 +1984,38 @@ HandleUnalignedAccess(FEXCore::Core::InternalThreadState* Thread, UnalignedHandl (Instr & LDAXR_MASK) == LDAPR_INST) { // LDAPR* if (ArchHelpers::Arm64::HandleAtomicLoad(Instr, GPRs, 0)) { // Skip this instruction now - return std::make_pair(true, 4); + return 4; } else { LogMan::Msg::EFmt("Unhandled JIT SIGBUS LDAR*: PC: 0x{:x} Instruction: 0x{:08x}\n", ProgramCounter, PC[0]); - return NotHandled; + return std::nullopt; } } else if ((Instr & LDAXR_MASK) == STLR_INST) { // STLR* if (ArchHelpers::Arm64::HandleAtomicStore(Instr, GPRs, 0, StrictSplitLockMutex)) { // Skip this instruction now - return std::make_pair(true, 4); + return 4; } else { LogMan::Msg::EFmt("Unhandled JIT SIGBUS STLR*: PC: 0x{:x} Instruction: 0x{:08x}\n", ProgramCounter, PC[0]); - return NotHandled; + return std::nullopt; } } else if ((Instr & RCPC2_MASK) == LDAPUR_INST) { // LDAPUR* // Extract the 9-bit offset from the instruction int32_t Offset = static_cast(Instr) << 11 >> 23; if (ArchHelpers::Arm64::HandleAtomicLoad(Instr, GPRs, Offset)) { // Skip this instruction now - return std::make_pair(true, 4); + return 4; } else { LogMan::Msg::EFmt("Unhandled JIT SIGBUS LDAPUR*: PC: 0x{:x} Instruction: 0x{:08x}\n", ProgramCounter, PC[0]); - return NotHandled; + return std::nullopt; } } else if ((Instr & RCPC2_MASK) == STLUR_INST) { // STLUR* // Extract the 9-bit offset from the instruction int32_t Offset = static_cast(Instr) << 11 >> 23; if (ArchHelpers::Arm64::HandleAtomicStore(Instr, GPRs, Offset, StrictSplitLockMutex)) { // Skip this instruction now - return std::make_pair(true, 4); + return 4; } else { LogMan::Msg::EFmt("Unhandled JIT SIGBUS LDLUR*: PC: 0x{:x} Instruction: 0x{:08x}\n", ProgramCounter, PC[0]); - return NotHandled; + return std::nullopt; } } } @@ -2030,18 +2029,18 @@ HandleUnalignedAccess(FEXCore::Core::InternalThreadState* Thread, UnalignedHandl if ((Instr & ArchHelpers::Arm64::CASPAL_MASK) == ArchHelpers::Arm64::CASPAL_INST) { // CASPAL if (ArchHelpers::Arm64::HandleCASPAL(Instr, GPRs, StrictSplitLockMutex)) { // Skip this instruction now - return std::make_pair(true, 4); + return 4; } else { LogMan::Msg::EFmt("Unhandled JIT SIGBUS CASPAL: PC: 0x{:x} Instruction: 0x{:08x}\n", ProgramCounter, PC[0]); - return NotHandled; + return std::nullopt; } } else if ((Instr & ArchHelpers::Arm64::CASAL_MASK) == ArchHelpers::Arm64::CASAL_INST) { // CASAL if (ArchHelpers::Arm64::HandleCASAL(GPRs, Instr, StrictSplitLockMutex)) { // Skip this instruction now - return std::make_pair(true, 4); + return 4; } else { LogMan::Msg::EFmt("Unhandled JIT SIGBUS CASAL: PC: 0x{:x} Instruction: 0x{:08x}\n", ProgramCounter, PC[0]); - return NotHandled; + return std::nullopt; } } else if ((Instr & LDAXR_MASK) == LDAR_INST || // LDAR* (Instr & LDAXR_MASK) == LDAPR_INST || // LDAPR* @@ -2051,17 +2050,17 @@ HandleUnalignedAccess(FEXCore::Core::InternalThreadState* Thread, UnalignedHandl } else if ((Instr & ArchHelpers::Arm64::ATOMIC_MEM_MASK) == ArchHelpers::Arm64::ATOMIC_MEM_INST) { // Atomic memory op if (ArchHelpers::Arm64::HandleAtomicMemOp(Instr, GPRs, StrictSplitLockMutex)) { // Skip this instruction now - return std::make_pair(true, 4); + return 4; } else { uint8_t Op = (PC[0] >> 12) & 0xF; LogMan::Msg::EFmt("Unhandled JIT SIGBUS Atomic mem op 0x{:02x}: PC: 0x{:x} Instruction: 0x{:08x}\n", Op, ProgramCounter, PC[0]); - return NotHandled; + return std::nullopt; } } else if ((Instr & ArchHelpers::Arm64::LDAXR_MASK) == ArchHelpers::Arm64::LDAXR_INST) { // LDAXR* uint64_t BytesToSkip = ArchHelpers::Arm64::HandleAtomicLoadstoreExclusive(ProgramCounter, GPRs, StrictSplitLockMutex); if (BytesToSkip) { // Skip this instruction now - return std::make_pair(true, BytesToSkip); + return BytesToSkip; } // Explicit fallthrough to the backpatch handler below! } else if ((Instr & ArchHelpers::Arm64::LDAXP_MASK) == ArchHelpers::Arm64::LDAXP_INST) { // LDAXP @@ -2069,7 +2068,7 @@ HandleUnalignedAccess(FEXCore::Core::InternalThreadState* Thread, UnalignedHandl uint64_t BytesToSkip = ArchHelpers::Arm64::HandleCASPAL_ARMv8(Instr, ProgramCounter, GPRs, StrictSplitLockMutex); if (BytesToSkip) { // Skip this instruction now - return std::make_pair(true, BytesToSkip); + return BytesToSkip; } } @@ -2091,7 +2090,7 @@ HandleUnalignedAccess(FEXCore::Core::InternalThreadState* Thread, UnalignedHandl std::atomic_ref(PC[0]).store(LDR, std::memory_order_release); ClearICache(&PC[0], 8); // With the instruction modified, now execute again. - return std::make_pair(true, 0); + return 0; } else if ((Instr & LDAXR_MASK) == STLR_INST) { // STLR* uint32_t STR = STR_INST; STR |= Size << 30; @@ -2103,7 +2102,7 @@ HandleUnalignedAccess(FEXCore::Core::InternalThreadState* Thread, UnalignedHandl std::atomic_ref(PC[0]).store(STR, std::memory_order_release); ClearICache(&PC[-1], 8); // Back up one instruction and have another go - return std::make_pair(true, -4); + return -4; } else if ((Instr & RCPC2_MASK) == LDAPUR_INST) { // LDAPUR* // Extract the 9-bit offset from the instruction uint32_t LDUR = LDUR_INST; @@ -2118,7 +2117,7 @@ HandleUnalignedAccess(FEXCore::Core::InternalThreadState* Thread, UnalignedHandl std::atomic_ref(PC[0]).store(LDUR, std::memory_order_release); ClearICache(&PC[0], 8); // With the instruction modified, now execute again. - return std::make_pair(true, 0); + return 0; } else if ((Instr & RCPC2_MASK) == STLUR_INST) { // STLUR* uint32_t STUR = STUR_INST; STUR |= Size << 30; @@ -2132,20 +2131,20 @@ HandleUnalignedAccess(FEXCore::Core::InternalThreadState* Thread, UnalignedHandl ClearICache(&PC[-1], 8); // Back up one instruction and have another go - return std::make_pair(true, -4); + return -4; } else if ((Instr & ArchHelpers::Arm64::LDAXP_MASK) == ArchHelpers::Arm64::LDAXP_INST) { // LDAXP /// This is handling the case of paranoid ARMv8.0-a atomic stores. /// This backpatches the ldaxp+stlxp+cbnz if the previous `HandleCASPAL_ARMv8` didn't handle the case. if (ArchHelpers::Arm64::HandleAtomicVectorStore(Instr, ProgramCounter)) { - return std::make_pair(true, 0); + return 0; } else { LogMan::Msg::EFmt("Unhandled JIT SIGBUS LDAXP: PC: 0x{:x} Instruction: 0x{:08x}\n", ProgramCounter, PC[0]); - return NotHandled; + return std::nullopt; } } else if ((Instr & ArchHelpers::Arm64::STLXP_MASK) == ArchHelpers::Arm64::STLXP_INST) { // STLXP // Should not trigger - middle of an LDAXP/STAXP pair. LogMan::Msg::EFmt("Unhandled JIT SIGBUS STLXP: PC: 0x{:x} Instruction: 0x{:08x}\n", ProgramCounter, PC[0]); - return NotHandled; + return std::nullopt; } // Check if another thread backpatched this instruction before this thread got here @@ -2159,11 +2158,11 @@ HandleUnalignedAccess(FEXCore::Core::InternalThreadState* Thread, UnalignedHandl // Check if the next instruction is a DMB. auto DMBInst = std::atomic_ref(PC[1]).load(std::memory_order_acquire); if (DMBInst == DMB_LD) { - return std::make_pair(true, 0); + return 0; } } else { // No DMB instruction with this HandleType. - return std::make_pair(true, 0); + return 0; } } else if ((AtomicInst & LDSTREGISTER_MASK) == STR_INST || (AtomicInst & LDSTUNSCALED_MASK) == STUR_INST) { if (HandleType != UnalignedHandlerType::NonAtomic) { @@ -2171,11 +2170,11 @@ HandleUnalignedAccess(FEXCore::Core::InternalThreadState* Thread, UnalignedHandl auto DMBInst = std::atomic_ref(PC[-1]).load(std::memory_order_acquire); if (DMBInst == DMB) { // Return handled, make sure to adjust PC so we run the DMB. - return std::make_pair(true, -4); + return -4; } } else { // No DMB instruction with this HandleType. - return std::make_pair(true, 0); + return 0; } } else if (AtomicInst == DMB) { // ARMv8.0-a LDAXP backpatch handling. Will have turned in to the following: @@ -2186,12 +2185,12 @@ HandleUnalignedAccess(FEXCore::Core::InternalThreadState* Thread, UnalignedHandl auto DMBInst = std::atomic_ref(PC[2]).load(std::memory_order_acquire); if ((STPInst & LDSTP_MASK) == STP_INST && DMBInst == DMB) { // Code that was backpatched is what was expected for ARMv8.0-a LDAXP. - return std::make_pair(true, 0); + return 0; } } LogMan::Msg::EFmt("Unhandled JIT SIGBUS: PC: 0x{:x} Instruction: 0x{:08x}\n", ProgramCounter, PC[0]); - return NotHandled; + return std::nullopt; } diff --git a/FEXCore/Source/Utils/ArchHelpers/Arm64_stubs.cpp b/FEXCore/Source/Utils/ArchHelpers/Arm64_stubs.cpp index e35981a5d..253071697 100644 --- a/FEXCore/Source/Utils/ArchHelpers/Arm64_stubs.cpp +++ b/FEXCore/Source/Utils/ArchHelpers/Arm64_stubs.cpp @@ -11,7 +11,7 @@ namespace FEXCore::ArchHelpers::Arm64 { // Obvously such a configuration can't do the actual arm64-specific stuff -std::pair +std::optional HandleUnalignedAccess(FEXCore::Core::InternalThreadState* Thread, UnalignedHandlerType HandleType, uintptr_t ProgramCounter, uint64_t* GPRs) { ERROR_AND_DIE_FMT("HandleAtomicMemOp Not Implemented"); } diff --git a/FEXCore/include/FEXCore/Utils/ArchHelpers/Arm64.h b/FEXCore/include/FEXCore/Utils/ArchHelpers/Arm64.h index b5aebd0f3..766dbe5fe 100644 --- a/FEXCore/include/FEXCore/Utils/ArchHelpers/Arm64.h +++ b/FEXCore/include/FEXCore/Utils/ArchHelpers/Arm64.h @@ -4,7 +4,7 @@ #include #include -#include +#include namespace FEXCore::Core { struct InternalThreadState; @@ -30,10 +30,10 @@ enum class UnalignedHandlerType { * @param ProgramCounter The location in memory for the instruction that did the access * @param GPRs The array of GPRs from the signal context. This will be modified and the host context needs to be updated on signal return. * - * @return A pair where the first element is if the unaligned access has been handle and the second element is how many bytes to modify the host PC + * @return Returns a value if the unaligned access has been handled with how many bytes to modify the host PC * by. FEXCore will return a positive or negative offset depending on internal handling. */ [[nodiscard]] -FEX_DEFAULT_VISIBILITY std::pair +FEX_DEFAULT_VISIBILITY std::optional HandleUnalignedAccess(FEXCore::Core::InternalThreadState* Thread, UnalignedHandlerType HandleType, uintptr_t ProgramCounter, uint64_t* GPRs); } // namespace FEXCore::ArchHelpers::Arm64 diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp index 872a65cd0..4984205dd 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/SignalDelegator.cpp @@ -945,8 +945,8 @@ SignalDelegator::SignalDelegator(FEXCore::Context::Context* _CTX, const std::str const auto Delegator = FEX::HLE::ThreadManager::GetStateObjectFromFEXCoreThread(Thread)->SignalInfo.Delegator; const auto Result = FEXCore::ArchHelpers::Arm64::HandleUnalignedAccess(Thread, Delegator->GetUnalignedHandlerType(), PC, ArchHelpers::Context::GetArmGPRs(ucontext)); - ArchHelpers::Context::SetPc(ucontext, PC + Result.second); - return Result.first; + ArchHelpers::Context::SetPc(ucontext, PC + Result.value_or(0)); + return Result.has_value(); }; RegisterHostSignalHandler(SIGBUS, SigbusHandler, true); diff --git a/Source/Tools/TestHarnessRunner/TestHarnessRunner.cpp b/Source/Tools/TestHarnessRunner/TestHarnessRunner.cpp index 9c858d37c..0e49e4809 100644 --- a/Source/Tools/TestHarnessRunner/TestHarnessRunner.cpp +++ b/Source/Tools/TestHarnessRunner/TestHarnessRunner.cpp @@ -153,8 +153,8 @@ LONG WINAPI VectoredExceptionHandler(struct _EXCEPTION_POINTERS* ExceptionInfo) } const auto Result = FEXCore::ArchHelpers::Arm64::HandleUnalignedAccess(true, PC, FEX::ArchHelpers::Context::GetArmGPRs(Context)); - FEX::ArchHelpers::Context::SetPc(Context, PC + Result.second); - return Result.first ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH; + FEX::ArchHelpers::Context::SetPc(Context, PC + Result.value_or(0)); + return Result ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_CONTINUE_SEARCH; } case STATUS_ACCESS_VIOLATION: { constexpr uint8_t HLT = 0xF4; diff --git a/Source/Windows/ARM64EC/Module.cpp b/Source/Windows/ARM64EC/Module.cpp index 190e0eff0..933e4383b 100644 --- a/Source/Windows/ARM64EC/Module.cpp +++ b/Source/Windows/ARM64EC/Module.cpp @@ -335,12 +335,8 @@ static bool HandleUnalignedAccess(ARM64_NT_CONTEXT& Context) { FEXCORE_PROFILE_INSTANT_INCREMENT(Thread, AccumulatedSIGBUSCount, 1); const auto Result = FEXCore::ArchHelpers::Arm64::HandleUnalignedAccess(Thread, HandlerConfig->GetUnalignedHandlerType(), Context.Pc, &Context.X0); - if (!Result.first) { - return false; - } - - Context.Pc += Result.second; - return true; + Context.Pc += Result.value_or(0); + return Result.has_value(); } static void LoadStateFromECContext(FEXCore::Core::InternalThreadState* Thread, CONTEXT& Context) { diff --git a/Source/Windows/WOW64/Module.cpp b/Source/Windows/WOW64/Module.cpp index b99c4b6b3..6227f14a1 100644 --- a/Source/Windows/WOW64/Module.cpp +++ b/Source/Windows/WOW64/Module.cpp @@ -318,12 +318,8 @@ bool HandleUnalignedAccess(CONTEXT* Context) { const auto Result = FEXCore::ArchHelpers::Arm64::HandleUnalignedAccess(Thread, HandlerConfig->GetUnalignedHandlerType(), Context->Pc, &Context->X0); - if (!Result.first) { - return false; - } - - Context->Pc += Result.second; - return true; + Context->Pc += Result.value_or(0); + return Result.has_value(); } void LockJITContext() {