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