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"
17*4e30b20bSLang Hames #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
18633ea072SLang Hames #include "llvm/ExecutionEngine/Orc/LLJIT.h"
19633ea072SLang Hames #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
20633ea072SLang Hames #include "llvm/Support/InitLLVM.h"
21633ea072SLang Hames #include "llvm/Support/TargetSelect.h"
22633ea072SLang Hames #include "llvm/Support/raw_ostream.h"
23633ea072SLang Hames 
24633ea072SLang Hames #include "../ExampleModules.h"
25633ea072SLang Hames 
26633ea072SLang Hames using namespace llvm;
27633ea072SLang Hames using namespace llvm::orc;
28633ea072SLang Hames 
29633ea072SLang Hames ExitOnError ExitOnErr;
30633ea072SLang Hames 
31633ea072SLang Hames const llvm::StringRef TestMod =
32633ea072SLang Hames     R"(
33633ea072SLang Hames   define i32 @callee() {
34633ea072SLang Hames   entry:
35633ea072SLang Hames     ret i32 7
36633ea072SLang Hames   }
37633ea072SLang Hames 
38633ea072SLang Hames   define i32 @entry() {
39633ea072SLang Hames   entry:
40633ea072SLang Hames     %0 = call i32 @callee()
41633ea072SLang Hames     ret i32 %0
42633ea072SLang Hames   }
43633ea072SLang Hames )";
44633ea072SLang Hames 
45633ea072SLang Hames class MyPlugin : public ObjectLinkingLayer::Plugin {
46633ea072SLang Hames public:
47633ea072SLang Hames   // The modifyPassConfig callback gives us a chance to inspect the
48633ea072SLang Hames   // MaterializationResponsibility and target triple for the object being
49633ea072SLang Hames   // linked, then add any JITLink passes that we would like to run on the
50633ea072SLang Hames   // link graph. A pass is just a function object that is callable as
51633ea072SLang Hames   // Error(jitlink::LinkGraph&). In this case we will add two passes
52633ea072SLang Hames   // defined as lambdas that call the printLinkerGraph method on our
53633ea072SLang Hames   // plugin: One to run before the linker applies fixups and another to
54633ea072SLang Hames   // run afterwards.
55*4e30b20bSLang Hames   void modifyPassConfig(MaterializationResponsibility &MR,
56*4e30b20bSLang Hames                         jitlink::LinkGraph &LG,
57633ea072SLang Hames                         jitlink::PassConfiguration &Config) override {
58*4e30b20bSLang Hames 
59*4e30b20bSLang Hames     outs() << "MyPlugin -- Modifying pass config for " << LG.getName() << " ("
60*4e30b20bSLang Hames            << LG.getTargetTriple().str() << "):\n";
61*4e30b20bSLang Hames 
62*4e30b20bSLang Hames     // Print sections, symbol names and addresses, and any edges for the
63*4e30b20bSLang Hames     // associated blocks.
64*4e30b20bSLang Hames     Config.PostPrunePasses.push_back(printGraph);
65*4e30b20bSLang Hames 
66*4e30b20bSLang Hames     // Print graph contents before and after fixups:
67*4e30b20bSLang Hames     //
68*4e30b20bSLang Hames     // Config.PostPrunePasses.push_back([this](jitlink::LinkGraph &G) -> Error {
69*4e30b20bSLang Hames     //   printLinkGraphContent(G, "Before fixup:");
70*4e30b20bSLang Hames     //   return Error::success();
71*4e30b20bSLang Hames     // });
72*4e30b20bSLang Hames     // Config.PostFixupPasses.push_back([this](jitlink::LinkGraph &G) -> Error {
73*4e30b20bSLang Hames     //   printLinkGraphContent(G, "After fixup:");
74*4e30b20bSLang Hames     //   return Error::success();
75*4e30b20bSLang Hames     // });
76633ea072SLang Hames   }
77633ea072SLang Hames 
78633ea072SLang Hames   void notifyLoaded(MaterializationResponsibility &MR) override {
79*4e30b20bSLang Hames     outs() << "Loading object defining " << MR.getSymbols() << "\n";
80633ea072SLang Hames   }
81633ea072SLang Hames 
82633ea072SLang Hames   Error notifyEmitted(MaterializationResponsibility &MR) override {
83*4e30b20bSLang Hames     outs() << "Emitted object defining " << MR.getSymbols() << "\n";
84633ea072SLang Hames     return Error::success();
85633ea072SLang Hames   }
86633ea072SLang Hames 
870aec49c8SLang Hames   Error notifyFailed(MaterializationResponsibility &MR) override {
880aec49c8SLang Hames     return Error::success();
890aec49c8SLang Hames   }
900aec49c8SLang Hames 
910aec49c8SLang Hames   Error notifyRemovingResources(ResourceKey K) override {
920aec49c8SLang Hames     return Error::success();
930aec49c8SLang Hames   }
940aec49c8SLang Hames 
950aec49c8SLang Hames   void notifyTransferringResources(ResourceKey DstKey,
960aec49c8SLang Hames                                    ResourceKey SrcKey) override {}
970aec49c8SLang Hames 
98633ea072SLang Hames private:
99*4e30b20bSLang Hames   static void printBlockContent(jitlink::Block &B) {
100633ea072SLang Hames     constexpr JITTargetAddress LineWidth = 16;
101633ea072SLang Hames 
102*4e30b20bSLang Hames     if (B.isZeroFill()) {
103*4e30b20bSLang Hames       outs() << "    " << formatv("{0:x16}", B.getAddress()) << ": "
104*4e30b20bSLang Hames              << B.getSize() << " bytes of zero-fill.\n";
105*4e30b20bSLang Hames       return;
106*4e30b20bSLang Hames     }
107633ea072SLang Hames 
108*4e30b20bSLang Hames     JITTargetAddress InitAddr = B.getAddress() & ~(LineWidth - 1);
109*4e30b20bSLang Hames     JITTargetAddress StartAddr = B.getAddress();
110*4e30b20bSLang Hames     JITTargetAddress EndAddr = B.getAddress() + B.getSize();
111*4e30b20bSLang Hames     auto *Data = reinterpret_cast<const uint8_t *>(B.getContent().data());
112633ea072SLang Hames 
113*4e30b20bSLang Hames     for (JITTargetAddress CurAddr = InitAddr; CurAddr != EndAddr; ++CurAddr) {
114633ea072SLang Hames       if (CurAddr % LineWidth == 0)
115*4e30b20bSLang Hames         outs() << "          " << formatv("{0:x16}", CurAddr) << ": ";
116633ea072SLang Hames       if (CurAddr < StartAddr)
117*4e30b20bSLang Hames         outs() << "   ";
118633ea072SLang Hames       else
119*4e30b20bSLang Hames         outs() << formatv("{0:x-2}", Data[CurAddr - StartAddr]) << " ";
120633ea072SLang Hames       if (CurAddr % LineWidth == LineWidth - 1)
121*4e30b20bSLang Hames         outs() << "\n";
122633ea072SLang Hames     }
123633ea072SLang Hames     if (EndAddr % LineWidth != 0)
124*4e30b20bSLang Hames       outs() << "\n";
125*4e30b20bSLang Hames   }
126*4e30b20bSLang Hames 
127*4e30b20bSLang Hames   static Error printGraph(jitlink::LinkGraph &G) {
128*4e30b20bSLang Hames 
129*4e30b20bSLang Hames     DenseSet<jitlink::Block *> BlocksAlreadyVisited;
130*4e30b20bSLang Hames 
131*4e30b20bSLang Hames     outs() << "Graph \"" << G.getName() << "\"\n";
132*4e30b20bSLang Hames     // Loop over all sections...
133*4e30b20bSLang Hames     for (auto &S : G.sections()) {
134*4e30b20bSLang Hames       outs() << "  Section " << S.getName() << ":\n";
135*4e30b20bSLang Hames 
136*4e30b20bSLang Hames       // Loop over all symbols in the current section...
137*4e30b20bSLang Hames       for (auto *Sym : S.symbols()) {
138*4e30b20bSLang Hames 
139*4e30b20bSLang Hames         // Print the symbol's address.
140*4e30b20bSLang Hames         outs() << "    " << formatv("{0:x16}", Sym->getAddress()) << ": ";
141*4e30b20bSLang Hames 
142*4e30b20bSLang Hames         // Print the symbol's name, or "<anonymous symbol>" if it doesn't have
143*4e30b20bSLang Hames         // one.
144*4e30b20bSLang Hames         if (Sym->hasName())
145*4e30b20bSLang Hames           outs() << Sym->getName() << "\n";
146*4e30b20bSLang Hames         else
147*4e30b20bSLang Hames           outs() << "<anonymous symbol>\n";
148*4e30b20bSLang Hames 
149*4e30b20bSLang Hames         // Get the content block for this symbol.
150*4e30b20bSLang Hames         auto &B = Sym->getBlock();
151*4e30b20bSLang Hames 
152*4e30b20bSLang Hames         if (BlocksAlreadyVisited.count(&B)) {
153*4e30b20bSLang Hames           outs() << "      Block " << formatv("{0:x16}", B.getAddress())
154*4e30b20bSLang Hames                  << " already printed.\n";
155*4e30b20bSLang Hames           continue;
156*4e30b20bSLang Hames         } else
157*4e30b20bSLang Hames           outs() << "      Block " << formatv("{0:x16}", B.getAddress())
158*4e30b20bSLang Hames                  << ":\n";
159*4e30b20bSLang Hames 
160*4e30b20bSLang Hames         outs() << "        Content:\n";
161*4e30b20bSLang Hames         printBlockContent(B);
162*4e30b20bSLang Hames         BlocksAlreadyVisited.insert(&B);
163*4e30b20bSLang Hames 
164*4e30b20bSLang Hames         if (!llvm::empty(B.edges())) {
165*4e30b20bSLang Hames           outs() << "        Edges:\n";
166*4e30b20bSLang Hames           for (auto &E : B.edges()) {
167*4e30b20bSLang Hames             outs() << "          "
168*4e30b20bSLang Hames                    << formatv("{0:x16}", B.getAddress() + E.getOffset())
169*4e30b20bSLang Hames                    << ": kind = " << formatv("{0:d}", E.getKind())
170*4e30b20bSLang Hames                    << ", addend = " << formatv("{0:x}", E.getAddend())
171*4e30b20bSLang Hames                    << ", target = ";
172*4e30b20bSLang Hames             jitlink::Symbol &TargetSym = E.getTarget();
173*4e30b20bSLang Hames             if (TargetSym.hasName())
174*4e30b20bSLang Hames               outs() << TargetSym.getName() << "\n";
175*4e30b20bSLang Hames             else
176*4e30b20bSLang Hames               outs() << "<anonymous target>\n";
177633ea072SLang Hames           }
178633ea072SLang Hames         }
179*4e30b20bSLang Hames         outs() << "\n";
180*4e30b20bSLang Hames       }
181*4e30b20bSLang Hames     }
182*4e30b20bSLang Hames     return Error::success();
183633ea072SLang Hames   }
184633ea072SLang Hames };
185633ea072SLang Hames 
186*4e30b20bSLang Hames static cl::opt<std::string>
187*4e30b20bSLang Hames     EntryPointName("entry", cl::desc("Symbol to call as main entry point"),
188*4e30b20bSLang Hames                    cl::init("entry"));
189*4e30b20bSLang Hames 
190*4e30b20bSLang Hames static cl::list<std::string> InputObjects(cl::Positional, cl::ZeroOrMore,
191*4e30b20bSLang Hames                                           cl::desc("input objects"));
192*4e30b20bSLang Hames 
193633ea072SLang Hames int main(int argc, char *argv[]) {
194633ea072SLang Hames   // Initialize LLVM.
195633ea072SLang Hames   InitLLVM X(argc, argv);
196633ea072SLang Hames 
197633ea072SLang Hames   InitializeNativeTarget();
198633ea072SLang Hames   InitializeNativeTargetAsmPrinter();
199633ea072SLang Hames 
200633ea072SLang Hames   cl::ParseCommandLineOptions(argc, argv, "LLJITWithObjectLinkingLayerPlugin");
201633ea072SLang Hames   ExitOnErr.setBanner(std::string(argv[0]) + ": ");
202633ea072SLang Hames 
203633ea072SLang Hames   // Detect the host and set code model to small.
204633ea072SLang Hames   auto JTMB = ExitOnErr(JITTargetMachineBuilder::detectHost());
205633ea072SLang Hames   JTMB.setCodeModel(CodeModel::Small);
206633ea072SLang Hames 
207633ea072SLang Hames   // Create an LLJIT instance with an ObjectLinkingLayer as the base layer.
208633ea072SLang Hames   // We attach our plugin in to the newly created ObjectLinkingLayer before
209633ea072SLang Hames   // returning it.
210633ea072SLang Hames   auto J = ExitOnErr(
211633ea072SLang Hames       LLJITBuilder()
212633ea072SLang Hames           .setJITTargetMachineBuilder(std::move(JTMB))
213633ea072SLang Hames           .setObjectLinkingLayerCreator(
214633ea072SLang Hames               [&](ExecutionSession &ES, const Triple &TT) {
215633ea072SLang Hames                 // Create ObjectLinkingLayer.
216633ea072SLang Hames                 auto ObjLinkingLayer = std::make_unique<ObjectLinkingLayer>(
217633ea072SLang Hames                     ES, std::make_unique<jitlink::InProcessMemoryManager>());
218633ea072SLang Hames                 // Add an instance of our plugin.
219633ea072SLang Hames                 ObjLinkingLayer->addPlugin(std::make_unique<MyPlugin>());
2206edc3fe5SStefan Gränitz                 return ObjLinkingLayer;
221633ea072SLang Hames               })
222633ea072SLang Hames           .create());
223633ea072SLang Hames 
224*4e30b20bSLang Hames   if (!InputObjects.empty()) {
225633ea072SLang Hames 
226*4e30b20bSLang Hames     // If we have input objects then reflect process symbols so the input
227*4e30b20bSLang Hames     // objects can do interesting things, like call printf.
228*4e30b20bSLang Hames     J->getMainJITDylib().addGenerator(
229*4e30b20bSLang Hames         ExitOnErr(DynamicLibrarySearchGenerator::GetForCurrentProcess(
230*4e30b20bSLang Hames             J->getDataLayout().getGlobalPrefix())));
231*4e30b20bSLang Hames 
232*4e30b20bSLang Hames     // Load the input objects.
233*4e30b20bSLang Hames     for (auto InputObject : InputObjects) {
234*4e30b20bSLang Hames       auto ObjBuffer =
235*4e30b20bSLang Hames           ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputObject)));
236*4e30b20bSLang Hames       ExitOnErr(J->addObjectFile(std::move(ObjBuffer)));
237*4e30b20bSLang Hames     }
238*4e30b20bSLang Hames   } else {
239*4e30b20bSLang Hames     auto M = ExitOnErr(parseExampleModule(TestMod, "test-module"));
240*4e30b20bSLang Hames     M.withModuleDo([](Module &MP) {
241*4e30b20bSLang Hames       outs() << "No input objects specified. Using demo module:\n"
242*4e30b20bSLang Hames              << MP << "\n";
243*4e30b20bSLang Hames     });
244633ea072SLang Hames     ExitOnErr(J->addIRModule(std::move(M)));
245*4e30b20bSLang Hames   }
246633ea072SLang Hames 
247633ea072SLang Hames   // Look up the JIT'd function, cast it to a function pointer, then call it.
248*4e30b20bSLang Hames   auto EntrySym = ExitOnErr(J->lookup(EntryPointName));
249633ea072SLang Hames   auto *Entry = (int (*)())EntrySym.getAddress();
250633ea072SLang Hames 
251633ea072SLang Hames   int Result = Entry();
252633ea072SLang Hames   outs() << "---Result---\n"
253*4e30b20bSLang Hames          << EntryPointName << "() = " << Result << "\n";
254633ea072SLang Hames 
255633ea072SLang Hames   return 0;
256633ea072SLang Hames }
257