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"
174e30b20bSLang 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.
554e30b20bSLang Hames   void modifyPassConfig(MaterializationResponsibility &MR,
564e30b20bSLang Hames                         jitlink::LinkGraph &LG,
57633ea072SLang Hames                         jitlink::PassConfiguration &Config) override {
584e30b20bSLang Hames 
594e30b20bSLang Hames     outs() << "MyPlugin -- Modifying pass config for " << LG.getName() << " ("
604e30b20bSLang Hames            << LG.getTargetTriple().str() << "):\n";
614e30b20bSLang Hames 
624e30b20bSLang Hames     // Print sections, symbol names and addresses, and any edges for the
63*70c92126SLang Hames     // associated blocks at the 'PostPrune' phase of JITLink (after
64*70c92126SLang Hames     // dead-stripping, but before addresses are allocated in the target
65*70c92126SLang Hames     // address space. See llvm/docs/JITLink.rst).
664e30b20bSLang Hames     //
67*70c92126SLang Hames     // Experiment with adding the 'printGraph' pass at other points in the
68*70c92126SLang Hames     // pipeline. E.g. PrePrunePasses, PostAllocationPasses, and
69*70c92126SLang Hames     // PostFixupPasses.
70*70c92126SLang Hames     Config.PostPrunePasses.push_back(printGraph);
71633ea072SLang Hames   }
72633ea072SLang Hames 
73633ea072SLang Hames   void notifyLoaded(MaterializationResponsibility &MR) override {
744e30b20bSLang Hames     outs() << "Loading object defining " << MR.getSymbols() << "\n";
75633ea072SLang Hames   }
76633ea072SLang Hames 
77633ea072SLang Hames   Error notifyEmitted(MaterializationResponsibility &MR) override {
784e30b20bSLang Hames     outs() << "Emitted object defining " << MR.getSymbols() << "\n";
79633ea072SLang Hames     return Error::success();
80633ea072SLang Hames   }
81633ea072SLang Hames 
820aec49c8SLang Hames   Error notifyFailed(MaterializationResponsibility &MR) override {
830aec49c8SLang Hames     return Error::success();
840aec49c8SLang Hames   }
850aec49c8SLang Hames 
860aec49c8SLang Hames   Error notifyRemovingResources(ResourceKey K) override {
870aec49c8SLang Hames     return Error::success();
880aec49c8SLang Hames   }
890aec49c8SLang Hames 
900aec49c8SLang Hames   void notifyTransferringResources(ResourceKey DstKey,
910aec49c8SLang Hames                                    ResourceKey SrcKey) override {}
920aec49c8SLang Hames 
93633ea072SLang Hames private:
944e30b20bSLang Hames   static void printBlockContent(jitlink::Block &B) {
95633ea072SLang Hames     constexpr JITTargetAddress LineWidth = 16;
96633ea072SLang Hames 
974e30b20bSLang Hames     if (B.isZeroFill()) {
984e30b20bSLang Hames       outs() << "    " << formatv("{0:x16}", B.getAddress()) << ": "
994e30b20bSLang Hames              << B.getSize() << " bytes of zero-fill.\n";
1004e30b20bSLang Hames       return;
1014e30b20bSLang Hames     }
102633ea072SLang Hames 
1034e30b20bSLang Hames     JITTargetAddress InitAddr = B.getAddress() & ~(LineWidth - 1);
1044e30b20bSLang Hames     JITTargetAddress StartAddr = B.getAddress();
1054e30b20bSLang Hames     JITTargetAddress EndAddr = B.getAddress() + B.getSize();
1064e30b20bSLang Hames     auto *Data = reinterpret_cast<const uint8_t *>(B.getContent().data());
107633ea072SLang Hames 
1084e30b20bSLang Hames     for (JITTargetAddress CurAddr = InitAddr; CurAddr != EndAddr; ++CurAddr) {
109633ea072SLang Hames       if (CurAddr % LineWidth == 0)
1104e30b20bSLang Hames         outs() << "          " << formatv("{0:x16}", CurAddr) << ": ";
111633ea072SLang Hames       if (CurAddr < StartAddr)
1124e30b20bSLang Hames         outs() << "   ";
113633ea072SLang Hames       else
1144e30b20bSLang Hames         outs() << formatv("{0:x-2}", Data[CurAddr - StartAddr]) << " ";
115633ea072SLang Hames       if (CurAddr % LineWidth == LineWidth - 1)
1164e30b20bSLang Hames         outs() << "\n";
117633ea072SLang Hames     }
118633ea072SLang Hames     if (EndAddr % LineWidth != 0)
1194e30b20bSLang Hames       outs() << "\n";
1204e30b20bSLang Hames   }
1214e30b20bSLang Hames 
1224e30b20bSLang Hames   static Error printGraph(jitlink::LinkGraph &G) {
1234e30b20bSLang Hames 
1244e30b20bSLang Hames     DenseSet<jitlink::Block *> BlocksAlreadyVisited;
1254e30b20bSLang Hames 
1264e30b20bSLang Hames     outs() << "Graph \"" << G.getName() << "\"\n";
1274e30b20bSLang Hames     // Loop over all sections...
1284e30b20bSLang Hames     for (auto &S : G.sections()) {
1294e30b20bSLang Hames       outs() << "  Section " << S.getName() << ":\n";
1304e30b20bSLang Hames 
1314e30b20bSLang Hames       // Loop over all symbols in the current section...
1324e30b20bSLang Hames       for (auto *Sym : S.symbols()) {
1334e30b20bSLang Hames 
1344e30b20bSLang Hames         // Print the symbol's address.
1354e30b20bSLang Hames         outs() << "    " << formatv("{0:x16}", Sym->getAddress()) << ": ";
1364e30b20bSLang Hames 
1374e30b20bSLang Hames         // Print the symbol's name, or "<anonymous symbol>" if it doesn't have
1384e30b20bSLang Hames         // one.
1394e30b20bSLang Hames         if (Sym->hasName())
1404e30b20bSLang Hames           outs() << Sym->getName() << "\n";
1414e30b20bSLang Hames         else
1424e30b20bSLang Hames           outs() << "<anonymous symbol>\n";
1434e30b20bSLang Hames 
1444e30b20bSLang Hames         // Get the content block for this symbol.
1454e30b20bSLang Hames         auto &B = Sym->getBlock();
1464e30b20bSLang Hames 
1474e30b20bSLang Hames         if (BlocksAlreadyVisited.count(&B)) {
1484e30b20bSLang Hames           outs() << "      Block " << formatv("{0:x16}", B.getAddress())
1494e30b20bSLang Hames                  << " already printed.\n";
1504e30b20bSLang Hames           continue;
1514e30b20bSLang Hames         } else
1524e30b20bSLang Hames           outs() << "      Block " << formatv("{0:x16}", B.getAddress())
1534e30b20bSLang Hames                  << ":\n";
1544e30b20bSLang Hames 
1554e30b20bSLang Hames         outs() << "        Content:\n";
1564e30b20bSLang Hames         printBlockContent(B);
1574e30b20bSLang Hames         BlocksAlreadyVisited.insert(&B);
1584e30b20bSLang Hames 
1594e30b20bSLang Hames         if (!llvm::empty(B.edges())) {
1604e30b20bSLang Hames           outs() << "        Edges:\n";
1614e30b20bSLang Hames           for (auto &E : B.edges()) {
1624e30b20bSLang Hames             outs() << "          "
1634e30b20bSLang Hames                    << formatv("{0:x16}", B.getAddress() + E.getOffset())
1644e30b20bSLang Hames                    << ": kind = " << formatv("{0:d}", E.getKind())
1654e30b20bSLang Hames                    << ", addend = " << formatv("{0:x}", E.getAddend())
1664e30b20bSLang Hames                    << ", target = ";
1674e30b20bSLang Hames             jitlink::Symbol &TargetSym = E.getTarget();
1684e30b20bSLang Hames             if (TargetSym.hasName())
1694e30b20bSLang Hames               outs() << TargetSym.getName() << "\n";
1704e30b20bSLang Hames             else
1714e30b20bSLang Hames               outs() << "<anonymous target>\n";
172633ea072SLang Hames           }
173633ea072SLang Hames         }
1744e30b20bSLang Hames         outs() << "\n";
1754e30b20bSLang Hames       }
1764e30b20bSLang Hames     }
1774e30b20bSLang Hames     return Error::success();
178633ea072SLang Hames   }
179633ea072SLang Hames };
180633ea072SLang Hames 
1814e30b20bSLang Hames static cl::opt<std::string>
1824e30b20bSLang Hames     EntryPointName("entry", cl::desc("Symbol to call as main entry point"),
1834e30b20bSLang Hames                    cl::init("entry"));
1844e30b20bSLang Hames 
1854e30b20bSLang Hames static cl::list<std::string> InputObjects(cl::Positional, cl::ZeroOrMore,
1864e30b20bSLang Hames                                           cl::desc("input objects"));
1874e30b20bSLang Hames 
188633ea072SLang Hames int main(int argc, char *argv[]) {
189633ea072SLang Hames   // Initialize LLVM.
190633ea072SLang Hames   InitLLVM X(argc, argv);
191633ea072SLang Hames 
192633ea072SLang Hames   InitializeNativeTarget();
193633ea072SLang Hames   InitializeNativeTargetAsmPrinter();
194633ea072SLang Hames 
195633ea072SLang Hames   cl::ParseCommandLineOptions(argc, argv, "LLJITWithObjectLinkingLayerPlugin");
196633ea072SLang Hames   ExitOnErr.setBanner(std::string(argv[0]) + ": ");
197633ea072SLang Hames 
198633ea072SLang Hames   // Detect the host and set code model to small.
199633ea072SLang Hames   auto JTMB = ExitOnErr(JITTargetMachineBuilder::detectHost());
200633ea072SLang Hames   JTMB.setCodeModel(CodeModel::Small);
201633ea072SLang Hames 
202633ea072SLang Hames   // Create an LLJIT instance with an ObjectLinkingLayer as the base layer.
203633ea072SLang Hames   // We attach our plugin in to the newly created ObjectLinkingLayer before
204633ea072SLang Hames   // returning it.
205633ea072SLang Hames   auto J = ExitOnErr(
206633ea072SLang Hames       LLJITBuilder()
207633ea072SLang Hames           .setJITTargetMachineBuilder(std::move(JTMB))
208633ea072SLang Hames           .setObjectLinkingLayerCreator(
209633ea072SLang Hames               [&](ExecutionSession &ES, const Triple &TT) {
210633ea072SLang Hames                 // Create ObjectLinkingLayer.
211633ea072SLang Hames                 auto ObjLinkingLayer = std::make_unique<ObjectLinkingLayer>(
212633ea072SLang Hames                     ES, std::make_unique<jitlink::InProcessMemoryManager>());
213633ea072SLang Hames                 // Add an instance of our plugin.
214633ea072SLang Hames                 ObjLinkingLayer->addPlugin(std::make_unique<MyPlugin>());
2156edc3fe5SStefan Gränitz                 return ObjLinkingLayer;
216633ea072SLang Hames               })
217633ea072SLang Hames           .create());
218633ea072SLang Hames 
2194e30b20bSLang Hames   if (!InputObjects.empty()) {
220633ea072SLang Hames 
2214e30b20bSLang Hames     // If we have input objects then reflect process symbols so the input
2224e30b20bSLang Hames     // objects can do interesting things, like call printf.
2234e30b20bSLang Hames     J->getMainJITDylib().addGenerator(
2244e30b20bSLang Hames         ExitOnErr(DynamicLibrarySearchGenerator::GetForCurrentProcess(
2254e30b20bSLang Hames             J->getDataLayout().getGlobalPrefix())));
2264e30b20bSLang Hames 
2274e30b20bSLang Hames     // Load the input objects.
2284e30b20bSLang Hames     for (auto InputObject : InputObjects) {
2294e30b20bSLang Hames       auto ObjBuffer =
2304e30b20bSLang Hames           ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputObject)));
2314e30b20bSLang Hames       ExitOnErr(J->addObjectFile(std::move(ObjBuffer)));
2324e30b20bSLang Hames     }
2334e30b20bSLang Hames   } else {
2344e30b20bSLang Hames     auto M = ExitOnErr(parseExampleModule(TestMod, "test-module"));
2354e30b20bSLang Hames     M.withModuleDo([](Module &MP) {
2364e30b20bSLang Hames       outs() << "No input objects specified. Using demo module:\n"
2374e30b20bSLang Hames              << MP << "\n";
2384e30b20bSLang Hames     });
239633ea072SLang Hames     ExitOnErr(J->addIRModule(std::move(M)));
2404e30b20bSLang Hames   }
241633ea072SLang Hames 
242633ea072SLang Hames   // Look up the JIT'd function, cast it to a function pointer, then call it.
2434e30b20bSLang Hames   auto EntrySym = ExitOnErr(J->lookup(EntryPointName));
244633ea072SLang Hames   auto *Entry = (int (*)())EntrySym.getAddress();
245633ea072SLang Hames 
246633ea072SLang Hames   int Result = Entry();
247633ea072SLang Hames   outs() << "---Result---\n"
2484e30b20bSLang Hames          << EntryPointName << "() = " << Result << "\n";
249633ea072SLang Hames 
250633ea072SLang Hames   return 0;
251633ea072SLang Hames }
252