1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-18 10:32:48 +02:00

[JITLink][ORC] Make the LinkGraph available to modifyPassConfig.

This makes the target triple, graph name, and full graph content available
when making decisions about how to populate the linker pass pipeline.

Also updates the LLJITWithObjectLinkingLayerPlugin example to show more
API use, including use of the API changes in this patch.
This commit is contained in:
Lang Hames 2021-03-12 17:02:01 -08:00
parent 4a11d40768
commit d7eedad739
13 changed files with 151 additions and 58 deletions

View File

@ -14,6 +14,7 @@
#include "llvm/ADT/StringMap.h"
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
#include "llvm/Support/InitLLVM.h"
@ -51,24 +52,35 @@ public:
// defined as lambdas that call the printLinkerGraph method on our
// plugin: One to run before the linker applies fixups and another to
// run afterwards.
void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT,
void modifyPassConfig(MaterializationResponsibility &MR,
jitlink::LinkGraph &LG,
jitlink::PassConfiguration &Config) override {
Config.PostPrunePasses.push_back([this](jitlink::LinkGraph &G) -> Error {
printLinkGraph(G, "Before fixup:");
return Error::success();
});
Config.PostFixupPasses.push_back([this](jitlink::LinkGraph &G) -> Error {
printLinkGraph(G, "After fixup:");
return Error::success();
});
outs() << "MyPlugin -- Modifying pass config for " << LG.getName() << " ("
<< LG.getTargetTriple().str() << "):\n";
// Print sections, symbol names and addresses, and any edges for the
// associated blocks.
Config.PostPrunePasses.push_back(printGraph);
// Print graph contents before and after fixups:
//
// Config.PostPrunePasses.push_back([this](jitlink::LinkGraph &G) -> Error {
// printLinkGraphContent(G, "Before fixup:");
// return Error::success();
// });
// Config.PostFixupPasses.push_back([this](jitlink::LinkGraph &G) -> Error {
// printLinkGraphContent(G, "After fixup:");
// return Error::success();
// });
}
void notifyLoaded(MaterializationResponsibility &MR) override {
dbgs() << "Loading object defining " << MR.getSymbols() << "\n";
outs() << "Loading object defining " << MR.getSymbols() << "\n";
}
Error notifyEmitted(MaterializationResponsibility &MR) override {
dbgs() << "Emitted object defining " << MR.getSymbols() << "\n";
outs() << "Emitted object defining " << MR.getSymbols() << "\n";
return Error::success();
}
@ -84,42 +96,100 @@ public:
ResourceKey SrcKey) override {}
private:
void printLinkGraph(jitlink::LinkGraph &G, StringRef Title) {
static void printBlockContent(jitlink::Block &B) {
constexpr JITTargetAddress LineWidth = 16;
dbgs() << "--- " << Title << "---\n";
if (B.isZeroFill()) {
outs() << " " << formatv("{0:x16}", B.getAddress()) << ": "
<< B.getSize() << " bytes of zero-fill.\n";
return;
}
JITTargetAddress InitAddr = B.getAddress() & ~(LineWidth - 1);
JITTargetAddress StartAddr = B.getAddress();
JITTargetAddress EndAddr = B.getAddress() + B.getSize();
auto *Data = reinterpret_cast<const uint8_t *>(B.getContent().data());
for (JITTargetAddress CurAddr = InitAddr; CurAddr != EndAddr; ++CurAddr) {
if (CurAddr % LineWidth == 0)
outs() << " " << formatv("{0:x16}", CurAddr) << ": ";
if (CurAddr < StartAddr)
outs() << " ";
else
outs() << formatv("{0:x-2}", Data[CurAddr - StartAddr]) << " ";
if (CurAddr % LineWidth == LineWidth - 1)
outs() << "\n";
}
if (EndAddr % LineWidth != 0)
outs() << "\n";
}
static Error printGraph(jitlink::LinkGraph &G) {
DenseSet<jitlink::Block *> BlocksAlreadyVisited;
outs() << "Graph \"" << G.getName() << "\"\n";
// Loop over all sections...
for (auto &S : G.sections()) {
dbgs() << " section: " << S.getName() << "\n";
for (auto *B : S.blocks()) {
dbgs() << " block@" << formatv("{0:x16}", B->getAddress()) << ":\n";
outs() << " Section " << S.getName() << ":\n";
if (B->isZeroFill())
// Loop over all symbols in the current section...
for (auto *Sym : S.symbols()) {
// Print the symbol's address.
outs() << " " << formatv("{0:x16}", Sym->getAddress()) << ": ";
// Print the symbol's name, or "<anonymous symbol>" if it doesn't have
// one.
if (Sym->hasName())
outs() << Sym->getName() << "\n";
else
outs() << "<anonymous symbol>\n";
// Get the content block for this symbol.
auto &B = Sym->getBlock();
if (BlocksAlreadyVisited.count(&B)) {
outs() << " Block " << formatv("{0:x16}", B.getAddress())
<< " already printed.\n";
continue;
} else
outs() << " Block " << formatv("{0:x16}", B.getAddress())
<< ":\n";
JITTargetAddress InitAddr = B->getAddress() & ~(LineWidth - 1);
JITTargetAddress StartAddr = B->getAddress();
JITTargetAddress EndAddr = B->getAddress() + B->getSize();
auto *Data = reinterpret_cast<const uint8_t *>(B->getContent().data());
outs() << " Content:\n";
printBlockContent(B);
BlocksAlreadyVisited.insert(&B);
for (JITTargetAddress CurAddr = InitAddr; CurAddr != EndAddr;
++CurAddr) {
if (CurAddr % LineWidth == 0)
dbgs() << " " << formatv("{0:x16}", CurAddr) << ": ";
if (CurAddr < StartAddr)
dbgs() << " ";
else
dbgs() << formatv("{0:x-2}", Data[CurAddr - StartAddr]) << " ";
if (CurAddr % LineWidth == LineWidth - 1)
dbgs() << "\n";
if (!llvm::empty(B.edges())) {
outs() << " Edges:\n";
for (auto &E : B.edges()) {
outs() << " "
<< formatv("{0:x16}", B.getAddress() + E.getOffset())
<< ": kind = " << formatv("{0:d}", E.getKind())
<< ", addend = " << formatv("{0:x}", E.getAddend())
<< ", target = ";
jitlink::Symbol &TargetSym = E.getTarget();
if (TargetSym.hasName())
outs() << TargetSym.getName() << "\n";
else
outs() << "<anonymous target>\n";
}
}
if (EndAddr % LineWidth != 0)
dbgs() << "\n";
dbgs() << "\n";
outs() << "\n";
}
}
return Error::success();
}
};
static cl::opt<std::string>
EntryPointName("entry", cl::desc("Symbol to call as main entry point"),
cl::init("entry"));
static cl::list<std::string> InputObjects(cl::Positional, cl::ZeroOrMore,
cl::desc("input objects"));
int main(int argc, char *argv[]) {
// Initialize LLVM.
InitLLVM X(argc, argv);
@ -151,17 +221,36 @@ int main(int argc, char *argv[]) {
})
.create());
auto M = ExitOnErr(parseExampleModule(TestMod, "test-module"));
if (!InputObjects.empty()) {
ExitOnErr(J->addIRModule(std::move(M)));
// If we have input objects then reflect process symbols so the input
// objects can do interesting things, like call printf.
J->getMainJITDylib().addGenerator(
ExitOnErr(DynamicLibrarySearchGenerator::GetForCurrentProcess(
J->getDataLayout().getGlobalPrefix())));
// Load the input objects.
for (auto InputObject : InputObjects) {
auto ObjBuffer =
ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputObject)));
ExitOnErr(J->addObjectFile(std::move(ObjBuffer)));
}
} else {
auto M = ExitOnErr(parseExampleModule(TestMod, "test-module"));
M.withModuleDo([](Module &MP) {
outs() << "No input objects specified. Using demo module:\n"
<< MP << "\n";
});
ExitOnErr(J->addIRModule(std::move(M)));
}
// Look up the JIT'd function, cast it to a function pointer, then call it.
auto EntrySym = ExitOnErr(J->lookup("entry"));
auto EntrySym = ExitOnErr(J->lookup(EntryPointName));
auto *Entry = (int (*)())EntrySym.getAddress();
int Result = Entry();
outs() << "---Result---\n"
<< "entry() = " << Result << "\n";
<< EntryPointName << "() = " << Result << "\n";
return 0;
}

