diff --git a/include/llvm/Bitcode/BitcodeReader.h b/include/llvm/Bitcode/BitcodeReader.h index 4e60101727d..ab2f25186d7 100644 --- a/include/llvm/Bitcode/BitcodeReader.h +++ b/include/llvm/Bitcode/BitcodeReader.h @@ -70,6 +70,8 @@ namespace llvm { return StringRef((const char *)Buffer.begin(), Buffer.size()); } + StringRef getModuleIdentifier() const { return ModuleIdentifier; } + /// Read the bitcode module and prepare for lazy deserialization of function /// bodies. If ShouldLazyLoadMetadata is true, lazily load metadata as well. Expected> diff --git a/include/llvm/LTO/LTO.h b/include/llvm/LTO/LTO.h index 28c05ed3fa1..bc435702157 100644 --- a/include/llvm/LTO/LTO.h +++ b/include/llvm/LTO/LTO.h @@ -31,6 +31,7 @@ namespace llvm { +class BitcodeModule; class Error; class LLVMContext; class MemoryBufferRef; @@ -80,14 +81,16 @@ class InputFile { // FIXME: Remove the LLVMContext once we have bitcode symbol tables. LLVMContext Ctx; + struct InputModule; + std::vector Mods; ModuleSymbolTable SymTab; - std::unique_ptr Mod; - MemoryBufferRef MBRef; std::vector Comdats; DenseMap ComdatMap; public: + ~InputFile(); + /// Create an InputFile. static Expected> create(MemoryBufferRef Object); @@ -217,11 +220,17 @@ public: symbol_iterator(SymTab.symbols().end(), SymTab, this)); } - StringRef getSourceFileName() const { return Mod->getSourceFileName(); } - MemoryBufferRef getMemoryBufferRef() const { return MBRef; } + /// Returns the path to the InputFile. + StringRef getName() const; + + /// Returns the source file path specified at compile time. + StringRef getSourceFileName() const; // Returns a table with all the comdats used by this file. ArrayRef getComdatTable() const { return Comdats; } + +private: + iterator_range module_symbols(InputModule &IM); }; /// This class wraps an output stream for a native object. Most clients should @@ -311,6 +320,7 @@ public: /// Until that is fixed, a Config argument is required. LTO(Config Conf, ThinBackend Backend = nullptr, unsigned ParallelCodeGenParallelismLevel = 1); + ~LTO(); /// Add an input file to the LTO link, using the provided symbol resolutions. /// The symbol resolutions must appear in the enumeration order given by @@ -357,7 +367,7 @@ private: ThinBackend Backend; ModuleSummaryIndex CombinedIndex; - MapVector ModuleMap; + MapVector ModuleMap; DenseMap PrevailingModuleForGUID; } ThinLTO; @@ -405,10 +415,17 @@ private: const InputFile::Symbol &Sym, SymbolResolution Res, unsigned Partition); - Error addRegularLTO(std::unique_ptr Input, - ArrayRef Res); - Error addThinLTO(std::unique_ptr Input, - ArrayRef Res); + // These functions take a range of symbol resolutions [ResI, ResE) and consume + // the resolutions used by a single input module by incrementing ResI. After + // these functions return, [ResI, ResE) will refer to the resolution range for + // the remaining modules in the InputFile. + Error addModule(InputFile &Input, InputFile::InputModule &IM, + const SymbolResolution *&ResI, const SymbolResolution *ResE); + Error addRegularLTO(BitcodeModule BM, const SymbolResolution *&ResI, + const SymbolResolution *ResE); + Error addThinLTO(BitcodeModule BM, Module &M, + iterator_range Syms, + const SymbolResolution *&ResI, const SymbolResolution *ResE); Error runRegularLTO(AddStreamFn AddStream); Error runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache, diff --git a/include/llvm/LTO/LTOBackend.h b/include/llvm/LTO/LTOBackend.h index 5a80ca58d87..933503afddc 100644 --- a/include/llvm/LTO/LTOBackend.h +++ b/include/llvm/LTO/LTOBackend.h @@ -27,6 +27,7 @@ namespace llvm { +class BitcodeModule; class Error; class Module; class Target; @@ -43,7 +44,7 @@ Error thinBackend(Config &C, unsigned Task, AddStreamFn AddStream, Module &M, ModuleSummaryIndex &CombinedIndex, const FunctionImporter::ImportMapTy &ImportList, const GVSummaryMapTy &DefinedGlobals, - MapVector &ModuleMap); + MapVector &ModuleMap); } } diff --git a/lib/LTO/LTO.cpp b/lib/LTO/LTO.cpp index 8a68025121c..718cbf17048 100644 --- a/lib/LTO/LTO.cpp +++ b/lib/LTO/LTO.cpp @@ -214,6 +214,17 @@ void llvm::thinLTOInternalizeAndPromoteInIndex( thinLTOInternalizeAndPromoteGUID(I.second, I.first, isExported); } +struct InputFile::InputModule { + BitcodeModule BM; + std::unique_ptr Mod; + + // The range of ModuleSymbolTable entries for this input module. + size_t SymBegin, SymEnd; +}; + +// Requires a destructor for std::vector. +InputFile::~InputFile() = default; + Expected> InputFile::create(MemoryBufferRef Object) { std::unique_ptr File(new InputFile); @@ -221,23 +232,37 @@ Expected> InputFile::create(MemoryBufferRef Object) { IRObjectFile::findBitcodeInMemBuffer(Object); if (!BCOrErr) return errorCodeToError(BCOrErr.getError()); - File->MBRef = *BCOrErr; - Expected> MOrErr = - getLazyBitcodeModule(*BCOrErr, File->Ctx, - /*ShouldLazyLoadMetadata*/ true); - if (!MOrErr) - return MOrErr.takeError(); + Expected> BMsOrErr = + getBitcodeModuleList(*BCOrErr); + if (!BMsOrErr) + return BMsOrErr.takeError(); - File->Mod = std::move(*MOrErr); - File->SymTab.addModule(File->Mod.get()); + if (BMsOrErr->empty()) + return make_error("Bitcode file does not contain any modules", + inconvertibleErrorCode()); - for (const auto &C : File->Mod->getComdatSymbolTable()) { - auto P = - File->ComdatMap.insert(std::make_pair(&C.second, File->Comdats.size())); - assert(P.second); - (void)P; - File->Comdats.push_back(C.first()); + // Create an InputModule for each module in the InputFile, and add it to the + // ModuleSymbolTable. + for (auto BM : *BMsOrErr) { + Expected> MOrErr = + BM.getLazyModule(File->Ctx, /*ShouldLazyLoadMetadata*/ true); + if (!MOrErr) + return MOrErr.takeError(); + + size_t SymBegin = File->SymTab.symbols().size(); + File->SymTab.addModule(MOrErr->get()); + size_t SymEnd = File->SymTab.symbols().size(); + + for (const auto &C : (*MOrErr)->getComdatSymbolTable()) { + auto P = File->ComdatMap.insert( + std::make_pair(&C.second, File->Comdats.size())); + assert(P.second); + (void)P; + File->Comdats.push_back(C.first()); + } + + File->Mods.push_back({BM, std::move(*MOrErr), SymBegin, SymEnd}); } return std::move(File); @@ -258,6 +283,21 @@ Expected InputFile::Symbol::getComdatIndex() const { return -1; } +StringRef InputFile::getName() const { + return Mods[0].BM.getModuleIdentifier(); +} + +StringRef InputFile::getSourceFileName() const { + return Mods[0].Mod->getSourceFileName(); +} + +iterator_range +InputFile::module_symbols(InputModule &IM) { + return llvm::make_range( + symbol_iterator(SymTab.symbols().data() + IM.SymBegin, SymTab, this), + symbol_iterator(SymTab.symbols().data() + IM.SymEnd, SymTab, this)); +} + LTO::RegularLTOState::RegularLTOState(unsigned ParallelCodeGenParallelismLevel, Config &Conf) : ParallelCodeGenParallelismLevel(ParallelCodeGenParallelismLevel), @@ -275,6 +315,9 @@ LTO::LTO(Config Conf, ThinBackend Backend, RegularLTO(ParallelCodeGenParallelismLevel, this->Conf), ThinLTO(std::move(Backend)) {} +// Requires a destructor for MapVector. +LTO::~LTO() = default; + // Add the given symbol to the GlobalResolutions map, and resolve its partition. void LTO::addSymbolToGlobalRes(SmallPtrSet &Used, const InputFile::Symbol &Sym, @@ -297,7 +340,7 @@ void LTO::addSymbolToGlobalRes(SmallPtrSet &Used, static void writeToResolutionFile(raw_ostream &OS, InputFile *Input, ArrayRef Res) { - StringRef Path = Input->getMemoryBufferRef().getBufferIdentifier(); + StringRef Path = Input->getName(); OS << Path << '\n'; auto ResI = Res.begin(); for (const InputFile::Symbol &Sym : Input->symbols()) { @@ -323,34 +366,45 @@ Error LTO::add(std::unique_ptr Input, if (Conf.ResolutionFile) writeToResolutionFile(*Conf.ResolutionFile, Input.get(), Res); + const SymbolResolution *ResI = Res.begin(); + for (InputFile::InputModule &IM : Input->Mods) + if (Error Err = addModule(*Input, IM, ResI, Res.end())) + return Err; + + assert(ResI == Res.end()); + return Error::success(); +} + +Error LTO::addModule(InputFile &Input, InputFile::InputModule &IM, + const SymbolResolution *&ResI, + const SymbolResolution *ResE) { // FIXME: move to backend - Module &M = *Input->Mod; + Module &M = *IM.Mod; if (!Conf.OverrideTriple.empty()) M.setTargetTriple(Conf.OverrideTriple); else if (M.getTargetTriple().empty()) M.setTargetTriple(Conf.DefaultTriple); - Expected HasThinLTOSummary = hasGlobalValueSummary(Input->MBRef); + Expected HasThinLTOSummary = IM.BM.hasSummary(); if (!HasThinLTOSummary) return HasThinLTOSummary.takeError(); if (*HasThinLTOSummary) - return addThinLTO(std::move(Input), Res); + return addThinLTO(IM.BM, M, Input.module_symbols(IM), ResI, ResE); else - return addRegularLTO(std::move(Input), Res); + return addRegularLTO(IM.BM, ResI, ResE); } // Add a regular LTO object to the link. -Error LTO::addRegularLTO(std::unique_ptr Input, - ArrayRef Res) { +Error LTO::addRegularLTO(BitcodeModule BM, const SymbolResolution *&ResI, + const SymbolResolution *ResE) { if (!RegularLTO.CombinedModule) { RegularLTO.CombinedModule = llvm::make_unique("ld-temp.o", RegularLTO.Ctx); RegularLTO.Mover = llvm::make_unique(*RegularLTO.CombinedModule); } Expected> MOrErr = - getLazyBitcodeModule(Input->MBRef, RegularLTO.Ctx, - /*ShouldLazyLoadMetadata*/ true); + BM.getLazyModule(RegularLTO.Ctx, /*ShouldLazyLoadMetadata*/ true); if (!MOrErr) return MOrErr.takeError(); @@ -371,13 +425,12 @@ Error LTO::addRegularLTO(std::unique_ptr Input, if (GV.hasAppendingLinkage()) Keep.push_back(&GV); - auto ResI = Res.begin(); for (const InputFile::Symbol &Sym : make_range(InputFile::symbol_iterator(SymTab.symbols().begin(), SymTab, nullptr), InputFile::symbol_iterator(SymTab.symbols().end(), SymTab, nullptr))) { - assert(ResI != Res.end()); + assert(ResI != ResE); SymbolResolution Res = *ResI++; addSymbolToGlobalRes(Used, Sym, Res, 0); @@ -411,7 +464,6 @@ Error LTO::addRegularLTO(std::unique_ptr Input, // FIXME: use proposed local attribute for FinalDefinitionInLinkageUnit. } - assert(ResI == Res.end()); return RegularLTO.Mover->move(std::move(*MOrErr), Keep, [](GlobalValue &, IRMover::ValueAdder) {}, @@ -420,33 +472,36 @@ Error LTO::addRegularLTO(std::unique_ptr Input, } // Add a ThinLTO object to the link. -Error LTO::addThinLTO(std::unique_ptr Input, - ArrayRef Res) { - Module &M = *Input->Mod; +// FIXME: This function should not need to take as many parameters once we have +// a bitcode symbol table. +Error LTO::addThinLTO(BitcodeModule BM, Module &M, + iterator_range Syms, + const SymbolResolution *&ResI, + const SymbolResolution *ResE) { SmallPtrSet Used; collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false); - MemoryBufferRef MBRef = Input->MBRef; - Expected> - SummaryObjOrErr = object::ModuleSummaryIndexObjectFile::create(MBRef); - if (!SummaryObjOrErr) - return SummaryObjOrErr.takeError(); - ThinLTO.CombinedIndex.mergeFrom((*SummaryObjOrErr)->takeIndex(), + Expected> SummaryOrErr = BM.getSummary(); + if (!SummaryOrErr) + return SummaryOrErr.takeError(); + ThinLTO.CombinedIndex.mergeFrom(std::move(*SummaryOrErr), ThinLTO.ModuleMap.size()); - auto ResI = Res.begin(); - for (const InputFile::Symbol &Sym : Input->symbols()) { - assert(ResI != Res.end()); + for (const InputFile::Symbol &Sym : Syms) { + assert(ResI != ResE); SymbolResolution Res = *ResI++; addSymbolToGlobalRes(Used, Sym, Res, ThinLTO.ModuleMap.size() + 1); if (Res.Prevailing && Sym.isGV()) ThinLTO.PrevailingModuleForGUID[Sym.getGV()->getGUID()] = - MBRef.getBufferIdentifier(); + BM.getModuleIdentifier(); } - assert(ResI == Res.end()); - ThinLTO.ModuleMap[MBRef.getBufferIdentifier()] = MBRef; + if (!ThinLTO.ModuleMap.insert({BM.getModuleIdentifier(), BM}).second) + return make_error( + "Expected at most one ThinLTO module per bitcode file", + inconvertibleErrorCode()); + return Error::success(); } @@ -543,11 +598,11 @@ public: virtual ~ThinBackendProc() {} virtual Error start( - unsigned Task, MemoryBufferRef MBRef, + unsigned Task, BitcodeModule BM, const FunctionImporter::ImportMapTy &ImportList, const FunctionImporter::ExportSetTy &ExportList, const std::map &ResolvedODR, - MapVector &ModuleMap) = 0; + MapVector &ModuleMap) = 0; virtual Error wait() = 0; }; @@ -572,16 +627,15 @@ public: Error runThinLTOBackendThread( AddStreamFn AddStream, NativeObjectCache Cache, unsigned Task, - MemoryBufferRef MBRef, ModuleSummaryIndex &CombinedIndex, + BitcodeModule BM, ModuleSummaryIndex &CombinedIndex, const FunctionImporter::ImportMapTy &ImportList, const FunctionImporter::ExportSetTy &ExportList, const std::map &ResolvedODR, const GVSummaryMapTy &DefinedGlobals, - MapVector &ModuleMap) { + MapVector &ModuleMap) { auto RunThinBackend = [&](AddStreamFn AddStream) { LTOLLVMContext BackendContext(Conf); - Expected> MOrErr = - parseBitcodeFile(MBRef, BackendContext); + Expected> MOrErr = BM.parseModule(BackendContext); if (!MOrErr) return MOrErr.takeError(); @@ -589,7 +643,7 @@ public: ImportList, DefinedGlobals, ModuleMap); }; - auto ModuleID = MBRef.getBufferIdentifier(); + auto ModuleID = BM.getModuleIdentifier(); if (!Cache || !CombinedIndex.modulePaths().count(ModuleID) || all_of(CombinedIndex.getModuleHash(ModuleID), @@ -609,25 +663,25 @@ public: } Error start( - unsigned Task, MemoryBufferRef MBRef, + unsigned Task, BitcodeModule BM, const FunctionImporter::ImportMapTy &ImportList, const FunctionImporter::ExportSetTy &ExportList, const std::map &ResolvedODR, - MapVector &ModuleMap) override { - StringRef ModulePath = MBRef.getBufferIdentifier(); + MapVector &ModuleMap) override { + StringRef ModulePath = BM.getModuleIdentifier(); assert(ModuleToDefinedGVSummaries.count(ModulePath)); const GVSummaryMapTy &DefinedGlobals = ModuleToDefinedGVSummaries.find(ModulePath)->second; BackendThreadPool.async( - [=](MemoryBufferRef MBRef, ModuleSummaryIndex &CombinedIndex, + [=](BitcodeModule BM, ModuleSummaryIndex &CombinedIndex, const FunctionImporter::ImportMapTy &ImportList, const FunctionImporter::ExportSetTy &ExportList, const std::map &ResolvedODR, const GVSummaryMapTy &DefinedGlobals, - MapVector &ModuleMap) { + MapVector &ModuleMap) { Error E = runThinLTOBackendThread( - AddStream, Cache, Task, MBRef, CombinedIndex, ImportList, + AddStream, Cache, Task, BM, CombinedIndex, ImportList, ExportList, ResolvedODR, DefinedGlobals, ModuleMap); if (E) { std::unique_lock L(ErrMu); @@ -637,7 +691,7 @@ public: Err = std::move(E); } }, - MBRef, std::ref(CombinedIndex), std::ref(ImportList), + BM, std::ref(CombinedIndex), std::ref(ImportList), std::ref(ExportList), std::ref(ResolvedODR), std::ref(DefinedGlobals), std::ref(ModuleMap)); return Error::success(); @@ -703,12 +757,12 @@ public: LinkedObjectsFileName(LinkedObjectsFileName) {} Error start( - unsigned Task, MemoryBufferRef MBRef, + unsigned Task, BitcodeModule BM, const FunctionImporter::ImportMapTy &ImportList, const FunctionImporter::ExportSetTy &ExportList, const std::map &ResolvedODR, - MapVector &ModuleMap) override { - StringRef ModulePath = MBRef.getBufferIdentifier(); + MapVector &ModuleMap) override { + StringRef ModulePath = BM.getModuleIdentifier(); std::string NewModulePath = getThinLTOOutputFile(ModulePath, OldPrefix, NewPrefix); diff --git a/lib/LTO/LTOBackend.cpp b/lib/LTO/LTOBackend.cpp index ad76e717981..9d4cbdde3ff 100644 --- a/lib/LTO/LTOBackend.cpp +++ b/lib/LTO/LTOBackend.cpp @@ -318,7 +318,7 @@ Error lto::thinBackend(Config &Conf, unsigned Task, AddStreamFn AddStream, Module &Mod, ModuleSummaryIndex &CombinedIndex, const FunctionImporter::ImportMapTy &ImportList, const GVSummaryMapTy &DefinedGlobals, - MapVector &ModuleMap) { + MapVector &ModuleMap) { Expected TOrErr = initAndLookupTarget(Conf, Mod); if (!TOrErr) return TOrErr.takeError(); @@ -353,8 +353,10 @@ Error lto::thinBackend(Config &Conf, unsigned Task, AddStreamFn AddStream, auto ModuleLoader = [&](StringRef Identifier) { assert(Mod.getContext().isODRUniquingDebugTypes() && "ODR Type uniquing should be enabled on the context"); - return getLazyBitcodeModule(ModuleMap[Identifier], Mod.getContext(), - /*ShouldLazyLoadMetadata=*/true); + auto I = ModuleMap.find(Identifier); + assert(I != ModuleMap.end()); + return I->second.getLazyModule(Mod.getContext(), + /*ShouldLazyLoadMetadata=*/true); }; FunctionImporter Importer(CombinedIndex, ModuleLoader); diff --git a/test/LTO/Resolution/X86/empty-bitcode.test b/test/LTO/Resolution/X86/empty-bitcode.test new file mode 100644 index 00000000000..c98c54499ef --- /dev/null +++ b/test/LTO/Resolution/X86/empty-bitcode.test @@ -0,0 +1,3 @@ +RUN: llvm-cat -o %t.o +RUN: not llvm-lto2 -o %t2 %t.o 2>&1 | FileCheck %s +CHECK: Bitcode file does not contain any modules diff --git a/test/LTO/Resolution/X86/mixed_lto.ll b/test/LTO/Resolution/X86/mixed_lto.ll index 02e6186a3f5..0302ed990e0 100644 --- a/test/LTO/Resolution/X86/mixed_lto.ll +++ b/test/LTO/Resolution/X86/mixed_lto.ll @@ -13,6 +13,12 @@ ; NM1-DAG: T main ; NM1-DAG: U g +; Do the same test again, but with the regular and thin LTO modules in the same file. +; RUN: llvm-cat -b -o %t4.o %t2.o %t1.o +; RUN: llvm-lto2 -o %t5.o %t4.o -r %t4.o,main,px -r %t4.o,g, -r %t4.o,g,px +; RUN: llvm-nm %t5.o.0 | FileCheck %s --check-prefix=NM0 +; RUN: llvm-nm %t5.o.1 | FileCheck %s --check-prefix=NM1 + target triple = "x86_64-unknown-linux-gnu" define i32 @g() { ret i32 0 diff --git a/test/LTO/Resolution/X86/multi-thinlto.ll b/test/LTO/Resolution/X86/multi-thinlto.ll new file mode 100644 index 00000000000..605c9694ced --- /dev/null +++ b/test/LTO/Resolution/X86/multi-thinlto.ll @@ -0,0 +1,6 @@ +; RUN: opt -module-summary %s -o %t.o +; RUN: llvm-cat -b -o %t2.o %t.o %t.o +; RUN: not llvm-lto2 -o %t3.o %t2.o 2>&1 | FileCheck %s +; CHECK: Expected at most one ThinLTO module per bitcode file + +target triple = "x86_64-unknown-linux-gnu"