Merge pull request #2868 from Sonicadvance1/irdumper_passmanager

IR: Adds Option to run the IRDumper with more configurations
This commit is contained in:
Mai authored and GitHub committed 2023-08-09 10:28:25 -04:00
commit ea8fbc61c2
13 files changed
+183 -34

No files matched your search

+1
View File
@@ -133,6 +133,7 @@ set (SRCS
Interface/IR/Passes/DeadCodeElimination.cpp
Interface/IR/Passes/DeadContextStoreElimination.cpp
Interface/IR/Passes/IRCompaction.cpp
Interface/IR/Passes/IRDumperPass.cpp
Interface/IR/Passes/IRValidation.cpp
Interface/IR/Passes/RAValidation.cpp
Interface/IR/Passes/LongDivideRemovalPass.cpp
+18
View File
@@ -198,6 +198,24 @@
"[no, stdout, stderr, <Folder>]"
]
},
"PassManagerDumpIR": {
"Type": "strenum",
"Default": "FEXCore::Config::PassManagerDumpIR::OFF",
"Enums": {
"BEFOREOPT": "beforeopt",
"AFTEROPT": "afteropt",
"BEFORE": "beforepass",
"AFTER": "afterpass"
},
"Desc": [
"Allows controlling when FEX dumps its IR.",
"\toff: IR dumping will be disabled",
"\tbeforeopt: Dump IR before any optimizations",
"\tafteropt: Dump IR after all optimizations",
"\tbeforepass: Dump IR before every optimization pass",
"\tafterpass: Dump IR after every optimization pass"
]
},
"DumpGPRs": {
"Type": "bool",
"Default": "false",
-1
View File
@@ -230,7 +230,6 @@ namespace FEXCore::Context {
FEX_CONFIG_OPT(ThunkHostLibsPath, THUNKHOSTLIBS);
FEX_CONFIG_OPT(ThunkHostLibsPath32, THUNKHOSTLIBS32);
FEX_CONFIG_OPT(ThunkConfigFile, THUNKCONFIG);
FEX_CONFIG_OPT(DumpIR, DUMPIR);
FEX_CONFIG_OPT(StaticRegisterAllocation, SRA);
FEX_CONFIG_OPT(GlobalJITNaming, GLOBALJITNAMING);
FEX_CONFIG_OPT(LibraryJITNaming, LIBRARYJITNAMING);
+8 -25
View File
@@ -603,6 +603,8 @@ namespace FEXCore::Context {
ERROR_AND_DIE_FMT("Unknown core configuration");
break;
}
Thread->PassManager->Finalize();
}
FEXCore::Core::InternalThreadState* ContextImpl::CreateThread(FEXCore::Core::CPUState *NewThreadState, uint64_t ParentTID) {
@@ -729,30 +731,11 @@ namespace FEXCore::Context {
}
static void IRDumper(FEXCore::Core::InternalThreadState *Thread, IR::IREmitter *IREmitter, uint64_t GuestRIP, IR::RegisterAllocationData* RA) {
FEXCore::File::File FD;
const auto DumpIRStr = static_cast<ContextImpl*>(Thread->CTX)->Config.DumpIR();
// DumpIRStr might be no if not dumping but ShouldDump is set in OpDisp
if (DumpIRStr =="stderr" || DumpIRStr =="no") {
FD = FEXCore::File::File::GetStdERR();
}
else if (DumpIRStr =="stdout") {
FD = FEXCore::File::File::GetStdOUT();
}
else {
const auto fileName = fextl::fmt::format("{}/{:x}{}", DumpIRStr, GuestRIP, RA ? "-post.ir" : "-pre.ir");
FD = FEXCore::File::File(fileName.c_str(),
FEXCore::File::FileModes::WRITE |
FEXCore::File::FileModes::CREATE |
FEXCore::File::FileModes::TRUNCATE);
}
if (FD.IsValid()) {
fextl::stringstream out;
auto NewIR = IREmitter->ViewIR();
FEXCore::IR::Dump(&out, &NewIR, RA);
fextl::fmt::print(FD, "IR-{} 0x{:x}:\n{}\n@@@@@\n", RA ? "post" : "pre", GuestRIP, out.str());
}
FEXCore::File::File FD = FEXCore::File::File::GetStdERR();
fextl::stringstream out;
auto NewIR = IREmitter->ViewIR();
FEXCore::IR::Dump(&out, &NewIR, RA);
fextl::fmt::print(FD, "IR-ShouldDump-{} 0x{:x}:\n{}\n@@@@@\n", RA ? "post" : "pre", GuestRIP, out.str());
};
static void ValidateIR(ContextImpl *ctx, IR::IREmitter *IREmitter) {
@@ -920,7 +903,7 @@ namespace FEXCore::Context {
IR::IREmitter *IREmitter = Thread->OpDispatcher.get();
auto ShouldDump = static_cast<ContextImpl*>(Thread->CTX)->Config.DumpIR() != "no" || Thread->OpDispatcher->ShouldDumpIR();
auto ShouldDump = Thread->OpDispatcher->ShouldDumpIR();
// Debug
{
if (ShouldDump) {
@@ -4734,7 +4734,7 @@ void OpDispatchBuilder::CreateJumpBlocks(fextl::vector<FEXCore::Frontend::Decode
void OpDispatchBuilder::BeginFunction(uint64_t RIP, fextl::vector<FEXCore::Frontend::Decoder::DecodedBlocks> const *Blocks) {
Entry = RIP;
auto IRHeader = _IRHeader(InvalidNode, 0);
auto IRHeader = _IRHeader(InvalidNode, RIP, 0);
CreateJumpBlocks(Blocks);
auto Block = GetNewJumpBlock(RIP);
+1 -1
View File
@@ -208,7 +208,7 @@ namespace FEXCore {
auto Result = Thread->CTX->AddCustomIREntrypoint(
args->original_callee,
[CTX, GuestThunkEntrypoint = args->target_addr](uintptr_t Entrypoint, FEXCore::IR::IREmitter *emit) {
auto IRHeader = emit->_IRHeader(emit->Invalid(), 0);
auto IRHeader = emit->_IRHeader(emit->Invalid(), Entrypoint, 0);
auto Block = emit->CreateCodeNode();
IRHeader.first->Blocks = emit->WrapNode(Block);
emit->SetCurrentCodeBlock(Block);
+1 -1
View File
@@ -160,7 +160,7 @@
"HasSideEffects": true,
"SwitchGen": false
},
"IRHeader SSA:$Blocks, u32:$BlockCount": {
"IRHeader SSA:$Blocks, u64:$OriginalRIP, u32:$BlockCount": {
"SwitchGen": false
},
"CodeBlock SSA:$Begin, SSA:$Last": {
+5 -1
View File
@@ -533,11 +533,15 @@ class IRParser: public FEXCore::IR::IREmitter {
return false;
}
auto OriginalRIP = DecodeValue<uint64_t>(Def.Args[1]);
if (!CheckPrintError(Def, OriginalRIP.first)) return false;
auto CodeBlockCount = DecodeValue<uint64_t>(Def.Args[1]);
if (!CheckPrintError(Def, CodeBlockCount.first)) return false;
IRHeader = _IRHeader(InvalidNode, CodeBlockCount.second);
IRHeader = _IRHeader(InvalidNode, OriginalRIP.second, CodeBlockCount.second);
}
SetWriteCursor(nullptr); // isolate the header from everything following
+48
View File
@@ -17,6 +17,54 @@ $end_info$
namespace FEXCore::IR {
class IREmitter;
void PassManager::Finalize() {
if (!PassManagerDumpIR()) {
// Not configured to dump any IR, just return.
return;
}
auto it = Passes.begin();
// Walk the passes and add them where asked.
if (PassManagerDumpIR() & FEXCore::Config::PassManagerDumpIR::BEFORE) {
// Insert at the start.
it = InsertAt(it, Debug::CreateIRDumper());
++it; // Skip what we inserted.
}
if ((PassManagerDumpIR() & FEXCore::Config::PassManagerDumpIR::BEFOREOPT) ||
(PassManagerDumpIR() & FEXCore::Config::PassManagerDumpIR::AFTEROPT)) {
bool SkipFirstBefore = PassManagerDumpIR() & FEXCore::Config::PassManagerDumpIR::BEFORE;
for (; it != Passes.end();) {
if (PassManagerDumpIR() & FEXCore::Config::PassManagerDumpIR::BEFOREOPT) {
if (SkipFirstBefore) {
// If we need to skip the first one, then continue.
SkipFirstBefore = false;
++it;
continue;
}
// Insert before
it = InsertAt(it, Debug::CreateIRDumper());
++it; // Skip what we inserted.
}
++it; // Skip current pass.
if (PassManagerDumpIR() & FEXCore::Config::PassManagerDumpIR::AFTEROPT) {
// Insert after
it = InsertAt(it, Debug::CreateIRDumper());
++it; // Skip what we inserted.
}
}
}
if (PassManagerDumpIR() & FEXCore::Config::PassManagerDumpIR::AFTER) {
if (!(PassManagerDumpIR() & FEXCore::Config::PassManagerDumpIR::AFTEROPT)) {
// Insert final IRDumper.
it = InsertAt(it, Debug::CreateIRDumper());
}
}
}
void PassManager::AddDefaultPasses(FEXCore::Context::ContextImpl *ctx, bool InlineConstants, bool StaticRegisterAllocation) {
FEX_CONFIG_OPT(DisablePasses, O0);
+10 -3
View File
@@ -49,8 +49,7 @@ public:
void AddDefaultPasses(FEXCore::Context::ContextImpl *ctx, bool InlineConstants, bool StaticRegisterAllocation);
void AddDefaultValidationPasses();
Pass* InsertPass(fextl::unique_ptr<Pass> Pass, fextl::string Name = "") {
Pass->RegisterPassManager(this);
auto PassPtr = Passes.emplace_back(std::move(Pass)).get();
auto PassPtr = InsertAt(Passes.end(), std::move(Pass))->get();
if (!Name.empty()) {
NameToPassMaping[Name] = PassPtr;
@@ -83,12 +82,19 @@ public:
SyscallHandler = Handler;
}
void Finalize();
protected:
ShouldExitHandler ExitHandler;
FEXCore::HLE::SyscallHandler *SyscallHandler;
private:
fextl::vector<fextl::unique_ptr<Pass>> Passes;
using PassArrayType = fextl::vector<fextl::unique_ptr<Pass>>;
PassArrayType::iterator InsertAt(PassArrayType::iterator pos, fextl::unique_ptr<Pass> Pass) {
Pass->RegisterPassManager(this);
return Passes.insert(pos, std::move(Pass));
}
PassArrayType Passes;
fextl::unordered_map<fextl::string, Pass*> NameToPassMaping;
#if defined(ASSERTIONS_ENABLED) && ASSERTIONS_ENABLED
@@ -104,6 +110,7 @@ private:
#endif
FEX_CONFIG_OPT(Is64BitMode, IS64BIT_MODE);
FEX_CONFIG_OPT(PassManagerDumpIR, PASSMANAGERDUMPIR);
};
}
+4
View File
@@ -29,5 +29,9 @@ fextl::unique_ptr<FEXCore::IR::Pass> CreateRAValidation();
fextl::unique_ptr<FEXCore::IR::Pass> CreatePhiValidation();
fextl::unique_ptr<FEXCore::IR::Pass> CreateValueDominanceValidation();
}
namespace Debug {
fextl::unique_ptr<FEXCore::IR::Pass> CreateIRDumper();
}
}
@@ -98,7 +98,8 @@ bool IRCompaction::Run(IREmitter *IREmit) {
// Zero is always zero(invalid)
OldToNewRemap[0].NodeID.Invalidate();
auto LocalHeaderOp = LocalBuilder._IRHeader(OrderedNodeWrapper::WrapOffset(0).GetNode(ListBegin), HeaderOp->BlockCount);
auto LocalHeaderOp = LocalBuilder._IRHeader(OrderedNodeWrapper::WrapOffset(0).GetNode(ListBegin), HeaderOp->OriginalRIP, HeaderOp->BlockCount);
OldToNewRemap[CurrentIR.GetID(HeaderNode).Value].NodeID = LocalIR.GetID(LocalHeaderOp.Node);
{
@@ -0,0 +1,84 @@
/*
$info$
tags: ir|debug
desc: Prints IR
$end_info$
*/
#include "Interface/IR/PassManager.h"
#include "Interface/IR/Passes/RegisterAllocationPass.h"
#include "Interface/Core/OpcodeDispatcher.h"
#include <FEXCore/IR/IR.h>
namespace FEXCore::IR::Debug {
class IRDumper final : public FEXCore::IR::Pass {
public:
IRDumper();
bool Run(IREmitter *IREmit) override;
private:
FEX_CONFIG_OPT(DumpIR, DUMPIR);
bool DumpToFile{};
bool DumpToLog{};
};
IRDumper::IRDumper() {
const auto DumpIRStr = DumpIR();
if (DumpIRStr == "stderr" || DumpIRStr == "stdout" || DumpIRStr == "no") {
// Intentionally do nothing
}
else if (DumpIRStr == "server") {
DumpToLog = true;
}
else {
DumpToFile = true;
}
}
bool IRDumper::Run(IREmitter *IREmit) {
auto RAPass = Manager->GetPass<IR::RegisterAllocationPass>("RA");
IR::RegisterAllocationData* RA{};
if (RAPass) {
RA = RAPass->GetAllocationData();
}
FEXCore::File::File FD{};
if (DumpIR() == "stderr") {
FD = FEXCore::File::File::GetStdERR();
}
else if (DumpIR() == "stdout") {
FD = FEXCore::File::File::GetStdOUT();
}
auto IR = IREmit->ViewIR();
auto HeaderOp = IR.GetHeader();
LOGMAN_THROW_AA_FMT(HeaderOp->Header.Op == OP_IRHEADER, "First op wasn't IRHeader");
// DumpIRStr might be no if not dumping but ShouldDump is set in OpDisp
if (DumpToFile) {
const auto fileName = fextl::fmt::format("{}/{:x}{}", DumpIR(), HeaderOp->OriginalRIP, RA ? "-post.ir" : "-pre.ir");
FD = FEXCore::File::File(fileName.c_str(),
FEXCore::File::FileModes::WRITE |
FEXCore::File::FileModes::CREATE |
FEXCore::File::FileModes::TRUNCATE);
}
if (FD.IsValid() || DumpToLog) {
fextl::stringstream out;
FEXCore::IR::Dump(&out, &IR, RA);
if (FD.IsValid()) {
fextl::fmt::print(FD, "IR-{} 0x{:x}:\n{}\n@@@@@\n", RA ? "post" : "pre", HeaderOp->OriginalRIP, out.str());
}
else {
LogMan::Msg::IFmt("IR-{} 0x{:x}:\n{}\n@@@@@\n", RA ? "post" : "pre", HeaderOp->OriginalRIP, out.str());
}
}
return false;
}
fextl::unique_ptr<FEXCore::IR::Pass> CreateIRDumper() {
return fextl::make_unique<IRDumper>();
}
}