1633ea072SLang Hames //===--------------- LLJITWithCustomObjectLinkingLayer.cpp ----------------===// 2633ea072SLang Hames // 3633ea072SLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4633ea072SLang Hames // See https://llvm.org/LICENSE.txt for license information. 5633ea072SLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6633ea072SLang Hames // 7633ea072SLang Hames //===----------------------------------------------------------------------===// 8633ea072SLang Hames // 9633ea072SLang Hames // This file shows how to switch LLJIT to use a custom object linking layer (we 10633ea072SLang Hames // use ObjectLinkingLayer, which is backed by JITLink, as an example). 11633ea072SLang Hames // 12633ea072SLang Hames //===----------------------------------------------------------------------===// 13633ea072SLang Hames 14633ea072SLang Hames #include "llvm/ADT/StringMap.h" 15633ea072SLang Hames #include "llvm/ExecutionEngine/JITLink/JITLink.h" 16633ea072SLang Hames #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h" 17633ea072SLang Hames #include "llvm/ExecutionEngine/Orc/LLJIT.h" 18633ea072SLang Hames #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" 19633ea072SLang Hames #include "llvm/Support/InitLLVM.h" 20633ea072SLang Hames #include "llvm/Support/TargetSelect.h" 21633ea072SLang Hames #include "llvm/Support/raw_ostream.h" 22633ea072SLang Hames 23633ea072SLang Hames #include "../ExampleModules.h" 24633ea072SLang Hames 25633ea072SLang Hames using namespace llvm; 26633ea072SLang Hames using namespace llvm::orc; 27633ea072SLang Hames 28633ea072SLang Hames ExitOnError ExitOnErr; 29633ea072SLang Hames 30633ea072SLang Hames const llvm::StringRef TestMod = 31633ea072SLang Hames R"( 32633ea072SLang Hames define i32 @callee() { 33633ea072SLang Hames entry: 34633ea072SLang Hames ret i32 7 35633ea072SLang Hames } 36633ea072SLang Hames 37633ea072SLang Hames define i32 @entry() { 38633ea072SLang Hames entry: 39633ea072SLang Hames %0 = call i32 @callee() 40633ea072SLang Hames ret i32 %0 41633ea072SLang Hames } 42633ea072SLang Hames )"; 43633ea072SLang Hames 44633ea072SLang Hames class MyPlugin : public ObjectLinkingLayer::Plugin { 45633ea072SLang Hames public: 46633ea072SLang Hames // The modifyPassConfig callback gives us a chance to inspect the 47633ea072SLang Hames // MaterializationResponsibility and target triple for the object being 48633ea072SLang Hames // linked, then add any JITLink passes that we would like to run on the 49633ea072SLang Hames // link graph. A pass is just a function object that is callable as 50633ea072SLang Hames // Error(jitlink::LinkGraph&). In this case we will add two passes 51633ea072SLang Hames // defined as lambdas that call the printLinkerGraph method on our 52633ea072SLang Hames // plugin: One to run before the linker applies fixups and another to 53633ea072SLang Hames // run afterwards. 54633ea072SLang Hames void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT, 55633ea072SLang Hames jitlink::PassConfiguration &Config) override { 56633ea072SLang Hames Config.PostPrunePasses.push_back([this](jitlink::LinkGraph &G) -> Error { 57633ea072SLang Hames printLinkGraph(G, "Before fixup:"); 58633ea072SLang Hames return Error::success(); 59633ea072SLang Hames }); 60633ea072SLang Hames Config.PostFixupPasses.push_back([this](jitlink::LinkGraph &G) -> Error { 61633ea072SLang Hames printLinkGraph(G, "After fixup:"); 62633ea072SLang Hames return Error::success(); 63633ea072SLang Hames }); 64633ea072SLang Hames } 65633ea072SLang Hames 66633ea072SLang Hames void notifyLoaded(MaterializationResponsibility &MR) override { 67633ea072SLang Hames dbgs() << "Loading object defining " << MR.getSymbols() << "\n"; 68633ea072SLang Hames } 69633ea072SLang Hames 70633ea072SLang Hames Error notifyEmitted(MaterializationResponsibility &MR) override { 71633ea072SLang Hames dbgs() << "Emitted object defining " << MR.getSymbols() << "\n"; 72633ea072SLang Hames return Error::success(); 73633ea072SLang Hames } 74633ea072SLang Hames 75*0aec49c8SLang Hames Error notifyFailed(MaterializationResponsibility &MR) override { 76*0aec49c8SLang Hames return Error::success(); 77*0aec49c8SLang Hames } 78*0aec49c8SLang Hames 79*0aec49c8SLang Hames Error notifyRemovingResources(ResourceKey K) override { 80*0aec49c8SLang Hames return Error::success(); 81*0aec49c8SLang Hames } 82*0aec49c8SLang Hames 83*0aec49c8SLang Hames void notifyTransferringResources(ResourceKey DstKey, 84*0aec49c8SLang Hames ResourceKey SrcKey) override {} 85*0aec49c8SLang Hames 86633ea072SLang Hames private: 87633ea072SLang Hames void printLinkGraph(jitlink::LinkGraph &G, StringRef Title) { 88633ea072SLang Hames constexpr JITTargetAddress LineWidth = 16; 89633ea072SLang Hames 90633ea072SLang Hames dbgs() << "--- " << Title << "---\n"; 91633ea072SLang Hames for (auto &S : G.sections()) { 92633ea072SLang Hames dbgs() << " section: " << S.getName() << "\n"; 93633ea072SLang Hames for (auto *B : S.blocks()) { 94633ea072SLang Hames dbgs() << " block@" << formatv("{0:x16}", B->getAddress()) << ":\n"; 95633ea072SLang Hames 96633ea072SLang Hames if (B->isZeroFill()) 97633ea072SLang Hames continue; 98633ea072SLang Hames 99633ea072SLang Hames JITTargetAddress InitAddr = B->getAddress() & ~(LineWidth - 1); 100633ea072SLang Hames JITTargetAddress StartAddr = B->getAddress(); 101633ea072SLang Hames JITTargetAddress EndAddr = B->getAddress() + B->getSize(); 102633ea072SLang Hames auto *Data = reinterpret_cast<const uint8_t *>(B->getContent().data()); 103633ea072SLang Hames 104633ea072SLang Hames for (JITTargetAddress CurAddr = InitAddr; CurAddr != EndAddr; 105633ea072SLang Hames ++CurAddr) { 106633ea072SLang Hames if (CurAddr % LineWidth == 0) 107633ea072SLang Hames dbgs() << " " << formatv("{0:x16}", CurAddr) << ": "; 108633ea072SLang Hames if (CurAddr < StartAddr) 109633ea072SLang Hames dbgs() << " "; 110633ea072SLang Hames else 111633ea072SLang Hames dbgs() << formatv("{0:x-2}", Data[CurAddr - StartAddr]) << " "; 112633ea072SLang Hames if (CurAddr % LineWidth == LineWidth - 1) 113633ea072SLang Hames dbgs() << "\n"; 114633ea072SLang Hames } 115633ea072SLang Hames if (EndAddr % LineWidth != 0) 116633ea072SLang Hames dbgs() << "\n"; 117633ea072SLang Hames dbgs() << "\n"; 118633ea072SLang Hames } 119633ea072SLang Hames } 120633ea072SLang Hames } 121633ea072SLang Hames }; 122633ea072SLang Hames 123633ea072SLang Hames int main(int argc, char *argv[]) { 124633ea072SLang Hames // Initialize LLVM. 125633ea072SLang Hames InitLLVM X(argc, argv); 126633ea072SLang Hames 127633ea072SLang Hames InitializeNativeTarget(); 128633ea072SLang Hames InitializeNativeTargetAsmPrinter(); 129633ea072SLang Hames 130633ea072SLang Hames cl::ParseCommandLineOptions(argc, argv, "LLJITWithObjectLinkingLayerPlugin"); 131633ea072SLang Hames ExitOnErr.setBanner(std::string(argv[0]) + ": "); 132633ea072SLang Hames 133633ea072SLang Hames // Detect the host and set code model to small. 134633ea072SLang Hames auto JTMB = ExitOnErr(JITTargetMachineBuilder::detectHost()); 135633ea072SLang Hames JTMB.setCodeModel(CodeModel::Small); 136633ea072SLang Hames 137633ea072SLang Hames // Create an LLJIT instance with an ObjectLinkingLayer as the base layer. 138633ea072SLang Hames // We attach our plugin in to the newly created ObjectLinkingLayer before 139633ea072SLang Hames // returning it. 140633ea072SLang Hames auto J = ExitOnErr( 141633ea072SLang Hames LLJITBuilder() 142633ea072SLang Hames .setJITTargetMachineBuilder(std::move(JTMB)) 143633ea072SLang Hames .setObjectLinkingLayerCreator( 144633ea072SLang Hames [&](ExecutionSession &ES, const Triple &TT) { 145633ea072SLang Hames // Create ObjectLinkingLayer. 146633ea072SLang Hames auto ObjLinkingLayer = std::make_unique<ObjectLinkingLayer>( 147633ea072SLang Hames ES, std::make_unique<jitlink::InProcessMemoryManager>()); 148633ea072SLang Hames // Add an instance of our plugin. 149633ea072SLang Hames ObjLinkingLayer->addPlugin(std::make_unique<MyPlugin>()); 150633ea072SLang Hames return ObjLinkingLayer; 151633ea072SLang Hames }) 152633ea072SLang Hames .create()); 153633ea072SLang Hames 154633ea072SLang Hames auto M = ExitOnErr(parseExampleModule(TestMod, "test-module")); 155633ea072SLang Hames 156633ea072SLang Hames ExitOnErr(J->addIRModule(std::move(M))); 157633ea072SLang Hames 158633ea072SLang Hames // Look up the JIT'd function, cast it to a function pointer, then call it. 159633ea072SLang Hames auto EntrySym = ExitOnErr(J->lookup("entry")); 160633ea072SLang Hames auto *Entry = (int (*)())EntrySym.getAddress(); 161633ea072SLang Hames 162633ea072SLang Hames int Result = Entry(); 163633ea072SLang Hames outs() << "---Result---\n" 164633ea072SLang Hames << "entry() = " << Result << "\n"; 165633ea072SLang Hames 166633ea072SLang Hames return 0; 167633ea072SLang Hames } 168