From 17a6e72a3e5932e3370823776cd03d6fe078358f Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 6 Oct 2025 15:08:24 -0700 Subject: [PATCH 1/3] [Embeddedd] Protocol conformance tables have nonunique definitions Fixes rdar://162071487. --- lib/IRGen/Linking.cpp | 7 +++++ test/embedded/linkage/diamond.swift | 28 ++++++++++++++++++ test/embedded/linkage/leaf_application.swift | 30 ++++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/lib/IRGen/Linking.cpp b/lib/IRGen/Linking.cpp index 0baac699309eb..e9323b7285576 100644 --- a/lib/IRGen/Linking.cpp +++ b/lib/IRGen/Linking.cpp @@ -1757,5 +1757,12 @@ bool LinkEntity::hasNonUniqueDefinition() const { return true; } + // Always treat witness tables as having non-unique definitions. + if (getKind() == Kind::ProtocolWitnessTable) { + if (auto context = getDeclContextForEmission()) + if (context->getParentModule()->getASTContext().LangOpts.hasFeature(Feature::Embedded)) + return true; + } + return false; } diff --git a/test/embedded/linkage/diamond.swift b/test/embedded/linkage/diamond.swift index b3a0031a82b90..753d035799a62 100644 --- a/test/embedded/linkage/diamond.swift +++ b/test/embedded/linkage/diamond.swift @@ -86,6 +86,25 @@ public func getPointOffsets() -> [Int] { enumerateByteOffsets(Point.self) } +public class PointClass { + public var x, y: Int + + public init(x: Int, y: Int) { + self.x = x + self.y = y + } +} + +public protocol Reflectable: AnyObject { + func reflect() +} + +extension PointClass: Reflectable { + public func reflect() { + swap(&x, &y) + } +} + //--- ClientA.swift import Root @@ -99,6 +118,10 @@ public func getPointAndColorOffsets() -> [Int] { getPointOffsets() + enumerateByteOffsets(Color.self) } +public func getReflectableA() -> any AnyObject & Reflectable { + return PointClass(x: 5, y: 5) +} + //--- ClientB.swift import Root @@ -112,6 +135,10 @@ public func getExtraPoint3DOffsets() -> [Int] { return Array(point3DOffsets[pointOffsets.count...]) } +public func getReflectableB() -> any AnyObject & Reflectable { + return PointClass(x: 5, y: 5) +} + //--- Application.swift import ClientA import ClientB @@ -124,6 +151,7 @@ struct Main { print(pointAndColorOffsets.count) print(extraColor3DOffsets.count) + let reflected = [getReflectableA(), getReflectableB()] // CHECK: DONE print("DONE") } diff --git a/test/embedded/linkage/leaf_application.swift b/test/embedded/linkage/leaf_application.swift index 9087abc5ceb4b..cd14d630287d6 100644 --- a/test/embedded/linkage/leaf_application.swift +++ b/test/embedded/linkage/leaf_application.swift @@ -21,6 +21,8 @@ //--- Library.swift +// LIBRARY-IR: @"$e7Library10PointClassCN" = weak_odr global + // Never referenced. // LIBRARY-IR-NOT: @"$es23_swiftEmptyArrayStorageSi_S3itvp" = weak_odr {{(protected |dllexport )?}}global @@ -54,6 +56,34 @@ public func unnecessary() -> Int64 { 5 } @_neverEmitIntoClient public func unusedYetThere() -> Int64 { 5 } +public class PointClass { + public var x, y: Int + + public init(x: Int, y: Int) { + self.x = x + self.y = y + } +} + +public protocol Reflectable: AnyObject { + func reflect() +} + +// LIBRARY-IR: define linkonce_odr hidden swiftcc void @"$es4swapyyxz_xztlFSi_Tg5" +// LIBRARY-IR: define linkonce_odr hidden swiftcc void @"$e7Library10PointClassCAA11ReflectableA2aDP7reflectyyFTW" + +extension PointClass: Reflectable { + public func reflect() { + swap(&x, &y) + } +} + +// LIBRARY-IR: define {{.*}} @"$e7Library18createsExistentialAA11Reflectable_pyF"() +@_neverEmitIntoClient +public func createsExistential() -> any Reflectable { + return PointClass(x: 5, y: 5) +} + // LIBRARY-IR-NOT: define swiftcc // LIBRARY-IR-NOT: define hidden swiftcc From 69717bd8c867750250669a4ff5c01832786c56b1 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Mon, 6 Oct 2025 19:43:46 -0700 Subject: [PATCH 2/3] Fixup test for Linux --- test/embedded/linkage/leaf_application.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/embedded/linkage/leaf_application.swift b/test/embedded/linkage/leaf_application.swift index cd14d630287d6..165de44b21ea3 100644 --- a/test/embedded/linkage/leaf_application.swift +++ b/test/embedded/linkage/leaf_application.swift @@ -21,7 +21,7 @@ //--- Library.swift -// LIBRARY-IR: @"$e7Library10PointClassCN" = weak_odr global +// LIBRARY-IR: @"$e7Library10PointClassCN" = weak_odr {{.*}}global // Never referenced. // LIBRARY-IR-NOT: @"$es23_swiftEmptyArrayStorageSi_S3itvp" = weak_odr {{(protected |dllexport )?}}global From 4952a2c9efb45c75e874d4f4b42b3a40c72b5a0d Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Tue, 7 Oct 2025 14:57:31 -0700 Subject: [PATCH 3/3] [Embedded] Prefer linkonce_odr to weak_odr for nonunique definitions This allows the implementation to drop definitions that it does need. --- include/swift/SIL/SILFunction.h | 4 ++++ lib/IRGen/GenDecl.cpp | 11 ++++++++--- lib/SIL/IR/SILFunction.cpp | 11 +++++++---- test/embedded/linkage/leaf_application.swift | 6 +++--- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/include/swift/SIL/SILFunction.h b/include/swift/SIL/SILFunction.h index 881e2c093d564..aeaeb6c8d7bd8 100644 --- a/include/swift/SIL/SILFunction.h +++ b/include/swift/SIL/SILFunction.h @@ -930,6 +930,10 @@ class SILFunction /// function, such as swift_retain. bool isSwiftRuntimeFunction() const; + /// Helper method that determines whether a function with the given name and + /// parent module is a Swift runtime function such as swift_retain. + static bool isSwiftRuntimeFunction(StringRef name, const ModuleDecl *module); + /// Helper method which returns true if the linkage of the SILFunction /// indicates that the object's definition might be required outside the /// current SILModule. diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index 41f0e9a266591..c0e262d6ba87b 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -2329,8 +2329,13 @@ getIRLinkage(StringRef name, const UniversalLinkageInfo &info, case SILLinkage::Package: { auto linkage = llvm::GlobalValue::ExternalLinkage; - if (hasNonUniqueDefinition) - linkage = llvm::GlobalValue::WeakODRLinkage; + if (hasNonUniqueDefinition) { + // Keep Swift runtime functions around so IRGen can reference them. + if (SILFunction::isSwiftRuntimeFunction(name, nullptr)) + linkage = llvm::GlobalValue::WeakODRLinkage; + else + linkage = llvm::GlobalValue::LinkOnceODRLinkage; + } return {linkage, PublicDefinitionVisibility, info.Internalize ? llvm::GlobalValue::DefaultStorageClass @@ -2348,7 +2353,7 @@ getIRLinkage(StringRef name, const UniversalLinkageInfo &info, case SILLinkage::Hidden: if (hasNonUniqueDefinition) - return RESULT(WeakODR, Hidden, Default); + return RESULT(LinkOnceODR, Hidden, Default); return RESULT(External, Hidden, Default); diff --git a/lib/SIL/IR/SILFunction.cpp b/lib/SIL/IR/SILFunction.cpp index 69e1d4793c999..bf1d41eaf903a 100644 --- a/lib/SIL/IR/SILFunction.cpp +++ b/lib/SIL/IR/SILFunction.cpp @@ -1038,17 +1038,20 @@ bool SILFunction::hasValidLinkageForFragileRef(SerializedKind_t callerSerialized return hasPublicOrPackageVisibility(getLinkage(), /*includePackage*/ true); } -bool SILFunction::isSwiftRuntimeFunction() const { - if (!getName().starts_with("swift_") && - !getName().starts_with("_swift_")) +bool SILFunction::isSwiftRuntimeFunction( + StringRef name, const ModuleDecl *module) { + if (!name.starts_with("swift_") && !name.starts_with("_swift_")) return false; - auto module = getParentModule(); return !module || module->getName().str() == "Swift" || module->getName().str() == "_Concurrency"; } +bool SILFunction::isSwiftRuntimeFunction() const { + return isSwiftRuntimeFunction(getName(), getParentModule()); +} + bool SILFunction::isPossiblyUsedExternally() const { auto linkage = getLinkage(); diff --git a/test/embedded/linkage/leaf_application.swift b/test/embedded/linkage/leaf_application.swift index 165de44b21ea3..40c8a83b0fb30 100644 --- a/test/embedded/linkage/leaf_application.swift +++ b/test/embedded/linkage/leaf_application.swift @@ -21,13 +21,13 @@ //--- Library.swift -// LIBRARY-IR: @"$e7Library10PointClassCN" = weak_odr {{.*}}global +// LIBRARY-IR: @"$e7Library10PointClassCN" = linkonce_odr {{.*}}global // Never referenced. -// LIBRARY-IR-NOT: @"$es23_swiftEmptyArrayStorageSi_S3itvp" = weak_odr {{(protected |dllexport )?}}global +// LIBRARY-IR-NOT: @"$es23_swiftEmptyArrayStorageSi_S3itvp" = linkonce_odr {{(protected |dllexport )?}}global // Note: referenced by swift_allocEmptyBox. -// LIBRARY-IR: @"$es16_emptyBoxStorageSi_Sitvp" = weak_odr {{(protected |dllexport )?}}global +// LIBRARY-IR: @"$es16_emptyBoxStorageSi_Sitvp" = linkonce_odr {{(protected |dllexport )?}}global // LIBRARY-IR-NOT: define {{.*}}@"$e7Library5helloSaySiGyF"() public func hello() -> [Int] {