diff --git a/include/swift/IRGen/Linking.h b/include/swift/IRGen/Linking.h index 7570d5ac7c3fd..d60a3d977d90f 100644 --- a/include/swift/IRGen/Linking.h +++ b/include/swift/IRGen/Linking.h @@ -1886,7 +1886,7 @@ class ApplyIRLinkage { IRLinkage IRL; public: ApplyIRLinkage(IRLinkage IRL) : IRL(IRL) {} - void to(llvm::GlobalValue *GV, bool definition = true) const { + void to(llvm::GlobalValue *GV, bool nonAliasedDefinition = true) const { llvm::Module *M = GV->getParent(); const llvm::Triple Triple(M->getTargetTriple()); @@ -1899,9 +1899,16 @@ class ApplyIRLinkage { if (Triple.isOSBinFormatELF()) return; - // COMDATs cannot be applied to declarations. If we have a definition, - // apply the COMDAT. - if (definition) + // COMDATs cannot be applied to declarations. Also, definitions that are + // exported through aliases should not have COMDATs, because the alias + // itself might represent an externally visible symbol but such symbols + // are discarded from the symtab when other object files have a COMDAT + // group with the same signature. + // + // If we have a non-aliased definition with ODR-based linkage, attach it + // to a COMDAT group so that duplicate definitions across object files + // can be merged by the linker. + if (nonAliasedDefinition) if (IRL.Linkage == llvm::GlobalValue::LinkOnceODRLinkage || IRL.Linkage == llvm::GlobalValue::WeakODRLinkage) if (Triple.supportsCOMDAT()) diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index cf41c9e353d0c..971fbc1edeb0f 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -2201,7 +2201,7 @@ void IRGenModule::emitVTableStubs() { &Module); ApplyIRLinkage(canLinkOnce ? IRLinkage::InternalLinkOnceODR : IRLinkage::Internal) - .to(stub); + .to(stub, /* nonAliasedDefinition */ false); stub->setAttributes(constructInitialAttributes()); stub->setCallingConv(DefaultCC); auto *entry = llvm::BasicBlock::Create(getLLVMContext(), "entry", stub); diff --git a/test/IRGen/dead-stub-method-dedup.swift b/test/IRGen/dead-stub-method-dedup.swift new file mode 100644 index 0000000000000..c5d75dddaa34f --- /dev/null +++ b/test/IRGen/dead-stub-method-dedup.swift @@ -0,0 +1,42 @@ +// RUN: %empty-directory(%t) +// RUN: split-file --leading-lines %s %t + +// Note: IRGen uses internal linkage instead of linkonce_odr only for COFF for dead stub methods. +// UNSUPPORTED: OS=windows-msvc + +// Ensure that swift_dead_method_stub is emitted without comdat linkage +// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -parse-as-library -O -module-name A -c -primary-file %t/A.swift %t/B.swift -emit-ir -o - | %FileCheck %s -check-prefix CHECK +// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -parse-as-library -O -module-name A -c %t/A.swift -primary-file %t/B.swift -emit-ir -o - | %FileCheck %s -check-prefix CHECK + +// CHECK-LABEL: define {{(linkonce_odr )?}}hidden void @_swift_dead_method_stub( +// CHECK-NOT: comdat +// CHECK: { + + +// Ensure that link-time deduplication for swift_dead_method_stub works correctly +// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -parse-as-library -O -module-name A -c -primary-file %t/A.swift %t/B.swift -o %t/A.swift.o +// RUN: %target-swift-frontend -target %target-swift-5.1-abi-triple -parse-as-library -O -module-name A -c %t/A.swift -primary-file %t/B.swift -o %t/B.swift.o +// RUN: %target-build-swift -target %target-swift-5.1-abi-triple %t/B.swift.o %t/A.swift.o -o %t/a.out + +//--- A.swift + +// Define an open class with a dead vtable entry +class C1 { + private func dead() {} +} + +//--- B.swift + +class C2: C1 { + // Define another dead vtable entry to ensure that this object file + // also should have dead vtable stub definition + private func beef() {} +} + +@main +struct Entry { + static func main() { + _ = C2() + } +} +