#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"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
#include "../ExampleModules.h"
using namespace llvm;
using namespace llvm::orc;
ExitOnError ExitOnErr;
const llvm::StringRef TestMod =
R"(
define i32 @callee() {
entry:
ret i32 7
}
define i32 @entry() {
entry:
%0 = call i32 @callee()
ret i32 %0
}
)";
class MyPlugin : public ObjectLinkingLayer::Plugin {
public:
void modifyPassConfig(MaterializationResponsibility &MR,
jitlink::LinkGraph &LG,
jitlink::PassConfiguration &Config) override {
outs() << "MyPlugin -- Modifying pass config for " << LG.getName() << " ("
<< LG.getTargetTriple().str() << "):\n";
Config.PostPrunePasses.push_back(printGraph);
}
void notifyLoaded(MaterializationResponsibility &MR) override {
outs() << "Loading object defining " << MR.getSymbols() << "\n";
}
Error notifyEmitted(MaterializationResponsibility &MR) override {
outs() << "Emitted object defining " << MR.getSymbols() << "\n";
return Error::success();
}
Error notifyFailed(MaterializationResponsibility &MR) override {
return Error::success();
}
Error notifyRemovingResources(ResourceKey K) override {
return Error::success();
}
void notifyTransferringResources(ResourceKey DstKey,
ResourceKey SrcKey) override {}
private:
static void printBlockContent(jitlink::Block &B) {
constexpr JITTargetAddress LineWidth = 16;
if (B.isZeroFill()) {
outs() << " " << formatv("{0:x16}", B.getAddress()) << ": "
<< B.getSize() << " bytes of zero-fill.\n";
return;
}
ExecutorAddr InitAddr(B.getAddress().getValue() & ~(LineWidth - 1));
ExecutorAddr StartAddr = B.getAddress();
ExecutorAddr EndAddr = B.getAddress() + B.getSize();
auto *Data = reinterpret_cast<const uint8_t *>(B.getContent().data());
for (ExecutorAddr CurAddr = InitAddr; CurAddr != EndAddr; ++CurAddr) {
if (CurAddr % LineWidth == 0)
outs() << " " << formatv("{0:x16}", CurAddr.getValue())
<< ": ";
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";
for (auto &S : G.sections()) {
outs() << " Section " << S.getName() << ":\n";
for (auto *Sym : S.symbols()) {
outs() << " " << formatv("{0:x16}", Sym->getAddress()) << ": ";
if (Sym->hasName())
outs() << Sym->getName() << "\n";
else
outs() << "<anonymous symbol>\n";
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";
outs() << " Content:\n";
printBlockContent(B);
BlocksAlreadyVisited.insert(&B);
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";
}
}
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::desc("input objects"));
int main(int argc, char *argv[]) {
InitLLVM X(argc, argv);
InitializeNativeTarget();
InitializeNativeTargetAsmPrinter();
cl::ParseCommandLineOptions(argc, argv, "LLJITWithObjectLinkingLayerPlugin");
ExitOnErr.setBanner(std::string(argv[0]) + ": ");
auto JTMB = ExitOnErr(JITTargetMachineBuilder::detectHost());
JTMB.setCodeModel(CodeModel::Small);
auto J = ExitOnErr(
LLJITBuilder()
.setJITTargetMachineBuilder(std::move(JTMB))
.setObjectLinkingLayerCreator(
[&](ExecutionSession &ES, const Triple &TT) {
auto ObjLinkingLayer = std::make_unique<ObjectLinkingLayer>(
ES, ExitOnErr(jitlink::InProcessMemoryManager::Create()));
ObjLinkingLayer->addPlugin(std::make_unique<MyPlugin>());
return ObjLinkingLayer;
})
.create());
if (!InputObjects.empty()) {
J->getMainJITDylib().addGenerator(
ExitOnErr(DynamicLibrarySearchGenerator::GetForCurrentProcess(
J->getDataLayout().getGlobalPrefix())));
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)));
}
auto EntryAddr = ExitOnErr(J->lookup(EntryPointName));
auto *Entry = EntryAddr.toPtr<int()>();
int Result = Entry();
outs() << "---Result---\n"
<< EntryPointName << "() = " << Result << "\n";
return 0;
}