mirror of
https://github.com/FEX-Emu/FEX.git
synced 2025-01-11 00:26:15 +00:00
IR: Add AOT Cache
This commit is contained in:
parent
7b97c3fa23
commit
816c4656df
@ -151,6 +151,13 @@ namespace FEXCore::Context {
|
|||||||
return CTX->CPUID.RunFunction(Function);
|
return CTX->CPUID.RunFunction(Function);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ReadAOT(FEXCore::Context::Context *CTX, std::istream& stream) {
|
||||||
|
return CTX->LoadAOTCache(stream);
|
||||||
|
}
|
||||||
|
void WriteAOT(FEXCore::Context::Context *CTX, std::ostream& stream) {
|
||||||
|
CTX->WriteAOTCache(stream);
|
||||||
|
}
|
||||||
|
|
||||||
namespace Debug {
|
namespace Debug {
|
||||||
void CompileRIP(FEXCore::Context::Context *CTX, uint64_t RIP) {
|
void CompileRIP(FEXCore::Context::Context *CTX, uint64_t RIP) {
|
||||||
CTX->CompileRIP(CTX->ParentThread, RIP);
|
CTX->CompileRIP(CTX->ParentThread, RIP);
|
||||||
|
@ -6,13 +6,18 @@
|
|||||||
#include "Interface/Core/InternalThreadState.h"
|
#include "Interface/Core/InternalThreadState.h"
|
||||||
#include "Interface/Core/X86HelperGen.h"
|
#include "Interface/Core/X86HelperGen.h"
|
||||||
#include "Interface/IR/PassManager.h"
|
#include "Interface/IR/PassManager.h"
|
||||||
|
#include "Interface/IR/Passes/RegisterAllocationPass.h"
|
||||||
#include <FEXCore/Config/Config.h>
|
#include <FEXCore/Config/Config.h>
|
||||||
#include <FEXCore/Core/CPUBackend.h>
|
#include <FEXCore/Core/CPUBackend.h>
|
||||||
#include <FEXCore/Utils/Event.h>
|
#include <FEXCore/Utils/Event.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <istream>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
namespace FEXCore {
|
namespace FEXCore {
|
||||||
class ThunkHandler;
|
class ThunkHandler;
|
||||||
@ -30,6 +35,8 @@ class SyscallHandler;
|
|||||||
|
|
||||||
namespace FEXCore::IR {
|
namespace FEXCore::IR {
|
||||||
class RegisterAllocationPass;
|
class RegisterAllocationPass;
|
||||||
|
class RegisterAllocationData;
|
||||||
|
class IRListView;
|
||||||
namespace Validation {
|
namespace Validation {
|
||||||
class IRValidation;
|
class IRValidation;
|
||||||
}
|
}
|
||||||
@ -96,6 +103,14 @@ namespace FEXCore::Context {
|
|||||||
CustomCPUFactoryType FallbackCPUFactory;
|
CustomCPUFactoryType FallbackCPUFactory;
|
||||||
std::function<void(uint64_t ThreadId, FEXCore::Context::ExitReason)> CustomExitHandler;
|
std::function<void(uint64_t ThreadId, FEXCore::Context::ExitReason)> CustomExitHandler;
|
||||||
|
|
||||||
|
struct AOTCacheEntry {
|
||||||
|
uint64_t start;
|
||||||
|
uint64_t len;
|
||||||
|
uint64_t crc;
|
||||||
|
IR::IRListView *IR;
|
||||||
|
IR::RegisterAllocationData *RAData;
|
||||||
|
};
|
||||||
|
std::map<uint64_t, AOTCacheEntry> AOTCache;
|
||||||
#ifdef BLOCKSTATS
|
#ifdef BLOCKSTATS
|
||||||
std::unique_ptr<FEXCore::BlockSamplingData> BlockData;
|
std::unique_ptr<FEXCore::BlockSamplingData> BlockData;
|
||||||
#endif
|
#endif
|
||||||
@ -142,11 +157,13 @@ namespace FEXCore::Context {
|
|||||||
FEXCore::Core::ThreadState *GetThreadState();
|
FEXCore::Core::ThreadState *GetThreadState();
|
||||||
void LoadEntryList();
|
void LoadEntryList();
|
||||||
|
|
||||||
std::tuple<FEXCore::IR::IRListView<true> *, FEXCore::IR::RegisterAllocationData *, uint64_t, uint64_t> GenerateIR(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP);
|
std::tuple<FEXCore::IR::IRListView *, FEXCore::IR::RegisterAllocationData *, uint64_t, uint64_t> GenerateIR(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP);
|
||||||
|
|
||||||
std::tuple<void *, FEXCore::IR::IRListView<true> *, FEXCore::Core::DebugData *, FEXCore::IR::RegisterAllocationData *, bool> CompileCode(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP);
|
std::tuple<void *, FEXCore::IR::IRListView *, 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 CompileBlock(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP);
|
||||||
|
|
||||||
|
bool LoadAOTCache(std::istream &stream);
|
||||||
|
void WriteAOTCache(std::ostream &stream);
|
||||||
// Used for thread creation from syscalls
|
// Used for thread creation from syscalls
|
||||||
void InitializeCompiler(FEXCore::Core::InternalThreadState* State, bool CompileThread);
|
void InitializeCompiler(FEXCore::Core::InternalThreadState* State, bool CompileThread);
|
||||||
FEXCore::Core::InternalThreadState* CreateThread(FEXCore::Core::CPUState *NewThreadState, uint64_t ParentTID);
|
FEXCore::Core::InternalThreadState* CreateThread(FEXCore::Core::CPUState *NewThreadState, uint64_t ParentTID);
|
||||||
|
@ -31,7 +31,7 @@ class CompileService final {
|
|||||||
|
|
||||||
// Outgoing
|
// Outgoing
|
||||||
void *CodePtr{};
|
void *CodePtr{};
|
||||||
FEXCore::IR::IRListView<true> *IRList{};
|
FEXCore::IR::IRListView *IRList{};
|
||||||
FEXCore::IR::RegisterAllocationData *RAData{};
|
FEXCore::IR::RegisterAllocationData *RAData{};
|
||||||
FEXCore::Core::DebugData *DebugData{};
|
FEXCore::Core::DebugData *DebugData{};
|
||||||
|
|
||||||
|
102
External/FEXCore/Source/Interface/Core/Core.cpp
vendored
102
External/FEXCore/Source/Interface/Core/Core.cpp
vendored
@ -35,6 +35,8 @@ namespace FEXCore::CPU {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::mutex AOTCacheLock;
|
||||||
|
|
||||||
namespace FEXCore::Core {
|
namespace FEXCore::Core {
|
||||||
struct ThreadLocalData {
|
struct ThreadLocalData {
|
||||||
FEXCore::Core::InternalThreadState* Thread;
|
FEXCore::Core::InternalThreadState* Thread;
|
||||||
@ -111,7 +113,7 @@ namespace DefaultFallbackCore {
|
|||||||
void Initialize() override {}
|
void Initialize() override {}
|
||||||
bool NeedsOpDispatch() override { return false; }
|
bool NeedsOpDispatch() override { return false; }
|
||||||
|
|
||||||
void *CompileCode(FEXCore::IR::IRListView<true> const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override {
|
void *CompileCode(FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override {
|
||||||
LogMan::Msg::E("Fell back to default code handler at RIP: 0x%lx", ThreadState->State.State.rip);
|
LogMan::Msg::E("Fell back to default code handler at RIP: 0x%lx", ThreadState->State.State.rip);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -572,7 +574,7 @@ namespace FEXCore::Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<FEXCore::IR::IRListView<true> *, FEXCore::IR::RegisterAllocationData *, uint64_t, uint64_t> Context::GenerateIR(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) {
|
std::tuple<FEXCore::IR::IRListView *, FEXCore::IR::RegisterAllocationData *, uint64_t, uint64_t> Context::GenerateIR(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) {
|
||||||
uint8_t const *GuestCode{};
|
uint8_t const *GuestCode{};
|
||||||
GuestCode = reinterpret_cast<uint8_t const*>(GuestRIP);
|
GuestCode = reinterpret_cast<uint8_t const*>(GuestRIP);
|
||||||
|
|
||||||
@ -764,8 +766,8 @@ namespace FEXCore::Context {
|
|||||||
return {IRList, RAData.release(), TotalInstructions, TotalInstructionsLength};
|
return {IRList, RAData.release(), TotalInstructions, TotalInstructionsLength};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<void *, FEXCore::IR::IRListView<true> *, FEXCore::Core::DebugData *, FEXCore::IR::RegisterAllocationData *, bool> Context::CompileCode(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) {
|
std::tuple<void *, FEXCore::IR::IRListView *, FEXCore::Core::DebugData *, FEXCore::IR::RegisterAllocationData *, bool> Context::CompileCode(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) {
|
||||||
FEXCore::IR::IRListView<true> *IRList {};
|
FEXCore::IR::IRListView *IRList {};
|
||||||
FEXCore::Core::DebugData *DebugData {};
|
FEXCore::Core::DebugData *DebugData {};
|
||||||
FEXCore::IR::RegisterAllocationData *RAData {};
|
FEXCore::IR::RegisterAllocationData *RAData {};
|
||||||
bool GeneratedIR {};
|
bool GeneratedIR {};
|
||||||
@ -781,8 +783,21 @@ namespace FEXCore::Context {
|
|||||||
RAData = Thread->RALists.find(GuestRIP)->second.get();
|
RAData = Thread->RALists.find(GuestRIP)->second.get();
|
||||||
|
|
||||||
GeneratedIR = false;
|
GeneratedIR = false;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
if (IRList == nullptr) {
|
||||||
|
std::lock_guard<std::mutex> lk(AOTCacheLock);
|
||||||
|
auto AOTEntry = AOTCache.find(GuestRIP);
|
||||||
|
if (AOTEntry != AOTCache.end()) {
|
||||||
|
IRList = AOTEntry->second.IR;
|
||||||
|
RAData = AOTEntry->second.RAData;
|
||||||
|
DebugData = new FEXCore::Core::DebugData();
|
||||||
|
|
||||||
|
GeneratedIR = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IRList == nullptr) {
|
||||||
// Generate IR + Meta Info
|
// Generate IR + Meta Info
|
||||||
auto [IRCopy, RACopy, TotalInstructions, TotalInstructionsLength] = GenerateIR(Thread, GuestRIP);
|
auto [IRCopy, RACopy, TotalInstructions, TotalInstructionsLength] = GenerateIR(Thread, GuestRIP);
|
||||||
|
|
||||||
@ -806,6 +821,76 @@ namespace FEXCore::Context {
|
|||||||
return { Thread->CPUBackend->CompileCode(IRList, DebugData, RAData), IRList, DebugData, RAData, GeneratedIR};
|
return { Thread->CPUBackend->CompileCode(IRList, DebugData, RAData), IRList, DebugData, RAData, GeneratedIR};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Context::LoadAOTCache(std::istream &stream) {
|
||||||
|
std::lock_guard<std::mutex> lk(AOTCacheLock);
|
||||||
|
AOTCache.clear();
|
||||||
|
uint64_t tag;
|
||||||
|
stream.read((char*)&tag, sizeof(tag));
|
||||||
|
if (!stream || tag != 0xDEADBEEFC0D30000)
|
||||||
|
return false;
|
||||||
|
do {
|
||||||
|
uint64_t addr, start, crc, len;
|
||||||
|
stream.read((char*)&addr, sizeof(addr));
|
||||||
|
if (!stream)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
stream.read((char*)&start, sizeof(start));
|
||||||
|
if (!stream)
|
||||||
|
return false;
|
||||||
|
stream.read((char*)&len, sizeof(len));
|
||||||
|
if (!stream)
|
||||||
|
return false;
|
||||||
|
stream.read((char*)&crc, sizeof(crc));
|
||||||
|
if (!stream)
|
||||||
|
return false;
|
||||||
|
auto IR = new IR::IRListView(stream);
|
||||||
|
if (!stream) {
|
||||||
|
delete IR;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint64_t RASize;
|
||||||
|
stream.read((char*)&RASize, sizeof(RASize));
|
||||||
|
if (!stream) {
|
||||||
|
delete IR;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
IR::RegisterAllocationData *RAData = (IR::RegisterAllocationData *)malloc(IR::RegisterAllocationData::Size(RASize));
|
||||||
|
RAData->MapCount = RASize;
|
||||||
|
|
||||||
|
stream.read((char*)&RAData->Map[0], sizeof(RAData->Map[0]) * RASize);
|
||||||
|
|
||||||
|
if (!stream) {
|
||||||
|
delete IR;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
stream.read((char*)&RAData->SpillSlotCount, sizeof(RAData->SpillSlotCount));
|
||||||
|
if (!stream) {
|
||||||
|
delete IR;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
AOTCache.insert({addr, {start, len, crc, IR, RAData}});
|
||||||
|
} while(!stream.eof());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Context::WriteAOTCache(std::ostream &stream) {
|
||||||
|
std::lock_guard<std::mutex> lk(AOTCacheLock);
|
||||||
|
uint64_t tag = 0xDEADBEEFC0D30000;
|
||||||
|
stream.write((char*)&tag, sizeof(tag));
|
||||||
|
for (auto entry: AOTCache) {
|
||||||
|
stream.write((char*)&entry.first, sizeof(entry.first));
|
||||||
|
stream.write((char*)&entry.second.start, sizeof(entry.second.start));
|
||||||
|
stream.write((char*)&entry.second.len, sizeof(entry.second.len));
|
||||||
|
stream.write((char*)&entry.second.crc, sizeof(entry.second.crc));
|
||||||
|
entry.second.IR->Serialize(stream);
|
||||||
|
uint64_t RASize = entry.second.RAData->MapCount;
|
||||||
|
stream.write((char*)&RASize, sizeof(RASize));
|
||||||
|
stream.write((char*)&entry.second.RAData->Map[0], sizeof(entry.second.RAData->Map[0]) * RASize);
|
||||||
|
stream.write((char*)&entry.second.RAData->SpillSlotCount, sizeof(entry.second.RAData->SpillSlotCount));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
uintptr_t Context::CompileBlock(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) {
|
uintptr_t Context::CompileBlock(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) {
|
||||||
|
|
||||||
// Is the code in the cache?
|
// Is the code in the cache?
|
||||||
@ -815,7 +900,7 @@ namespace FEXCore::Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void *CodePtr {};
|
void *CodePtr {};
|
||||||
FEXCore::IR::IRListView<true> *IRList {};
|
FEXCore::IR::IRListView *IRList {};
|
||||||
FEXCore::Core::DebugData *DebugData {};
|
FEXCore::Core::DebugData *DebugData {};
|
||||||
FEXCore::IR::RegisterAllocationData *RAData {};
|
FEXCore::IR::RegisterAllocationData *RAData {};
|
||||||
|
|
||||||
@ -872,6 +957,11 @@ namespace FEXCore::Context {
|
|||||||
Thread->IRLists.emplace(GuestRIP, IRList);
|
Thread->IRLists.emplace(GuestRIP, IRList);
|
||||||
Thread->DebugData.emplace(GuestRIP, DebugData);
|
Thread->DebugData.emplace(GuestRIP, DebugData);
|
||||||
Thread->RALists.emplace(GuestRIP, RAData);
|
Thread->RALists.emplace(GuestRIP, RAData);
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(AOTCacheLock);
|
||||||
|
AOTCache.insert({GuestRIP, {0, 0, 0, IRList, RAData}});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DecrementRefCount)
|
if (DecrementRefCount)
|
||||||
|
@ -992,6 +992,9 @@ bool Decoder::DecodeInstructionsAtEntry(uint8_t const* _InstStream, uint64_t PC)
|
|||||||
SymbolMinAddress = EntryPoint;
|
SymbolMinAddress = EntryPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DecodedMinAddress = EntryPoint;
|
||||||
|
DecodedMaxAddress = EntryPoint;
|
||||||
|
|
||||||
// Entry is a jump target
|
// Entry is a jump target
|
||||||
BlocksToDecode.emplace(PC);
|
BlocksToDecode.emplace(PC);
|
||||||
|
|
||||||
@ -1024,6 +1027,9 @@ bool Decoder::DecodeInstructionsAtEntry(uint8_t const* _InstStream, uint64_t PC)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DecodedMinAddress = std::min(DecodedMinAddress, PCOffset);
|
||||||
|
DecodedMaxAddress = std::max(DecodedMaxAddress, PCOffset + DecodeInst->InstSize);
|
||||||
|
|
||||||
++TotalInstructions;
|
++TotalInstructions;
|
||||||
++BlockNumberOfInstructions;
|
++BlockNumberOfInstructions;
|
||||||
++DecodedSize;
|
++DecodedSize;
|
||||||
|
@ -30,6 +30,9 @@ public:
|
|||||||
return &Blocks;
|
return &Blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t DecodedMinAddress {};
|
||||||
|
uint64_t DecodedMaxAddress {~0ULL};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FEXCore::Context::Context *CTX;
|
FEXCore::Context::Context *CTX;
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ public:
|
|||||||
explicit InterpreterCore(FEXCore::Context::Context *ctx, FEXCore::Core::InternalThreadState *Thread, bool CompileThread);
|
explicit InterpreterCore(FEXCore::Context::Context *ctx, FEXCore::Core::InternalThreadState *Thread, bool CompileThread);
|
||||||
~InterpreterCore() override;
|
~InterpreterCore() override;
|
||||||
std::string GetName() override { return "Interpreter"; }
|
std::string GetName() override { return "Interpreter"; }
|
||||||
void *CompileCode(FEXCore::IR::IRListView<true> const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override;
|
void *CompileCode(FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override;
|
||||||
|
|
||||||
void *MapRegion(void* HostPtr, uint64_t, uint64_t) override { return HostPtr; }
|
void *MapRegion(void* HostPtr, uint64_t, uint64_t) override { return HostPtr; }
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ InterpreterCore::~InterpreterCore() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void *InterpreterCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView<true> const *IR, [[maybe_unused]] FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) {
|
void *InterpreterCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *IR, [[maybe_unused]] FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) {
|
||||||
return reinterpret_cast<void*>(InterpreterExecution);
|
return reinterpret_cast<void*>(InterpreterExecution);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -922,7 +922,7 @@ bool InterpreterOps::GetFallbackHandler(IR::IROp_Header *IROp, FallbackInfo *Inf
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterpreterOps::InterpretIR(FEXCore::Core::InternalThreadState *Thread, FEXCore::IR::IRListView<true> *CurrentIR, FEXCore::Core::DebugData *DebugData) {
|
void InterpreterOps::InterpretIR(FEXCore::Core::InternalThreadState *Thread, FEXCore::IR::IRListView *CurrentIR, FEXCore::Core::DebugData *DebugData) {
|
||||||
volatile void* stack = alloca(0);
|
volatile void* stack = alloca(0);
|
||||||
|
|
||||||
// Debug data is only passed in debug builds
|
// Debug data is only passed in debug builds
|
||||||
|
@ -3,8 +3,7 @@ namespace FEXCore::Core {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace FEXCore::IR {
|
namespace FEXCore::IR {
|
||||||
template<bool copy>
|
class IRListView;
|
||||||
class IRListView;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace FEXCore::Core{
|
namespace FEXCore::Core{
|
||||||
@ -37,7 +36,7 @@ namespace FEXCore::CPU {
|
|||||||
class InterpreterOps {
|
class InterpreterOps {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void InterpretIR(FEXCore::Core::InternalThreadState *Thread, FEXCore::IR::IRListView<true> *CurrentIR, FEXCore::Core::DebugData *DebugData);
|
static void InterpretIR(FEXCore::Core::InternalThreadState *Thread, FEXCore::IR::IRListView *CurrentIR, FEXCore::Core::DebugData *DebugData);
|
||||||
static bool GetFallbackHandler(IR::IROp_Header *IROp, FallbackInfo *Info);
|
static bool GetFallbackHandler(IR::IROp_Header *IROp, FallbackInfo *Info);
|
||||||
};
|
};
|
||||||
};
|
};
|
@ -1033,7 +1033,7 @@ bool JITCore::IsGPR(uint32_t Node) {
|
|||||||
return Class == IR::GPRClass || Class == IR::GPRFixedClass;
|
return Class == IR::GPRClass || Class == IR::GPRFixedClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView<true> const *IR, [[maybe_unused]] FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) {
|
void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *IR, [[maybe_unused]] FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) {
|
||||||
using namespace aarch64;
|
using namespace aarch64;
|
||||||
JumpTargets.clear();
|
JumpTargets.clear();
|
||||||
uint32_t SSACount = IR->GetSSACount();
|
uint32_t SSACount = IR->GetSSACount();
|
||||||
|
@ -78,7 +78,7 @@ public:
|
|||||||
|
|
||||||
~JITCore() override;
|
~JITCore() override;
|
||||||
std::string GetName() override { return "JIT"; }
|
std::string GetName() override { return "JIT"; }
|
||||||
void *CompileCode(FEXCore::IR::IRListView<true> const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override;
|
void *CompileCode(FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override;
|
||||||
|
|
||||||
void *MapRegion(void* HostPtr, uint64_t, uint64_t) override { return HostPtr; }
|
void *MapRegion(void* HostPtr, uint64_t, uint64_t) override { return HostPtr; }
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ private:
|
|||||||
Label *PendingTargetLabel;
|
Label *PendingTargetLabel;
|
||||||
FEXCore::Context::Context *CTX;
|
FEXCore::Context::Context *CTX;
|
||||||
FEXCore::Core::InternalThreadState *State;
|
FEXCore::Core::InternalThreadState *State;
|
||||||
FEXCore::IR::IRListView<true> const *IR;
|
FEXCore::IR::IRListView const *IR;
|
||||||
|
|
||||||
std::map<IR::OrderedNodeWrapper::NodeOffsetType, aarch64::Label> JumpTargets;
|
std::map<IR::OrderedNodeWrapper::NodeOffsetType, aarch64::Label> JumpTargets;
|
||||||
|
|
||||||
|
@ -838,7 +838,7 @@ std::tuple<JITCore::SetCC, JITCore::CMovCC, JITCore::JCC> JITCore::GetCC(IR::Con
|
|||||||
return { &CodeGenerator::sete , &CodeGenerator::cmove , &CodeGenerator::je };
|
return { &CodeGenerator::sete , &CodeGenerator::cmove , &CodeGenerator::je };
|
||||||
}
|
}
|
||||||
|
|
||||||
void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView<true> const *IR, [[maybe_unused]] FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) {
|
void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *IR, [[maybe_unused]] FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) {
|
||||||
JumpTargets.clear();
|
JumpTargets.clear();
|
||||||
uint32_t SSACount = IR->GetSSACount();
|
uint32_t SSACount = IR->GetSSACount();
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ public:
|
|||||||
explicit JITCore(FEXCore::Context::Context *ctx, FEXCore::Core::InternalThreadState *Thread, CodeBuffer Buffer, bool CompileThread);
|
explicit JITCore(FEXCore::Context::Context *ctx, FEXCore::Core::InternalThreadState *Thread, CodeBuffer Buffer, bool CompileThread);
|
||||||
~JITCore() override;
|
~JITCore() override;
|
||||||
std::string GetName() override { return "JIT"; }
|
std::string GetName() override { return "JIT"; }
|
||||||
void *CompileCode(FEXCore::IR::IRListView<true> const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override;
|
void *CompileCode(FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override;
|
||||||
|
|
||||||
void *MapRegion(void* HostPtr, uint64_t, uint64_t) override { return HostPtr; }
|
void *MapRegion(void* HostPtr, uint64_t, uint64_t) override { return HostPtr; }
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ private:
|
|||||||
Label* PendingTargetLabel{};
|
Label* PendingTargetLabel{};
|
||||||
FEXCore::Context::Context *CTX;
|
FEXCore::Context::Context *CTX;
|
||||||
FEXCore::Core::InternalThreadState *ThreadState;
|
FEXCore::Core::InternalThreadState *ThreadState;
|
||||||
FEXCore::IR::IRListView<true> const *IR;
|
FEXCore::IR::IRListView const *IR;
|
||||||
|
|
||||||
std::unordered_map<IR::OrderedNodeWrapper::NodeOffsetType, Label> JumpTargets;
|
std::unordered_map<IR::OrderedNodeWrapper::NodeOffsetType, Label> JumpTargets;
|
||||||
Xbyak::util::Cpu Features{};
|
Xbyak::util::Cpu Features{};
|
||||||
|
@ -12,15 +12,15 @@ namespace FEXCore::IR {
|
|||||||
|
|
||||||
#include <FEXCore/IR/IRDefines.inc>
|
#include <FEXCore/IR/IRDefines.inc>
|
||||||
|
|
||||||
static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView<false> const* IR, uint64_t Arg) {
|
static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView const* IR, uint64_t Arg) {
|
||||||
*out << "#0x" << std::hex << Arg;
|
*out << "#0x" << std::hex << Arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView<false> const* IR, const char* Arg) {
|
static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView const* IR, const char* Arg) {
|
||||||
*out << Arg;
|
*out << Arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView<false> const* IR, CondClassType Arg) {
|
static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView const* IR, CondClassType Arg) {
|
||||||
std::array<std::string, 22> CondNames = {
|
std::array<std::string, 22> CondNames = {
|
||||||
"EQ",
|
"EQ",
|
||||||
"NEQ",
|
"NEQ",
|
||||||
@ -49,7 +49,7 @@ static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView<false>
|
|||||||
*out << CondNames[Arg];
|
*out << CondNames[Arg];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView<false> const* IR, MemOffsetType Arg) {
|
static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView const* IR, MemOffsetType Arg) {
|
||||||
std::array<std::string, 3> Names = {
|
std::array<std::string, 3> Names = {
|
||||||
"SXTX",
|
"SXTX",
|
||||||
"UXTW",
|
"UXTW",
|
||||||
@ -59,7 +59,7 @@ static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView<false>
|
|||||||
*out << Names[Arg];
|
*out << Names[Arg];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView<false> const* IR, RegisterClassType Arg) {
|
static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView const* IR, RegisterClassType Arg) {
|
||||||
if (Arg == GPRClass.Val)
|
if (Arg == GPRClass.Val)
|
||||||
*out << "GPR";
|
*out << "GPR";
|
||||||
else if (Arg == GPRFixedClass.Val)
|
else if (Arg == GPRFixedClass.Val)
|
||||||
@ -74,7 +74,7 @@ static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView<false>
|
|||||||
*out << "Unknown Registerclass " << Arg;
|
*out << "Unknown Registerclass " << Arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrintArg(std::stringstream *out, IRListView<false> const* IR, OrderedNodeWrapper Arg, IR::RegisterAllocationData *RAData) {
|
static void PrintArg(std::stringstream *out, IRListView const* IR, OrderedNodeWrapper Arg, IR::RegisterAllocationData *RAData) {
|
||||||
auto [CodeNode, IROp] = IR->at(Arg)();
|
auto [CodeNode, IROp] = IR->at(Arg)();
|
||||||
|
|
||||||
if (Arg.ID() == 0) {
|
if (Arg.ID() == 0) {
|
||||||
@ -123,7 +123,7 @@ static void PrintArg(std::stringstream *out, IRListView<false> const* IR, Ordere
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView<false> const* IR, FEXCore::IR::FenceType Arg) {
|
static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView const* IR, FEXCore::IR::FenceType Arg) {
|
||||||
if (Arg == IR::Fence_Load) {
|
if (Arg == IR::Fence_Load) {
|
||||||
*out << "Loads";
|
*out << "Loads";
|
||||||
}
|
}
|
||||||
@ -138,7 +138,7 @@ static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView<false>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dump(std::stringstream *out, IRListView<false> const* IR, IR::RegisterAllocationData *RAData) {
|
void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAllocationData *RAData) {
|
||||||
auto HeaderOp = IR->GetHeader();
|
auto HeaderOp = IR->GetHeader();
|
||||||
|
|
||||||
int8_t CurrentIndent = 0;
|
int8_t CurrentIndent = 0;
|
||||||
|
@ -258,6 +258,7 @@ namespace {
|
|||||||
Graph->AllocData.reset();
|
Graph->AllocData.reset();
|
||||||
Graph->AllocData.reset((FEXCore::IR::RegisterAllocationData*)malloc(FEXCore::IR::RegisterAllocationData::Size(NodeCount)));
|
Graph->AllocData.reset((FEXCore::IR::RegisterAllocationData*)malloc(FEXCore::IR::RegisterAllocationData::Size(NodeCount)));
|
||||||
memset(&Graph->AllocData->Map[0], INVALID_REGCLASS.Raw, NodeCount);
|
memset(&Graph->AllocData->Map[0], INVALID_REGCLASS.Raw, NodeCount);
|
||||||
|
Graph->AllocData->MapCount = NodeCount;
|
||||||
Graph->NodeCount = NodeCount;
|
Graph->NodeCount = NodeCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,7 +303,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FEXCore::IR::RegisterClassType GetRegClassFromNode(FEXCore::IR::IRListView<false> *IR, FEXCore::IR::IROp_Header *IROp) {
|
FEXCore::IR::RegisterClassType GetRegClassFromNode(FEXCore::IR::IRListView *IR, FEXCore::IR::IROp_Header *IROp) {
|
||||||
using namespace FEXCore;
|
using namespace FEXCore;
|
||||||
|
|
||||||
FEXCore::IR::RegisterClassType Class = IR::GetRegClass(IROp->Op);
|
FEXCore::IR::RegisterClassType Class = IR::GetRegClass(IROp->Op);
|
||||||
@ -356,7 +357,7 @@ namespace {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Walk the IR and set the node classes
|
// Walk the IR and set the node classes
|
||||||
void FindNodeClasses(RegisterGraph *Graph, FEXCore::IR::IRListView<false> *IR) {
|
void FindNodeClasses(RegisterGraph *Graph, FEXCore::IR::IRListView *IR) {
|
||||||
for (auto [CodeNode, IROp] : IR->GetAllCode()) {
|
for (auto [CodeNode, IROp] : IR->GetAllCode()) {
|
||||||
// If the destination hasn't yet been set then set it now
|
// If the destination hasn't yet been set then set it now
|
||||||
if (IROp->HasDest) {
|
if (IROp->HasDest) {
|
||||||
@ -410,14 +411,14 @@ namespace FEXCore::IR {
|
|||||||
std::unordered_map<uint32_t, BlockInterferences> LocalBlockInterferences;
|
std::unordered_map<uint32_t, BlockInterferences> LocalBlockInterferences;
|
||||||
BlockInterferences GlobalBlockInterferences;
|
BlockInterferences GlobalBlockInterferences;
|
||||||
|
|
||||||
void CalculateLiveRange(FEXCore::IR::IRListView<false> *IR);
|
void CalculateLiveRange(FEXCore::IR::IRListView *IR);
|
||||||
void OptimizeStaticRegisters(FEXCore::IR::IRListView<false> *IR);
|
void OptimizeStaticRegisters(FEXCore::IR::IRListView *IR);
|
||||||
void CalculateBlockInterferences(FEXCore::IR::IRListView<false> *IR);
|
void CalculateBlockInterferences(FEXCore::IR::IRListView *IR);
|
||||||
void CalculateBlockNodeInterference(FEXCore::IR::IRListView<false> *IR);
|
void CalculateBlockNodeInterference(FEXCore::IR::IRListView *IR);
|
||||||
void CalculateNodeInterference(FEXCore::IR::IRListView<false> *IR);
|
void CalculateNodeInterference(FEXCore::IR::IRListView *IR);
|
||||||
void AllocateVirtualRegisters();
|
void AllocateVirtualRegisters();
|
||||||
void CalculatePredecessors(FEXCore::IR::IRListView<false> *IR);
|
void CalculatePredecessors(FEXCore::IR::IRListView *IR);
|
||||||
void RecursiveLiveRangeExpansion(FEXCore::IR::IRListView<false> *IR, uint32_t Node, uint32_t DefiningBlockID, LiveRange *LiveRange, const std::unordered_set<uint32_t> &Predecessors, std::unordered_set<uint32_t> &VisitedPredecessors);
|
void RecursiveLiveRangeExpansion(FEXCore::IR::IRListView *IR, uint32_t Node, uint32_t DefiningBlockID, LiveRange *LiveRange, const std::unordered_set<uint32_t> &Predecessors, std::unordered_set<uint32_t> &VisitedPredecessors);
|
||||||
|
|
||||||
FEXCore::IR::AllNodesIterator FindFirstUse(FEXCore::IR::IREmitter *IREmit, FEXCore::IR::OrderedNode* Node, FEXCore::IR::AllNodesIterator Begin, FEXCore::IR::AllNodesIterator End);
|
FEXCore::IR::AllNodesIterator FindFirstUse(FEXCore::IR::IREmitter *IREmit, FEXCore::IR::OrderedNode* Node, FEXCore::IR::AllNodesIterator Begin, FEXCore::IR::AllNodesIterator End);
|
||||||
FEXCore::IR::AllNodesIterator FindLastUseBefore(FEXCore::IR::IREmitter *IREmit, FEXCore::IR::OrderedNode* Node, FEXCore::IR::AllNodesIterator Begin, FEXCore::IR::AllNodesIterator End);
|
FEXCore::IR::AllNodesIterator FindLastUseBefore(FEXCore::IR::IREmitter *IREmit, FEXCore::IR::OrderedNode* Node, FEXCore::IR::AllNodesIterator Begin, FEXCore::IR::AllNodesIterator End);
|
||||||
@ -468,7 +469,7 @@ namespace FEXCore::IR {
|
|||||||
return std::move(Graph->AllocData);
|
return std::move(Graph->AllocData);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConstrainedRAPass::RecursiveLiveRangeExpansion(FEXCore::IR::IRListView<false> *IR, uint32_t Node, uint32_t DefiningBlockID, LiveRange *LiveRange, const std::unordered_set<uint32_t> &Predecessors, std::unordered_set<uint32_t> &VisitedPredecessors) {
|
void ConstrainedRAPass::RecursiveLiveRangeExpansion(FEXCore::IR::IRListView *IR, uint32_t Node, uint32_t DefiningBlockID, LiveRange *LiveRange, const std::unordered_set<uint32_t> &Predecessors, std::unordered_set<uint32_t> &VisitedPredecessors) {
|
||||||
for (auto PredecessorId: Predecessors) {
|
for (auto PredecessorId: Predecessors) {
|
||||||
if (DefiningBlockID != PredecessorId && !VisitedPredecessors.contains(PredecessorId)) {
|
if (DefiningBlockID != PredecessorId && !VisitedPredecessors.contains(PredecessorId)) {
|
||||||
// do the magic
|
// do the magic
|
||||||
@ -491,7 +492,7 @@ namespace FEXCore::IR {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConstrainedRAPass::CalculateLiveRange(FEXCore::IR::IRListView<false> *IR) {
|
void ConstrainedRAPass::CalculateLiveRange(FEXCore::IR::IRListView *IR) {
|
||||||
using namespace FEXCore;
|
using namespace FEXCore;
|
||||||
size_t Nodes = IR->GetSSACount();
|
size_t Nodes = IR->GetSSACount();
|
||||||
LiveRanges.clear();
|
LiveRanges.clear();
|
||||||
@ -579,7 +580,7 @@ namespace FEXCore::IR {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConstrainedRAPass::OptimizeStaticRegisters(FEXCore::IR::IRListView<false> *IR) {
|
void ConstrainedRAPass::OptimizeStaticRegisters(FEXCore::IR::IRListView *IR) {
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
|
|
||||||
@ -790,7 +791,7 @@ namespace FEXCore::IR {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConstrainedRAPass::CalculateBlockInterferences(FEXCore::IR::IRListView<false> *IR) {
|
void ConstrainedRAPass::CalculateBlockInterferences(FEXCore::IR::IRListView *IR) {
|
||||||
using namespace FEXCore;
|
using namespace FEXCore;
|
||||||
|
|
||||||
for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) {
|
for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) {
|
||||||
@ -818,7 +819,7 @@ namespace FEXCore::IR {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConstrainedRAPass::CalculateBlockNodeInterference(FEXCore::IR::IRListView<false> *IR) {
|
void ConstrainedRAPass::CalculateBlockNodeInterference(FEXCore::IR::IRListView *IR) {
|
||||||
#if 0
|
#if 0
|
||||||
auto AddInterference = [&](uint32_t Node1, uint32_t Node2) {
|
auto AddInterference = [&](uint32_t Node1, uint32_t Node2) {
|
||||||
RegisterNode *Node = &Graph->Nodes[Node1];
|
RegisterNode *Node = &Graph->Nodes[Node1];
|
||||||
@ -877,7 +878,7 @@ namespace FEXCore::IR {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConstrainedRAPass::CalculateNodeInterference(FEXCore::IR::IRListView<false> *IR) {
|
void ConstrainedRAPass::CalculateNodeInterference(FEXCore::IR::IRListView *IR) {
|
||||||
auto AddInterference = [this](uint32_t Node1, uint32_t Node2) {
|
auto AddInterference = [this](uint32_t Node1, uint32_t Node2) {
|
||||||
RegisterNode *Node = &Graph->Nodes[Node1];
|
RegisterNode *Node = &Graph->Nodes[Node1];
|
||||||
Node->Interferences.Append(Node2);
|
Node->Interferences.Append(Node2);
|
||||||
@ -1477,7 +1478,7 @@ namespace FEXCore::IR {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ConstrainedRAPass::CalculatePredecessors(FEXCore::IR::IRListView<false> *IR) {
|
void ConstrainedRAPass::CalculatePredecessors(FEXCore::IR::IRListView *IR) {
|
||||||
Graph->BlockPredecessors.clear();
|
Graph->BlockPredecessors.clear();
|
||||||
|
|
||||||
for (auto [BlockNode, BlockIROp] : IR->GetBlocks()) {
|
for (auto [BlockNode, BlockIROp] : IR->GetBlocks()) {
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace FEXCore::IR {
|
namespace FEXCore::IR {
|
||||||
template<bool>
|
|
||||||
class IRListView;
|
class IRListView;
|
||||||
|
|
||||||
class RegisterAllocationPass : public FEXCore::IR::Pass {
|
class RegisterAllocationPass : public FEXCore::IR::Pass {
|
||||||
|
4
External/FEXCore/docs/IR.md
vendored
4
External/FEXCore/docs/IR.md
vendored
@ -79,10 +79,10 @@ This is an intrusive allocator that is used by the `OpDispatchBuilder` for stori
|
|||||||
|
|
||||||
### OpDispatchBuilder
|
### OpDispatchBuilder
|
||||||
OpDispatchBuilder provides two routines for handling the IR outside of the class
|
OpDispatchBuilder provides two routines for handling the IR outside of the class
|
||||||
* `IRListView<false> ViewIR();`
|
* `IRListView ViewIR();`
|
||||||
* Returns a wrapper container class the allows you to view the IR. This doesn't take ownership of the IR data.
|
* Returns a wrapper container class the allows you to view the IR. This doesn't take ownership of the IR data.
|
||||||
* If the OpDispatcherBuilder changes its IR then changes are also visible to this class
|
* If the OpDispatcherBuilder changes its IR then changes are also visible to this class
|
||||||
* `IRListView<true> *CreateIRCopy()`
|
* `IRListView *CreateIRCopy()`
|
||||||
* As the name says, it creates a new copy of the IR that is in the OpDispatchBuilder
|
* As the name says, it creates a new copy of the IR that is in the OpDispatchBuilder
|
||||||
* Copying the IR only copies the memory used and doesn't have any free space for optimizations after this copy operation
|
* Copying the IR only copies the memory used and doesn't have any free space for optimizations after this copy operation
|
||||||
* Useful for tiered recompilers, AOT, and offline analysis
|
* Useful for tiered recompilers, AOT, and offline analysis
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
namespace FEXCore {
|
namespace FEXCore {
|
||||||
|
|
||||||
namespace IR {
|
namespace IR {
|
||||||
template<bool Copy>
|
|
||||||
class IRListView;
|
class IRListView;
|
||||||
class RegisterAllocationData;
|
class RegisterAllocationData;
|
||||||
}
|
}
|
||||||
@ -45,7 +44,7 @@ class LLVMCore;
|
|||||||
* @return An executable function pointer that is theoretically compiled from this point.
|
* @return An executable function pointer that is theoretically compiled from this point.
|
||||||
* Is actually a function pointer of type `void (FEXCore::Core::ThreadState *Thread)
|
* Is actually a function pointer of type `void (FEXCore::Core::ThreadState *Thread)
|
||||||
*/
|
*/
|
||||||
virtual void *CompileCode(FEXCore::IR::IRListView<true> const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) = 0;
|
virtual void *CompileCode(FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Function for mapping memory in to the CPUBackend's visible space. Allows setting up virtual mappings if required
|
* @brief Function for mapping memory in to the CPUBackend's visible space. Allows setting up virtual mappings if required
|
||||||
|
@ -6,6 +6,9 @@
|
|||||||
#include <FEXCore/Core/SignalDelegator.h>
|
#include <FEXCore/Core/SignalDelegator.h>
|
||||||
#include <FEXCore/Core/CPUID.h>
|
#include <FEXCore/Core/CPUID.h>
|
||||||
|
|
||||||
|
#include<istream>
|
||||||
|
#include<ostream>
|
||||||
|
|
||||||
namespace FEXCore {
|
namespace FEXCore {
|
||||||
class CodeLoader;
|
class CodeLoader;
|
||||||
}
|
}
|
||||||
@ -229,4 +232,7 @@ namespace FEXCore::Context {
|
|||||||
void SetSignalDelegator(FEXCore::Context::Context *CTX, FEXCore::SignalDelegator *SignalDelegation);
|
void SetSignalDelegator(FEXCore::Context::Context *CTX, FEXCore::SignalDelegator *SignalDelegation);
|
||||||
void SetSyscallHandler(FEXCore::Context::Context *CTX, FEXCore::HLE::SyscallHandler *Handler);
|
void SetSyscallHandler(FEXCore::Context::Context *CTX, FEXCore::HLE::SyscallHandler *Handler);
|
||||||
FEXCore::CPUID::FunctionResults RunCPUIDFunction(FEXCore::Context::Context *CTX, uint32_t Function, uint32_t Leaf);
|
FEXCore::CPUID::FunctionResults RunCPUIDFunction(FEXCore::Context::Context *CTX, uint32_t Function, uint32_t Leaf);
|
||||||
|
|
||||||
|
bool ReadAOT(FEXCore::Context::Context *CTX, std::istream& stream);
|
||||||
|
void WriteAOT(FEXCore::Context::Context *CTX, std::ostream& stream);
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ namespace FEXCore::Core {
|
|||||||
std::unique_ptr<FEXCore::CPU::CPUBackend> CPUBackend;
|
std::unique_ptr<FEXCore::CPU::CPUBackend> CPUBackend;
|
||||||
std::unique_ptr<FEXCore::LookupCache> LookupCache;
|
std::unique_ptr<FEXCore::LookupCache> LookupCache;
|
||||||
|
|
||||||
std::unordered_map<uint64_t, std::unique_ptr<FEXCore::IR::IRListView<true>>> IRLists;
|
std::unordered_map<uint64_t, std::unique_ptr<FEXCore::IR::IRListView>> IRLists;
|
||||||
std::unordered_map<uint64_t, std::unique_ptr<FEXCore::IR::RegisterAllocationData, FEXCore::IR::RegisterAllocationDataDeleter>> RALists;
|
std::unordered_map<uint64_t, std::unique_ptr<FEXCore::IR::RegisterAllocationData, FEXCore::IR::RegisterAllocationDataDeleter>> RALists;
|
||||||
std::unordered_map<uint64_t, std::unique_ptr<FEXCore::Core::DebugData>> DebugData;
|
std::unordered_map<uint64_t, std::unique_ptr<FEXCore::Core::DebugData>> DebugData;
|
||||||
|
|
||||||
|
3
External/FEXCore/include/FEXCore/IR/IR.h
vendored
3
External/FEXCore/include/FEXCore/IR/IR.h
vendored
@ -456,11 +456,10 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<bool>
|
|
||||||
class IRListView;
|
class IRListView;
|
||||||
class IREmitter;
|
class IREmitter;
|
||||||
|
|
||||||
void Dump(std::stringstream *out, IRListView<false> const* IR, IR::RegisterAllocationData *RAData);
|
void Dump(std::stringstream *out, IRListView const* IR, IR::RegisterAllocationData *RAData);
|
||||||
IREmitter* Parse(std::istream *in);
|
IREmitter* Parse(std::istream *in);
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
|
@ -21,8 +21,8 @@ friend class FEXCore::IR::PassManager;
|
|||||||
ResetWorkingList();
|
ResetWorkingList();
|
||||||
}
|
}
|
||||||
|
|
||||||
IRListView<false> ViewIR() { return IRListView<false>(&Data, &ListData); }
|
IRListView ViewIR() { return IRListView(&Data, &ListData, false); }
|
||||||
IRListView<true> *CreateIRCopy() { return new IRListView<true>(&Data, &ListData); }
|
IRListView *CreateIRCopy() { return new IRListView(&Data, &ListData, true); }
|
||||||
void ResetWorkingList();
|
void ResetWorkingList();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <istream>
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
namespace FEXCore::IR {
|
namespace FEXCore::IR {
|
||||||
/**
|
/**
|
||||||
@ -62,17 +64,16 @@ class IntrusiveAllocator final {
|
|||||||
uintptr_t Data;
|
uintptr_t Data;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<bool Copy>
|
|
||||||
class IRListView final {
|
class IRListView final {
|
||||||
public:
|
public:
|
||||||
IRListView() = delete;
|
IRListView() = delete;
|
||||||
IRListView(IRListView<Copy> &&) = delete;
|
IRListView(IRListView &&) = delete;
|
||||||
|
|
||||||
IRListView(IntrusiveAllocator *Data, IntrusiveAllocator *List) {
|
IRListView(IntrusiveAllocator *Data, IntrusiveAllocator *List, bool _IsCopy) : IsCopy(_IsCopy) {
|
||||||
DataSize = Data->Size();
|
DataSize = Data->Size();
|
||||||
ListSize = List->Size();
|
ListSize = List->Size();
|
||||||
|
|
||||||
if (Copy) {
|
if (IsCopy) {
|
||||||
IRData = malloc(DataSize + ListSize);
|
IRData = malloc(DataSize + ListSize);
|
||||||
ListData = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRData) + DataSize);
|
ListData = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRData) + DataSize);
|
||||||
memcpy(IRData, reinterpret_cast<void*>(Data->Begin()), DataSize);
|
memcpy(IRData, reinterpret_cast<void*>(Data->Begin()), DataSize);
|
||||||
@ -85,24 +86,46 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IRListView<true>(IRListView<true> *Old) {
|
IRListView(IRListView *Old, bool _IsCopy) : IsCopy(_IsCopy) {
|
||||||
DataSize = Old->DataSize;
|
DataSize = Old->DataSize;
|
||||||
ListSize = Old->ListSize;
|
ListSize = Old->ListSize;
|
||||||
|
if (IsCopy) {
|
||||||
|
IRData = malloc(DataSize + ListSize);
|
||||||
|
ListData = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRData) + DataSize);
|
||||||
|
memcpy(IRData, Old->IRData, DataSize);
|
||||||
|
memcpy(ListData, Old->ListData, ListSize);
|
||||||
|
} else {
|
||||||
|
IRData = Old->IRData;
|
||||||
|
ListData = Old->ListData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IRListView(std::istream& stream) : IsCopy(true) {
|
||||||
|
stream.read((char*)&DataSize, sizeof(DataSize));
|
||||||
|
stream.read((char*)&ListSize, sizeof(ListSize));
|
||||||
|
|
||||||
IRData = malloc(DataSize + ListSize);
|
IRData = malloc(DataSize + ListSize);
|
||||||
ListData = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRData) + DataSize);
|
ListData = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRData) + DataSize);
|
||||||
memcpy(IRData, Old->IRData, DataSize);
|
stream.read((char*)IRData, DataSize);
|
||||||
memcpy(ListData, Old->ListData, ListSize);
|
stream.read((char*)ListData, ListSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
~IRListView() {
|
~IRListView() {
|
||||||
if (Copy) {
|
if (IsCopy) {
|
||||||
free (IRData);
|
free (IRData);
|
||||||
// ListData is just offset from IRData
|
// ListData is just offset from IRData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IRListView<true> *CreateCopy() {
|
void Serialize(std::ostream& stream) {
|
||||||
return new IRListView<true>(this);
|
stream.write((char*)&DataSize, sizeof(DataSize));
|
||||||
|
stream.write((char*)&ListSize, sizeof(ListSize));
|
||||||
|
stream.write((char*)IRData, DataSize);
|
||||||
|
stream.write((char*)ListData, ListSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
IRListView *CreateCopy() {
|
||||||
|
return new IRListView(this, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t const GetData() const { return reinterpret_cast<uintptr_t>(IRData); }
|
uintptr_t const GetData() const { return reinterpret_cast<uintptr_t>(IRData); }
|
||||||
@ -259,6 +282,7 @@ private:
|
|||||||
void *ListData;
|
void *ListData;
|
||||||
size_t DataSize;
|
size_t DataSize;
|
||||||
size_t ListSize;
|
size_t ListSize;
|
||||||
|
bool IsCopy;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ struct RegisterAllocationDataDeleter {
|
|||||||
class RegisterAllocationData {
|
class RegisterAllocationData {
|
||||||
public:
|
public:
|
||||||
uint32_t SpillSlotCount {};
|
uint32_t SpillSlotCount {};
|
||||||
|
uint32_t MapCount {};
|
||||||
PhysicalRegister Map[0];
|
PhysicalRegister Map[0];
|
||||||
|
|
||||||
PhysicalRegister GetNodeRegister(uint32_t Node) const {
|
PhysicalRegister GetNodeRegister(uint32_t Node) const {
|
||||||
|
@ -30,7 +30,7 @@ namespace HostFactory {
|
|||||||
explicit HostCore(FEXCore::Context::Context* CTX, FEXCore::Core::ThreadState *Thread, bool Fallback);
|
explicit HostCore(FEXCore::Context::Context* CTX, FEXCore::Core::ThreadState *Thread, bool Fallback);
|
||||||
~HostCore() override;
|
~HostCore() override;
|
||||||
std::string GetName() override { return "Host Core"; }
|
std::string GetName() override { return "Host Core"; }
|
||||||
void* CompileCode(FEXCore::IR::IRListView<true> const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override;
|
void* CompileCode(FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) override;
|
||||||
|
|
||||||
void *MapRegion(void *HostPtr, uint64_t VirtualGuestPtr, uint64_t Size) override {
|
void *MapRegion(void *HostPtr, uint64_t VirtualGuestPtr, uint64_t Size) override {
|
||||||
return HostPtr;
|
return HostPtr;
|
||||||
@ -170,7 +170,7 @@ namespace HostFactory {
|
|||||||
ready();
|
ready();
|
||||||
}
|
}
|
||||||
|
|
||||||
void* HostCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView<true> const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) {
|
void* HostCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const *IR, FEXCore::Core::DebugData *DebugData, FEXCore::IR::RegisterAllocationData *RAData) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <fstream>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
static bool SilentLog;
|
static bool SilentLog;
|
||||||
@ -287,8 +289,31 @@ int main(int argc, char **argv, char **const envp) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string base_filename = Program.substr(Program.find_last_of("/\\") + 1) + ".fex-emu.aot";
|
||||||
|
|
||||||
|
{
|
||||||
|
std::ifstream AOTRead(base_filename, std::ios::in | std::ios::binary);
|
||||||
|
|
||||||
|
if (AOTRead) {
|
||||||
|
if (FEXCore::Context::ReadAOT(CTX, AOTRead)) {
|
||||||
|
LogMan::Msg::I("AOT Cache Loaded\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FEXCore::Context::RunUntilExit(CTX);
|
FEXCore::Context::RunUntilExit(CTX);
|
||||||
|
|
||||||
|
{
|
||||||
|
std::ofstream AOTWrite(base_filename, std::ios::out | std::ios::binary );
|
||||||
|
|
||||||
|
if (AOTWrite) {
|
||||||
|
std::filesystem::resize_file(base_filename, 0);
|
||||||
|
AOTWrite.seekp(0);
|
||||||
|
FEXCore::Context::WriteAOT(CTX, AOTWrite);
|
||||||
|
LogMan::Msg::I("AOT Cache Stored\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto ProgramStatus = FEXCore::Context::GetProgramStatus(CTX);
|
auto ProgramStatus = FEXCore::Context::GetProgramStatus(CTX);
|
||||||
|
|
||||||
SyscallHandler.reset();
|
SyscallHandler.reset();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user