Index: llvm/trunk/lib/LTO/LTO.cpp =================================================================== --- llvm/trunk/lib/LTO/LTO.cpp +++ llvm/trunk/lib/LTO/LTO.cpp @@ -128,20 +128,25 @@ function_ref recordNewLinkage) { for (auto &S : GVSummaryList) { - if (GlobalInvolvedWithAlias.count(S.get())) - continue; GlobalValue::LinkageTypes OriginalLinkage = S->linkage(); if (!GlobalValue::isWeakForLinker(OriginalLinkage)) continue; // We need to emit only one of these. The prevailing module will keep it, // but turned into a weak, while the others will drop it when possible. + // This is both a compile-time optimization and a correctness + // transformation. This is necessary for correctness when we have exported + // a reference - we need to convert the linkonce to weak to + // ensure a copy is kept to satisfy the exported reference. + // FIXME: We may want to split the compile time and correctness + // aspects into separate routines. if (isPrevailing(GUID, S.get())) { if (GlobalValue::isLinkOnceLinkage(OriginalLinkage)) S->setLinkage(GlobalValue::getWeakLinkage( GlobalValue::isLinkOnceODRLinkage(OriginalLinkage))); } - // Alias can't be turned into available_externally. + // Alias and aliasee can't be turned into available_externally. else if (!isa(S.get()) && + !GlobalInvolvedWithAlias.count(S.get()) && (GlobalValue::isLinkOnceODRLinkage(OriginalLinkage) || GlobalValue::isWeakODRLinkage(OriginalLinkage))) S->setLinkage(GlobalValue::AvailableExternallyLinkage); Index: llvm/trunk/test/ThinLTO/X86/Inputs/linkonce_aliasee_ref_import.ll =================================================================== --- llvm/trunk/test/ThinLTO/X86/Inputs/linkonce_aliasee_ref_import.ll +++ llvm/trunk/test/ThinLTO/X86/Inputs/linkonce_aliasee_ref_import.ll @@ -0,0 +1,10 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-grtev4-linux-gnu" + +define i32 @main() #0 { +entry: + call void @foo() + ret i32 0 +} + +declare void @foo() Index: llvm/trunk/test/ThinLTO/X86/alias_import.ll =================================================================== --- llvm/trunk/test/ThinLTO/X86/alias_import.ll +++ llvm/trunk/test/ThinLTO/X86/alias_import.ll @@ -46,9 +46,9 @@ ; These will be imported, check the linkage/renaming after promotion ; 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 @linkonceODRfunc() ; PROMOTE-DAG: define weak_odr void @weakODRfunc() -; PROMOTE-DAG: define linkonce void @linkoncefunc() +; PROMOTE-DAG: define weak void @linkoncefunc() ; PROMOTE-DAG: define weak void @weakfunc() ; On the import side now, verify that aliases to a linkonce_odr are imported, but the weak/linkonce (we can't inline them) Index: llvm/trunk/test/ThinLTO/X86/linkonce_aliasee_ref_import.ll =================================================================== --- llvm/trunk/test/ThinLTO/X86/linkonce_aliasee_ref_import.ll +++ llvm/trunk/test/ThinLTO/X86/linkonce_aliasee_ref_import.ll @@ -0,0 +1,50 @@ +; RUN: opt -module-summary %s -o %t1.bc +; RUN: opt -module-summary %p/Inputs/linkonce_aliasee_ref_import.ll -o %t2.bc + +; Import with instr limit to ensure only foo imported. +; RUN: llvm-lto -thinlto-action=run -exported-symbol=main -import-instr-limit=5 %t1.bc %t2.bc +; RUN: llvm-nm -o - < %t1.bc.thinlto.o | FileCheck %s --check-prefix=NM1 +; RUN: llvm-nm -o - < %t2.bc.thinlto.o | FileCheck %s --check-prefix=NM2 + +; Import with instr limit to ensure only foo imported. +; RUN: llvm-lto2 %t1.bc %t2.bc -o %t.o -save-temps \ +; RUN: -r=%t1.bc,foo,pxl \ +; RUN: -r=%t1.bc,baz,pxl \ +; RUN: -r=%t1.bc,baz.clone,pxl \ +; RUN: -r=%t1.bc,bar,pl \ +; RUN: -r=%t2.bc,main,pxl \ +; RUN: -r=%t2.bc,foo,l \ +; RUN: -import-instr-limit=5 +; RUN: llvm-nm -o - < %t1.bc.thinlto.o | FileCheck %s --check-prefix=NM1 +; RUN: llvm-nm -o - < %t2.bc.thinlto.o | FileCheck %s --check-prefix=NM2 + +; Check that we converted baz.clone to a weak +; NM1: W baz.clone + +; Check that we imported a ref (and not def) to baz.clone +; NM2: U baz.clone + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-grtev4-linux-gnu" + +$baz.clone = comdat any +@baz = weak alias void (), void ()* @baz.clone + +define void @foo() #5 align 2 { + tail call void @baz.clone() + ret void +} +define linkonce_odr void @baz.clone() #5 comdat align 2 { + call void @bar() + call void @bar() + call void @bar() + call void @bar() + call void @bar() + call void @bar() + call void @bar() + ret void +} + +define void @bar() { + ret void +} Index: llvm/trunk/test/ThinLTO/X86/weak_resolution.ll =================================================================== --- llvm/trunk/test/ThinLTO/X86/weak_resolution.ll +++ llvm/trunk/test/ThinLTO/X86/weak_resolution.ll @@ -25,16 +25,20 @@ ; MOD2: @linkoncealias = linkonce alias void (), void ()* @linkoncefuncwithalias @linkoncealias = linkonce alias void (), void ()* @linkoncefuncwithalias -; Function with an alias are not optimized -; MOD1: define linkonce_odr void @linkonceodrfuncwithalias() +; Function with an alias are resolved to weak_odr in prevailing module, but +; not optimized in non-prevailing module (illegal to have an +; available_externally aliasee). +; MOD1: define weak_odr void @linkonceodrfuncwithalias() ; MOD2: define linkonce_odr void @linkonceodrfuncwithalias() define linkonce_odr void @linkonceodrfuncwithalias() #0 { entry: ret void } -; Function with an alias are not optimized -; MOD1: define linkonce void @linkoncefuncwithalias() +; Function with an alias are resolved to weak in prevailing module, but +; not optimized in non-prevailing module (illegal to have an +; available_externally aliasee). +; MOD1: define weak void @linkoncefuncwithalias() ; MOD2: define linkonce void @linkoncefuncwithalias() define linkonce void @linkoncefuncwithalias() #0 { entry: Index: llvm/trunk/test/tools/gold/X86/thinlto_weak_resolution.ll =================================================================== --- llvm/trunk/test/tools/gold/X86/thinlto_weak_resolution.ll +++ llvm/trunk/test/tools/gold/X86/thinlto_weak_resolution.ll @@ -23,7 +23,8 @@ ; OPT2: @weakfunc ; OPT2-NOT: @ -; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck --check-prefix=OPT %s +; RUN: llvm-dis %t.o.3.import.bc -o - | FileCheck --check-prefix=IMPORT %s +; RUN llvm-dis %t2.o.3.import.bc -o - | FileCheck --check-prefix=IMPORT2 %s target triple = "x86_64-unknown-linux-gnu" @@ -42,50 +43,64 @@ ret i32 0 } -; Alias are resolved -; OPT: @linkonceodralias = weak_odr alias void (), void ()* @linkonceodrfuncwithalias +; Alias are resolved to weak_odr in prevailing module, but left as linkonce_odr +; in non-prevailing module (illegal to have an available_externally alias). +; IMPORT: @linkonceodralias = weak_odr alias void (), void ()* @linkonceodrfuncwithalias +; IMPORT2: @linkonceodralias = linkonce_odr alias void (), void ()* @linkonceodrfuncwithalias @linkonceodralias = linkonce_odr alias void (), void ()* @linkonceodrfuncwithalias -; Alias are resolved -; OPT: @linkoncealias = weak alias void (), void ()* @linkoncefuncwithalias +; Alias are resolved in prevailing module, but not optimized in +; non-prevailing module (illegal to have an available_externally alias). +; IMPORT: @linkoncealias = weak alias void (), void ()* @linkoncefuncwithalias +; IMPORT2: @linkoncealias = linkonce alias void (), void ()* @linkoncefuncwithalias @linkoncealias = linkonce alias void (), void ()* @linkoncefuncwithalias -; Function with an alias are not optimized -; OPT: define linkonce_odr void @linkonceodrfuncwithalias() +; Function with an alias are resolved in prevailing module, but +; not optimized in non-prevailing module (illegal to have an +; available_externally aliasee). +; IMPORT: define weak_odr void @linkonceodrfuncwithalias() +; IMPORT2: define linkonce_odr void @linkonceodrfuncwithalias() define linkonce_odr void @linkonceodrfuncwithalias() #0 { entry: ret void } -; Function with an alias are not optimized -; OPT: define linkonce void @linkoncefuncwithalias() +; Function with an alias are resolved to weak in prevailing module, but +; not optimized in non-prevailing module (illegal to have an +; available_externally aliasee). +; IMPORT: define weak void @linkoncefuncwithalias() +; IMPORT2: define linkonce void @linkoncefuncwithalias() define linkonce void @linkoncefuncwithalias() #0 { entry: ret void } -; OPT: define weak_odr void @linkonceodrfunc() +; IMPORT: define weak_odr void @linkonceodrfunc() +; IMPORT2: define available_externally void @linkonceodrfunc() define linkonce_odr void @linkonceodrfunc() #0 { entry: ret void } -; OPT: define weak void @linkoncefunc() +; IMPORT: define weak void @linkoncefunc() +; IMPORT2: define linkonce void @linkoncefunc() define linkonce void @linkoncefunc() #0 { entry: ret void } -; OPT: define weak_odr void @weakodrfunc() +; IMPORT: define weak_odr void @weakodrfunc() +; IMPORT2: define available_externally void @weakodrfunc() define weak_odr void @weakodrfunc() #0 { entry: ret void } -; OPT: define weak void @weakfunc() +; IMPORT: define weak void @weakfunc() +; IMPORT2: define weak void @weakfunc() define weak void @weakfunc() #0 { entry: ret void } -; OPT: weak_odr void @linkonceodrfuncInSingleModule() +; IMPORT: weak_odr void @linkonceodrfuncInSingleModule() define linkonce_odr void @linkonceodrfuncInSingleModule() #0 { entry: ret void