brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.2 KiB · fd69369 Raw
242 lines · cpp
1//===--------------- LLJITWithCustomObjectLinkingLayer.cpp ----------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file shows how to switch LLJIT to use a custom object linking layer (we10// use ObjectLinkingLayer, which is backed by JITLink, as an example).11//12//===----------------------------------------------------------------------===//13 14#include "llvm/ADT/StringMap.h"15#include "llvm/ExecutionEngine/JITLink/JITLink.h"16#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"17#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"18#include "llvm/ExecutionEngine/Orc/LLJIT.h"19#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"20#include "llvm/Support/InitLLVM.h"21#include "llvm/Support/TargetSelect.h"22#include "llvm/Support/raw_ostream.h"23 24#include "../ExampleModules.h"25 26using namespace llvm;27using namespace llvm::orc;28 29ExitOnError ExitOnErr;30 31const llvm::StringRef TestMod =32    R"(33  define i32 @callee() {34  entry:35    ret i32 736  }37 38  define i32 @entry() {39  entry:40    %0 = call i32 @callee()41    ret i32 %042  }43)";44 45class MyPlugin : public ObjectLinkingLayer::Plugin {46public:47  // The modifyPassConfig callback gives us a chance to inspect the48  // MaterializationResponsibility and target triple for the object being49  // linked, then add any JITLink passes that we would like to run on the50  // link graph. A pass is just a function object that is callable as51  // Error(jitlink::LinkGraph&). In this case we will add two passes52  // defined as lambdas that call the printLinkerGraph method on our53  // plugin: One to run before the linker applies fixups and another to54  // run afterwards.55  void modifyPassConfig(MaterializationResponsibility &MR,56                        jitlink::LinkGraph &LG,57                        jitlink::PassConfiguration &Config) override {58 59    outs() << "MyPlugin -- Modifying pass config for " << LG.getName() << " ("60           << LG.getTargetTriple().str() << "):\n";61 62    // Print sections, symbol names and addresses, and any edges for the63    // associated blocks at the 'PostPrune' phase of JITLink (after64    // dead-stripping, but before addresses are allocated in the target65    // address space. See llvm/docs/JITLink.rst).66    //67    // Experiment with adding the 'printGraph' pass at other points in the68    // pipeline. E.g. PrePrunePasses, PostAllocationPasses, and69    // PostFixupPasses.70    Config.PostPrunePasses.push_back(printGraph);71  }72 73  Error notifyEmitted(MaterializationResponsibility &MR) override {74    outs() << "Emitted object defining " << MR.getSymbols() << "\n";75    return Error::success();76  }77 78  Error notifyFailed(MaterializationResponsibility &MR) override {79    return Error::success();80  }81 82  Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {83    return Error::success();84  }85 86  void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,87                                   ResourceKey SrcKey) override {}88 89private:90  static void printBlockContent(jitlink::Block &B) {91    constexpr JITTargetAddress LineWidth = 16;92 93    if (B.isZeroFill()) {94      outs() << "    " << formatv("{0:x16}", B.getAddress()) << ": "95             << B.getSize() << " bytes of zero-fill.\n";96      return;97    }98 99    ExecutorAddr InitAddr(B.getAddress().getValue() & ~(LineWidth - 1));100    ExecutorAddr StartAddr = B.getAddress();101    ExecutorAddr EndAddr = B.getAddress() + B.getSize();102    auto *Data = reinterpret_cast<const uint8_t *>(B.getContent().data());103 104    for (ExecutorAddr CurAddr = InitAddr; CurAddr != EndAddr; ++CurAddr) {105      if (CurAddr % LineWidth == 0)106        outs() << "          " << formatv("{0:x16}", CurAddr.getValue())107               << ": ";108      if (CurAddr < StartAddr)109        outs() << "   ";110      else111        outs() << formatv("{0:x-2}", Data[CurAddr - StartAddr]) << " ";112      if (CurAddr % LineWidth == LineWidth - 1)113        outs() << "\n";114    }115    if (EndAddr % LineWidth != 0)116      outs() << "\n";117  }118 119  static Error printGraph(jitlink::LinkGraph &G) {120 121    DenseSet<jitlink::Block *> BlocksAlreadyVisited;122 123    outs() << "Graph \"" << G.getName() << "\"\n";124    // Loop over all sections...125    for (auto &S : G.sections()) {126      outs() << "  Section " << S.getName() << ":\n";127 128      // Loop over all symbols in the current section...129      for (auto *Sym : S.symbols()) {130 131        // Print the symbol's address.132        outs() << "    " << formatv("{0:x16}", Sym->getAddress()) << ": ";133 134        // Print the symbol's name, or "<anonymous symbol>" if it doesn't have135        // one.136        if (Sym->hasName())137          outs() << Sym->getName() << "\n";138        else139          outs() << "<anonymous symbol>\n";140 141        // Get the content block for this symbol.142        auto &B = Sym->getBlock();143 144        if (BlocksAlreadyVisited.count(&B)) {145          outs() << "      Block " << formatv("{0:x16}", B.getAddress())146                 << " already printed.\n";147          continue;148        } else149          outs() << "      Block " << formatv("{0:x16}", B.getAddress())150                 << ":\n";151 152        outs() << "        Content:\n";153        printBlockContent(B);154        BlocksAlreadyVisited.insert(&B);155 156        if (!B.edges().empty()) {157          outs() << "        Edges:\n";158          for (auto &E : B.edges()) {159            outs() << "          "160                   << formatv("{0:x16}", B.getAddress() + E.getOffset())161                   << ": kind = " << formatv("{0:d}", E.getKind())162                   << ", addend = " << formatv("{0:x}", E.getAddend())163                   << ", target = ";164            jitlink::Symbol &TargetSym = E.getTarget();165            if (TargetSym.hasName())166              outs() << TargetSym.getName() << "\n";167            else168              outs() << "<anonymous target>\n";169          }170        }171        outs() << "\n";172      }173    }174    return Error::success();175  }176};177 178static cl::opt<std::string>179    EntryPointName("entry", cl::desc("Symbol to call as main entry point"),180                   cl::init("entry"));181 182static cl::list<std::string> InputObjects(cl::Positional,183                                          cl::desc("input objects"));184 185int main(int argc, char *argv[]) {186  // Initialize LLVM.187  InitLLVM X(argc, argv);188 189  InitializeNativeTarget();190  InitializeNativeTargetAsmPrinter();191 192  cl::ParseCommandLineOptions(argc, argv, "LLJITWithObjectLinkingLayerPlugin");193  ExitOnErr.setBanner(std::string(argv[0]) + ": ");194 195  // Detect the host and set code model to small.196  auto JTMB = ExitOnErr(JITTargetMachineBuilder::detectHost());197  JTMB.setCodeModel(CodeModel::Small);198 199  // Create an LLJIT instance with an ObjectLinkingLayer as the base layer.200  // We attach our plugin in to the newly created ObjectLinkingLayer before201  // returning it.202  auto J = ExitOnErr(203      LLJITBuilder()204          .setJITTargetMachineBuilder(std::move(JTMB))205          .setObjectLinkingLayerCreator(206              [&](ExecutionSession &ES) {207                // Create ObjectLinkingLayer.208                auto ObjLinkingLayer = std::make_unique<ObjectLinkingLayer>(209                    ES, ExitOnErr(jitlink::InProcessMemoryManager::Create()));210                // Add an instance of our plugin.211                ObjLinkingLayer->addPlugin(std::make_unique<MyPlugin>());212                return ObjLinkingLayer;213              })214          .create());215 216  if (!InputObjects.empty()) {217    // Load the input objects.218    for (auto InputObject : InputObjects) {219      auto ObjBuffer =220          ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(InputObject)));221      ExitOnErr(J->addObjectFile(std::move(ObjBuffer)));222    }223  } else {224    auto M = ExitOnErr(parseExampleModule(TestMod, "test-module"));225    M.withModuleDo([](Module &MP) {226      outs() << "No input objects specified. Using demo module:\n"227             << MP << "\n";228    });229    ExitOnErr(J->addIRModule(std::move(M)));230  }231 232  // Look up the JIT'd function, cast it to a function pointer, then call it.233  auto EntryAddr = ExitOnErr(J->lookup(EntryPointName));234  auto *Entry = EntryAddr.toPtr<int()>();235 236  int Result = Entry();237  outs() << "---Result---\n"238         << EntryPointName << "() = " << Result << "\n";239 240  return 0;241}242