Index: include/llvm/Linker/Linker.h =================================================================== --- include/llvm/Linker/Linker.h +++ include/llvm/Linker/Linker.h @@ -29,7 +29,9 @@ None = 0, OverrideFromSrc = (1 << 0), LinkOnlyNeeded = (1 << 1), - InternalizeLinkedSymbols = (1 << 2) + InternalizeLinkedSymbols = (1 << 2), + /// Don't link the definition referenced linkonce. + DontLazyAddLinkone = (1<<3) }; Linker(Module &M); Index: lib/LTO/ThinLTOCodeGenerator.cpp =================================================================== --- lib/LTO/ThinLTOCodeGenerator.cpp +++ lib/LTO/ThinLTOCodeGenerator.cpp @@ -122,10 +122,12 @@ return true; } -static GlobalValue::LinkageTypes ResolveODR(const ModuleSummaryIndex &Index, - StringRef ModuleIdentifier, - GlobalValue::GUID GUID, - const GlobalValueSummary &GV) { +static GlobalValue::LinkageTypes +ResolveODR(const ModuleSummaryIndex &Index, + const FunctionImporter::ExportSetTy &ExportList, + DenseSet &GlobalInvolvedWithAlias, + StringRef ModuleIdentifier, GlobalValue::GUID GUID, + const GlobalValueSummary &GV) { auto HasMultipleCopies = [&](const GlobalValueInfoList &GVInfo) { return GVInfo.size() > 1; }; @@ -146,11 +148,19 @@ auto &GVInfo = Index.findGlobalValueInfoList(GUID)->second; // We need to emit only one of these, the first module will keep // it, but turned into a weak while the others will drop it. - if (!HasMultipleCopies(GVInfo)) + if (!HasMultipleCopies(GVInfo)) { + // Exported ODR needs to be promoted to not be discarded + // Same if the ODR is referenced by an alias (FIXME: only if the alias is + // itself exported). + if (GlobalValue::isDiscardableIfUnused(OriginalLinkage) && + (ExportList.count(GUID) || GlobalInvolvedWithAlias.count(&GV))) + return GlobalValue::WeakODRLinkage; break; + } if (IsFirstDefinitionForLinker(GVInfo, Index, ModuleIdentifier)) return GlobalValue::WeakODRLinkage; - else + else if(!GlobalInvolvedWithAlias.count(&GV)) + // Alias cannot point to an AvailableExternallyLinkage return GlobalValue::AvailableExternallyLinkage; break; } @@ -166,6 +176,7 @@ /// one copy. static void ResolveODR( const ModuleSummaryIndex &Index, + const FunctionImporter::ExportSetTy &ExportList, const std::map &DefinedGlobals, StringRef ModuleIdentifier, DenseMap &ResolvedODR) { @@ -176,16 +187,16 @@ // We won't optimize the globals that are referenced by an alias for now // Ideally we should turn the alias into a global and duplicate the definition // when needed. - DenseSet GlobalInvolvedWithAlias; + DenseSet GlobalInvolvedWithAlias; for (auto &GA : DefinedGlobals) { if (auto AS = dyn_cast(GA.second)) GlobalInvolvedWithAlias.insert(&AS->getAliasee()); } for (auto &GV : DefinedGlobals) { - if (GlobalInvolvedWithAlias.count(GV.second)) - continue; - auto NewLinkage = ResolveODR(Index, ModuleIdentifier, GV.first, *GV.second); + auto NewLinkage = + ResolveODR(Index, ExportList, GlobalInvolvedWithAlias, + ModuleIdentifier, GV.first, *GV.second); if (NewLinkage != GV.second->linkage()) { ResolvedODR[GV.first] = NewLinkage; } @@ -453,17 +464,25 @@ */ void ThinLTOCodeGenerator::promote(Module &TheModule, ModuleSummaryIndex &Index) { + auto ModuleCount = Index.modulePaths().size(); auto ModuleIdentifier = TheModule.getModuleIdentifier(); // Collect for each module the list of function it defines (GUID -> Summary). StringMap> ModuleToDefinedGVSummaries; Index.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries); + // Generate import/export list + StringMap ImportLists(ModuleCount); + StringMap ExportLists(ModuleCount); + ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists, + ExportLists); + auto &ExportList = ExportLists[ModuleIdentifier]; + // Resolve the LinkOnceODR, trying to turn them into "available_externally" // where possible. // This is a compile-time optimization. DenseMap ResolvedODR; - ResolveODR(Index, ModuleToDefinedGVSummaries[ModuleIdentifier], + ResolveODR(Index, ExportList, ModuleToDefinedGVSummaries[ModuleIdentifier], ModuleIdentifier, ResolvedODR); fixupODR(TheModule, ResolvedODR); @@ -576,9 +595,11 @@ LLVMContext Context; Context.setDiscardValueNames(LTODiscardValueNames); auto ModuleIdentifier = ModuleBuffer.getBufferIdentifier(); + auto &ExportList = ExportLists[ModuleIdentifier]; DenseMap ResolvedODR; - ResolveODR(*Index, ModuleToDefinedGVSummaries[ModuleIdentifier], + ResolveODR(*Index, ExportList, + ModuleToDefinedGVSummaries[ModuleIdentifier], ModuleIdentifier, ResolvedODR); // Parse module now Index: lib/Linker/LinkModules.cpp =================================================================== --- lib/Linker/LinkModules.cpp +++ lib/Linker/LinkModules.cpp @@ -45,6 +45,7 @@ /// to Add. void addLazyFor(GlobalValue &GV, IRMover::ValueAdder Add); + bool shouldLinkReferencedLinkOnce() { return !(Flags & Linker::DontLazyAddLinkone); } bool shouldOverrideFromSrc() { return Flags & Linker::OverrideFromSrc; } bool shouldLinkOnlyNeeded() { return Flags & Linker::LinkOnlyNeeded; } bool shouldInternalizeLinkedSymbols() { @@ -429,6 +430,10 @@ } void ModuleLinker::addLazyFor(GlobalValue &GV, IRMover::ValueAdder Add) { + if (!shouldLinkReferencedLinkOnce()) + // The client takes care of linkonce availability. + return; + // Add these to the internalize list if (!GV.hasLinkOnceLinkage()) return; Index: lib/Transforms/IPO/FunctionImport.cpp =================================================================== --- lib/Transforms/IPO/FunctionImport.cpp +++ lib/Transforms/IPO/FunctionImport.cpp @@ -322,6 +322,7 @@ // Linker that will be used for importing function Linker TheLinker(DestModule); + // Do the actual import of functions now, one Module at a time std::set ModuleNameOrderedList; for (auto &FunctionsToImportPerModule : ImportList) { @@ -407,8 +408,11 @@ << " from " << SrcModule->getSourceFileName() << "\n"; } - if (TheLinker.linkInModule(std::move(SrcModule), Linker::Flags::None, - &GlobalsToImport)) + + // Instruct the link that the client will take care of linkonce resolution. + unsigned Flags = Linker::Flags::DontLazyAddLinkone; + + if (TheLinker.linkInModule(std::move(SrcModule), Flags, &GlobalsToImport)) report_fatal_error("Function Import: link error"); ImportedCount += GlobalsToImport.size(); Index: test/ThinLTO/X86/odr_resolution.ll =================================================================== --- test/ThinLTO/X86/odr_resolution.ll +++ test/ThinLTO/X86/odr_resolution.ll @@ -15,8 +15,8 @@ ; MOD2: @linkoncealias = linkonce_odr alias void (), void ()* @linkonceodrfuncwithalias @linkoncealias = linkonce_odr alias void (), void ()* @linkonceodrfuncwithalias -; Function with an alias are not optimized -; MOD1: define linkonce_odr void @linkonceodrfuncwithalias() +; Function with an alias are resolved +; MOD1: define weak_odr void @linkonceodrfuncwithalias() ; MOD2: define linkonce_odr void @linkonceodrfuncwithalias() define linkonce_odr void @linkonceodrfuncwithalias() #0 { entry: Index: test/Transforms/FunctionImport/Inputs/funcimport.ll =================================================================== --- test/Transforms/FunctionImport/Inputs/funcimport.ll +++ test/Transforms/FunctionImport/Inputs/funcimport.ll @@ -99,4 +99,46 @@ ret void } +define void @referencelargelinkonce() #0 { +entry: + call void @linkonceodr() + ret void +} + +; A large enough linkonce_odr function that should never be imported +define linkonce_odr void @linkonceodr() #0 { +entry: + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + call void @globalfunc2() + ret void +} + Index: test/Transforms/FunctionImport/funcimport.ll =================================================================== --- test/Transforms/FunctionImport/funcimport.ll +++ test/Transforms/FunctionImport/funcimport.ll @@ -23,6 +23,7 @@ call void (...) @setfuncptr() call void (...) @callfuncptr() call void (...) @weakfunc() + call void (...) @referencelargelinkonce() ret i32 0 } @@ -78,6 +79,12 @@ ; CHECK-DAG: %0 = load void ()*, void ()** @P.llvm. ; CHECK-DAG: store void ()* @staticfunc2.llvm.{{.*}}, void ()** @P.llvm. +; Ensure that @referencelargelinkonce definition is pulled in, but later we +; also check that the linkonceodr function is not. +; CHECK-DAG: define available_externally void @referencelargelinkonce() +; INSTLIM5-DAG: declare extern_weak void @linkonceodr() +declare void @referencelargelinkonce(...) + ; Won't import weak func ; CHECK-DAG: declare void @weakfunc(...) declare void @weakfunc(...) #1 @@ -87,7 +94,7 @@ ; INSTLIM5-DAG: declare hidden void @funcwithpersonality.llvm.{{.*}}() ; INSTLIMDEF-DAG: Import globalfunc2 -; INSTLIMDEF-DAG: 11 function-import - Number of functions imported +; INSTLIMDEF-DAG: 13 function-import - Number of functions imported ; The actual GUID values will depend on path to test. ; GUID-DAG: GUID {{.*}} is weakalias