mirror of
https://github.com/FEX-Emu/FEX.git
synced 2025-01-10 15:50:18 +00:00
Merge pull request #725 from FEX-Emu/skmp/single-compiler-backend
Core: Single compiler backend
This commit is contained in:
commit
2edb14538f
1
External/FEXCore/Source/CMakeLists.txt
vendored
1
External/FEXCore/Source/CMakeLists.txt
vendored
@ -131,6 +131,7 @@ set (SRCS
|
||||
Interface/Core/X86DebugInfo.cpp
|
||||
Interface/Core/X86HelperGen.cpp
|
||||
Interface/Core/Interpreter/InterpreterCore.cpp
|
||||
Interface/Core/Interpreter/InterpreterOps.cpp
|
||||
Interface/Core/X86Tables/BaseTables.cpp
|
||||
Interface/Core/X86Tables/DDDTables.cpp
|
||||
Interface/Core/X86Tables/EVEXTables.cpp
|
||||
|
@ -70,6 +70,9 @@ namespace FEXCore::Context {
|
||||
|
||||
} Config;
|
||||
|
||||
using IntCallbackReturn = __attribute__((naked)) void(*)(FEXCore::Core::InternalThreadState *Thread, volatile void *Host_RSP);
|
||||
IntCallbackReturn InterpreterCallbackReturn;
|
||||
|
||||
FEXCore::HostFeatures HostFeatures;
|
||||
|
||||
std::mutex ThreadCreationMutex;
|
||||
@ -143,7 +146,6 @@ namespace FEXCore::Context {
|
||||
|
||||
std::tuple<void *, FEXCore::IR::IRListView<true> *, FEXCore::Core::DebugData *, FEXCore::IR::RegisterAllocationData *, bool> CompileCode(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP);
|
||||
uintptr_t CompileBlock(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP);
|
||||
uintptr_t CompileFallbackBlock(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP);
|
||||
|
||||
// Used for thread creation from syscalls
|
||||
void InitializeCompiler(FEXCore::Core::InternalThreadState* State, bool CompileThread);
|
||||
|
@ -68,7 +68,6 @@ namespace FEXCore {
|
||||
auto SelectedThread = Thread->IsCompileService ? ParentThread : Thread;
|
||||
SelectedThread->LookupCache->ClearCache();
|
||||
SelectedThread->CPUBackend->ClearCache();
|
||||
SelectedThread->IntBackend->ClearCache();
|
||||
}
|
||||
|
||||
|
||||
|
69
External/FEXCore/Source/Interface/Core/Core.cpp
vendored
69
External/FEXCore/Source/Interface/Core/Core.cpp
vendored
@ -457,8 +457,6 @@ namespace FEXCore::Context {
|
||||
|
||||
void Context::InitializeThreadData(FEXCore::Core::InternalThreadState *Thread) {
|
||||
Thread->CPUBackend->Initialize();
|
||||
Thread->IntBackend->Initialize();
|
||||
Thread->FallbackBackend->Initialize();
|
||||
|
||||
auto IRHandler = [Thread](uint64_t Addr, IR::IREmitter *IR) -> void {
|
||||
// Run the passmanager over the IR from the dispatcher
|
||||
@ -520,23 +518,14 @@ namespace FEXCore::Context {
|
||||
switch (Config.Core) {
|
||||
case FEXCore::Config::CONFIG_INTERPRETER:
|
||||
State->CPUBackend.reset(FEXCore::CPU::CreateInterpreterCore(this, State, CompileThread));
|
||||
State->IntBackend = State->CPUBackend;
|
||||
break;
|
||||
case FEXCore::Config::CONFIG_IRJIT:
|
||||
State->PassManager->InsertRegisterAllocationPass(DoSRA);
|
||||
// Initialization order matters here, the IR JIT may want to have the interpreter created first to get a pointer to its execution function
|
||||
// This is useful for JIT to interpreter fallback support
|
||||
State->IntBackend.reset(FEXCore::CPU::CreateInterpreterCore(this, State, CompileThread));
|
||||
State->CPUBackend.reset(FEXCore::CPU::CreateJITCore(this, State, CompileThread));
|
||||
break;
|
||||
case FEXCore::Config::CONFIG_CUSTOM: State->CPUBackend.reset(CustomCPUFactory(this, &State->State)); break;
|
||||
default: LogMan::Msg::A("Unknown core configuration");
|
||||
}
|
||||
|
||||
if (!State->IntBackend) {
|
||||
State->IntBackend.reset(FEXCore::CPU::CreateInterpreterCore(this, State, CompileThread));
|
||||
}
|
||||
State->FallbackBackend.reset(FallbackCPUFactory(this, &State->State));
|
||||
}
|
||||
|
||||
FEXCore::Core::InternalThreadState* Context::CreateThread(FEXCore::Core::CPUState *NewThreadState, uint64_t ParentTID) {
|
||||
@ -557,7 +546,6 @@ namespace FEXCore::Context {
|
||||
|
||||
InitializeCompiler(Thread, false);
|
||||
|
||||
LogMan::Throw::A(!Thread->FallbackBackend->NeedsOpDispatch(), "Fallback CPU backend must not require OpDispatch");
|
||||
return Thread;
|
||||
}
|
||||
|
||||
@ -568,7 +556,9 @@ namespace FEXCore::Context {
|
||||
void Context::ClearCodeCache(FEXCore::Core::InternalThreadState *Thread, bool AlsoClearIRCache) {
|
||||
Thread->LookupCache->ClearCache();
|
||||
Thread->CPUBackend->ClearCache();
|
||||
Thread->IntBackend->ClearCache();
|
||||
if (Thread->CompileService) {
|
||||
Thread->CompileService->ClearCache(Thread);
|
||||
}
|
||||
|
||||
if (AlsoClearIRCache) {
|
||||
Thread->IRLists.clear();
|
||||
@ -857,49 +847,40 @@ namespace FEXCore::Context {
|
||||
GeneratedIR = Generated;
|
||||
}
|
||||
|
||||
if (CodePtr != nullptr) {
|
||||
// The core managed to compile the code.
|
||||
LogMan::Throw::A(CodePtr != nullptr, "Failed to compile code %lX", GuestRIP);
|
||||
|
||||
// The core managed to compile the code.
|
||||
#if ENABLE_JITSYMBOLS
|
||||
if (DebugData) {
|
||||
if (DebugData->Subblocks.size()) {
|
||||
for (auto& Subblock: DebugData->Subblocks) {
|
||||
Symbols.Register((void*)Subblock.HostCodeStart, GuestRIP, Subblock.HostCodeSize);
|
||||
}
|
||||
} else {
|
||||
Symbols.Register(CodePtr, GuestRIP, DebugData->HostCodeSize);
|
||||
if (DebugData) {
|
||||
if (DebugData->Subblocks.size()) {
|
||||
for (auto& Subblock: DebugData->Subblocks) {
|
||||
Symbols.Register((void*)Subblock.HostCodeStart, GuestRIP, Subblock.HostCodeSize);
|
||||
}
|
||||
} else {
|
||||
Symbols.Register(CodePtr, GuestRIP, DebugData->HostCodeSize);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Insert to caches if we generated IR
|
||||
if (GeneratedIR) {
|
||||
Thread->IRLists.emplace(GuestRIP, IRList);
|
||||
Thread->DebugData.emplace(GuestRIP, DebugData);
|
||||
Thread->RALists.emplace(GuestRIP, RAData);
|
||||
}
|
||||
|
||||
if (DecrementRefCount)
|
||||
--Thread->CompileBlockReentrantRefCount;
|
||||
|
||||
// Insert to lookup cache
|
||||
AddBlockMapping(Thread, GuestRIP, CodePtr);
|
||||
|
||||
return (uintptr_t)CodePtr;
|
||||
// Insert to caches if we generated IR
|
||||
if (GeneratedIR) {
|
||||
Thread->IRLists.emplace(GuestRIP, IRList);
|
||||
Thread->DebugData.emplace(GuestRIP, DebugData);
|
||||
Thread->RALists.emplace(GuestRIP, RAData);
|
||||
}
|
||||
|
||||
if (DecrementRefCount)
|
||||
--Thread->CompileBlockReentrantRefCount;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uintptr_t Context::CompileFallbackBlock(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) {
|
||||
// We have ONE more chance to try and fallback to the fallback CPU backend
|
||||
// This will most likely fail since regular code use won't be using a fallback core.
|
||||
// It's mainly for testing new instruction encodings
|
||||
void *CodePtr = Thread->FallbackBackend->CompileCode(nullptr, nullptr, nullptr);
|
||||
// Insert to lookup cache
|
||||
AddBlockMapping(Thread, GuestRIP, CodePtr);
|
||||
|
||||
return (uintptr_t)CodePtr;
|
||||
|
||||
if (DecrementRefCount)
|
||||
--Thread->CompileBlockReentrantRefCount;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Context::ExecutionThread(FEXCore::Core::InternalThreadState *Thread) {
|
||||
|
@ -540,6 +540,10 @@ void InterpreterCore::CreateAsmDispatch(FEXCore::Context::Context *ctx, FEXCore:
|
||||
Generator = new DispatchGenerator(ctx, Thread);
|
||||
DispatchPtr = Generator->DispatchPtr;
|
||||
CallbackPtr = Generator->CallbackPtr;
|
||||
|
||||
// TODO: Implement this. It is missing from the dispatcher
|
||||
// TODO: It feels wrong to initialize this way
|
||||
ctx->InterpreterCallbackReturn = nullptr;
|
||||
}
|
||||
|
||||
bool InterpreterCore::HandleGuestSignal(int Signal, void *info, void *ucontext, GuestSigAction *GuestAction, stack_t *GuestStack) {
|
||||
|
@ -28,14 +28,9 @@ public:
|
||||
|
||||
bool NeedsOpDispatch() override { return true; }
|
||||
|
||||
void ExecuteCode(FEXCore::Core::InternalThreadState *Thread);
|
||||
|
||||
void CreateAsmDispatch(FEXCore::Context::Context *ctx, FEXCore::Core::InternalThreadState *Thread);
|
||||
void DeleteAsmDispatch();
|
||||
|
||||
using CallbackReturn = __attribute__((naked)) void(*)(FEXCore::Core::InternalThreadState *Thread, volatile void *Host_RSP);
|
||||
CallbackReturn ReturnPtr;
|
||||
|
||||
bool HandleSIGBUS(int Signal, void *info, void *ucontext);
|
||||
|
||||
private:
|
||||
|
File diff suppressed because it is too large
Load Diff
4635
External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.cpp
vendored
Normal file
4635
External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
19
External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.h
vendored
Normal file
19
External/FEXCore/Source/Interface/Core/Interpreter/InterpreterOps.h
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
namespace FEXCore::Core {
|
||||
struct InternalThreadState;
|
||||
}
|
||||
|
||||
namespace FEXCore::IR {
|
||||
template<bool copy>
|
||||
class IRListView;
|
||||
}
|
||||
|
||||
namespace FEXCore::Core{
|
||||
struct DebugData;
|
||||
}
|
||||
|
||||
namespace FEXCore::CPU {
|
||||
class InterpreterOps {
|
||||
public:
|
||||
static void InterpretIR(FEXCore::Core::InternalThreadState *Thread, FEXCore::IR::IRListView<true> *CurrentIR, FEXCore::Core::DebugData *DebugData);
|
||||
};
|
||||
};
|
@ -1,5 +1,6 @@
|
||||
#include "Common/MathUtils.h"
|
||||
#include "Interface/Core/Interpreter/InterpreterClass.h"
|
||||
#include "Interface/Context/Context.h"
|
||||
#include <FEXCore/Core/X86Enums.h>
|
||||
|
||||
#include <cmath>
|
||||
@ -17,7 +18,7 @@ class DispatchGenerator : public Xbyak::CodeGenerator {
|
||||
|
||||
CPUBackend::AsmDispatch DispatchPtr;
|
||||
CPUBackend::JITCallback CallbackPtr;
|
||||
InterpreterCore::CallbackReturn ReturnPtr;
|
||||
FEXCore::Context::Context::IntCallbackReturn ReturnPtr;
|
||||
|
||||
uint64_t ThreadStopHandlerAddress;
|
||||
uint64_t AbsoluteLoopTopAddress;
|
||||
@ -238,7 +239,7 @@ DispatchGenerator::DispatchGenerator(FEXCore::Context::Context *ctx, FEXCore::Co
|
||||
|
||||
|
||||
{
|
||||
ReturnPtr = getCurr<InterpreterCore::CallbackReturn>();
|
||||
ReturnPtr = getCurr<FEXCore::Context::Context::IntCallbackReturn>();
|
||||
// using CallbackReturn = __attribute__((naked)) void(*)(FEXCore::Core::InternalThreadState *Thread, volatile void *Host_RSP);
|
||||
|
||||
// rdi = thread
|
||||
@ -447,7 +448,9 @@ void InterpreterCore::CreateAsmDispatch(FEXCore::Context::Context *ctx, FEXCore:
|
||||
Generator = new DispatchGenerator(ctx, Thread);
|
||||
DispatchPtr = Generator->DispatchPtr;
|
||||
CallbackPtr = Generator->CallbackPtr;
|
||||
ReturnPtr = Generator->ReturnPtr;
|
||||
|
||||
// TODO: It feels wrong to initialize this way
|
||||
ctx->InterpreterCallbackReturn = Generator->ReturnPtr;
|
||||
}
|
||||
|
||||
bool InterpreterCore::HandleGuestSignal(int Signal, void *info, void *ucontext, GuestSigAction *GuestAction, stack_t *GuestStack) {
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <FEXCore/Core/X86Enums.h>
|
||||
#include <FEXCore/Core/UContext.h>
|
||||
#include "Interface/Core/Interpreter/InterpreterOps.h"
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <stdio.h>
|
||||
@ -854,6 +855,12 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView<true> const
|
||||
str(x0, MemOperand(STATE, offsetof(FEXCore::Core::ThreadState, State.rip)));
|
||||
|
||||
LoadConstant(x0, ThreadSharedData.InterpreterFallbackHelperAddress);
|
||||
LoadConstant(x1, (uintptr_t)IR);
|
||||
|
||||
// Debug data is only used in debug builds
|
||||
#ifndef NDEBUG
|
||||
LoadConstant(x2, (uintptr_t)DebugData);
|
||||
#endif
|
||||
br(x0);
|
||||
} else {
|
||||
//LogMan::Throw::A(RAData->HasFullRA(), "Arm64 JIT only works with RA");
|
||||
@ -1092,11 +1099,10 @@ void JITCore::CreateCustomDispatch(FEXCore::Core::InternalThreadState *Thread) {
|
||||
Literal l_VirtualMemory {VirtualMemorySize};
|
||||
Literal l_PagePtr {Thread->LookupCache->GetPagePointer()};
|
||||
Literal l_CTX {reinterpret_cast<uintptr_t>(CTX)};
|
||||
Literal l_Interpreter {reinterpret_cast<uint64_t>(State->IntBackend->CompileCode(nullptr, nullptr, nullptr))};
|
||||
Literal l_Interpreter {reinterpret_cast<uint64_t>(&InterpreterOps::InterpretIR)};
|
||||
Literal l_Sleep {reinterpret_cast<uint64_t>(SleepThread)};
|
||||
|
||||
uintptr_t CompileBlockPtr{};
|
||||
uintptr_t CompileFallbackPtr{};
|
||||
{
|
||||
using ClassPtrType = uintptr_t (FEXCore::Context::Context::*)(FEXCore::Core::InternalThreadState *, uint64_t);
|
||||
union PtrCast {
|
||||
@ -1108,20 +1114,8 @@ void JITCore::CreateCustomDispatch(FEXCore::Core::InternalThreadState *Thread) {
|
||||
Ptr.ClassPtr = &FEXCore::Context::Context::CompileBlock;
|
||||
CompileBlockPtr = Ptr.Data;
|
||||
}
|
||||
{
|
||||
using ClassPtrType = uintptr_t (FEXCore::Context::Context::*)(FEXCore::Core::InternalThreadState *, uint64_t);
|
||||
union PtrCast {
|
||||
ClassPtrType ClassPtr;
|
||||
uintptr_t Data;
|
||||
};
|
||||
|
||||
PtrCast Ptr;
|
||||
Ptr.ClassPtr = &FEXCore::Context::Context::CompileFallbackBlock;
|
||||
CompileFallbackPtr = Ptr.Data;
|
||||
}
|
||||
|
||||
Literal l_CompileBlock {CompileBlockPtr};
|
||||
Literal l_CompileFallback {CompileFallbackPtr};
|
||||
Literal l_ExitFunctionLink {(uintptr_t)&ExitFunctionLink};
|
||||
|
||||
// Push all the register we need to save
|
||||
@ -1257,7 +1251,6 @@ void JITCore::CreateCustomDispatch(FEXCore::Core::InternalThreadState *Thread) {
|
||||
br(x0);
|
||||
}
|
||||
|
||||
aarch64::Label FallbackCore;
|
||||
// Need to create the block
|
||||
{
|
||||
bind(&NoBlock);
|
||||
@ -1271,31 +1264,12 @@ void JITCore::CreateCustomDispatch(FEXCore::Core::InternalThreadState *Thread) {
|
||||
blr(x3); // { CTX, ThreadState, RIP}
|
||||
FillStaticRegs();
|
||||
|
||||
// X0 now contains either nullptr or block pointer
|
||||
cbz(x0, &FallbackCore);
|
||||
// X0 now contains the block pointer
|
||||
blr(x0);
|
||||
|
||||
b(&LoopTop);
|
||||
}
|
||||
|
||||
// We need to fallback to our fallback core
|
||||
{
|
||||
bind(&FallbackCore);
|
||||
|
||||
ldr(x0, &l_CTX);
|
||||
mov(x1, STATE);
|
||||
ldr(x3, &l_CompileFallback);
|
||||
|
||||
// X2 contains our guest RIP
|
||||
SpillStaticRegs();
|
||||
blr(x3); // {ThreadState, RIP}
|
||||
FillStaticRegs();
|
||||
|
||||
// X0 now contains either nullptr or block pointer
|
||||
cbz(x0, &ExitSpillSRA);
|
||||
br(x0);
|
||||
}
|
||||
|
||||
{
|
||||
Label RestoreContextStateHelperLabel{};
|
||||
bind(&RestoreContextStateHelperLabel);
|
||||
@ -1312,9 +1286,9 @@ void JITCore::CreateCustomDispatch(FEXCore::Core::InternalThreadState *Thread) {
|
||||
ThreadSharedData.InterpreterFallbackHelperAddress = Buffer->GetOffsetAddress<uint64_t>(GetCursorOffset());
|
||||
SpillStaticRegs();
|
||||
mov(x0, STATE);
|
||||
ldr(x1, &l_Interpreter);
|
||||
ldr(x3, &l_Interpreter);
|
||||
|
||||
blr(x1);
|
||||
blr(x3);
|
||||
FillStaticRegs();
|
||||
b(&LoopTop);
|
||||
}
|
||||
@ -1396,7 +1370,6 @@ void JITCore::CreateCustomDispatch(FEXCore::Core::InternalThreadState *Thread) {
|
||||
place(&l_Interpreter);
|
||||
place(&l_Sleep);
|
||||
place(&l_CompileBlock);
|
||||
place(&l_CompileFallback);
|
||||
place(&l_ExitFunctionLink);
|
||||
|
||||
FinalizeCode();
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include <cmath>
|
||||
#include <signal.h>
|
||||
|
||||
#include "Interface/Core/Interpreter/InterpreterOps.h"
|
||||
|
||||
// #define DEBUG_RA 1
|
||||
// #define DEBUG_CYCLES
|
||||
|
||||
@ -641,6 +643,13 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView<true> const
|
||||
if (HeaderOp->ShouldInterpret) {
|
||||
mov(rax, HeaderOp->Entry);
|
||||
mov(qword [STATE + offsetof(FEXCore::Core::CPUState, rip)], rax);
|
||||
mov(rsi, (uint64_t)IR);
|
||||
|
||||
// Debug data is only used in debug builds
|
||||
#ifndef NDEBUG
|
||||
mov(rdx, (uint64_t)DebugData);
|
||||
#endif
|
||||
|
||||
mov(rax, (uintptr_t)ThreadSharedData.InterpreterFallbackHelperAddress);
|
||||
jmp(rax);
|
||||
} else {
|
||||
@ -994,9 +1003,8 @@ void JITCore::CreateCustomDispatch(FEXCore::Core::InternalThreadState *Thread) {
|
||||
// Interpreter fallback helper code
|
||||
ThreadSharedData.InterpreterFallbackHelperAddress = getCurr<void*>();
|
||||
// This will get called so our stack is now misaligned
|
||||
mov(rax, reinterpret_cast<uint64_t>(&InterpreterOps::InterpretIR));
|
||||
mov(rdi, STATE);
|
||||
mov(rax, reinterpret_cast<uint64_t>(ThreadState->IntBackend->CompileCode(nullptr, nullptr, nullptr)));
|
||||
|
||||
call(rax);
|
||||
|
||||
jmp(LoopTop);
|
||||
|
@ -73,10 +73,7 @@ namespace FEXCore::Core {
|
||||
|
||||
std::unique_ptr<FEXCore::IR::OpDispatchBuilder> OpDispatcher;
|
||||
|
||||
std::shared_ptr<FEXCore::CPU::CPUBackend> CPUBackend;
|
||||
std::shared_ptr<FEXCore::CPU::CPUBackend> IntBackend;
|
||||
std::unique_ptr<FEXCore::CPU::CPUBackend> FallbackBackend;
|
||||
|
||||
std::unique_ptr<FEXCore::CPU::CPUBackend> CPUBackend;
|
||||
std::unique_ptr<FEXCore::LookupCache> LookupCache;
|
||||
|
||||
std::unordered_map<uint64_t, std::unique_ptr<FEXCore::IR::IRListView<true>>> IRLists;
|
||||
|
Loading…
x
Reference in New Issue
Block a user