Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1644,8 +1644,11 @@ const TargetLoweringObjectFile &Obj = getObjFileLowering(); const MCSymbol *KeySym = nullptr; if (GlobalValue *GV = S.ComdatKey) { - if (GV->hasAvailableExternallyLinkage()) - // If the associated variable is available_externally, some other TU + if (GV->isDeclarationForLinker()) + // If the associated variable is not defined in this module + // (it might be available_externally, or have been an + // available_externally definition that was dropped by the + // EliminateAvailableExternally pass), some other TU // will provide its dynamic initializer. continue; Index: test/ThinLTO/X86/Inputs/linkonce_comdat.ll =================================================================== --- /dev/null +++ test/ThinLTO/X86/Inputs/linkonce_comdat.ll @@ -0,0 +1,20 @@ +; ModuleID = 'thinlto_linkonce_comdat1.o' +source_filename = "thinlto_linkonce_comdat1.c" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@fv = linkonce_odr global i8 0, align 8 + +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__cxx_global_var_init.33, i8* @fv }] + +; Function Attrs: nounwind uwtable +define internal void @__cxx_global_var_init.33() section ".text.startup" { + store i8 1, i8* @fv, align 8 + ret void +} + +; Function Attrs: norecurse nounwind readnone uwtable +define void @test1() local_unnamed_addr { +entry: + ret void +} Index: test/ThinLTO/X86/linkonce_comdat.ll =================================================================== --- /dev/null +++ test/ThinLTO/X86/linkonce_comdat.ll @@ -0,0 +1,58 @@ +; Test to ensure that a global constructor and associated comdat isn't +; created when ThinLTO has dropped the non-prevailing copy of a +; linkonce_odr (otherwise we will end up with an incomplete comdat +; group). + +; 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/linkonce_comdat.ll -o %t2.bc +; RUN: llvm-lto -thinlto-action=thinlink -o %t3.bc %t1.bc %t2.bc + +; RUN: llvm-lto -thinlto-action=run -exported-symbol=main -exported-symbol=fv %t1.bc %t2.bc +; RUN: llvm-readobj -elf-section-groups %t1.bc.thinlto.o | FileCheck %s --check-prefix=OBJ1 +; RUN: llvm-readobj -elf-section-groups %t2.bc.thinlto.o | FileCheck %s --check-prefix=OBJ2 + +; RUN: llvm-lto2 %t1.bc %t2.bc -o %t.o -save-temps \ +; RUN: -r=%t1.bc,fv,plx \ +; RUN: -r=%t1.bc,test1,l \ +; RUN: -r=%t1.bc,main,plx \ +; RUN: -r=%t2.bc,fv,lx \ +; RUN: -r=%t2.bc,test1,pl +; RUN: llvm-readobj -elf-section-groups %t.o.0 | FileCheck %s --check-prefix=OBJ1 +; RUN: llvm-readobj -elf-section-groups %t.o.1 | FileCheck %s --check-prefix=OBJ2 + +; The prevailing copy in %t1 should result in a complete comdat group. +; OBJ1: Group { +; OBJ1: Signature: fv +; OBJ1: Section(s) in group [ +; OBJ1: .init_array +; OBJ1: .rela.init_array + +; We should not generate a comdat group in the object for %t2, even +; though it originally had an entry in the global_ctors list that +; would result in creation of a comdat group (unless those that become +; declarations are not properly ignored). +; OBJ2: There are no group sections in the file. + +; ModuleID = 'thinlto_linkonce_comdat.o' +source_filename = "thinlto_linkonce_comdat.c" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@fv = linkonce_odr global i8 0, align 8 + +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__cxx_global_var_init.34, i8* @fv }] + +define internal void @__cxx_global_var_init.34() section ".text.startup" { + store i8 1, i8* @fv, align 8 + ret void +} + +declare void @test1(...) local_unnamed_addr + +; Function Attrs: nounwind uwtable +define i32 @main() local_unnamed_addr { +entry: + tail call void (...) @test1() + ret i32 0 +} Index: test/tools/gold/X86/Inputs/thinlto_linkonce_comdat1.ll =================================================================== --- /dev/null +++ test/tools/gold/X86/Inputs/thinlto_linkonce_comdat1.ll @@ -0,0 +1,20 @@ +; ModuleID = 'thinlto_linkonce_comdat1.c' +source_filename = "thinlto_linkonce_comdat1.c" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@fv = linkonce_odr global i8 0, align 8 + +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__cxx_global_var_init.33, i8* @fv }] + +; Function Attrs: nounwind uwtable +define internal void @__cxx_global_var_init.33() section ".text.startup" { + store i8 1, i8* @fv, align 8 + ret void +} + +; Function Attrs: norecurse nounwind readnone uwtable +define void @test1() local_unnamed_addr { +entry: + ret void +} Index: test/tools/gold/X86/Inputs/thinlto_linkonce_comdat2.ll =================================================================== --- /dev/null +++ test/tools/gold/X86/Inputs/thinlto_linkonce_comdat2.ll @@ -0,0 +1,22 @@ +; ModuleID = 'thinlto_linkonce_comdat2.c' +source_filename = "thinlto_linkonce_comdat2.c" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@fv = linkonce_odr global i8 0, align 8 + +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @__cxx_global_var_init.34, i8* @fv }] + +define internal void @__cxx_global_var_init.34() section ".text.startup" { + store i8 1, i8* @fv, align 8 + ret void +} + +; Function Attrs: nounwind uwtable +define void @test2() local_unnamed_addr { +entry: + tail call void (...) @test1() + ret void +} + +declare void @test1(...) local_unnamed_addr Index: test/tools/gold/X86/thinlto_linkonce_comdat.ll =================================================================== --- /dev/null +++ test/tools/gold/X86/thinlto_linkonce_comdat.ll @@ -0,0 +1,51 @@ +; Test to ensure that a global constructor and associated comdat isn't +; created when ThinLTO has dropped the non-prevailing copy of a +; linkonce_odr (otherwise we will end up with an incomplete comdat +; group, which can override the intended complete comdat in the prevailing +; module). + +; First generate bitcode with a module summary index for each file +; RUN: opt -module-summary %s -o %t.o +; RUN: opt -module-summary %p/Inputs/thinlto_linkonce_comdat1.ll -o %t2.o +; RUN: opt -module-summary %p/Inputs/thinlto_linkonce_comdat2.ll -o %t3.o + +; Although the objects are ordered "%t2.o %t3.o" in the library, the +; linker selects %t3.o first since it satisfies a strong reference from +; %t.o. It later selects %t2.o based on the strong ref from %t3.o. +; Therefore, %t3.o's copy of @f is prevailing. +; RUN: %gold -plugin %llvmshlibdir/LLVMgold.so \ +; RUN: --plugin-opt=thinlto \ +; RUN: --plugin-opt=save-temps \ +; RUN: -m elf_x86_64 \ +; RUN: -o %t4 \ +; RUN: %t.o \ +; RUN: --start-lib %t2.o %t3.o --end-lib + +; We should not generate a comdat group in the object for %t2, even +; though it originally had an entry in the global_ctors list that +; would result in creation of a comdat group (unless those that become +; declarations are not properly ignored). +; RUN: llvm-readobj -elf-section-groups %t4.o1 | FileCheck %s --check-prefix=OBJ1 +; OBJ1: There are no group sections in the file. + +; The prevailing copy in %t3 should result in a complete comdat group. +; RUN: llvm-readobj -elf-section-groups %t4.o2 | FileCheck %s --check-prefix=OBJ2 +; OBJ2: Group { +; OBJ2: Signature: fv +; OBJ2: Section(s) in group [ +; OBJ2: .init_array +; OBJ2: .rela.init_array + +; ModuleID = 'thinlto_linkonce_comdat.c' +source_filename = "thinlto_linkonce_comdat.c" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: nounwind uwtable +define i32 @main() local_unnamed_addr { +entry: + tail call void (...) @test2() + ret i32 0 +} + +declare void @test2(...) local_unnamed_addr