View File

@ -1377,7 +1377,7 @@ public:
/// Called by JITLink to modify the pass pipeline prior to linking.
/// The default version performs no modification.
virtual Error modifyPassConfig(const Triple &TT, PassConfiguration &Config);
virtual Error modifyPassConfig(LinkGraph &G, PassConfiguration &Config);
private:
const JITLinkDylib *JD = nullptr;

View File

@ -62,7 +62,8 @@ public:
void notifyTransferringResources(ResourceKey DstKey,
ResourceKey SrcKey) override;
void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT,
void modifyPassConfig(MaterializationResponsibility &MR,
jitlink::LinkGraph &LG,
jitlink::PassConfiguration &PassConfig) override;
private:

View File

@ -114,7 +114,8 @@ private:
public:
InitScraperPlugin(MachOPlatform &MP) : MP(MP) {}
void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT,
void modifyPassConfig(MaterializationResponsibility &MR,
jitlink::LinkGraph &G,
jitlink::PassConfiguration &Config) override;
LocalDependenciesMap getSyntheticSymbolLocalDependencies(

View File

@ -69,7 +69,7 @@ public:
virtual ~Plugin();
virtual void modifyPassConfig(MaterializationResponsibility &MR,
const Triple &TT,
jitlink::LinkGraph &G,
jitlink::PassConfiguration &Config) {}
// Deprecated. Don't use this in new code. There will be a proper mechanism
@ -171,7 +171,8 @@ public:
private:
using AllocPtr = std::unique_ptr<jitlink::JITLinkMemoryManager::Allocation>;
void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT,
void modifyPassConfig(MaterializationResponsibility &MR,
jitlink::LinkGraph &G,
jitlink::PassConfiguration &PassConfig);
void notifyLoaded(MaterializationResponsibility &MR);
Error notifyEmitted(MaterializationResponsibility &MR, AllocPtr Alloc);
@ -194,7 +195,8 @@ public:
EHFrameRegistrationPlugin(
ExecutionSession &ES,
std::unique_ptr<jitlink::EHFrameRegistrar> Registrar);
void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT,
void modifyPassConfig(MaterializationResponsibility &MR,
jitlink::LinkGraph &G,
jitlink::PassConfiguration &PassConfig) override;
Error notifyEmitted(MaterializationResponsibility &MR) override;
Error notifyFailed(MaterializationResponsibility &MR) override;

View File

@ -787,7 +787,7 @@ void link_ELF_x86_64(std::unique_ptr<LinkGraph> G,
Config.PreFixupPasses.push_back(optimizeELF_x86_64_GOTAndStubs);
}
if (auto Err = Ctx->modifyPassConfig(G->getTargetTriple(), Config))
if (auto Err = Ctx->modifyPassConfig(*G, Config))
return Ctx->notifyFailed(std::move(Err));
ELFJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));

