IR: Add AOT Cache

This commit is contained in:
Stefanos Kornilios Mitsis Poiitidis 2021-01-29 21:10:30 +02:00
parent 7b97c3fa23
commit 816c4656df
27 changed files with 243 additions and 67 deletions

View File

@ -151,6 +151,13 @@ namespace FEXCore::Context {
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 {
void CompileRIP(FEXCore::Context::Context *CTX, uint64_t RIP) {
CTX->CompileRIP(CTX->ParentThread, RIP);

View File

@ -6,13 +6,18 @@
#include "Interface/Core/InternalThreadState.h"
#include "Interface/Core/X86HelperGen.h"
#include "Interface/IR/PassManager.h"
#include "Interface/IR/Passes/RegisterAllocationPass.h"
#include <FEXCore/Config/Config.h>
#include <FEXCore/Core/CPUBackend.h>
#include <FEXCore/Utils/Event.h>
#include <stdint.h>
#include <memory>
#include <map>
#include <set>
#include <mutex>
#include <istream>
#include <ostream>
namespace FEXCore {
class ThunkHandler;
@ -30,6 +35,8 @@ class SyscallHandler;
namespace FEXCore::IR {
class RegisterAllocationPass;
class RegisterAllocationData;
class IRListView;
namespace Validation {
class IRValidation;
}
@ -96,6 +103,14 @@ namespace FEXCore::Context {
CustomCPUFactoryType FallbackCPUFactory;
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
std::unique_ptr<FEXCore::BlockSamplingData> BlockData;
#endif
@ -142,11 +157,13 @@ namespace FEXCore::Context {
FEXCore::Core::ThreadState *GetThreadState();
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);
bool LoadAOTCache(std::istream &stream);
void WriteAOTCache(std::ostream &stream);
// Used for thread creation from syscalls
void InitializeCompiler(FEXCore::Core::InternalThreadState* State, bool CompileThread);
FEXCore::Core::InternalThreadState* CreateThread(FEXCore::Core::CPUState *NewThreadState, uint64_t ParentTID);

View File

@ -31,7 +31,7 @@ class CompileService final {
// Outgoing
void *CodePtr{};
FEXCore::IR::IRListView<true> *IRList{};
FEXCore::IR::IRListView *IRList{};
FEXCore::IR::RegisterAllocationData *RAData{};
FEXCore::Core::DebugData *DebugData{};

View File

@ -35,6 +35,8 @@ namespace FEXCore::CPU {
}
}
static std::mutex AOTCacheLock;
namespace FEXCore::Core {
struct ThreadLocalData {
FEXCore::Core::InternalThreadState* Thread;
@ -111,7 +113,7 @@ namespace DefaultFallbackCore {
void Initialize() override {}
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);
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{};
GuestCode = reinterpret_cast<uint8_t const*>(GuestRIP);
@ -764,8 +766,8 @@ namespace FEXCore::Context {
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) {
FEXCore::IR::IRListView<true> *IRList {};
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 *IRList {};
FEXCore::Core::DebugData *DebugData {};
FEXCore::IR::RegisterAllocationData *RAData {};
bool GeneratedIR {};
@ -781,8 +783,21 @@ namespace FEXCore::Context {
RAData = Thread->RALists.find(GuestRIP)->second.get();
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
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};
}
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) {
// Is the code in the cache?
@ -815,7 +900,7 @@ namespace FEXCore::Context {
}
void *CodePtr {};
FEXCore::IR::IRListView<true> *IRList {};
FEXCore::IR::IRListView *IRList {};
FEXCore::Core::DebugData *DebugData {};
FEXCore::IR::RegisterAllocationData *RAData {};
@ -872,6 +957,11 @@ namespace FEXCore::Context {
Thread->IRLists.emplace(GuestRIP, IRList);
Thread->DebugData.emplace(GuestRIP, DebugData);
Thread->RALists.emplace(GuestRIP, RAData);
{
std::lock_guard<std::mutex> lk(AOTCacheLock);
AOTCache.insert({GuestRIP, {0, 0, 0, IRList, RAData}});
}
}
if (DecrementRefCount)

View File

@ -992,6 +992,9 @@ bool Decoder::DecodeInstructionsAtEntry(uint8_t const* _InstStream, uint64_t PC)
SymbolMinAddress = EntryPoint;
}
DecodedMinAddress = EntryPoint;
DecodedMaxAddress = EntryPoint;
// Entry is a jump target
BlocksToDecode.emplace(PC);
@ -1024,6 +1027,9 @@ bool Decoder::DecodeInstructionsAtEntry(uint8_t const* _InstStream, uint64_t PC)
break;
}
DecodedMinAddress = std::min(DecodedMinAddress, PCOffset);
DecodedMaxAddress = std::max(DecodedMaxAddress, PCOffset + DecodeInst->InstSize);
++TotalInstructions;
++BlockNumberOfInstructions;
++DecodedSize;

View File

@ -30,6 +30,9 @@ public:
return &Blocks;
}
uint64_t DecodedMinAddress {};
uint64_t DecodedMaxAddress {~0ULL};
private:
FEXCore::Context::Context *CTX;

View File

@ -22,7 +22,7 @@ public:
explicit InterpreterCore(FEXCore::Context::Context *ctx, FEXCore::Core::InternalThreadState *Thread, bool CompileThread);
~InterpreterCore() override;
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; }

View File

@ -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);
}

View File

@ -922,7 +922,7 @@ bool InterpreterOps::GetFallbackHandler(IR::IROp_Header *IROp, FallbackInfo *Inf
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);
// Debug data is only passed in debug builds

View File

@ -3,8 +3,7 @@ namespace FEXCore::Core {
}
namespace FEXCore::IR {
template<bool copy>
class IRListView;
class IRListView;
}
namespace FEXCore::Core{
@ -37,7 +36,7 @@ namespace FEXCore::CPU {
class InterpreterOps {
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);
};
};

View File

@ -1033,7 +1033,7 @@ bool JITCore::IsGPR(uint32_t Node) {
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;
JumpTargets.clear();
uint32_t SSACount = IR->GetSSACount();

View File

@ -78,7 +78,7 @@ public:
~JITCore() override;
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; }
@ -100,7 +100,7 @@ private:
Label *PendingTargetLabel;
FEXCore::Context::Context *CTX;
FEXCore::Core::InternalThreadState *State;
FEXCore::IR::IRListView<true> const *IR;
FEXCore::IR::IRListView const *IR;
std::map<IR::OrderedNodeWrapper::NodeOffsetType, aarch64::Label> JumpTargets;

View File

@ -838,7 +838,7 @@ std::tuple<JITCore::SetCC, JITCore::CMovCC, JITCore::JCC> JITCore::GetCC(IR::Con
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();
uint32_t SSACount = IR->GetSSACount();

View File

@ -59,7 +59,7 @@ public:
explicit JITCore(FEXCore::Context::Context *ctx, FEXCore::Core::InternalThreadState *Thread, CodeBuffer Buffer, bool CompileThread);
~JITCore() override;
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; }
@ -79,7 +79,7 @@ private:
Label* PendingTargetLabel{};
FEXCore::Context::Context *CTX;
FEXCore::Core::InternalThreadState *ThreadState;
FEXCore::IR::IRListView<true> const *IR;
FEXCore::IR::IRListView const *IR;
std::unordered_map<IR::OrderedNodeWrapper::NodeOffsetType, Label> JumpTargets;
Xbyak::util::Cpu Features{};

View File

@ -12,15 +12,15 @@ namespace FEXCore::IR {
#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;
}
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;
}
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 = {
"EQ",
"NEQ",
@ -49,7 +49,7 @@ static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView<false>
*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 = {
"SXTX",
"UXTW",
@ -59,7 +59,7 @@ static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView<false>
*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)
*out << "GPR";
else if (Arg == GPRFixedClass.Val)
@ -74,7 +74,7 @@ static void PrintArg(std::stringstream *out, [[maybe_unused]] IRListView<false>
*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)();
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) {
*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();
int8_t CurrentIndent = 0;

View File

@ -258,6 +258,7 @@ namespace {
Graph->AllocData.reset();
Graph->AllocData.reset((FEXCore::IR::RegisterAllocationData*)malloc(FEXCore::IR::RegisterAllocationData::Size(NodeCount)));
memset(&Graph->AllocData->Map[0], INVALID_REGCLASS.Raw, NodeCount);
Graph->AllocData->MapCount = NodeCount;
Graph->NodeCount = NodeCount;
}
@ -302,7 +303,7 @@ namespace {
}
#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;
FEXCore::IR::RegisterClassType Class = IR::GetRegClass(IROp->Op);
@ -356,7 +357,7 @@ namespace {
};
// 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()) {
// If the destination hasn't yet been set then set it now
if (IROp->HasDest) {
@ -410,14 +411,14 @@ namespace FEXCore::IR {
std::unordered_map<uint32_t, BlockInterferences> LocalBlockInterferences;
BlockInterferences GlobalBlockInterferences;
void CalculateLiveRange(FEXCore::IR::IRListView<false> *IR);
void OptimizeStaticRegisters(FEXCore::IR::IRListView<false> *IR);
void CalculateBlockInterferences(FEXCore::IR::IRListView<false> *IR);
void CalculateBlockNodeInterference(FEXCore::IR::IRListView<false> *IR);
void CalculateNodeInterference(FEXCore::IR::IRListView<false> *IR);
void CalculateLiveRange(FEXCore::IR::IRListView *IR);
void OptimizeStaticRegisters(FEXCore::IR::IRListView *IR);
void CalculateBlockInterferences(FEXCore::IR::IRListView *IR);
void CalculateBlockNodeInterference(FEXCore::IR::IRListView *IR);
void CalculateNodeInterference(FEXCore::IR::IRListView *IR);
void AllocateVirtualRegisters();
void CalculatePredecessors(FEXCore::IR::IRListView<false> *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 CalculatePredecessors(FEXCore::IR::IRListView *IR);
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 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);
}
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) {
if (DefiningBlockID != PredecessorId && !VisitedPredecessors.contains(PredecessorId)) {
// 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;
size_t Nodes = IR->GetSSACount();
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
@ -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;
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
auto AddInterference = [&](uint32_t Node1, uint32_t Node2) {
RegisterNode *Node = &Graph->Nodes[Node1];
@ -877,7 +878,7 @@ namespace FEXCore::IR {
#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) {
RegisterNode *Node = &Graph->Nodes[Node1];
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();
for (auto [BlockNode, BlockIROp] : IR->GetBlocks()) {

View File

@ -4,7 +4,6 @@
#include <vector>
namespace FEXCore::IR {
template<bool>
class IRListView;
class RegisterAllocationPass : public FEXCore::IR::Pass {

View File

@ -79,10 +79,10 @@ This is an intrusive allocator that is used by the `OpDispatchBuilder` for stori
### OpDispatchBuilder
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.
* 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
* 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

View File

@ -5,7 +5,6 @@
namespace FEXCore {
namespace IR {
template<bool Copy>
class IRListView;
class RegisterAllocationData;
}
@ -45,7 +44,7 @@ class LLVMCore;
* @return An executable function pointer that is theoretically compiled from this point.
* 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

View File

@ -6,6 +6,9 @@
#include <FEXCore/Core/SignalDelegator.h>
#include <FEXCore/Core/CPUID.h>
#include<istream>
#include<ostream>
namespace FEXCore {
class CodeLoader;
}
@ -229,4 +232,7 @@ namespace FEXCore::Context {
void SetSignalDelegator(FEXCore::Context::Context *CTX, FEXCore::SignalDelegator *SignalDelegation);
void SetSyscallHandler(FEXCore::Context::Context *CTX, FEXCore::HLE::SyscallHandler *Handler);
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);
}

View File

@ -76,7 +76,7 @@ namespace FEXCore::Core {
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;
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::Core::DebugData>> DebugData;

View File

@ -456,11 +456,10 @@ public:
}
};
template<bool>
class IRListView;
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);
template<typename Type>

View File

@ -21,8 +21,8 @@ friend class FEXCore::IR::PassManager;
ResetWorkingList();
}
IRListView<false> ViewIR() { return IRListView<false>(&Data, &ListData); }
IRListView<true> *CreateIRCopy() { return new IRListView<true>(&Data, &ListData); }
IRListView ViewIR() { return IRListView(&Data, &ListData, false); }
IRListView *CreateIRCopy() { return new IRListView(&Data, &ListData, true); }
void ResetWorkingList();
/**

View File

@ -8,6 +8,8 @@
#include <cstring>
#include <tuple>
#include <vector>
#include <istream>
#include <ostream>
namespace FEXCore::IR {
/**
@ -62,17 +64,16 @@ class IntrusiveAllocator final {
uintptr_t Data;
};
template<bool Copy>
class IRListView final {
public:
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();
ListSize = List->Size();
if (Copy) {
if (IsCopy) {
IRData = malloc(DataSize + ListSize);
ListData = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRData) + 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;
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);
ListData = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(IRData) + DataSize);
memcpy(IRData, Old->IRData, DataSize);
memcpy(ListData, Old->ListData, ListSize);
stream.read((char*)IRData, DataSize);
stream.read((char*)ListData, ListSize);
}
~IRListView() {
if (Copy) {
if (IsCopy) {
free (IRData);
// ListData is just offset from IRData
}
}
IRListView<true> *CreateCopy() {
return new IRListView<true>(this);
void Serialize(std::ostream& stream) {
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); }
@ -259,6 +282,7 @@ private:
void *ListData;
size_t DataSize;
size_t ListSize;
bool IsCopy;
};
}

View File

@ -37,6 +37,7 @@ struct RegisterAllocationDataDeleter {
class RegisterAllocationData {
public:
uint32_t SpillSlotCount {};
uint32_t MapCount {};
PhysicalRegister Map[0];
PhysicalRegister GetNodeRegister(uint32_t Node) const {

View File

@ -30,7 +30,7 @@ namespace HostFactory {
explicit HostCore(FEXCore::Context::Context* CTX, FEXCore::Core::ThreadState *Thread, bool Fallback);
~HostCore() override;
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 {
return HostPtr;
@ -170,7 +170,7 @@ namespace HostFactory {
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;
}

View File

@ -16,6 +16,8 @@
#include <string>
#include <unistd.h>
#include <vector>
#include <fstream>
#include <filesystem>
namespace {
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);
{
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);
SyscallHandler.reset();