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); } _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits