Index: clang/lib/CodeGen/BackendUtil.cpp =================================================================== --- clang/lib/CodeGen/BackendUtil.cpp +++ clang/lib/CodeGen/BackendUtil.cpp @@ -964,11 +964,11 @@ if (!BMsOrErr) return BMsOrErr.takeError(); - // The bitcode file may contain multiple modules, we want the one with a - // summary. + // The bitcode file may contain multiple modules, we want the one that is + // marked as being the ThinLTO module. for (BitcodeModule &BM : *BMsOrErr) { - Expected HasSummary = BM.hasSummary(); - if (HasSummary && *HasSummary) + Expected LTOInfo = BM.getLTOInfo(); + if (LTOInfo && LTOInfo->IsThinLTO) return BM; } Index: clang/test/CodeGen/Inputs/thinlto-multi-module.ll =================================================================== --- /dev/null +++ clang/test/CodeGen/Inputs/thinlto-multi-module.ll @@ -0,0 +1,9 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @f2() { + ret void +} + +!0 = !{i32 1, !"ThinLTO", i32 0} +!llvm.module.flags = !{ !0 } Index: clang/test/CodeGen/thinlto-multi-module.ll =================================================================== --- clang/test/CodeGen/thinlto-multi-module.ll +++ clang/test/CodeGen/thinlto-multi-module.ll @@ -3,8 +3,8 @@ ; RUN: opt -module-summary -o %t1.o %s ; RUN: llvm-lto -thinlto -o %t %t1.o -; RUN: opt -o %t2.o %S/Inputs/thinlto_backend.ll -; RUN: llvm-cat -b -o %t1cat.o %t1.o %t2.o +; RUN: opt -module-summary -o %t2.o %S/Inputs/thinlto-multi-module.ll +; RUN: llvm-cat -b -o %t1cat.o %t2.o %t1.o ; RUN: cp %t1cat.o %t1.o ; RUN: %clang -target x86_64-unknown-linux-gnu -O2 -o %t3.o -x ir %t1.o -c -fthinlto-index=%t.thinlto.bc ; RUN: llvm-nm %t3.o | FileCheck --check-prefix=CHECK-OBJ %s Index: llvm/include/llvm/Bitcode/BitcodeReader.h =================================================================== --- llvm/include/llvm/Bitcode/BitcodeReader.h +++ llvm/include/llvm/Bitcode/BitcodeReader.h @@ -42,6 +42,12 @@ struct BitcodeFileContents; + /// Basic information extracted from a bitcode module to be used for LTO. + struct BitcodeLTOInfo { + bool IsThinLTO; + bool HasSummary; + }; + /// Represents a module in a bitcode file. class BitcodeModule { // This covers the identification (if present) and module blocks. @@ -90,15 +96,17 @@ /// Read the entire bitcode module and return it. Expected> parseModule(LLVMContext &Context); - /// Check if the given bitcode buffer contains a summary block. - Expected hasSummary(); + /// Returns information about the module to be used for LTO: whether to + /// compile with ThinLTO, and whether it has a summary. + Expected getLTOInfo(); /// Parse the specified bitcode buffer, returning the module summary index. Expected> getSummary(); /// Parse the specified bitcode buffer and merge its module summary index /// into CombinedIndex. - Error readSummary(ModuleSummaryIndex &CombinedIndex, unsigned ModuleId); + Error readSummary(ModuleSummaryIndex &CombinedIndex, StringRef ModulePath, + uint64_t ModuleId); }; struct BitcodeFileContents { @@ -147,8 +155,8 @@ Expected> parseBitcodeFile(MemoryBufferRef Buffer, LLVMContext &Context); - /// Check if the given bitcode buffer contains a summary block. - Expected hasGlobalValueSummary(MemoryBufferRef Buffer); + /// Returns LTO information for the specified bitcode file. + Expected getBitcodeLTOInfo(MemoryBufferRef Buffer); /// Parse the specified bitcode buffer, returning the module summary index. Expected> @@ -157,7 +165,7 @@ /// Parse the specified bitcode buffer and merge the index into CombinedIndex. Error readModuleSummaryIndex(MemoryBufferRef Buffer, ModuleSummaryIndex &CombinedIndex, - unsigned ModuleId); + uint64_t ModuleId); /// Parse the module summary index out of an IR file and return the module /// summary index object if found, or an empty summary if not. If Path refers Index: llvm/include/llvm/IR/ModuleSummaryIndex.h =================================================================== --- llvm/include/llvm/IR/ModuleSummaryIndex.h +++ llvm/include/llvm/IR/ModuleSummaryIndex.h @@ -567,6 +567,7 @@ bool isGlobalValueLive(const GlobalValueSummary *GVS) const { return !WithGlobalValueDeadStripping || GVS->isLive(); } + bool isGUIDLive(GlobalValue::GUID GUID) const; /// Return a ValueInfo for GUID if it exists, otherwise return ValueInfo(). ValueInfo getValueInfo(GlobalValue::GUID GUID) const { Index: llvm/include/llvm/LTO/LTO.h =================================================================== --- llvm/include/llvm/LTO/LTO.h +++ llvm/include/llvm/LTO/LTO.h @@ -281,6 +281,16 @@ bool HasModule = false; std::unique_ptr CombinedModule; std::unique_ptr Mover; + + // This stores the information about a regular LTO module that we have added + // to the link. It will either be linked immediately (for modules without + // summaries) or after summary-based dead stripping (for modules with + // summaries). + struct AddedModule { + std::unique_ptr M; + std::vector Keep; + }; + std::vector ModsWithSummaries; } RegularLTO; struct ThinLTOState { @@ -303,9 +313,10 @@ /// The unmangled name of the global. std::string IRName; - /// Keep track if the symbol is visible outside of ThinLTO (i.e. in - /// either a regular object or the regular LTO partition). - bool VisibleOutsideThinLTO = false; + /// Keep track if the symbol is visible outside of a module with a summary + /// (i.e. in either a regular object or a regular LTO module without a + /// summary). + bool VisibleOutsideSummary = false; bool UnnamedAddr = true; @@ -339,8 +350,9 @@ // Global mapping from mangled symbol names to resolutions. StringMap GlobalResolutions; - void addSymbolToGlobalRes(const InputFile::Symbol &Sym, SymbolResolution Res, - unsigned Partition); + void addModuleToGlobalRes(ArrayRef Syms, + ArrayRef Res, unsigned Partition, + bool InSummary); // These functions take a range of symbol resolutions [ResI, ResE) and consume // the resolutions used by a single input module by incrementing ResI. After @@ -348,10 +360,13 @@ // the remaining modules in the InputFile. Error addModule(InputFile &Input, unsigned ModI, const SymbolResolution *&ResI, const SymbolResolution *ResE); - Error addRegularLTO(BitcodeModule BM, - ArrayRef Syms, - const SymbolResolution *&ResI, - const SymbolResolution *ResE); + + Expected + addRegularLTO(BitcodeModule BM, ArrayRef Syms, + const SymbolResolution *&ResI, const SymbolResolution *ResE); + Error linkRegularLTO(RegularLTOState::AddedModule Mod, + bool LivenessFromIndex); + Error addThinLTO(BitcodeModule BM, ArrayRef Syms, const SymbolResolution *&ResI, const SymbolResolution *ResE); Index: llvm/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -733,7 +733,7 @@ std::vector makeCallList(ArrayRef Record, bool IsOldProfileFormat, bool HasProfile); - Error parseEntireSummary(); + Error parseEntireSummary(unsigned ID); Error parseModuleStringTable(); std::pair @@ -4854,6 +4854,7 @@ return error("Invalid record"); break; case bitc::GLOBALVAL_SUMMARY_BLOCK_ID: + case bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID: assert(!SeenValueSymbolTable && "Already read VST when parsing summary block?"); // We might not have a VST if there were no values in the @@ -4866,7 +4867,7 @@ SeenValueSymbolTable = true; } SeenGlobalValSummary = true; - if (Error Err = parseEntireSummary()) + if (Error Err = parseEntireSummary(Entry.ID)) return Err; break; case bitc::MODULE_STRTAB_BLOCK_ID: @@ -4974,8 +4975,8 @@ // Eagerly parse the entire summary block. This populates the GlobalValueSummary // objects in the index. -Error ModuleSummaryIndexBitcodeReader::parseEntireSummary() { - if (Stream.EnterSubBlock(bitc::GLOBALVAL_SUMMARY_BLOCK_ID)) +Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) { + if (Stream.EnterSubBlock(ID)) return error("Invalid record"); SmallVector Record; @@ -5517,13 +5518,16 @@ } // Parse the specified bitcode buffer and merge the index into CombinedIndex. +// We don't use ModuleIdentifier here because the client may need to control the +// module path used in the combined summary (e.g. when reading summaries for +// regular LTO modules). Error BitcodeModule::readSummary(ModuleSummaryIndex &CombinedIndex, - unsigned ModuleId) { + StringRef ModulePath, uint64_t ModuleId) { BitstreamCursor Stream(Buffer); Stream.JumpToBit(ModuleBit); ModuleSummaryIndexBitcodeReader R(std::move(Stream), Strtab, CombinedIndex, - ModuleIdentifier, ModuleId); + ModulePath, ModuleId); return R.parseModule(); } @@ -5543,7 +5547,7 @@ } // Check if the given bitcode buffer contains a global value summary block. -Expected BitcodeModule::hasSummary() { +Expected BitcodeModule::getLTOInfo() { BitstreamCursor Stream(Buffer); Stream.JumpToBit(ModuleBit); @@ -5557,11 +5561,14 @@ case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: - return false; + return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/false}; case BitstreamEntry::SubBlock: if (Entry.ID == bitc::GLOBALVAL_SUMMARY_BLOCK_ID) - return true; + return BitcodeLTOInfo{/*IsThinLTO=*/true, /*HasSummary=*/true}; + + if (Entry.ID == bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID) + return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/true}; // Ignore other sub-blocks. if (Stream.SkipBlock()) @@ -5648,12 +5655,12 @@ Error llvm::readModuleSummaryIndex(MemoryBufferRef Buffer, ModuleSummaryIndex &CombinedIndex, - unsigned ModuleId) { + uint64_t ModuleId) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); - return BM->readSummary(CombinedIndex, ModuleId); + return BM->readSummary(CombinedIndex, BM->getModuleIdentifier(), ModuleId); } Expected> @@ -5665,12 +5672,12 @@ return BM->getSummary(); } -Expected llvm::hasGlobalValueSummary(MemoryBufferRef Buffer) { +Expected llvm::getBitcodeLTOInfo(MemoryBufferRef Buffer) { Expected BM = getSingleModule(Buffer); if (!BM) return BM.takeError(); - return BM->hasSummary(); + return BM->getLTOInfo(); } Expected> Index: llvm/lib/IR/ModuleSummaryIndex.cpp =================================================================== --- llvm/lib/IR/ModuleSummaryIndex.cpp +++ llvm/lib/IR/ModuleSummaryIndex.cpp @@ -56,3 +56,13 @@ auto &Summary = VI.getSummaryList()[0]; return Summary.get(); } + +bool ModuleSummaryIndex::isGUIDLive(GlobalValue::GUID GUID) const { + auto VI = getValueInfo(GUID); + if (!VI) + return false; + for (auto &I : VI.getSummaryList()) + if (isGlobalValueLive(I.get())) + return true; + return false; +} Index: llvm/lib/LTO/LTO.cpp =================================================================== --- llvm/lib/LTO/LTO.cpp +++ llvm/lib/LTO/LTO.cpp @@ -364,31 +364,39 @@ // Requires a destructor for MapVector. LTO::~LTO() = default; -// Add the given symbol to the GlobalResolutions map, and resolve its partition. -void LTO::addSymbolToGlobalRes(const InputFile::Symbol &Sym, - SymbolResolution Res, unsigned Partition) { - auto &GlobalRes = GlobalResolutions[Sym.getName()]; - GlobalRes.UnnamedAddr &= Sym.isUnnamedAddr(); - if (Res.Prevailing) - GlobalRes.IRName = Sym.getIRName(); - - // Set the partition to external if we know it is re-defined by the linker - // with -defsym or -wrap options, used elsewhere, e.g. it is visible to a - // regular object, is referenced from llvm.compiler_used, or was already - // recorded as being referenced from a different partition. - if (Res.LinkerRedefined || Res.VisibleToRegularObj || Sym.isUsed() || - (GlobalRes.Partition != GlobalResolution::Unknown && - GlobalRes.Partition != Partition)) { - GlobalRes.Partition = GlobalResolution::External; - } else - // First recorded reference, save the current partition. - GlobalRes.Partition = Partition; - - // Flag as visible outside of ThinLTO if visible from a regular object or - // if this is a reference in the regular LTO partition. - GlobalRes.VisibleOutsideThinLTO |= - (Res.VisibleToRegularObj || Sym.isUsed() || - Partition == GlobalResolution::RegularLTO); +// Add the symbols in the given module to the GlobalResolutions map, and resolve +// their partitions. +void LTO::addModuleToGlobalRes(ArrayRef Syms, + ArrayRef Res, + unsigned Partition, bool InSummary) { + auto *ResI = Res.begin(); + auto *ResE = Res.end(); + for (const InputFile::Symbol &Sym : Syms) { + assert(ResI != ResE); + SymbolResolution Res = *ResI++; + + auto &GlobalRes = GlobalResolutions[Sym.getName()]; + GlobalRes.UnnamedAddr &= Sym.isUnnamedAddr(); + if (Res.Prevailing) + GlobalRes.IRName = Sym.getIRName(); + + // Set the partition to external if we know it is re-defined by the linker + // with -defsym or -wrap options, used elsewhere, e.g. it is visible to a + // regular object, is referenced from llvm.compiler_used, or was already + // recorded as being referenced from a different partition. + if (Res.LinkerRedefined || Res.VisibleToRegularObj || Sym.isUsed() || + (GlobalRes.Partition != GlobalResolution::Unknown && + GlobalRes.Partition != Partition)) { + GlobalRes.Partition = GlobalResolution::External; + } else + // First recorded reference, save the current partition. + GlobalRes.Partition = Partition; + + // Flag as visible outside of summary if visible from a regular object or + // from a module that does not have a summary. + GlobalRes.VisibleOutsideSummary |= + (Res.VisibleToRegularObj || Sym.isUsed() || !InSummary); + } } static void writeToResolutionFile(raw_ostream &OS, InputFile *Input, @@ -434,46 +442,61 @@ Error LTO::addModule(InputFile &Input, unsigned ModI, const SymbolResolution *&ResI, const SymbolResolution *ResE) { - Expected HasThinLTOSummary = Input.Mods[ModI].hasSummary(); - if (!HasThinLTOSummary) - return HasThinLTOSummary.takeError(); + Expected LTOInfo = Input.Mods[ModI].getLTOInfo(); + if (!LTOInfo) + return LTOInfo.takeError(); + BitcodeModule BM = Input.Mods[ModI]; auto ModSyms = Input.module_symbols(ModI); - if (*HasThinLTOSummary) - return addThinLTO(Input.Mods[ModI], ModSyms, ResI, ResE); - else - return addRegularLTO(Input.Mods[ModI], ModSyms, ResI, ResE); + addModuleToGlobalRes(ModSyms, {ResI, ResE}, + LTOInfo->IsThinLTO ? ThinLTO.ModuleMap.size() + 1 : 0, + LTOInfo->HasSummary); + + if (LTOInfo->IsThinLTO) + return addThinLTO(BM, ModSyms, ResI, ResE); + + Expected ModOrErr = + addRegularLTO(BM, ModSyms, ResI, ResE); + if (!ModOrErr) + return ModOrErr.takeError(); + + if (!LTOInfo->HasSummary) + return linkRegularLTO(std::move(*ModOrErr), /*LivenessFromIndex=*/false); + + // Regular LTO module summaries are added to a dummy module that represents + // the combined regular LTO module. + if (Error Err = BM.readSummary(ThinLTO.CombinedIndex, "", -1ull)) + return Err; + RegularLTO.ModsWithSummaries.push_back(std::move(*ModOrErr)); + return Error::success(); } // Add a regular LTO object to the link. -Error LTO::addRegularLTO(BitcodeModule BM, - ArrayRef Syms, - 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); - } +// The resulting module needs to be linked into the combined LTO module with +// linkRegularLTO. +Expected +LTO::addRegularLTO(BitcodeModule BM, ArrayRef Syms, + const SymbolResolution *&ResI, + const SymbolResolution *ResE) { + RegularLTOState::AddedModule Mod; Expected> MOrErr = BM.getLazyModule(RegularLTO.Ctx, /*ShouldLazyLoadMetadata*/ true, /*IsImporting*/ false); if (!MOrErr) return MOrErr.takeError(); - Module &M = **MOrErr; + Mod.M = std::move(*MOrErr); + if (Error Err = M.materializeMetadata()) - return Err; + return std::move(Err); UpgradeDebugInfo(M); ModuleSymbolTable SymTab; SymTab.addModule(&M); - std::vector Keep; - for (GlobalVariable &GV : M.globals()) if (GV.hasAppendingLinkage()) - Keep.push_back(&GV); + Mod.Keep.push_back(&GV); DenseSet AliasedGlobals; for (auto &GA : M.aliases()) @@ -502,7 +525,6 @@ for (const InputFile::Symbol &Sym : Syms) { assert(ResI != ResE); SymbolResolution Res = *ResI++; - addSymbolToGlobalRes(Sym, Res, 0); assert(MsymI != MsymE); ModuleSymbolTable::Symbol Msym = *MsymI++; @@ -512,7 +534,7 @@ if (Res.Prevailing) { if (Sym.isUndefined()) continue; - Keep.push_back(GV); + Mod.Keep.push_back(GV); // For symbols re-defined with linker -wrap and -defsym options, // set the linkage to weak to inhibit IPO. The linkage will be // restored by the linker. @@ -527,17 +549,14 @@ (GV->hasLinkOnceODRLinkage() || GV->hasWeakODRLinkage() || GV->hasAvailableExternallyLinkage()) && !AliasedGlobals.count(cast(GV))) { - // Either of the above three types of linkage indicates that the + // Any of the above three types of linkage indicates that the // chosen prevailing symbol will have the same semantics as this copy of - // the symbol, so we can link it with available_externally linkage. We - // only need to do this if the symbol is undefined. - GlobalValue *CombinedGV = - RegularLTO.CombinedModule->getNamedValue(GV->getName()); - if (!CombinedGV || CombinedGV->isDeclaration()) { - Keep.push_back(GV); - GV->setLinkage(GlobalValue::AvailableExternallyLinkage); - cast(GV)->setComdat(nullptr); - } + // the symbol, so we may be able to link it with available_externally + // linkage. We will decide later whether to do that when we link this + // module (in linkRegularLTO), based on whether it is undefined. + Mod.Keep.push_back(GV); + GV->setLinkage(GlobalValue::AvailableExternallyLinkage); + cast(GV)->setComdat(nullptr); } } // Common resolution: collect the maximum size/alignment over all commons. @@ -555,25 +574,54 @@ // FIXME: use proposed local attribute for FinalDefinitionInLinkageUnit. } assert(MsymI == MsymE); + return std::move(Mod); +} + +Error LTO::linkRegularLTO(RegularLTOState::AddedModule Mod, + bool LivenessFromIndex) { + if (!RegularLTO.CombinedModule) { + RegularLTO.CombinedModule = + llvm::make_unique("ld-temp.o", RegularLTO.Ctx); + RegularLTO.Mover = llvm::make_unique(*RegularLTO.CombinedModule); + } + + std::vector Keep; + for (GlobalValue *GV : Mod.Keep) { + if (LivenessFromIndex && !ThinLTO.CombinedIndex.isGUIDLive(GV->getGUID())) + continue; - return RegularLTO.Mover->move(std::move(*MOrErr), Keep, + if (!GV->hasAvailableExternallyLinkage()) { + Keep.push_back(GV); + continue; + } + + // Only link available_externally definitions if we don't already have a + // definition. + GlobalValue *CombinedGV = + RegularLTO.CombinedModule->getNamedValue(GV->getName()); + if (CombinedGV && !CombinedGV->isDeclaration()) + continue; + + Keep.push_back(GV); + } + + return RegularLTO.Mover->move(std::move(Mod.M), Keep, [](GlobalValue &, IRMover::ValueAdder) {}, /* IsPerformingImport */ false); } -// Add a ThinLTO object to the link. -Error LTO::addThinLTO(BitcodeModule BM, - ArrayRef Syms, +// Add a ThinLTO module to the link. +Error LTO::addThinLTO(BitcodeModule BM, ArrayRef Syms, const SymbolResolution *&ResI, const SymbolResolution *ResE) { if (Error Err = - BM.readSummary(ThinLTO.CombinedIndex, ThinLTO.ModuleMap.size())) + BM.readSummary(ThinLTO.CombinedIndex, BM.getModuleIdentifier(), + ThinLTO.ModuleMap.size())) return Err; for (const InputFile::Symbol &Sym : Syms) { assert(ResI != ResE); SymbolResolution Res = *ResI++; - addSymbolToGlobalRes(Sym, Res, ThinLTO.ModuleMap.size() + 1); if (Res.Prevailing) { if (!Sym.getIRName().empty()) { @@ -601,7 +649,7 @@ // Compute "dead" symbols, we don't want to import/export these! DenseSet GUIDPreservedSymbols; for (auto &Res : GlobalResolutions) { - if (Res.second.VisibleOutsideThinLTO && + if (Res.second.VisibleOutsideSummary && // IRName will be defined if we have seen the prevailing copy of // this value. If not, no need to preserve any ThinLTO copies. !Res.second.IRName.empty()) @@ -614,7 +662,8 @@ // Save the status of having a regularLTO combined module, as // this is needed for generating the ThinLTO Task ID, and // the CombinedModule will be moved at the end of runRegularLTO. - bool HasRegularLTO = RegularLTO.CombinedModule != nullptr; + bool HasRegularLTO = RegularLTO.CombinedModule != nullptr || + !RegularLTO.ModsWithSummaries.empty(); // Invoke regular LTO if there was a regular LTO module to start with. if (HasRegularLTO) if (auto E = runRegularLTO(AddStream)) @@ -623,6 +672,11 @@ } Error LTO::runRegularLTO(AddStreamFn AddStream) { + for (auto &M : RegularLTO.ModsWithSummaries) + if (Error Err = linkRegularLTO(std::move(M), + /*LivenessFromIndex=*/true)) + return Err; + // Make sure commons have the right size/alignment: we kept the largest from // all the prevailing when adding the inputs, and we apply it here. const DataLayout &DL = RegularLTO.CombinedModule->getDataLayout(); @@ -920,17 +974,6 @@ }; } -static bool IsLiveByGUID(const ModuleSummaryIndex &Index, - GlobalValue::GUID GUID) { - auto VI = Index.getValueInfo(GUID); - if (!VI) - return false; - for (auto &I : VI.getSummaryList()) - if (Index.isGlobalValueLive(I.get())) - return true; - return false; -} - Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache, bool HasRegularLTO) { if (ThinLTO.ModuleMap.empty()) @@ -979,7 +1022,7 @@ auto GUID = GlobalValue::getGUID( GlobalValue::dropLLVMManglingEscape(Res.second.IRName)); // Mark exported unless index-based analysis determined it to be dead. - if (IsLiveByGUID(ThinLTO.CombinedIndex, GUID)) + if (ThinLTO.CombinedIndex.isGUIDLive(GUID)) ExportedGUIDs.insert(GUID); } Index: llvm/lib/LTO/LTOModule.cpp =================================================================== --- llvm/lib/LTO/LTOModule.cpp +++ llvm/lib/LTO/LTOModule.cpp @@ -77,14 +77,12 @@ } bool LTOModule::isThinLTO() { - // Right now the detection is only based on the summary presence. We may want - // to add a dedicated flag at some point. - Expected Result = hasGlobalValueSummary(MBRef); + Expected Result = getBitcodeLTOInfo(MBRef); if (!Result) { logAllUnhandledErrors(Result.takeError(), errs(), ""); return false; } - return *Result; + return Result->IsThinLTO; } bool LTOModule::isBitcodeForTarget(MemoryBuffer *Buffer, Index: llvm/test/LTO/Resolution/X86/Inputs/dead-strip-fulllto.ll =================================================================== --- /dev/null +++ llvm/test/LTO/Resolution/X86/Inputs/dead-strip-fulllto.ll @@ -0,0 +1,16 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @live1() { + call void @live2() + ret void +} + +declare void @live2() + +define void @dead1() { + call void @dead2() + ret void +} + +declare void @dead2() Index: llvm/test/LTO/Resolution/X86/dead-strip-fulllto.ll =================================================================== --- /dev/null +++ llvm/test/LTO/Resolution/X86/dead-strip-fulllto.ll @@ -0,0 +1,37 @@ +; RUN: opt -module-summary -o %t %s +; RUN: opt -module-summary -o %t2 %S/Inputs/dead-strip-fulllto.ll +; RUN: llvm-lto2 run %t -r %t,main,px -r %t,live1,p -r %t,live2,p -r %t,dead2,p \ +; RUN: %t2 -r %t2,live1,p -r %t2,live2, -r %t2,dead1,p -r %t2,dead2, \ +; RUN: -save-temps -o %t3 +; RUN: llvm-nm %t3.0 | FileCheck --check-prefix=FULL %s +; RUN: llvm-nm %t3.1 | FileCheck --check-prefix=THIN %s + +; FULL-NOT: dead +; FULL: U live1 +; FULL: T live2 +; FULL: T main + +; THIN-NOT: dead +; THIN: T live1 +; THIN: U live2 + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @main() { + call void @live1() + ret void +} + +declare void @live1() + +define void @live2() { + ret void +} + +define void @dead2() { + ret void +} + +!0 = !{i32 1, !"ThinLTO", i32 0} +!llvm.module.flags = !{ !0 }