diff --git a/FEXCore/Source/Interface/Core/Core.cpp b/FEXCore/Source/Interface/Core/Core.cpp index 678903790..83fbbb905 100644 --- a/FEXCore/Source/Interface/Core/Core.cpp +++ b/FEXCore/Source/Interface/Core/Core.cpp @@ -603,11 +603,17 @@ ContextImpl::GenerateIR(FEXCore::Core::InternalThreadState* Thread, uint64_t Gue auto Fn = TableInfo->OpcodeDispatcher.OpDispatch; Thread->OpDispatcher->ResetHandledLock(); Thread->OpDispatcher->ResetDecodeFailure(); - IR::ForceTSOMode ForceTSO = - BlockInForceTSOValidRange ? - (InstForceTSOIt != ForceTSOInstructions.end() && *InstForceTSOIt == InstAddress ? IR::ForceTSOMode::ForceEnabled : - IR::ForceTSOMode::ForceDisabled) : - IR::ForceTSOMode::NoOverride; + IR::ForceTSOMode ForceTSO = IR::ForceTSOMode::NoOverride; + if (BlockInForceTSOValidRange) { + if (InstForceTSOIt != ForceTSOInstructions.end() && *InstForceTSOIt == InstAddress) { + ForceTSO = IR::ForceTSOMode::ForceEnabled; + } else { + ForceTSO = IR::ForceTSOMode::ForceDisabled; + } + } else if (DecodedInfo->ForceTSO) { + ForceTSO = IR::ForceTSOMode::ForceEnabled; + } + Thread->OpDispatcher->SetForceTSO(ForceTSO); std::invoke(Fn, Thread->OpDispatcher, DecodedInfo); if (Thread->OpDispatcher->HadDecodeFailure()) { diff --git a/FEXCore/Source/Interface/Core/Frontend.cpp b/FEXCore/Source/Interface/Core/Frontend.cpp index d68c4c2de..4cfa0c8b1 100644 --- a/FEXCore/Source/Interface/Core/Frontend.cpp +++ b/FEXCore/Source/Interface/Core/Frontend.cpp @@ -1046,6 +1046,22 @@ Decoder::DecodedBlockStatus Decoder::DecodeInstruction(uint64_t PC) { return DecodedBlockStatus::INVALID_INST; } + if (CTX->AreMonoHacksActive()) { + // Unity uses a standard SPSC ringbuffer with cached read/write pointers and thread waiting flags at the following + // offsets, which are consistent between 32-bit and 64-bit Unity versions from 2015 onwards. + auto IsKnownAtomicDisplacement = [](uint64_t Displacement) { + return Displacement == 0x80 || Displacement == 0x84 || Displacement == 0xC0 || Displacement == 0xC4; + }; + + if (DecodeInst->OP == 0x8b && DecodeInst->Src[0].IsGPRIndirect() && + IsKnownAtomicDisplacement(DecodeInst->Src[0].Data.GPRIndirect.Displacement)) { + DecodeInst->ForceTSO = true; + } + if (DecodeInst->OP == 0x89 && DecodeInst->Dest.IsGPRIndirect() && IsKnownAtomicDisplacement(DecodeInst->Dest.Data.GPRIndirect.Displacement)) { + DecodeInst->ForceTSO = true; + } + } + return DecodedBlockStatus::SUCCESS; } diff --git a/FEXCore/Source/Interface/Core/X86Tables/X86Tables.h b/FEXCore/Source/Interface/Core/X86Tables/X86Tables.h index ddf94011b..9e4e3d00f 100644 --- a/FEXCore/Source/Interface/Core/X86Tables/X86Tables.h +++ b/FEXCore/Source/Interface/Core/X86Tables/X86Tables.h @@ -200,6 +200,7 @@ struct DecodedInst { uint8_t LastEscapePrefix; bool DecodedModRM; bool DecodedSIB; + bool ForceTSO; }; union ModRMDecoded {