Index: test/tools/gold/X86/Inputs/thinlto_linkonceresolution.ll =================================================================== --- test/tools/gold/X86/Inputs/thinlto_linkonceresolution.ll +++ test/tools/gold/X86/Inputs/thinlto_linkonceresolution.ll @@ -1,4 +1,11 @@ target triple = "x86_64-unknown-linux-gnu" +@analias = linkonce_odr alias void (), void ()* @analiasee +define linkonce_odr hidden void @analiasee() { + ret void +} define linkonce_odr hidden void @f() { ret void } +define linkonce hidden void @h() { + ret void +} Index: test/tools/gold/X86/Inputs/thinlto_weakresolution.ll =================================================================== --- /dev/null +++ test/tools/gold/X86/Inputs/thinlto_weakresolution.ll @@ -0,0 +1,7 @@ +target triple = "x86_64-unknown-linux-gnu" +define weak_odr hidden void @f() { + ret void +} +define weak hidden void @h() { + ret void +} Index: test/tools/gold/X86/thinlto_linkonceresolution.ll =================================================================== --- test/tools/gold/X86/thinlto_linkonceresolution.ll +++ test/tools/gold/X86/thinlto_linkonceresolution.ll @@ -11,22 +11,47 @@ ; RUN: --plugin-opt=thinlto \ ; RUN: --plugin-opt=-import-instr-limit=0 \ ; RUN: --plugin-opt=save-temps \ +; RUN: --plugin-opt=O0 \ ; RUN: -o %t3.o %t2.o %t.o ; RUN: llvm-nm %t3.o | FileCheck %s ; RUN: llvm-dis %t.o.opt.bc -o - | FileCheck --check-prefix=OPT %s ; RUN: llvm-dis %t2.o.opt.bc -o - | FileCheck --check-prefix=OPT2 %s -; Ensure that f() is defined in resulting object file, and also -; confirm the weak linkage directly in the saved opt bitcode files. +; Ensure that f() and h() are defined in resulting object file. ; CHECK-NOT: U f -; OPT: declare extern_weak hidden void @f() -; OPT2: define weak_odr hidden void @f() +; CHECK-NOT: U h + +; The non-prevailing copy can be changed to available_externally in the +; linkonce_odr case, but must remain linkonce in the non-ODR case (which +; is eventually changed to an extern_weak declaration). +; OPT-DAG: define available_externally hidden void @f() +; OPT-DAG: declare extern_weak hidden void @h() +; Cannot convert alias or aliasee to available_externally (not a valid +; linkage type for alias, aliasee must be real definition for linker). +; OPT-DAG: @analias = extern_weak global void () +; OPT-DAG: declare extern_weak hidden void @analiasee() + +; The prevailing copy must be converted to weak so that it is kept. +; OPT2-DAG: define weak_odr hidden void @f() +; OPT2-DAG: define weak hidden void @h() +; OPT2-DAG: @analias = weak_odr alias void (), void ()* @analiasee +; OPT2-DAG: define weak_odr hidden void @analiasee() target triple = "x86_64-unknown-linux-gnu" define i32 @g() { call void @f() + call void @h() + call void @analias() + call void @analiasee() ret i32 0 } +@analias = linkonce_odr alias void (), void ()* @analiasee +define linkonce_odr hidden void @analiasee() { + ret void +} define linkonce_odr hidden void @f() { ret void } +define linkonce hidden void @h() { + ret void +} Index: test/tools/gold/X86/thinlto_weakresolution.ll =================================================================== --- /dev/null +++ test/tools/gold/X86/thinlto_weakresolution.ll @@ -0,0 +1,46 @@ +; RUN: llvm-as -module-summary %s -o %t.o +; RUN: llvm-as -module-summary %p/Inputs/thinlto_weakresolution.ll -o %t2.o + +; Check that for ThinLTO the plugin converts the preempted copy of a +; weak symbol to available_externally if it is weak_odr, or leaves it +; alone in the non-ODR case. +; Note that gold picks the first copy of f() as the prevailing one, +; so listing %t2.o first is sufficient to ensure that this copy is +; preempted. Also, set the import-instr-limit to 0 to prevent any effects +; from importing. +; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold.so \ +; RUN: --plugin-opt=thinlto \ +; RUN: --plugin-opt=-import-instr-limit=0 \ +; RUN: --plugin-opt=save-temps \ +; RUN: --plugin-opt=O0 \ +; RUN: -o %t3.o %t2.o %t.o +; RUN: llvm-nm %t3.o | FileCheck %s +; RUN: llvm-dis %t.o.opt.bc -o - | FileCheck --check-prefix=OPT %s +; RUN: llvm-dis %t2.o.opt.bc -o - | FileCheck --check-prefix=OPT2 %s + +; Ensure that f() and h() are defined in resulting object file. +; CHECK-NOT: U f +; CHECK-NOT: U h + +; The non-prevailing copy can be changed to available_externally in the +; weak_odr case, but must remain weak in the non-ODR case (which +; is eventually changed to an extern_weak declaration). +; OPT: define available_externally hidden void @f() +; OPT: declare extern_weak hidden void @h() + +; The prevailing copy remains weak so that it is kept. +; OPT2: define weak_odr hidden void @f() +; OPT2: define weak hidden void @h() + +target triple = "x86_64-unknown-linux-gnu" +define i32 @g() { + call void @f() + call void @h() + ret i32 0 +} +define weak_odr hidden void @f() { + ret void +} +define weak hidden void @h() { + ret void +} Index: tools/gold/gold-plugin.cpp =================================================================== --- tools/gold/gold-plugin.cpp +++ tools/gold/gold-plugin.cpp @@ -678,12 +678,18 @@ SmallPtrSet Used; collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false); + DenseSet Aliasees; + DenseSet PossibleAvailableExternally; + unsigned SymNum = 0; for (auto &ObjSym : Obj.symbols()) { GlobalValue *GV = Obj.getSymbolGV(ObjSym.getRawDataRefImpl()); if (GV && GV->hasAppendingLinkage()) Keep.push_back(GV); + if (auto *GA = dyn_cast(GV)) + Aliasees.insert(GA->getBaseObject()); + if (shouldSkip(ObjSym.getFlags())) continue; ld_plugin_symbol &Sym = F.syms[SymNum]; @@ -759,8 +765,26 @@ case LDPR_RESOLVED_IR: case LDPR_RESOLVED_EXEC: case LDPR_RESOLVED_DYN: + break; + case LDPR_PREEMPTED_IR: case LDPR_PREEMPTED_REG: + // For ThinLTO we can change the linkage type of preempted + // symbols to available_externally so that they can be dropped during + // the ThinLTO backend compile step. This is unnecessary for full LTO + // where all copies will be merged into a single one. Note that we + // already ensure the prevailing copy gets weak linkage in the ThinLTO + // so that it isn't eliminated if unreferenced in its module. + if (options::thinlto && + // Can't do this for WeakAny/LinkOnceAny since they may be overridden + // and are thus ineligible for optimizations such as being inlined. + // FIXME: In the non-ODR case drop the definitions. + (GV->hasWeakODRLinkage() || GV->hasLinkOnceODRLinkage()) && + // Alias can't be available_externally. + // FIXME: Turn the alias into a global and duplicate the definition. + !isa(GV)) + // Convert later if this is not found to be an aliasee. + PossibleAvailableExternally.insert(GV); break; case LDPR_UNDEF: @@ -806,6 +830,20 @@ freeSymName(Sym); } + // Convert to available_externally when not found to be an aliasee. + // FIXME: Turn the alias into a global and duplicate the definition. + for (auto *GV : PossibleAvailableExternally) { + if (Aliasees.count(GV)) + continue; + + GV->setLinkage(GlobalValue::AvailableExternallyLinkage); + + if (!GV->hasComdat()) + continue; + if (auto *GO = dyn_cast(GV)) + GO->setComdat(nullptr); + } + return Obj.takeModule(); }