View File

@ -311,7 +311,7 @@ LinkGraphPassFunction JITLinkContext::getMarkLivePass(const Triple &TT) const {
return LinkGraphPassFunction();
}
Error JITLinkContext::modifyPassConfig(const Triple &TT,
Error JITLinkContext::modifyPassConfig(LinkGraph &G,
PassConfiguration &Config) {
return Error::success();
}

View File

@ -701,7 +701,7 @@ void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
});
}
if (auto Err = Ctx->modifyPassConfig(G->getTargetTriple(), Config))
if (auto Err = Ctx->modifyPassConfig(*G, Config))
return Ctx->notifyFailed(std::move(Err));
// Construct a JITLinker and run the link function.

View File

@ -688,7 +688,7 @@ void link_MachO_x86_64(std::unique_ptr<LinkGraph> G,
Config.PreFixupPasses.push_back(optimizeMachO_x86_64_GOTAndStubs);
}
if (auto Err = Ctx->modifyPassConfig(G->getTargetTriple(), Config))
if (auto Err = Ctx->modifyPassConfig(*G, Config))
return Ctx->notifyFailed(std::move(Err));
// Construct a JITLinker and run the link function.

View File

@ -432,7 +432,7 @@ void DebugObjectManagerPlugin::notifyMaterializing(
}
void DebugObjectManagerPlugin::modifyPassConfig(
MaterializationResponsibility &MR, const Triple &TT,
MaterializationResponsibility &MR, LinkGraph &G,
PassConfiguration &PassConfig) {
// Not all link artifacts have associated debug objects.
std::lock_guard<std::mutex> Lock(PendingObjsLock);

View File

@ -298,7 +298,7 @@ getSectionExtent(jitlink::LinkGraph &G, StringRef SectionName) {
}
void MachOPlatform::InitScraperPlugin::modifyPassConfig(
MaterializationResponsibility &MR, const Triple &TT,
MaterializationResponsibility &MR, jitlink::LinkGraph &LG,
jitlink::PassConfiguration &Config) {
if (!MR.getInitializerSymbol())

View File

@ -218,14 +218,14 @@ public:
return [this](LinkGraph &G) { return markResponsibilitySymbolsLive(G); };
}
Error modifyPassConfig(const Triple &TT, PassConfiguration &Config) override {
Error modifyPassConfig(LinkGraph &LG, PassConfiguration &Config) override {
// Add passes to mark duplicate defs as should-discard, and to walk the
// link graph to build the symbol dependence graph.
Config.PrePrunePasses.push_back([this](LinkGraph &G) {
return claimOrExternalizeWeakAndCommonSymbols(G);
});
Layer.modifyPassConfig(*MR, TT, Config);
Layer.modifyPassConfig(*MR, LG, Config);
Config.PostPrunePasses.push_back(
[this](LinkGraph &G) { return computeNamedSymbolDependencies(G); });
@ -511,10 +511,10 @@ void ObjectLinkingLayer::emit(std::unique_ptr<MaterializationResponsibility> R,
}
void ObjectLinkingLayer::modifyPassConfig(MaterializationResponsibility &MR,
const Triple &TT,
LinkGraph &G,
PassConfiguration &PassConfig) {
for (auto &P : Plugins)
P->modifyPassConfig(MR, TT, PassConfig);
P->modifyPassConfig(MR, G, PassConfig);
}
void ObjectLinkingLayer::notifyLoaded(MaterializationResponsibility &MR) {
@ -583,11 +583,11 @@ EHFrameRegistrationPlugin::EHFrameRegistrationPlugin(
: ES(ES), Registrar(std::move(Registrar)) {}
void EHFrameRegistrationPlugin::modifyPassConfig(
MaterializationResponsibility &MR, const Triple &TT,
MaterializationResponsibility &MR, LinkGraph &G,
PassConfiguration &PassConfig) {
PassConfig.PostFixupPasses.push_back(createEHFrameRecorderPass(
TT, [this, &MR](JITTargetAddress Addr, size_t Size) {
G.getTargetTriple(), [this, &MR](JITTargetAddress Addr, size_t Size) {
if (Addr) {
std::lock_guard<std::mutex> Lock(EHFramePluginMutex);
assert(!InProcessLinks.count(&MR) &&

View File

@ -821,9 +821,9 @@ Session::Session(std::unique_ptr<TargetProcessControl> TPC, Error &Err)
class JITLinkSessionPlugin : public ObjectLinkingLayer::Plugin {
public:
JITLinkSessionPlugin(Session &S) : S(S) {}
void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT,
void modifyPassConfig(MaterializationResponsibility &MR, LinkGraph &G,
PassConfiguration &PassConfig) override {
S.modifyPassConfig(TT, PassConfig);
S.modifyPassConfig(G.getTargetTriple(), PassConfig);
}
Error notifyFailed(MaterializationResponsibility &MR) override {