Index: include/llvm/Linker/Linker.h =================================================================== --- include/llvm/Linker/Linker.h +++ include/llvm/Linker/Linker.h @@ -29,7 +29,10 @@ None = 0, OverrideFromSrc = (1 << 0), LinkOnlyNeeded = (1 << 1), - InternalizeLinkedSymbols = (1 << 2) + InternalizeLinkedSymbols = (1 << 2), + /// Don't force link referenced linkonce definitions, import declaration. + DontForceLinkLinkonceODR = (1<<3) + }; Linker(Module &M); Index: lib/LTO/ThinLTOCodeGenerator.cpp =================================================================== --- lib/LTO/ThinLTOCodeGenerator.cpp +++ lib/LTO/ThinLTOCodeGenerator.cpp @@ -122,10 +122,11 @@ 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, + StringRef ModuleIdentifier, GlobalValue::GUID GUID, + const GlobalValueSummary &GV) { auto HasMultipleCopies = [&](const GlobalValueInfoList &GVInfo) { return GVInfo.size() > 1; }; @@ -146,8 +147,13 @@ 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 + if (GlobalValue::isDiscardableIfUnused(OriginalLinkage) && + ExportList.count(GUID)) + return GlobalValue::WeakODRLinkage; break; + } if (IsFirstDefinitionForLinker(GVInfo, Index, ModuleIdentifier)) return GlobalValue::WeakODRLinkage; else @@ -166,6 +172,7 @@ /// one copy. static void ResolveODR( const ModuleSummaryIndex &Index, + const FunctionImporter::ExportSetTy &ExportList, const std::map &DefinedGlobals, StringRef ModuleIdentifier, DenseMap &ResolvedODR) { @@ -185,7 +192,8 @@ for (auto &GV : DefinedGlobals) { if (GlobalInvolvedWithAlias.count(GV.second)) continue; - auto NewLinkage = ResolveODR(Index, ModuleIdentifier, GV.first, *GV.second); + auto NewLinkage = + ResolveODR(Index, ExportList, ModuleIdentifier, GV.first, *GV.second); if (NewLinkage != GV.second->linkage()) { ResolvedODR[GV.first] = NewLinkage; } @@ -213,6 +221,14 @@ << GV.getLinkage() << " to " << NewLinkage->second << "\n"); GV.setLinkage(NewLinkage->second); } + for (auto &GV : TheModule.aliases()) { + auto NewLinkage = ResolvedODR.find(GV.getGUID()); + if (NewLinkage == ResolvedODR.end()) + continue; + DEBUG(dbgs() << "ODR fixing up linkage for `" << GV.getName() << "` from " + << GV.getLinkage() << " to " << NewLinkage->second << "\n"); + GV.setLinkage(NewLinkage->second); + } } static StringMap @@ -453,17 +469,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 +600,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::DontForceLinkLinkonceODR); } bool shouldOverrideFromSrc() { return Flags & Linker::OverrideFromSrc; } bool shouldLinkOnlyNeeded() { return Flags & Linker::LinkOnlyNeeded; } bool shouldInternalizeLinkedSymbols() { @@ -429,6 +430,12 @@ } void ModuleLinker::addLazyFor(GlobalValue &GV, IRMover::ValueAdder Add) { + if (!shouldLinkReferencedLinkOnce()) + // For ThinLTO we don't import more than what was required. + // The client has to guarantee that the linkonce will be availabe at link + // time (by promoting it to weak for instance). + 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 @@ -163,10 +163,19 @@ } // "Resolve" the summary, traversing alias, const FunctionSummary *ResolvedCalleeSummary; - if (isa(CalleeSummary)) + if (isa(CalleeSummary)) { ResolvedCalleeSummary = cast( &cast(CalleeSummary)->getAliasee()); - else + if (!GlobalValue::isLinkOnceODRLinkage(ResolvedCalleeSummary->linkage())) { + // Alias can't point to "available_externally". However when we import + // linkOnceODR the linkage does not change. So we import the alias + // and aliasee only in this case. + // FIXME: we should import alias as available_externally *function*, the + // destination module does need to know it is an alias. + DEBUG(dbgs() << "ignored! Aliasee is not linkonce_odr.\n"); + continue; + } + } else ResolvedCalleeSummary = cast(CalleeSummary); assert(ResolvedCalleeSummary->instCount() <= Threshold && @@ -380,10 +389,11 @@ if (Import) { // Alias can't point to "available_externally". However when we import // linkOnceODR the linkage does not change. So we import the alias - // and aliasee only in this case. + // and aliasee only in this case. This has been handled by + // computeImportForFunction() GlobalObject *GO = GV.getBaseObject(); - if (!GO->hasLinkOnceODRLinkage()) - continue; + assert(GO->hasLinkOnceODRLinkage() && + "Unexpected alias to a non-linkonceODR in import list"); #ifndef NDEBUG if (!GlobalsToImport.count(GO)) DEBUG(dbgs() << " alias triggers importing aliasee " << GO->getGUID() @@ -407,8 +417,10 @@ << " 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::DontForceLinkLinkonceODR; + + if (TheLinker.linkInModule(std::move(SrcModule), Flags, &GlobalsToImport)) report_fatal_error("Function Import: link error"); ImportedCount += GlobalsToImport.size(); Index: test/Linker/funcimport2.ll =================================================================== --- test/Linker/funcimport2.ll +++ test/Linker/funcimport2.ll @@ -3,7 +3,7 @@ ; RUN: llvm-lto -thinlto -o %t3 %t1.bc %t2.bc ; RUN: llvm-link -import=bar:%t2.bc %t1.bc -summary-index=%t3.thinlto.bc -S | FileCheck %s -; CHECK: define linkonce_odr hidden void @foo() { +; CHECK: define available_externally hidden void @foo() { define available_externally hidden void @foo() { ret void } Index: test/ThinLTO/X86/Inputs/alias_resolution.ll =================================================================== --- /dev/null +++ test/ThinLTO/X86/Inputs/alias_resolution.ll @@ -0,0 +1,64 @@ + + + + +@globalfuncAlias = alias void (...), bitcast (void ()* @globalfunc to void (...)*) +@globalfuncWeakAlias = weak alias void (...), bitcast (void ()* @globalfunc to void (...)*) +@globalfuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @globalfunc to void (...)*) +@globalfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @globalfunc to void (...)*) +@globalfuncLinkonceODRAlias = linkonce_odr alias void (...), bitcast (void ()* @globalfunc to void (...)*) +define void @globalfunc() { +entry: + ret void +} + +@internalfuncAlias = alias void (...), bitcast (void ()* @internalfunc to void (...)*) +@internalfuncWeakAlias = weak alias void (...), bitcast (void ()* @internalfunc to void (...)*) +@internalfuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @internalfunc to void (...)*) +@internalfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @internalfunc to void (...)*) +@internalfuncLinkonceODRAlias = linkonce_odr alias void (...), bitcast (void ()* @internalfunc to void (...)*) +define internal void @internalfunc() { +entry: + ret void +} + +@linkonceODRfuncAlias = alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) +@linkonceODRfuncWeakAlias = weak alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) +@linkonceODRfuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) +@linkonceODRfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) +@linkonceODRfuncLinkonceODRAlias = linkonce_odr alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) +define linkonce_odr void @linkonceODRfunc() { +entry: + ret void +} + +@weakODRfuncAlias = alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) +@weakODRfuncWeakAlias = weak alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) +@weakODRfuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) +@weakODRfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) +@weakODRfuncLinkonceODRAlias = linkonce_odr alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) +define weak_odr void @weakODRfunc() { +entry: + ret void +} + +@linkoncefuncAlias = alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) +@linkoncefuncWeakAlias = weak alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) +@linkoncefuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) +@linkoncefuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) +@linkoncefuncLinkonceODRAlias = linkonce_odr alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) +define linkonce void @linkoncefunc() { +entry: + ret void +} + +@weakfuncAlias = alias void (...), bitcast (void ()* @weakfunc to void (...)*) +@weakfuncWeakAlias = weak alias void (...), bitcast (void ()* @weakfunc to void (...)*) +@weakfuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @weakfunc to void (...)*) +@weakfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @weakfunc to void (...)*) +@weakfuncLinkonceODRAlias = linkonce_odr alias void (...), bitcast (void ()* @weakfunc to void (...)*) +define weak void @weakfunc() { +entry: + ret void +} + Index: test/ThinLTO/X86/alias_resolution.ll =================================================================== --- /dev/null +++ test/ThinLTO/X86/alias_resolution.ll @@ -0,0 +1,169 @@ + ; Do setup work for all below tests: generate bitcode and combined index +; RUN: opt -module-summary %s -o %t1.bc +; RUN: opt -module-summary %p/Inputs/alias_resolution.ll -o %t2.bc +; RUN: llvm-lto -thinlto-action=thinlink -o %t.index.bc %t1.bc %t2.bc +; RUN: llvm-lto -thinlto-action=promote -thinlto-index %t.index.bc %t2.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=PROMOTE +; RUN: llvm-lto -thinlto-action=import -thinlto-index %t.index.bc %t1.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=IMPORT + +; Do not resolve all these aliases +; PROMOTE-DAG: @globalfuncAlias = alias void (...), bitcast (void ()* @globalfunc to void (...)*) +; PROMOTE-DAG: @globalfuncWeakAlias = weak alias void (...), bitcast (void ()* @globalfunc to void (...)*) +; PROMOTE-DAG: @globalfuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @globalfunc to void (...)*) +; PROMOTE-DAG: @globalfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @globalfunc to void (...)*) +; PROMOTE-DAG: @globalfuncLinkonceODRAlias = linkonce_odr alias void (...), bitcast (void ()* @globalfunc to void (...)*) +; PROMOTE-DAG: @internalfuncAlias = alias void (...), bitcast (void ()* @internalfunc.llvm.0 to void (...)*) +; PROMOTE-DAG: @internalfuncWeakAlias = weak alias void (...), bitcast (void ()* @internalfunc.llvm.0 to void (...)*) +; PROMOTE-DAG: @internalfuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @internalfunc.llvm.0 to void (...)*) +; PROMOTE-DAG: @internalfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @internalfunc.llvm.0 to void (...)*) +; PROMOTE-DAG: @internalfuncLinkonceODRAlias = linkonce_odr alias void (...), bitcast (void ()* @internalfunc.llvm.0 to void (...)*) +; PROMOTE-DAG: @linkoncefuncAlias = alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) +; PROMOTE-DAG: @linkoncefuncWeakAlias = weak alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) +; PROMOTE-DAG: @linkoncefuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) +; PROMOTE-DAG: @linkoncefuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) +; PROMOTE-DAG: @linkoncefuncLinkonceODRAlias = linkonce_odr alias void (...), bitcast (void ()* @linkoncefunc to void (...)*) +; PROMOTE-DAG: @weakfuncAlias = alias void (...), bitcast (void ()* @weakfunc to void (...)*) +; PROMOTE-DAG: @weakfuncWeakAlias = weak alias void (...), bitcast (void ()* @weakfunc to void (...)*) +; PROMOTE-DAG: @weakfuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @weakfunc to void (...)*) +; PROMOTE-DAG: @weakfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @weakfunc to void (...)*) +; PROMOTE-DAG: @weakfuncLinkonceODRAlias = linkonce_odr alias void (...), bitcast (void ()* @weakfunc to void (...)*) +; PROMOTE-DAG: @weakODRfuncAlias = alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) +; PROMOTE-DAG: @weakODRfuncWeakAlias = weak alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) +; PROMOTE-DAG: @weakODRfuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) +; PROMOTE-DAG: @weakODRfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) +; PROMOTE-DAG: @weakODRfuncLinkonceODRAlias = linkonce_odr alias void (...), bitcast (void ()* @weakODRfunc to void (...)*) + +; Only alias to LinkonceODR function are resolved +; (This is a current limitation of the implementation that could be lifted) +; PROMOTE-DAG: @linkonceODRfuncAlias = alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) +; PROMOTE-DAG: @linkonceODRfuncWeakAlias = weak alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) +; PROMOTE-DAG: @linkonceODRfuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) +; PROMOTE-DAG: @linkonceODRfuncWeakODRAlias = weak_odr alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) +; PROMOTE-DAG: @linkonceODRfuncLinkonceODRAlias = weak_odr alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) + +; PROMOTE-DAG: define void @globalfunc() +; PROMOTE-DAG: define hidden void @internalfunc.llvm.0() +; PROMOTE-DAG: define linkonce_odr void @linkonceODRfunc() +; PROMOTE-DAG: define weak_odr void @weakODRfunc() +; PROMOTE-DAG: define linkonce void @linkoncefunc() +; PROMOTE-DAG: define weak void @weakfunc() + +; Only import aliases that have been resolved, i.e. alias to a linkonce_odr. +; IMPORT-DAG: @linkonceODRfuncAlias = alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) +; IMPORT-DAG: @linkonceODRfuncLinkonceAlias = linkonce alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) +; IMPORT-DAG: @linkonceODRfuncWeakODRAlias = alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) +; IMPORT-DAG: @linkonceODRfuncLinkonceODRAlias = linkonce_odr alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) +; IMPORT-DAG: define linkonce_odr void @linkonceODRfunc() +; FIXME: not sure why we would want an extern_weak here. +; IMPORT-DAG: @linkonceODRfuncWeakAlias = extern_weak alias void (...), bitcast (void ()* @linkonceODRfunc to void (...)*) + + + +; IMPORT-DAG: declare void @globalfuncAlias() +; IMPORT-DAG: declare void @globalfuncWeakAlias() +; IMPORT-DAG: declare void @globalfuncLinkonceAlias() +; IMPORT-DAG: declare void @globalfuncWeakODRAlias() +; IMPORT-DAG: declare void @globalfuncLinkonceODRAlias() +; IMPORT-DAG: declare void @internalfuncAlias() +; IMPORT-DAG: declare void @internalfuncWeakAlias() +; IMPORT-DAG: declare void @internalfuncLinkonceAlias() +; IMPORT-DAG: declare void @internalfuncWeakODRAlias() +; IMPORT-DAG: declare void @internalfuncLinkonceODRAlias() +; IMPORT-DAG: declare void @weakODRfuncAlias() +; IMPORT-DAG: declare void @weakODRfuncWeakAlias() +; IMPORT-DAG: declare void @weakODRfuncLinkonceAlias() +; IMPORT-DAG: declare void @weakODRfuncWeakODRAlias() +; IMPORT-DAG: declare void @weakODRfuncLinkonceODRAlias() +; IMPORT-DAG: declare void @linkoncefuncAlias() +; IMPORT-DAG: declare void @linkoncefuncWeakAlias() +; IMPORT-DAG: declare void @linkoncefuncLinkonceAlias() +; IMPORT-DAG: declare void @linkoncefuncWeakODRAlias() +; IMPORT-DAG: declare void @linkoncefuncLinkonceODRAlias() +; IMPORT-DAG: declare void @weakfuncAlias() +; IMPORT-DAG: declare void @weakfuncWeakAlias() +; IMPORT-DAG: declare void @weakfuncLinkonceAlias() +; IMPORT-DAG: declare void @weakfuncWeakODRAlias() +; IMPORT-DAG: declare void @weakfuncLinkonceODRAlias() + + + + + + +define i32 @main() #0 { +entry: + call void @globalfuncAlias() + call void @globalfuncWeakAlias() + call void @globalfuncLinkonceAlias() + call void @globalfuncWeakODRAlias() + call void @globalfuncLinkonceODRAlias() + + call void @internalfuncAlias() + call void @internalfuncWeakAlias() + call void @internalfuncLinkonceAlias() + call void @internalfuncWeakODRAlias() + call void @internalfuncLinkonceODRAlias() + call void @linkonceODRfuncAlias() + call void @linkonceODRfuncWeakAlias() + call void @linkonceODRfuncLinkonceAlias() + call void @linkonceODRfuncWeakODRAlias() + call void @linkonceODRfuncLinkonceODRAlias() + + call void @weakODRfuncAlias() + call void @weakODRfuncWeakAlias() + call void @weakODRfuncLinkonceAlias() + call void @weakODRfuncWeakODRAlias() + call void @weakODRfuncLinkonceODRAlias() + + call void @linkoncefuncAlias() + call void @linkoncefuncWeakAlias() + call void @linkoncefuncLinkonceAlias() + call void @linkoncefuncWeakODRAlias() + call void @linkoncefuncLinkonceODRAlias() + + call void @weakfuncAlias() + call void @weakfuncWeakAlias() + call void @weakfuncLinkonceAlias() + call void @weakfuncWeakODRAlias() + call void @weakfuncLinkonceODRAlias() + + ret i32 0 +} + + +declare void @globalfuncAlias() +declare void @globalfuncWeakAlias() +declare void @globalfuncLinkonceAlias() +declare void @globalfuncWeakODRAlias() +declare void @globalfuncLinkonceODRAlias() + +declare void @internalfuncAlias() +declare void @internalfuncWeakAlias() +declare void @internalfuncLinkonceAlias() +declare void @internalfuncWeakODRAlias() +declare void @internalfuncLinkonceODRAlias() + +declare void @linkonceODRfuncAlias() +declare void @linkonceODRfuncWeakAlias() +declare void @linkonceODRfuncLinkonceAlias() +declare void @linkonceODRfuncWeakODRAlias() +declare void @linkonceODRfuncLinkonceODRAlias() + +declare void @weakODRfuncAlias() +declare void @weakODRfuncWeakAlias() +declare void @weakODRfuncLinkonceAlias() +declare void @weakODRfuncWeakODRAlias() +declare void @weakODRfuncLinkonceODRAlias() + +declare void @linkoncefuncAlias() +declare void @linkoncefuncWeakAlias() +declare void @linkoncefuncLinkonceAlias() +declare void @linkoncefuncWeakODRAlias() +declare void @linkoncefuncLinkonceODRAlias() + +declare void @weakfuncAlias() +declare void @weakfuncWeakAlias() +declare void @weakfuncLinkonceAlias() +declare void @weakfuncWeakODRAlias() +declare void @weakfuncLinkonceODRAlias() + + Index: test/ThinLTO/X86/odr_resolution.ll =================================================================== --- test/ThinLTO/X86/odr_resolution.ll +++ test/ThinLTO/X86/odr_resolution.ll @@ -11,8 +11,8 @@ target triple = "x86_64-apple-macosx10.11.0" ; Alias are not optimized -; MOD1: @linkoncealias = linkonce_odr alias void (), void ()* @linkonceodrfuncwithalias -; MOD2: @linkoncealias = linkonce_odr alias void (), void ()* @linkonceodrfuncwithalias +; MOD1: @linkoncealias = weak_odr alias void (), void ()* @linkonceodrfuncwithalias +; MOD2: @linkoncealias = available_externally alias void (), void ()* @linkonceodrfuncwithalias @linkoncealias = linkonce_odr alias void (), void ()* @linkonceodrfuncwithalias ; Function with an alias are not optimized 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 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 Index: tools/llvm-link/llvm-link.cpp =================================================================== --- tools/llvm-link/llvm-link.cpp +++ tools/llvm-link/llvm-link.cpp @@ -276,8 +276,10 @@ if (renameModuleForThinLTO(*SrcModule, *Index, &GlobalsToImport)) return true; - if (L.linkInModule(std::move(SrcModule), Linker::Flags::None, - &GlobalsToImport)) + // Instruct the linker to not automatically import linkonce defintion. + unsigned Flags = Linker::Flags::DontForceLinkLinkonceODR; + + if (L.linkInModule(std::move(SrcModule), Flags, &GlobalsToImport)) return false; }