[llvm-branch-commits] [llvm] 3ba66b6 - upgrade IR symtab in parallel ahead of time.

Yuanfang Chen via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Dec 2 15:25:53 PST 2019


Author: Yuanfang Chen
Date: 2019-11-05T00:01:43-08:00
New Revision: 3ba66b6229f5400a2637cd3b4529b1dd7987feee

URL: https://github.com/llvm/llvm-project/commit/3ba66b6229f5400a2637cd3b4529b1dd7987feee
DIFF: https://github.com/llvm/llvm-project/commit/3ba66b6229f5400a2637cd3b4529b1dd7987feee.diff

LOG: upgrade IR symtab in parallel ahead of time.

Added: 
    

Modified: 
    lld/ELF/Driver.cpp
    lld/ELF/Driver.h
    lld/ELF/InputFiles.cpp
    llvm/include/llvm/Bitcode/BitcodeReader.h
    llvm/include/llvm/LTO/LTO.h
    llvm/include/llvm/Object/IRObjectFile.h
    llvm/include/llvm/Object/IRSymtab.h
    llvm/include/llvm/Support/MemoryBuffer.h
    llvm/lib/LTO/LTO.cpp
    llvm/lib/Object/IRObjectFile.cpp
    llvm/lib/Object/IRSymtab.cpp

Removed: 
    


################################################################################
diff  --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 1b1a50bf6d1c..0f5f63093633 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -49,6 +49,7 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/LTO/LTO.h"
+#include "llvm/Bitcode/BitcodeReader.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Compression.h"
 #include "llvm/Support/GlobPattern.h"
