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 @@ -2,3 +2,6 @@ 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,35 @@ ; 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() +; 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: define available_externally hidden void @f() +; OPT: declare extern_weak hidden void @h() + +; The prevailing copy must be converted to 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 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 @@ -759,8 +759,24 @@ 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 non-comdat + // 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. + // FIXME: For can preempted Comdat members be dropped from their + // Comdat so they can use available_externally linkage? + if (options::thinlto && !GV->hasComdat() && + // 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())) + GV->setLinkage(GlobalValue::AvailableExternallyLinkage); break; case LDPR_UNDEF: