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