@@ -67,6 +68,8 @@ using namespace llvm::sys;
 using namespace llvm::support;
 
 namespace lld {
+llvm::lto::IRSymtabFileCache *irSymTabCache;
+
 namespace elf {
 
 Configuration *config;
@@ -189,10 +192,18 @@ std::vector<std::pair<MemoryBufferRef, uint64_t>> static getArchiveMembers(
 void LinkerDriver::addFile(StringRef path, bool withLOption) {
   using namespace sys::fs;
 
-  Optional<MemoryBufferRef> buffer = readFile(path);
-  if (!buffer.hasValue())
-    return;
-  MemoryBufferRef mbref = *buffer;
+  MemoryBufferRef mbref;
+  MemoryBufferRef *MB = nullptr;
+  if (irSymTabCache)
+    MB = irSymTabCache->getMemBufferForPath(path);
+  if (MB) {
+    mbref = *MB;
+  } else {
+    Optional<MemoryBufferRef> buffer = readFile(path);
+    if (!buffer.hasValue())
+      return;
+    mbref = *buffer;
+  }
 
   if (config->formatBinary) {
     files.push_back(make<BinaryFile>(mbref));
@@ -486,6 +497,8 @@ void LinkerDriver::main(ArrayRef<const char *> argsArr) {
   if (args.hasArg(OPT_version))
     return;
 
+  irSymTabCache = new lto::IRSymtabFileCache();
+
   initLLVM();
   createFiles(args);
   if (errorCount())
@@ -1161,10 +1174,54 @@ static bool isFormatBinary(StringRef s) {
   return false;
 }
 
+void addFileToIrSymTabCache(StringRef path,
+                            llvm::StringMap<MemoryBufferRef> &LoadedFiles,
+                            std::vector<MemoryBufferRef> &ToCache) {
+  using namespace sys::fs;
+
+  Optional<MemoryBufferRef> buffer = readFile(path);
+  if (!buffer.hasValue())
+    return;
+  MemoryBufferRef mbref = *buffer;
+  LoadedFiles.try_emplace(path, mbref);
+
+  switch (identify_magic(mbref.getBuffer())) {
+  case file_magic::archive: {
+    for (const std::pair<MemoryBufferRef, uint64_t> &p :
+         getArchiveMembers(mbref))
+      if (identify_magic(p.first.getBuffer()) == file_magic::bitcode)
+        ToCache.push_back(p.first);
+    break;
+  }
+
+  case file_magic::bitcode:
+    ToCache.push_back(mbref);
+    break;
+  default:
+    break;
+  }
+}
+
 void LinkerDriver::createFiles(opt::InputArgList &args) {
   // For --{push,pop}-state.
   std::vector<std::tuple<bool, bool, bool>> stack;
 
+  if (irSymTabCache) {
+    std::vector<std::string> Files;
+    for (auto *arg : args) {
+      switch (arg->getOption().getID()) {
+      case OPT_library:
+        if (Optional<std::string> path = searchLibrary(arg->getValue()))
+          Files.push_back(*path);
+        break;
+      case OPT_INPUT:
+        Files.push_back(arg->getValue());
+        break;
+      }
+    }
+    irSymTabCache->upgrade(Files, addFileToIrSymTabCache);
+  }
+
   // Iterate over argv to process input files and positional arguments.
   for (auto *arg : args) {
     switch (arg->getOption().getID()) {
@@ -1755,6 +1812,11 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
   for (size_t i = 0; i < files.size(); ++i)
     parseFile(files[i]);
 
+  if (irSymTabCache) {
+    delete irSymTabCache;
+    irSymTabCache = nullptr;
+  }
+
   // Now that we have every file, we can decide if we will need a
   // dynamic symbol table.
   // We need one if we were asked to export dynamic symbols or if we are

diff  --git a/lld/ELF/Driver.h b/lld/ELF/Driver.h
index 3115e28d1669..a7ebf1e49eba 100644
--- a/lld/ELF/Driver.h
+++ b/lld/ELF/Driver.h
@@ -14,13 +14,25 @@
 #include "lld/Common/LLVM.h"
 #include "lld/Common/Reproduce.h"
 #include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/StringSet.h"
 #include "llvm/Option/ArgList.h"
 #include "llvm/Support/raw_ostream.h"
 
+namespace llvm {
+namespace lto {
+  class IRSymtabFileCache;
+}
+}
+
 namespace lld {
+extern llvm::lto::IRSymtabFileCache *irSymTabCache;
+
 namespace elf {
+void addFileToIrSymTabCache(StringRef path,
+                            llvm::StringMap<MemoryBufferRef> &LoadedFiles,
+                            std::vector<MemoryBufferRef> &ToCache);
 
 extern class LinkerDriver *driver;
 

diff  --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 09b20463af2f..cbc1d9fa98cc 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -475,6 +475,16 @@ template <class ELFT> void ObjFile<ELFT>::initializeJustSymbols() {
   this->sections.resize(sections.size());
 }
 
+static Optional<std::pair<std::string, bool>> getPath(StringRef specifier) {
+  if (fs::exists(specifier))
+    return std::make_pair(specifier.str(), false);
+  else if (Optional<std::string> s = findFromSearchPaths(specifier))
+    return std::make_pair(*s, true);
+  else if (Optional<std::string> s = searchLibraryBaseName(specifier))
+    return std::make_pair(*s, true);
+  return None;
+}
+
 // An ELF object file may contain a `.deplibs` section. If it exists, the
 // section contains a list of library specifiers such as `m` for libm. This
 // function resolves a given name by finding the first matching library checking
@@ -484,12 +494,8 @@ template <class ELFT> void ObjFile<ELFT>::initializeJustSymbols() {
 static void addDependentLibrary(StringRef specifier, const InputFile *f) {
   if (!config->dependentLibraries)
     return;
-  if (fs::exists(specifier))
-    driver->addFile(specifier, /*withLOption=*/false);
-  else if (Optional<std::string> s = findFromSearchPaths(specifier))
-    driver->addFile(*s, /*withLOption=*/true);
-  else if (Optional<std::string> s = searchLibraryBaseName(specifier))
-    driver->addFile(*s, /*withLOption=*/true);
+  if (Optional<std::pair<std::string, bool>> path = getPath(specifier))
+    driver->addFile(path->first, /*withLOption=*/path->second);
   else
     error(toString(f) +
           ": unable to find library from dependent library specifier: " +
@@ -1365,6 +1371,11 @@ BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
   if (config->thinLTOIndexOnly)
     path = replaceThinLTOSuffix(mb.getBufferIdentifier());
 
+  if (irSymTabCache)
+    obj = CHECK(lto::InputFile::create(mb, *irSymTabCache), this);
+  else
+    obj = CHECK(lto::InputFile::create(mb), this);
+
   // ThinLTO assumes that all MemoryBufferRefs given to it have a unique
   // name. If two archives define two members with the same name, this
   // causes a collision which result in only one of the objects being taken
@@ -1375,9 +1386,7 @@ BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
                        ? saver.save(path)
                        : saver.save(archiveName + "(" + path + " at " +
                                     utostr(offsetInArchive) + ")");
-  MemoryBufferRef mbref(mb.getBuffer(), name);
-
-  obj = CHECK(lto::InputFile::create(mbref), this);
+  obj->getSingleBitcodeModule().setModuleIdentifier(name);
 
   Triple t(obj->getTargetTriple());
   ekind = getBitcodeELFKind(t);
@@ -1436,6 +1445,14 @@ template <class ELFT> void BitcodeFile::parse() {
   for (const lto::InputFile::Symbol &objSym : obj->symbols())
     symbols.push_back(createBitcodeSymbol<ELFT>(keptComdats, objSym, *this));
 
+  if (config->dependentLibraries && irSymTabCache) {
+    std::vector<std::string> filesToUpgrade;
+    for (auto l : obj->getDependentLibraries())
+      if (Optional<std::pair<std::string, bool>> path = getPath(l))
+        filesToUpgrade.push_back(path->first);
+    irSymTabCache->upgrade(filesToUpgrade, addFileToIrSymTabCache);
+  }
+
   for (auto l : obj->getDependentLibraries())
     addDependentLibrary(l, this);
 }

diff  --git a/llvm/include/llvm/Bitcode/BitcodeReader.h b/llvm/include/llvm/Bitcode/BitcodeReader.h
index ba61da733bea..404f061bbb2a 100644
--- a/llvm/include/llvm/Bitcode/BitcodeReader.h
+++ b/llvm/include/llvm/Bitcode/BitcodeReader.h
@@ -90,6 +90,7 @@ class Module;
     StringRef getStrtab() const { return Strtab; }
 
     StringRef getModuleIdentifier() const { return ModuleIdentifier; }
+    void setModuleIdentifier(StringRef ModId) { ModuleIdentifier = ModId; }
 
     /// Read the bitcode module and prepare for lazy deserialization of function
     /// bodies. If ShouldLazyLoadMetadata is true, lazily load metadata as well.

diff  --git a/llvm/include/llvm/LTO/LTO.h b/llvm/include/llvm/LTO/LTO.h
index 0a1e3e1d0e42..ea86ecb90452 100644
--- a/llvm/include/llvm/LTO/LTO.h
+++ b/llvm/include/llvm/LTO/LTO.h
@@ -18,14 +18,17 @@
 #include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringSet.h"
+#include "llvm/Bitcode/BitcodeReader.h"
 #include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/ModuleSummaryIndex.h"
 #include "llvm/IR/RemarkStreamer.h"
 #include "llvm/LTO/Config.h"
 #include "llvm/Linker/IRMover.h"
+#include "llvm/Object/IRObjectFile.h"
 #include "llvm/Object/IRSymtab.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/ThreadPool.h"
 #include "llvm/Support/thread.h"
 #include "llvm/Target/TargetOptions.h"
 #include "llvm/Transforms/IPO/FunctionImport.h"
@@ -99,6 +102,28 @@ class LTO;
 struct SymbolResolution;
 class ThinBackendProc;
 
+// For parallelizing IR symtab upgrading.
+class IRSymtabFileCache {
+  unsigned ThinLTOParallelismLevel;
+  ThreadPool BackendThreadPool;
+  using CacheType =
+      DenseMap<MemoryBufferRef, std::unique_ptr<object::IRSymtabFile>>;
+  CacheType Cache;
+  StringMap<MemoryBufferRef> LoadedFiles;
+
+  using AddFileFn = std::function<void(StringRef path,
+                                       StringMap<MemoryBufferRef> &LoadedFiles,
+                                       std::vector<MemoryBufferRef> &ToLoad)>;
+
+public:
+  IRSymtabFileCache()
+      : ThinLTOParallelismLevel(std::thread::hardware_concurrency()),
+        BackendThreadPool(ThinLTOParallelismLevel) {}
+  void upgrade(const std::vector<std::string> &Files, AddFileFn AFF);
+  object::IRSymtabFile *get(const MemoryBufferRef &M);
+  MemoryBufferRef *getMemBufferForPath(StringRef Path);
+};
+
 /// An input file. This is a symbol table wrapper that only exposes the
 /// information that an LTO client should need in order to do symbol resolution.
 class InputFile {
@@ -109,6 +134,7 @@ class InputFile {
   // FIXME: Remove LTO class friendship once we have bitcode symbol tables.
   friend LTO;
   InputFile() = default;
+  InputFile(object::IRSymtabFile &SF);
 
   std::vector<BitcodeModule> Mods;
   SmallVector<char, 0> Strtab;
@@ -126,6 +152,8 @@ class InputFile {
 
   /// Create an InputFile.
   static Expected<std::unique_ptr<InputFile>> create(MemoryBufferRef Object);
+  static Expected<std::unique_ptr<InputFile>>
+  create(MemoryBufferRef Object, IRSymtabFileCache &IRSymTabCache);
 
   /// The purpose of this class is to only expose the symbol information that an
   /// LTO client should need in order to do symbol resolution.

diff  --git a/llvm/include/llvm/Object/IRObjectFile.h b/llvm/include/llvm/Object/IRObjectFile.h
index 08b92f1bae50..a0fc57343d57 100644
--- a/llvm/include/llvm/Object/IRObjectFile.h
+++ b/llvm/include/llvm/Object/IRObjectFile.h
@@ -83,6 +83,7 @@ struct IRSymtabFile {
 
 /// Reads a bitcode file, creating its irsymtab if necessary.
 Expected<IRSymtabFile> readIRSymtab(MemoryBufferRef MBRef);
+bool needToUpgradeIRSymtab(MemoryBufferRef MBRef);
 
 }
 

diff  --git a/llvm/include/llvm/Object/IRSymtab.h b/llvm/include/llvm/Object/IRSymtab.h
index 0bbfc932493c..025b3fa2fb67 100644
--- a/llvm/include/llvm/Object/IRSymtab.h
+++ b/llvm/include/llvm/Object/IRSymtab.h
@@ -366,6 +366,7 @@ struct FileContents {
 
 /// Reads the contents of a bitcode file, creating its irsymtab if necessary.
 Expected<FileContents> readBitcode(const BitcodeFileContents &BFC);
+bool needUpgrade(const BitcodeFileContents &BFC);
 
 } // end namespace irsymtab
 } // end namespace llvm

diff  --git a/llvm/include/llvm/Support/MemoryBuffer.h b/llvm/include/llvm/Support/MemoryBuffer.h
index b5196cd84cb4..acfba5761bab 100644
--- a/llvm/include/llvm/Support/MemoryBuffer.h
+++ b/llvm/include/llvm/Support/MemoryBuffer.h
@@ -15,6 +15,7 @@
 
 #include "llvm-c/Types.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/Support/CBindingWrapping.h"
@@ -281,6 +282,28 @@ class MemoryBufferRef {
 // Create wrappers for C Binding types (see CBindingWrapping.h).
 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(MemoryBuffer, LLVMMemoryBufferRef)
 
+// Support MemoryBufferRef as DenseMap keys.
+template <> struct DenseMapInfo<MemoryBufferRef> {
+  static inline MemoryBufferRef getEmptyKey() {
+    static MemoryBufferRef EmptyKey(DenseMapInfo<StringRef>::getEmptyKey(),
+                                    DenseMapInfo<StringRef>::getEmptyKey());
+    return EmptyKey;
+  }
+  static inline MemoryBufferRef getTombstoneKey() {
+    static MemoryBufferRef TombstoneKey(
+        DenseMapInfo<StringRef>::getTombstoneKey(),
+        DenseMapInfo<StringRef>::getTombstoneKey());
+    return TombstoneKey;
+  }
+  static unsigned getHashValue(const MemoryBufferRef &mbref) {
+    return hash_combine(mbref.getBuffer().data(), mbref.getBuffer().size());
+  }
+  static bool isEqual(const MemoryBufferRef &LHS, const MemoryBufferRef &RHS) {
+    return LHS.getBuffer().data() == RHS.getBuffer().data() &&
+           LHS.getBuffer().size() == RHS.getBuffer().size();
+  }
+};
+
 } // end namespace llvm
 
 #endif // LLVM_SUPPORT_MEMORYBUFFER_H

diff  --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp
index 1e345e7dd89e..e2cc99fb94e0 100644
--- a/llvm/lib/LTO/LTO.cpp
+++ b/llvm/lib/LTO/LTO.cpp
@@ -28,15 +28,14 @@
 #include "llvm/LTO/LTOBackend.h"
 #include "llvm/LTO/SummaryBasedOptimizations.h"
 #include "llvm/Linker/IRMover.h"
-#include "llvm/Object/IRObjectFile.h"
 #include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/SHA1.h"
 #include "llvm/Support/SourceMgr.h"
 #include "llvm/Support/TargetRegistry.h"
-#include "llvm/Support/ThreadPool.h"
 #include "llvm/Support/Threading.h"
 #include "llvm/Support/VCSRevision.h"
 #include "llvm/Support/raw_ostream.h"
@@ -426,33 +425,41 @@ void llvm::thinLTOInternalizeAndPromoteInIndex(
 // Requires a destructor for std::vector<InputModule>.
 InputFile::~InputFile() = default;
 
-Expected<std::unique_ptr<InputFile>> InputFile::create(MemoryBufferRef Object) {
-  std::unique_ptr<InputFile> File(new InputFile);
+InputFile::InputFile(IRSymtabFile &SF) {
+  TargetTriple = SF.TheReader.getTargetTriple();
+  SourceFileName = SF.TheReader.getSourceFileName();
+  COFFLinkerOpts = SF.TheReader.getCOFFLinkerOpts();
+  DependentLibraries = SF.TheReader.getDependentLibraries();
+  ComdatTable = SF.TheReader.getComdatTable();
 
-  Expected<IRSymtabFile> FOrErr = readIRSymtab(Object);
-  if (!FOrErr)
-    return FOrErr.takeError();
-
-  File->TargetTriple = FOrErr->TheReader.getTargetTriple();
-  File->SourceFileName = FOrErr->TheReader.getSourceFileName();
-  File->COFFLinkerOpts = FOrErr->TheReader.getCOFFLinkerOpts();
-  File->DependentLibraries = FOrErr->TheReader.getDependentLibraries();
-  File->ComdatTable = FOrErr->TheReader.getComdatTable();
-
-  for (unsigned I = 0; I != FOrErr->Mods.size(); ++I) {
-    size_t Begin = File->Symbols.size();
+  for (unsigned I = 0; I != SF.Mods.size(); ++I) {
+    size_t Begin = Symbols.size();
     for (const irsymtab::Reader::SymbolRef &Sym :
-         FOrErr->TheReader.module_symbols(I))
+         SF.TheReader.module_symbols(I))
       // Skip symbols that are irrelevant to LTO. Note that this condition needs
       // to match the one in Skip() in LTO::addRegularLTO().
       if (Sym.isGlobal() && !Sym.isFormatSpecific())
-        File->Symbols.push_back(Sym);
-    File->ModuleSymIndices.push_back({Begin, File->Symbols.size()});
+        Symbols.push_back(Sym);
+    ModuleSymIndices.push_back({Begin, Symbols.size()});
   }
 
-  File->Mods = FOrErr->Mods;
-  File->Strtab = std::move(FOrErr->Strtab);
-  return std::move(File);
+  Mods = SF.Mods;
+  Strtab = std::move(SF.Strtab);
+}
+
+Expected<std::unique_ptr<InputFile>>
+InputFile::create(MemoryBufferRef Object) {
+  Expected<IRSymtabFile> FOrErr = readIRSymtab(Object);
+  if (!FOrErr)
+    return FOrErr.takeError();
+  return std::unique_ptr<InputFile>(new InputFile(*FOrErr));
+}
+
+Expected<std::unique_ptr<InputFile>>
+InputFile::create(MemoryBufferRef Object, IRSymtabFileCache &IRSymTabCache) {
+  if (IRSymtabFile *FOrErr = IRSymTabCache.get(Object))
+    return std::unique_ptr<InputFile>(new InputFile(*FOrErr));
+  return InputFile::create(Object);
 }
 
 StringRef InputFile::getName() const {
@@ -1375,6 +1382,76 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,
   return BackendProc->wait();
 }
 
+IRSymtabFile *IRSymtabFileCache::get(const MemoryBufferRef &M) {
+  auto Iter = Cache.find(M);
+  if (Iter != Cache.end())
+    return Iter->second.get();
+  return nullptr;
+}
+
+void IRSymtabFileCache::upgrade(const std::vector<std::string> &Files,
+                                AddFileFn AFF) {
+  std::vector<MemoryBufferRef> MBrefs;
+  for (auto &F : Files)
+    AFF(F, LoadedFiles, MBrefs);
+
+  // Cache IR SymTab only if it needs upgrade. Also try to balance the amount
+  // work each thread will do based on aggregate MemoryBufferRef size.
+  std::vector<MemoryBufferRef> ToCache;
+  unsigned TotalBufSize = 0;
+  for (auto &M : MBrefs)
+    if (Cache.count(M) == 0 && needToUpgradeIRSymtab(M)) {
+      ToCache.push_back(M);
+      TotalBufSize += M.getBufferSize();
+      Cache.try_emplace(M, nullptr);
+    }
+
+  if (!ToCache.size())
+    return;
+
+  // If too few symtabs to cache, assign one to each thread.
+  const unsigned ThreadLocal = ToCache.size() >= ThinLTOParallelismLevel
+                                   ? TotalBufSize / ThinLTOParallelismLevel
+                                   : 0;
+
+  auto PreLoad = [&](std::vector<MemoryBufferRef>::iterator II,
+                     std::vector<MemoryBufferRef>::iterator IE) {
+    for (; II != IE; ++II) {
+      Expected<IRSymtabFile> FOrErr = readIRSymtab(*II);
+      if (FOrErr)
+        Cache.find(*II)->second.reset(new IRSymtabFile(std::move(*FOrErr)));
+      else
+        consumeError(FOrErr.takeError());
+    }
+  };
+
+  auto CI = ToCache.begin();
+  unsigned CurTotal = 0;
+  unsigned NumThread = 0;
+  for (auto I = ToCache.begin(), E = ToCache.end(); I != E; ++I) {
+    CurTotal += I->getBufferSize();
+    if (CurTotal < ThreadLocal)
+      continue;
+
+    CurTotal = 0;
+    auto TI = I;
+    BackendThreadPool.async(PreLoad, CI, ++TI);
+    CI = TI;
+    if (++NumThread == (ThinLTOParallelismLevel - 1)) {
+      BackendThreadPool.async(PreLoad, CI, ToCache.end());
+      break;
+    }
+  }
+  BackendThreadPool.wait();
+}
+
+MemoryBufferRef *IRSymtabFileCache::getMemBufferForPath(StringRef Path) {
+  auto I = LoadedFiles.find(Path);
+  if (I != LoadedFiles.end())
+    return &I->second;
+  return nullptr;
+}
+
 Expected<std::unique_ptr<ToolOutputFile>>
 lto::setupOptimizationRemarks(LLVMContext &Context, StringRef RemarksFilename,
                               StringRef RemarksPasses, StringRef RemarksFormat,

diff  --git a/llvm/lib/Object/IRObjectFile.cpp b/llvm/lib/Object/IRObjectFile.cpp
index 636f1521262f..bb0da6bb5e42 100644
--- a/llvm/lib/Object/IRObjectFile.cpp
+++ b/llvm/lib/Object/IRObjectFile.cpp
@@ -132,6 +132,18 @@ IRObjectFile::create(MemoryBufferRef Object, LLVMContext &Context) {
       new IRObjectFile(*BCOrErr, std::move(Mods)));
 }
 
+bool object::needToUpgradeIRSymtab(MemoryBufferRef MBRef) {
+  Expected<MemoryBufferRef> BCOrErr =
+      IRObjectFile::findBitcodeInMemBuffer(MBRef);
+  if (!BCOrErr)
+    return false;
+
+  Expected<BitcodeFileContents> BFCOrErr = getBitcodeFileContents(*BCOrErr);
+  if (!BFCOrErr)
+    return false;
+  return irsymtab::needUpgrade(*BFCOrErr);
+}
+
 Expected<IRSymtabFile> object::readIRSymtab(MemoryBufferRef MBRef) {
   IRSymtabFile F;
   Expected<MemoryBufferRef> BCOrErr =

diff  --git a/llvm/lib/Object/IRSymtab.cpp b/llvm/lib/Object/IRSymtab.cpp
index e4282b9d6bd3..a5a4d5bce582 100644
--- a/llvm/lib/Object/IRSymtab.cpp
+++ b/llvm/lib/Object/IRSymtab.cpp
@@ -374,14 +374,13 @@ static Expected<FileContents> upgrade(ArrayRef<BitcodeModule> BMs) {
   return std::move(FC);
 }
 
-Expected<FileContents> irsymtab::readBitcode(const BitcodeFileContents &BFC) {
+bool irsymtab::needUpgrade(const BitcodeFileContents &BFC) {
   if (BFC.Mods.empty())
-    return make_error<StringError>("Bitcode file does not contain any modules",
-                                   inconvertibleErrorCode());
+    return false;
 
   if (BFC.StrtabForSymtab.empty() ||
       BFC.Symtab.size() < sizeof(storage::Header))
-    return upgrade(BFC.Mods);
+    return true;
 
   // We cannot use the regular reader to read the version and producer, because
   // it will expect the header to be in the current format. The only thing we
@@ -392,7 +391,7 @@ Expected<FileContents> irsymtab::readBitcode(const BitcodeFileContents &BFC) {
   StringRef Producer = Hdr->Producer.get(BFC.StrtabForSymtab);
   if (Version != storage::Header::kCurrentVersion ||
       Producer != kExpectedProducerName)
-    return upgrade(BFC.Mods);
+    return true;
 
   FileContents FC;
   FC.TheReader = {{BFC.Symtab.data(), BFC.Symtab.size()},
@@ -403,7 +402,20 @@ Expected<FileContents> irsymtab::readBitcode(const BitcodeFileContents &BFC) {
   // the bitcode file was created by binary concatenation, so we need to create
   // a new symbol table from scratch.
   if (FC.TheReader.getNumModules() != BFC.Mods.size())
-    return upgrade(std::move(BFC.Mods));
+    return true;
+
+  return false;
+}
+
+Expected<FileContents> irsymtab::readBitcode(const BitcodeFileContents &BFC) {
+  if (BFC.Mods.empty())
+    return make_error<StringError>("Bitcode file does not contain any modules",
+                                   inconvertibleErrorCode());
+  if (needUpgrade(BFC))
+    return upgrade(BFC.Mods);
 
+  FileContents FC;
+  FC.TheReader = {{BFC.Symtab.data(), BFC.Symtab.size()},
+                  {BFC.StrtabForSymtab.data(), BFC.StrtabForSymtab.size()}};
   return std::move(FC);
 }


        


More information about the llvm-branch-commits mailing list