1*633ea072SLang Hames //===--------------- LLJITWithCustomObjectLinkingLayer.cpp ----------------===// 2*633ea072SLang Hames // 3*633ea072SLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*633ea072SLang Hames // See https://llvm.org/LICENSE.txt for license information. 5*633ea072SLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*633ea072SLang Hames // 7*633ea072SLang Hames //===----------------------------------------------------------------------===// 8*633ea072SLang Hames // 9*633ea072SLang Hames // This file shows how to switch LLJIT to use a custom object linking layer (we 10*633ea072SLang Hames // use ObjectLinkingLayer, which is backed by JITLink, as an example). 11*633ea072SLang Hames // 12*633ea072SLang Hames //===----------------------------------------------------------------------===// 13*633ea072SLang Hames 14*633ea072SLang Hames #include "llvm/ADT/StringMap.h" 15*633ea072SLang Hames #include "llvm/ExecutionEngine/JITLink/JITLink.h" 16*633ea072SLang Hames #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h" 17*633ea072SLang Hames #include "llvm/ExecutionEngine/Orc/LLJIT.h" 18*633ea072SLang Hames #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" 19*633ea072SLang Hames #include "llvm/Support/InitLLVM.h" 20*633ea072SLang Hames #include "llvm/Support/TargetSelect.h" 21*633ea072SLang Hames #include "llvm/Support/raw_ostream.h" 22*633ea072SLang Hames 23*633ea072SLang Hames #include "../ExampleModules.h" 24*633ea072SLang Hames 25*633ea072SLang Hames using namespace llvm; 26*633ea072SLang Hames using namespace llvm::orc; 27*633ea072SLang Hames 28*633ea072SLang Hames ExitOnError ExitOnErr; 29*633ea072SLang Hames 30*633ea072SLang Hames const llvm::StringRef TestMod = 31*633ea072SLang Hames R"( 32*633ea072SLang Hames define i32 @callee() { 33*633ea072SLang Hames entry: 34*633ea072SLang Hames ret i32 7 35*633ea072SLang Hames } 36*633ea072SLang Hames 37*633ea072SLang Hames define i32 @entry() { 38*633ea072SLang Hames entry: 39*633ea072SLang Hames %0 = call i32 @callee() 40*633ea072SLang Hames ret i32 %0 41*633ea072SLang Hames } 42*633ea072SLang Hames )"; 43*633ea072SLang Hames 44*633ea072SLang Hames class MyPlugin : public ObjectLinkingLayer::Plugin { 45*633ea072SLang Hames public: 46*633ea072SLang Hames // The modifyPassConfig callback gives us a chance to inspect the 47*633ea072SLang Hames // MaterializationResponsibility and target triple for the object being 48*633ea072SLang Hames // linked, then add any JITLink passes that we would like to run on the 49*633ea072SLang Hames // link graph. A pass is just a function object that is callable as 50*633ea072SLang Hames // Error(jitlink::LinkGraph&). In this case we will add two passes 51*633ea072SLang Hames // defined as lambdas that call the printLinkerGraph method on our 52*633ea072SLang Hames // plugin: One to run before the linker applies fixups and another to 53*633ea072SLang Hames // run afterwards. 54*633ea072SLang Hames void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT, 55*633ea072SLang Hames jitlink::PassConfiguration &Config) override { 56*633ea072SLang Hames Config.PostPrunePasses.push_back([this](jitlink::LinkGraph &G) -> Error { 57*633ea072SLang Hames printLinkGraph(G, "Before fixup:"); 58*633ea072SLang Hames return Error::success(); 59*633ea072SLang Hames }); 60*633ea072SLang Hames Config.PostFixupPasses.push_back([this](jitlink::LinkGraph &G) -> Error { 61*633ea072SLang Hames printLinkGraph(G, "After fixup:"); 62*633ea072SLang Hames return Error::success(); 63*633ea072SLang Hames }); 64*633ea072SLang Hames } 65*633ea072SLang Hames 66*633ea072SLang Hames void notifyLoaded(MaterializationResponsibility &MR) override { 67*633ea072SLang Hames dbgs() << "Loading object defining " << MR.getSymbols() << "\n"; 68*633ea072SLang Hames } 69*633ea072SLang Hames 70*633ea072SLang Hames Error notifyEmitted(MaterializationResponsibility &MR) override { 71*633ea072SLang Hames dbgs() << "Emitted object defining " << MR.getSymbols() << "\n"; 72*633ea072SLang Hames return Error::success(); 73*633ea072SLang Hames } 74*633ea072SLang Hames 75*633ea072SLang Hames private: 76*633ea072SLang Hames void printLinkGraph(jitlink::LinkGraph &G, StringRef Title) { 77*633ea072SLang Hames constexpr JITTargetAddress LineWidth = 16; 78*633ea072SLang Hames 79*633ea072SLang Hames dbgs() << "--- " << Title << "---\n"; 80*633ea072SLang Hames for (auto &S : G.sections()) { 81*633ea072SLang Hames dbgs() << " section: " << S.getName() << "\n"; 82*633ea072SLang Hames for (auto *B : S.blocks()) { 83*633ea072SLang Hames dbgs() << " block@" << formatv("{0:x16}", B->getAddress()) << ":\n"; 84*633ea072SLang Hames 85*633ea072SLang Hames if (B->isZeroFill()) 86*633ea072SLang Hames continue; 87*633ea072SLang Hames 88*633ea072SLang Hames JITTargetAddress InitAddr = B->getAddress() & ~(LineWidth - 1); 89*633ea072SLang Hames JITTargetAddress StartAddr = B->getAddress(); 90*633ea072SLang Hames JITTargetAddress EndAddr = B->getAddress() + B->getSize(); 91*633ea072SLang Hames auto *Data = reinterpret_cast<const uint8_t *>(B->getContent().data()); 92*633ea072SLang Hames 93*633ea072SLang Hames for (JITTargetAddress CurAddr = InitAddr; CurAddr != EndAddr; 94*633ea072SLang Hames ++CurAddr) { 95*633ea072SLang Hames if (CurAddr % LineWidth == 0) 96*633ea072SLang Hames dbgs() << " " << formatv("{0:x16}", CurAddr) << ": "; 97*633ea072SLang Hames if (CurAddr < StartAddr) 98*633ea072SLang Hames dbgs() << " "; 99*633ea072SLang Hames else 100*633ea072SLang Hames dbgs() << formatv("{0:x-2}", Data[CurAddr - StartAddr]) << " "; 101*633ea072SLang Hames if (CurAddr % LineWidth == LineWidth - 1) 102*633ea072SLang Hames dbgs() << "\n"; 103*633ea072SLang Hames } 104*633ea072SLang Hames if (EndAddr % LineWidth != 0) 105*633ea072SLang Hames dbgs() << "\n"; 106*633ea072SLang Hames dbgs() << "\n"; 107*633ea072SLang Hames } 108*633ea072SLang Hames } 109*633ea072SLang Hames } 110*633ea072SLang Hames }; 111*633ea072SLang Hames 112*633ea072SLang Hames int main(int argc, char *argv[]) { 113*633ea072SLang Hames // Initialize LLVM. 114*633ea072SLang Hames InitLLVM X(argc, argv); 115*633ea072SLang Hames 116*633ea072SLang Hames InitializeNativeTarget(); 117*633ea072SLang Hames InitializeNativeTargetAsmPrinter(); 118*633ea072SLang Hames 119*633ea072SLang Hames cl::ParseCommandLineOptions(argc, argv, "LLJITWithObjectLinkingLayerPlugin"); 120*633ea072SLang Hames ExitOnErr.setBanner(std::string(argv[0]) + ": "); 121*633ea072SLang Hames 122*633ea072SLang Hames // Detect the host and set code model to small. 123*633ea072SLang Hames auto JTMB = ExitOnErr(JITTargetMachineBuilder::detectHost()); 124*633ea072SLang Hames JTMB.setCodeModel(CodeModel::Small); 125*633ea072SLang Hames 126*633ea072SLang Hames // Create an LLJIT instance with an ObjectLinkingLayer as the base layer. 127*633ea072SLang Hames // We attach our plugin in to the newly created ObjectLinkingLayer before 128*633ea072SLang Hames // returning it. 129*633ea072SLang Hames auto J = ExitOnErr( 130*633ea072SLang Hames LLJITBuilder() 131*633ea072SLang Hames .setJITTargetMachineBuilder(std::move(JTMB)) 132*633ea072SLang Hames .setObjectLinkingLayerCreator( 133*633ea072SLang Hames [&](ExecutionSession &ES, const Triple &TT) { 134*633ea072SLang Hames // Create ObjectLinkingLayer. 135*633ea072SLang Hames auto ObjLinkingLayer = std::make_unique<ObjectLinkingLayer>( 136*633ea072SLang Hames ES, std::make_unique<jitlink::InProcessMemoryManager>()); 137*633ea072SLang Hames // Add an instance of our plugin. 138*633ea072SLang Hames ObjLinkingLayer->addPlugin(std::make_unique<MyPlugin>()); 139*633ea072SLang Hames return ObjLinkingLayer; 140*633ea072SLang Hames }) 141*633ea072SLang Hames .create()); 142*633ea072SLang Hames 143*633ea072SLang Hames auto M = ExitOnErr(parseExampleModule(TestMod, "test-module")); 144*633ea072SLang Hames 145*633ea072SLang Hames ExitOnErr(J->addIRModule(std::move(M))); 146*633ea072SLang Hames 147*633ea072SLang Hames // Look up the JIT'd function, cast it to a function pointer, then call it. 148*633ea072SLang Hames auto EntrySym = ExitOnErr(J->lookup("entry")); 149*633ea072SLang Hames auto *Entry = (int (*)())EntrySym.getAddress(); 150*633ea072SLang Hames 151*633ea072SLang Hames int Result = Entry(); 152*633ea072SLang Hames outs() << "---Result---\n" 153*633ea072SLang Hames << "entry() = " << Result << "\n"; 154*633ea072SLang Hames 155*633ea072SLang Hames return 0; 156*633ea072SLang Hames } 157