Index: clang/lib/CodeGen/BackendUtil.cpp =================================================================== --- clang/lib/CodeGen/BackendUtil.cpp +++ clang/lib/CodeGen/BackendUtil.cpp @@ -753,7 +753,7 @@ ImportList); std::vector> OwnedImports; - MapVector ModuleMap; + MapVector ModuleMap; for (auto &I : ImportList) { ErrorOr> MBOrErr = @@ -763,7 +763,16 @@ << "': " << MBOrErr.getError().message() << "\n"; return; } - ModuleMap[I.first()] = (*MBOrErr)->getMemBufferRef(); + + Expected> BMsOrErr = + getBitcodeModuleList(**MBOrErr); + if (!BMsOrErr) { + handleAllErrors(BMsOrErr.takeError(), [&](ErrorInfoBase &EIB) { + errs() << "Error running ThinLTO backend: " << EIB.message() << '\n'; + }); + return; + } + ModuleMap.insert({I.first(), (*BMsOrErr)[0]}); OwnedImports.push_back(std::move(*MBOrErr)); } auto AddStream = [&](size_t Task) { Index: llvm/include/llvm/Bitcode/BitcodeReader.h =================================================================== --- llvm/include/llvm/Bitcode/BitcodeReader.h +++ llvm/include/llvm/Bitcode/BitcodeReader.h @@ -70,6 +70,8 @@ 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> Index: llvm/include/llvm/LTO/LTO.h =================================================================== --- llvm/include/llvm/LTO/LTO.h +++ llvm/include/llvm/LTO/LTO.h @@ -31,6 +31,7 @@ namespace llvm { +class BitcodeModule; class Error; class LLVMContext; class MemoryBufferRef; @@ -80,14 +81,16 @@ // 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,14 @@ symbol_iterator(SymTab.symbols().end(), SymTab, this)); } - StringRef getSourceFileName() const { return Mod->getSourceFileName(); } - MemoryBufferRef getMemoryBufferRef() const { return MBRef; } + StringRef getName() const; + 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 +317,7 @@ /// 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 +364,7 @@ ThinBackend Backend; ModuleSummaryIndex CombinedIndex; - MapVector ModuleMap; + MapVector ModuleMap; DenseMap PrevailingModuleForGUID; } ThinLTO; @@ -405,10 +412,13 @@ const InputFile::Symbol &Sym, SymbolResolution Res, unsigned Partition); - Error addRegularLTO(std::unique_ptr Input, - ArrayRef Res); - Error addThinLTO(std::unique_ptr Input, - ArrayRef Res); + 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, Index: llvm/include/llvm/LTO/LTOBackend.h =================================================================== --- llvm/include/llvm/LTO/LTOBackend.h +++ llvm/include/llvm/LTO/LTOBackend.h @@ -27,6 +27,7 @@ namespace llvm { +class BitcodeModule; class Error; class Module; class Target; @@ -43,7 +44,7 @@ ModuleSummaryIndex &CombinedIndex, const FunctionImporter::ImportMapTy &ImportList, const GVSummaryMapTy &DefinedGlobals, - MapVector &ModuleMap); + MapVector &ModuleMap); } } Index: llvm/lib/LTO/LTO.cpp =================================================================== --- llvm/lib/LTO/LTO.cpp +++ llvm/lib/LTO/LTO.cpp @@ -181,6 +181,14 @@ thinLTOInternalizeAndPromoteGUID(I.second, I.first, isExported); } +struct InputFile::InputModule { + BitcodeModule BM; + std::unique_ptr Mod; + size_t SymBegin, SymEnd; +}; + +InputFile::~InputFile() = default; + Expected> InputFile::create(MemoryBufferRef Object) { std::unique_ptr File(new InputFile); @@ -188,23 +196,31 @@ 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(); - File->Mod = std::move(*MOrErr); - File->SymTab.addModule(File->Mod.get()); + Expected> BMsOrErr = + getBitcodeModuleList(*BCOrErr); + if (!BMsOrErr) + return BMsOrErr.takeError(); + + 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()); + } - 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()); + File->Mods.push_back({BM, std::move(*MOrErr), SymBegin, SymEnd}); } return std::move(File); @@ -225,6 +241,21 @@ 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), @@ -242,6 +273,8 @@ RegularLTO(ParallelCodeGenParallelismLevel, this->Conf), ThinLTO(std::move(Backend)) {} +LTO::~LTO() = default; + // Add the given symbol to the GlobalResolutions map, and resolve its partition. void LTO::addSymbolToGlobalRes(SmallPtrSet &Used, const InputFile::Symbol &Sym, @@ -264,7 +297,7 @@ 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()) { @@ -290,34 +323,45 @@ 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(); @@ -338,13 +382,12 @@ 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); @@ -378,7 +421,6 @@ // FIXME: use proposed local attribute for FinalDefinitionInLinkageUnit. } - assert(ResI == Res.end()); return RegularLTO.Mover->move(std::move(*MOrErr), Keep, [](GlobalValue &, IRMover::ValueAdder) {}, @@ -386,33 +428,32 @@ } // 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; + ThinLTO.ModuleMap.insert({BM.getModuleIdentifier(), BM}); return Error::success(); } @@ -509,11 +550,11 @@ 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; }; @@ -538,16 +579,15 @@ 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(); @@ -555,7 +595,7 @@ ImportList, DefinedGlobals, ModuleMap); }; - auto ModuleID = MBRef.getBufferIdentifier(); + auto ModuleID = BM.getModuleIdentifier(); if (!Cache || !CombinedIndex.modulePaths().count(ModuleID) || all_of(CombinedIndex.getModuleHash(ModuleID), @@ -575,25 +615,25 @@ } 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); @@ -603,7 +643,7 @@ 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(); @@ -669,12 +709,12 @@ 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); Index: llvm/lib/LTO/LTOBackend.cpp =================================================================== --- llvm/lib/LTO/LTOBackend.cpp +++ llvm/lib/LTO/LTOBackend.cpp @@ -318,7 +318,7 @@ 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 @@ 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); Index: llvm/test/LTO/Resolution/X86/mixed_lto.ll =================================================================== --- llvm/test/LTO/Resolution/X86/mixed_lto.ll +++ llvm/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