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/Linker/LinkModules.cpp =================================================================== --- lib/Linker/LinkModules.cpp +++ lib/Linker/LinkModules.cpp @@ -45,6 +45,9 @@ /// 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 +432,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 @@ -420,8 +420,10 @@ << " from " << SrcModule->getSourceFileName() << "\n"; } - if (TheLinker.linkInModule(std::move(SrcModule), Linker::Flags::None, - &GlobalsToImport)) + // Instruct the linker 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/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; }