Index: include/llvm/LTO/LTO.h =================================================================== --- include/llvm/LTO/LTO.h +++ include/llvm/LTO/LTO.h @@ -59,7 +59,9 @@ /// must apply the changes to the Module via thinLTOInternalizeModule. void thinLTOInternalizeAndPromoteInIndex( ModuleSummaryIndex &Index, - function_ref isExported); + function_ref isExported, + function_ref + isPrevailing); namespace lto { Index: lib/LTO/LTO.cpp =================================================================== --- lib/LTO/LTO.cpp +++ lib/LTO/LTO.cpp @@ -328,8 +328,12 @@ static void thinLTOInternalizeAndPromoteGUID( GlobalValueSummaryList &GVSummaryList, GlobalValue::GUID GUID, - function_ref isExported) { + function_ref isExported, + function_ref + isPrevailing) { for (auto &S : GVSummaryList) { + if (!isPrevailing(GUID, S.get())) + continue; if (isExported(S->modulePath(), GUID)) { if (GlobalValue::isLocalLinkage(S->linkage())) S->setLinkage(GlobalValue::ExternalLinkage); @@ -342,9 +346,12 @@ // as external and non-exported values as internal. void llvm::thinLTOInternalizeAndPromoteInIndex( ModuleSummaryIndex &Index, - function_ref isExported) { + function_ref isExported, + function_ref + isPrevailing) { for (auto &I : Index) - thinLTOInternalizeAndPromoteGUID(I.second.SummaryList, I.first, isExported); + thinLTOInternalizeAndPromoteGUID(I.second.SummaryList, I.first, isExported, + isPrevailing); } // Requires a destructor for std::vector. @@ -1139,12 +1146,12 @@ ExportList->second.count(GUID)) || ExportedGUIDs.count(GUID); }; - thinLTOInternalizeAndPromoteInIndex(ThinLTO.CombinedIndex, isExported); - - auto isPrevailing = [&](GlobalValue::GUID GUID, - const GlobalValueSummary *S) { + auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) { return ThinLTO.PrevailingModuleForGUID[GUID] == S->modulePath(); }; + + thinLTOInternalizeAndPromoteInIndex(ThinLTO.CombinedIndex, isExported, + isPrevailing); auto recordNewLinkage = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID, GlobalValue::LinkageTypes NewLinkage) { Index: lib/LTO/ThinLTOCodeGenerator.cpp =================================================================== --- lib/LTO/ThinLTOCodeGenerator.cpp +++ lib/LTO/ThinLTOCodeGenerator.cpp @@ -607,6 +607,30 @@ return CombinedIndex; } +static void internalizeAndPromoteInIndex( + const StringMap &ExportLists, + const DenseSet &GUIDPreservedSymbols, + ModuleSummaryIndex &Index) { + auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) { + const auto &ExportList = ExportLists.find(ModuleIdentifier); + return (ExportList != ExportLists.end() && + ExportList->second.count(GUID)) || + GUIDPreservedSymbols.count(GUID); + }; + + DenseMap PrevailingCopy; + computePrevailingCopies(Index, PrevailingCopy); + auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) { + const auto &Prevailing = PrevailingCopy.find(GUID); + // Not in map means that there was only one copy, which must be prevailing. + if (Prevailing == PrevailingCopy.end()) + return true; + return Prevailing->second == S; + }; + + thinLTOInternalizeAndPromoteInIndex(Index, isExported, isPrevailing); +} + /** * Perform promotion and renaming of exported internal functions. * Index is updated to reflect linkage changes from weak resolution. @@ -642,13 +666,7 @@ // Promote the exported values in the index, so that they are promoted // in the module. - auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) { - const auto &ExportList = ExportLists.find(ModuleIdentifier); - return (ExportList != ExportLists.end() && - ExportList->second.count(GUID)) || - GUIDPreservedSymbols.count(GUID); - }; - thinLTOInternalizeAndPromoteInIndex(Index, isExported); + internalizeAndPromoteInIndex(ExportLists, GUIDPreservedSymbols, Index); promoteModule(TheModule, Index); } @@ -762,13 +780,7 @@ return; // Internalization - auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) { - const auto &ExportList = ExportLists.find(ModuleIdentifier); - return (ExportList != ExportLists.end() && - ExportList->second.count(GUID)) || - GUIDPreservedSymbols.count(GUID); - }; - thinLTOInternalizeAndPromoteInIndex(Index, isExported); + internalizeAndPromoteInIndex(ExportLists, GUIDPreservedSymbols, Index); thinLTOInternalizeModule(TheModule, ModuleToDefinedGVSummaries[ModuleIdentifier]); } @@ -918,17 +930,10 @@ // impacts the caching. resolveWeakForLinkerInIndex(*Index, ResolvedODR); - auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) { - const auto &ExportList = ExportLists.find(ModuleIdentifier); - return (ExportList != ExportLists.end() && - ExportList->second.count(GUID)) || - GUIDPreservedSymbols.count(GUID); - }; - // Use global summary-based analysis to identify symbols that can be // internalized (because they aren't exported or preserved as per callback). // Changes are made in the index, consumed in the ThinLTO backends. - thinLTOInternalizeAndPromoteInIndex(*Index, isExported); + internalizeAndPromoteInIndex(ExportLists, GUIDPreservedSymbols, *Index); // Make sure that every module has an entry in the ExportLists and // ResolvedODR maps to enable threaded access to these maps below. Index: test/LTO/Resolution/X86/not-prevailing.ll =================================================================== --- test/LTO/Resolution/X86/not-prevailing.ll +++ test/LTO/Resolution/X86/not-prevailing.ll @@ -0,0 +1,25 @@ +; RUN: opt -module-summary %s -o %t.o +; RUN: llvm-lto2 run -o %t2.o %t.o -r %t.o,foo,x -r %t.o,zed,px -save-temps +; RUN: llvm-objdump -d %t2.o.1 | FileCheck %s +; RUN: llvm-readelf --symbols %t2.o.1 | FileCheck %s --check-prefix=SYMBOLS + +; Check that 'foo' was not inlined. +; CHECK: Disassembly of section .text: +; CHECK-NEXT: zed: +; CHECK-NEXT: 0: {{.*}} jmp 0 + +; Check that 'foo' produced as undefined. +; SYMBOLS: NOTYPE GLOBAL DEFAULT UND foo +; SYMBOLS: FUNC GLOBAL DEFAULT 2 zed + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define weak i32 @foo() local_unnamed_addr { + ret i32 65 +} + +define i32 @zed() local_unnamed_addr { + %1 = tail call i32 @foo() #1 + ret i32 %1 +}