brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.8 KiB · 84f1787 Raw
247 lines · cpp
1//===--- LLJITWithThinLTOSummaries.cpp - Module summaries as LLJIT input --===//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// In this example we will use a module summary index file produced for ThinLTO10// to (A) find the module that defines the main entry point and (B) find all11// extra modules that we need. We will do this in five steps:12//13// (1) Read the index file and parse the module summary index.14// (2) Find the path of the module that defines "main".15// (3) Parse the main module and create a matching LLJIT.16// (4) Add all modules to the LLJIT that are covered by the index.17// (5) Look up and run the JIT'd function.18//19// The index file name must be passed in as command line argument. Please find20// this test for instructions on creating the index file:21//22//       llvm/test/Examples/OrcV2Examples/lljit-with-thinlto-summaries.test23//24// If you use "build" as the build directory, you can run the test from the root25// of the monorepo like this:26//27// > build/bin/llvm-lit -a \28//       llvm/test/Examples/OrcV2Examples/lljit-with-thinlto-summaries.test29//30//===----------------------------------------------------------------------===//31 32#include "llvm/ADT/STLExtras.h"33#include "llvm/ADT/StringRef.h"34#include "llvm/Bitcode/BitcodeReader.h"35#include "llvm/ExecutionEngine/Orc/Core.h"36#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"37#include "llvm/ExecutionEngine/Orc/LLJIT.h"38#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"39#include "llvm/ExecutionEngine/Orc/TargetProcess/TargetExecutionUtils.h"40#include "llvm/IR/GlobalValue.h"41#include "llvm/IR/LLVMContext.h"42#include "llvm/IR/ModuleSummaryIndex.h"43#include "llvm/Support/CommandLine.h"44#include "llvm/Support/Error.h"45#include "llvm/Support/InitLLVM.h"46#include "llvm/Support/MemoryBuffer.h"47#include "llvm/Support/TargetSelect.h"48#include "llvm/Support/raw_ostream.h"49 50#include <string>51#include <system_error>52#include <vector>53 54using namespace llvm;55using namespace llvm::orc;56 57// Path of the module summary index file.58static cl::opt<std::string> IndexFile{cl::desc("<module summary index>"),59                                      cl::Positional, cl::init("-")};60 61// Describe a fail state that is caused by the given ModuleSummaryIndex62// providing multiple definitions of the given global value name. It will dump63// name and GUID for the global value and list the paths of the modules covered64// by the index.65class DuplicateDefinitionInSummary66    : public ErrorInfo<DuplicateDefinitionInSummary> {67public:68  static char ID;69 70  DuplicateDefinitionInSummary(std::string GlobalValueName, ValueInfo VI)71      : GlobalValueName(std::move(GlobalValueName)) {72    ModulePaths.reserve(VI.getSummaryList().size());73    for (const auto &S : VI.getSummaryList())74      ModulePaths.push_back(S->modulePath().str());75    llvm::sort(ModulePaths);76  }77 78  void log(raw_ostream &OS) const override {79    OS << "Duplicate symbol for global value '" << GlobalValueName80       << "' (GUID: "81       << GlobalValue::getGUIDAssumingExternalLinkage(GlobalValueName)82       << ") in:\n";83    for (const std::string &Path : ModulePaths) {84      OS << "    " << Path << "\n";85    }86  }87 88  std::error_code convertToErrorCode() const override {89    return inconvertibleErrorCode();90  }91 92private:93  std::string GlobalValueName;94  std::vector<std::string> ModulePaths;95};96 97// Describe a fail state where the given global value name was not found in the98// given ModuleSummaryIndex. It will dump name and GUID for the global value and99// list the paths of the modules covered by the index.100class DefinitionNotFoundInSummary101    : public ErrorInfo<DefinitionNotFoundInSummary> {102public:103  static char ID;104 105  DefinitionNotFoundInSummary(std::string GlobalValueName,106                              ModuleSummaryIndex &Index)107      : GlobalValueName(std::move(GlobalValueName)) {108    ModulePaths.reserve(Index.modulePaths().size());109    for (const auto &Entry : Index.modulePaths())110      ModulePaths.push_back(Entry.first().str());111    llvm::sort(ModulePaths);112  }113 114  void log(raw_ostream &OS) const override {115    OS << "No symbol for global value '" << GlobalValueName << "' (GUID: "116       << GlobalValue::getGUIDAssumingExternalLinkage(GlobalValueName)117       << ") in:\n";118    for (const std::string &Path : ModulePaths) {119      OS << "    " << Path << "\n";120    }121  }122 123  std::error_code convertToErrorCode() const override {124    return llvm::inconvertibleErrorCode();125  }126 127private:128  std::string GlobalValueName;129  std::vector<std::string> ModulePaths;130};131 132char DuplicateDefinitionInSummary::ID = 0;133char DefinitionNotFoundInSummary::ID = 0;134 135// Lookup the a function in the ModuleSummaryIndex and return the path of the136// module that defines it. Paths in the ModuleSummaryIndex are relative to the137// build directory of the covered modules.138Expected<StringRef> getMainModulePath(StringRef FunctionName,139                                      ModuleSummaryIndex &Index) {140  // Summaries use unmangled names.141  GlobalValue::GUID G =142      GlobalValue::getGUIDAssumingExternalLinkage(FunctionName);143  ValueInfo VI = Index.getValueInfo(G);144 145  // We need a unique definition, otherwise don't try further.146  if (!VI || VI.getSummaryList().empty())147    return make_error<DefinitionNotFoundInSummary>(FunctionName.str(), Index);148  if (VI.getSummaryList().size() > 1)149    return make_error<DuplicateDefinitionInSummary>(FunctionName.str(), VI);150 151  GlobalValueSummary *S = VI.getSummaryList().front()->getBaseObject();152  if (!isa<FunctionSummary>(S))153    return createStringError(inconvertibleErrorCode(),154                             "Entry point is not a function: " + FunctionName);155 156  // Return a reference. ModuleSummaryIndex owns the module paths.157  return S->modulePath();158}159 160// Parse the bitcode module from the given path into a ThreadSafeModule.161Expected<ThreadSafeModule> loadModule(StringRef Path,162                                      orc::ThreadSafeContext TSCtx) {163  outs() << "About to load module: " << Path << "\n";164 165  Expected<std::unique_ptr<MemoryBuffer>> BitcodeBuffer =166      errorOrToExpected(MemoryBuffer::getFile(Path));167  if (!BitcodeBuffer)168    return BitcodeBuffer.takeError();169 170  MemoryBufferRef BitcodeBufferRef = (**BitcodeBuffer).getMemBufferRef();171  Expected<std::unique_ptr<Module>> M =172      TSCtx.withContextDo([&](LLVMContext *Ctx) {173        return parseBitcodeFile(BitcodeBufferRef, *Ctx);174      });175  if (!M)176    return M.takeError();177 178  return ThreadSafeModule(std::move(*M), std::move(TSCtx));179}180 181int main(int Argc, char *Argv[]) {182  InitLLVM X(Argc, Argv);183 184  InitializeNativeTarget();185  InitializeNativeTargetAsmPrinter();186 187  cl::ParseCommandLineOptions(Argc, Argv, "LLJITWithThinLTOSummaries");188 189  ExitOnError ExitOnErr;190  ExitOnErr.setBanner(std::string(Argv[0]) + ": ");191 192  // (1) Read the index file and parse the module summary index.193  std::unique_ptr<MemoryBuffer> SummaryBuffer =194      ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(IndexFile)));195 196  std::unique_ptr<ModuleSummaryIndex> SummaryIndex =197      ExitOnErr(getModuleSummaryIndex(SummaryBuffer->getMemBufferRef()));198 199  // (2) Find the path of the module that defines "main".200  std::string MainFunctionName = "main";201  StringRef MainModulePath =202      ExitOnErr(getMainModulePath(MainFunctionName, *SummaryIndex));203 204  // (3) Parse the main module and create a matching LLJIT.205  ThreadSafeContext TSCtx(std::make_unique<LLVMContext>());206  ThreadSafeModule MainModule = ExitOnErr(loadModule(MainModulePath, TSCtx));207 208  auto Builder = LLJITBuilder();209 210  MainModule.withModuleDo([&](Module &M) {211    if (M.getTargetTriple().empty()) {212      Builder.setJITTargetMachineBuilder(213          ExitOnErr(JITTargetMachineBuilder::detectHost()));214    } else {215      Builder.setJITTargetMachineBuilder(216          JITTargetMachineBuilder(M.getTargetTriple()));217    }218    if (!M.getDataLayout().getStringRepresentation().empty())219      Builder.setDataLayout(M.getDataLayout());220  });221 222  auto J = ExitOnErr(Builder.create());223 224  // (4) Add all modules to the LLJIT that are covered by the index.225  JITDylib &JD = J->getMainJITDylib();226 227  for (const auto &Entry : SummaryIndex->modulePaths()) {228    StringRef Path = Entry.first();229    ThreadSafeModule M = (Path == MainModulePath)230                             ? std::move(MainModule)231                             : ExitOnErr(loadModule(Path, TSCtx));232    ExitOnErr(J->addIRModule(JD, std::move(M)));233  }234 235  // (5) Look up and run the JIT'd function.236  auto MainAddr = ExitOnErr(J->lookup(MainFunctionName));237 238  using MainFnPtr = int (*)(int, char *[]);239  auto *MainFunction = MainAddr.toPtr<MainFnPtr>();240 241  int Result = runAsMain(MainFunction, {}, MainModulePath);242  outs() << "'" << MainFunctionName << "' finished with exit code: " << Result243         << "\n";244 245  return 0;246}247