diff --git a/External/FEXCore/Source/Interface/Core/Core.cpp b/External/FEXCore/Source/Interface/Core/Core.cpp index 560a1b611..b664c1384 100644 --- a/External/FEXCore/Source/Interface/Core/Core.cpp +++ b/External/FEXCore/Source/Interface/Core/Core.cpp @@ -386,6 +386,7 @@ namespace FEXCore::Context { void Context::InitializeThreadData(FEXCore::Core::InternalThreadState *Thread) { Thread->CPUBackend->Initialize(); + Thread->IntBackend->Initialize(); Thread->FallbackBackend->Initialize(); auto IRHandler = [this, Thread](uint64_t Addr, IR::IREmitter *IR) -> void { @@ -442,13 +443,19 @@ namespace FEXCore::Context { // Create CPU backend switch (Config.Core) { - case FEXCore::Config::CONFIG_INTERPRETER: Thread->CPUBackend.reset(FEXCore::CPU::CreateInterpreterCore(this)); break; + case FEXCore::Config::CONFIG_INTERPRETER: + Thread->CPUBackend.reset(FEXCore::CPU::CreateInterpreterCore(this)); + Thread->IntBackend = Thread->CPUBackend; + break; case FEXCore::Config::CONFIG_IRJIT: Thread->CPUBackend.reset(FEXCore::CPU::CreateJITCore(this, Thread)); break; case FEXCore::Config::CONFIG_LLVMJIT: Thread->CPUBackend.reset(FEXCore::CPU::CreateLLVMCore(Thread)); break; case FEXCore::Config::CONFIG_CUSTOM: Thread->CPUBackend.reset(CustomCPUFactory(this, &Thread->State)); break; default: LogMan::Msg::A("Unknown core configuration"); } + if (!Thread->IntBackend) { + Thread->IntBackend.reset(FEXCore::CPU::CreateInterpreterCore(this)); + } Thread->FallbackBackend.reset(FallbackCPUFactory(this, &Thread->State)); LogMan::Throw::A(!Thread->FallbackBackend->NeedsOpDispatch(), "Fallback CPU backend must not require OpDispatch"); @@ -485,6 +492,8 @@ namespace FEXCore::Context { void Context::ClearCodeCache(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) { Thread->BlockCache->ClearCache(); Thread->CPUBackend->ClearCache(); + Thread->IntBackend->ClearCache(); + if (GuestRIP != 0) { auto IR = Thread->IRLists.find(GuestRIP)->second.release(); Thread->IRLists.clear(); diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp index 7484cc128..0fb1bd027 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp +++ b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp @@ -54,7 +54,8 @@ private: }; static void InterpreterExecution(FEXCore::Core::InternalThreadState *Thread) { - InterpreterCore *Core = reinterpret_cast(Thread->CPUBackend.get()); + // IntBackend will always point to this interpreter object + InterpreterCore *Core = reinterpret_cast(Thread->IntBackend.get()); Core->ExecuteCode(Thread); } diff --git a/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp b/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp index 0e0eed703..008815adb 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp @@ -374,6 +374,16 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const uintptr_t ListBegin = CurrentIR->GetListData(); uintptr_t DataBegin = CurrentIR->GetData(); + auto HeaderIterator = CurrentIR->begin(); + IR::OrderedNodeWrapper *HeaderNodeWrapper = HeaderIterator(); + IR::OrderedNode *HeaderNode = HeaderNodeWrapper->GetNode(ListBegin); + auto HeaderOp = HeaderNode->Op(DataBegin)->CW(); + LogMan::Throw::A(HeaderOp->Header.Op == IR::OP_IRHEADER, "First op wasn't IRHeader"); + + if (HeaderOp->ShouldInterpret) { + return State->IntBackend->CompileCode(IR, DebugData); + } + LogMan::Throw::A(RAPass->HasFullRA(), "Arm64 JIT only works with RA"); uint32_t SpillSlots = RAPass->SpillSlots(); @@ -409,12 +419,6 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const sub(sp, sp, SpillSlots * 16); } - auto HeaderIterator = CurrentIR->begin(); - IR::OrderedNodeWrapper *HeaderNodeWrapper = HeaderIterator(); - IR::OrderedNode *HeaderNode = HeaderNodeWrapper->GetNode(ListBegin); - auto HeaderOp = HeaderNode->Op(DataBegin)->CW(); - LogMan::Throw::A(HeaderOp->Header.Op == IR::OP_IRHEADER, "First op wasn't IRHeader"); - IR::OrderedNode *BlockNode = HeaderOp->Blocks.GetNode(ListBegin); while (1) { diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp index 49b4ddc46..7cf841534 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp @@ -235,6 +235,10 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const auto HeaderOp = HeaderNode->Op(DataBegin)->CW(); LogMan::Throw::A(HeaderOp->Header.Op == IR::OP_IRHEADER, "First op wasn't IRHeader"); + if (HeaderOp->ShouldInterpret) { + return ThreadState->IntBackend->CompileCode(IR, DebugData); + } + // Fairly excessive buffer range to make sure we don't overflow uint32_t BufferRange = SSACount * 16; if ((getSize() + BufferRange) > MAX_CODE_SIZE) { diff --git a/External/FEXCore/Source/Interface/Core/LLVMJIT/LLVMCore.cpp b/External/FEXCore/Source/Interface/Core/LLVMJIT/LLVMCore.cpp index 6c311e49c..19683a5d5 100644 --- a/External/FEXCore/Source/Interface/Core/LLVMJIT/LLVMCore.cpp +++ b/External/FEXCore/Source/Interface/Core/LLVMJIT/LLVMCore.cpp @@ -3921,15 +3921,6 @@ void* FEXCore::CPU::LLVMJITCore::CompileCode(FEXCore::IR::IRListView const CurrentIR = IR; -#if DESTMAP_AS_MAP - DestMap.clear(); -#else - uintptr_t ListSize = CurrentIR->GetListSize(); - if (ListSize > DestMap.size()) { - DestMap.resize(std::max(DestMap.size() * 2, ListSize)); - } -#endif - uintptr_t ListBegin = CurrentIR->GetListData(); uintptr_t DataBegin = CurrentIR->GetData(); @@ -3939,6 +3930,19 @@ void* FEXCore::CPU::LLVMJITCore::CompileCode(FEXCore::IR::IRListView const auto HeaderOp = HeaderNode->Op(DataBegin)->CW(); LogMan::Throw::A(HeaderOp->Header.Op == IR::OP_IRHEADER, "First op wasn't IRHeader"); + if (HeaderOp->ShouldInterpret) { + return ThreadState->IntBackend->CompileCode(IR, DebugData); + } + +#if DESTMAP_AS_MAP + DestMap.clear(); +#else + uintptr_t ListSize = CurrentIR->GetListSize(); + if (ListSize > DestMap.size()) { + DestMap.resize(std::max(DestMap.size() * 2, ListSize)); + } +#endif + std::ostringstream FunctionName; FunctionName << "Function_0x"; FunctionName << std::hex << HeaderOp->Entry; diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index ee8748f49..030dbf985 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -3348,7 +3348,8 @@ void OpDispatchBuilder::CreateJumpBlocks(std::vector const *Blocks) { Entry = RIP; - auto IRHeader = _IRHeader(InvalidNode, RIP, 0); + auto IRHeader = _IRHeader(InvalidNode, RIP, 0, false); + Current_Header = IRHeader.first; CreateJumpBlocks(Blocks); auto Block = GetNewJumpBlock(RIP); diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index 12251c9d0..3dc1f3b9f 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -346,6 +346,7 @@ public: private: bool DecodeFailure{false}; + FEXCore::IR::IROp_IRHeader *Current_Header{}; OrderedNode *LoadSource(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp const& Op, FEXCore::X86Tables::DecodedOperand const& Operand, uint32_t Flags, int8_t Align, bool LoadData = true, bool ForceLoad = false); OrderedNode *LoadSource_WithOpSize(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp const& Op, FEXCore::X86Tables::DecodedOperand const& Operand, uint8_t OpSize, uint32_t Flags, int8_t Align, bool LoadData = true, bool ForceLoad = false); diff --git a/External/FEXCore/Source/Interface/IR/IR.json b/External/FEXCore/Source/Interface/IR/IR.json index a43f65a62..f22c87b62 100644 --- a/External/FEXCore/Source/Interface/IR/IR.json +++ b/External/FEXCore/Source/Interface/IR/IR.json @@ -58,7 +58,8 @@ ], "Args": [ "uint64_t", "Entry", - "uint32_t", "BlockCount" + "uint32_t", "BlockCount", + "bool", "ShouldInterpret" ] }, "CodeBlock": { diff --git a/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp b/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp index f1d701874..2cb939bb8 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/IRCompaction.cpp @@ -61,7 +61,7 @@ bool IRCompaction::Run(IREmitter *IREmit) { // Zero is always zero(invalid) OldToNewRemap[0] = 0; - auto LocalHeaderOp = LocalBuilder._IRHeader(OrderedNodeWrapper::WrapOffset(0).GetNode(ListBegin), HeaderOp->Entry, HeaderOp->BlockCount); + auto LocalHeaderOp = LocalBuilder._IRHeader(OrderedNodeWrapper::WrapOffset(0).GetNode(ListBegin), HeaderOp->Entry, HeaderOp->BlockCount, HeaderOp->ShouldInterpret); OldToNewRemap[HeaderNode->Wrapped(ListBegin).ID()] = LocalHeaderOp.Node->Wrapped(LocalListBegin).ID(); struct CodeBlockData { diff --git a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp index 0013f1151..b77b7bacf 100644 --- a/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp +++ b/External/FEXCore/Source/Interface/IR/Passes/RegisterAllocationPass.cpp @@ -1220,6 +1220,21 @@ namespace FEXCore::IR { bool ConstrainedRAPass::Run(IREmitter *IREmit) { bool Changed = false; + auto IR = IREmit->ViewIR(); + uintptr_t ListBegin = IR.GetListData(); + uintptr_t DataBegin = IR.GetData(); + + auto Begin = IR.begin(); + auto Op = Begin(); + + IR::OrderedNode *RealNode = Op->GetNode(ListBegin); + auto HeaderOp = RealNode->Op(DataBegin)->CW(); + LogMan::Throw::A(HeaderOp->Header.Op == IR::OP_IRHEADER, "First op wasn't IRHeader"); + + if (HeaderOp->ShouldInterpret) { + return false; + } + SpillSlotCount = 0; Graph->SpillStack.clear(); diff --git a/External/FEXCore/include/FEXCore/Debug/InternalThreadState.h b/External/FEXCore/include/FEXCore/Debug/InternalThreadState.h index c5c416c22..3720fa0ed 100644 --- a/External/FEXCore/include/FEXCore/Debug/InternalThreadState.h +++ b/External/FEXCore/include/FEXCore/Debug/InternalThreadState.h @@ -49,7 +49,8 @@ namespace FEXCore::Core { std::unique_ptr OpDispatcher; - std::unique_ptr CPUBackend; + std::shared_ptr CPUBackend; + std::shared_ptr IntBackend; std::unique_ptr FallbackBackend; std::unique_ptr BlockCache; diff --git a/Source/Tests/IRLoader/Loader.cpp b/Source/Tests/IRLoader/Loader.cpp index 865080589..e3458163d 100644 --- a/Source/Tests/IRLoader/Loader.cpp +++ b/Source/Tests/IRLoader/Loader.cpp @@ -363,7 +363,7 @@ namespace FEX::IRLoader { if (!CheckPrintError(Def, CodeBlockCount.first)) return false; EntryRIP = Entry.second; - IRHeader = _IRHeader(InvalidNode, Entry.second, CodeBlockCount.second); + IRHeader = _IRHeader(InvalidNode, Entry.second, CodeBlockCount.second, false); } // Spin through the blocks and generate basic block ops