Skip to content

Commit 81dfb75

Browse files
committed
[embedded] Apply shared linkage to metadata of public types in embedded with existential mode
We generate public metadata lazily which implies it could be emitted into a different module. If we emit metadata for a public type into a module other than its "home module" apply "shared" linkage.
1 parent 93ab162 commit 81dfb75

File tree

2 files changed

+132
-5
lines changed

2 files changed

+132
-5
lines changed

lib/IRGen/Linking.cpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,21 @@ SILDeclRef LinkEntity::getSILDeclRef() const {
629629
return ref;
630630
}
631631

632+
static bool isLazyEmissionOfPublicSymbolInMultipleModulesPossible(CanType ty) {
633+
// In embedded existenitals mode we generate lazy public metadata on demand
634+
// which makes it non unique.
635+
if (ty->getASTContext().LangOpts.hasFeature(Feature::EmbeddedExistentials)) {
636+
if (auto nominal = ty->getAnyNominal()) {
637+
if (SILDeclRef::declHasNonUniqueDefinition(nominal)) {
638+
return true;
639+
}
640+
} else {
641+
return true;
642+
}
643+
}
644+
return false;
645+
}
646+
632647
SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const {
633648
// For when `this` is a protocol conformance of some kind.
634649
auto getLinkageAsConformance = [&] {
@@ -658,6 +673,11 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const {
658673
case Kind::ValueWitnessTable: {
659674
auto type = getType();
660675

676+
// In embedded existenitals mode we generate lazy public metadata on demand
677+
// which makes it non unique.
678+
if (isLazyEmissionOfPublicSymbolInMultipleModulesPossible(type))
679+
return SILLinkage::Shared;
680+
661681
// Builtin types, (), () -> () and so on are in the runtime.
662682
if (!type.getAnyNominal())
663683
return getSILLinkage(FormalLinkage::PublicUnique, forDefinition);
@@ -696,12 +716,10 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const {
696716
if (isForcedShared())
697717
return SILLinkage::Shared;
698718

699-
// In embedded existenitals mode we generate metadata for tuple types.
700-
if (getType()->getASTContext().LangOpts.hasFeature(Feature::EmbeddedExistentials) &&
701-
(isa<TupleType>(getType()) ||
702-
isa<FunctionType>(getType()))) {
719+
// In embedded existenitals mode we generate lazy public metadata on demand
720+
// which makes it non unique.
721+
if (isLazyEmissionOfPublicSymbolInMultipleModulesPossible(getType()))
703722
return SILLinkage::Shared;
704-
}
705723

706724
auto *nominal = getType().getAnyNominal();
707725
switch (getMetadataAddress()) {

test/embedded/lazy_metadata.swift

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend -wmo -module-name A -emit-irgen -o %t/A1.ll %t/A.swift -enable-experimental-feature Embedded -enable-experimental-feature EmbeddedExistentials -parse-as-library
5+
// RUN: %FileCheck --check-prefix=A1 %s < %t/A1.ll
6+
7+
// RUN: %target-swift-frontend -wmo -module-name A -num-threads 1 -emit-ir -o %t/A2.ll -o %t/B2.ll %t/A.swift %t/B.swift -enable-experimental-feature Embedded -enable-experimental-feature EmbeddedExistentials -parse-as-library
8+
// RUN: %FileCheck --check-prefix=A2 %s < %t/A2.ll
9+
// RUN: %FileCheck --check-prefix=B2 %s < %t/B2.ll
10+
11+
// RUN: %target-swift-frontend -emit-module -emit-module-path %t/A.swiftmodule -wmo -module-name A -emit-ir -o %t/A3.ll %t/A.swift %t/B.swift -enable-experimental-feature Embedded -enable-experimental-feature EmbeddedExistentials -parse-as-library
12+
// RUN: %FileCheck --check-prefix=A3 %s < %t/A3.ll
13+
14+
// RUN: %target-swift-frontend -wmo -I %t -module-name C -emit-irgen -o %t/C4.ll %t/C.swift -enable-experimental-feature Embedded -enable-experimental-feature EmbeddedExistentials -parse-as-library
15+
// RUN: %FileCheck --check-prefix=C4 %s < %t/C4.ll
16+
17+
// REQUIRES: swift_in_compiler
18+
// REQUIRES: optimized_stdlib
19+
// REQUIRES: swift_feature_Embedded
20+
// REQUIRES: swift_feature_EmbeddedExistentials
21+
22+
23+
//--- A.swift
24+
public class SomeClass {
25+
}
26+
27+
public struct SomeStruct {
28+
var x = 1
29+
var y = 2
30+
}
31+
32+
public enum SomeEnum {
33+
case a(Int)
34+
case b(Float)
35+
}
36+
37+
//--- B.swift
38+
public func getSomeClass() -> SomeClass {
39+
return SomeClass()
40+
}
41+
42+
public func getSomeStructAsAny() -> Any {
43+
return SomeStruct()
44+
}
45+
46+
public func getSomeStruct() -> SomeStruct {
47+
return SomeStruct()
48+
}
49+
50+
public func getSomeEnumAsAny() -> Any {
51+
return SomeEnum.a(1)
52+
}
53+
54+
public func getSomeEnum()-> SomeEnum {
55+
return SomeEnum.b(2.0)
56+
}
57+
58+
//--- C.swift
59+
import A
60+
public func useMetadata() -> Any {
61+
return getSomeClass()
62+
}
63+
64+
public func useMetadata2() -> Any {
65+
return getSomeStruct()
66+
}
67+
68+
public func useMetadata3() -> Any {
69+
return getSomeEnum()
70+
}
71+
72+
// Test no reference of metadata.
73+
// A1-NOT: CMf
74+
75+
// Test reference of metadata. Because we are the defining module metadata is
76+
// visible outside of the image per current policy.
77+
// In multiple llvm modules per SIL module mode "Private" SIL linkage becomes
78+
// hidden linkonce_odr.
79+
// A2: @"$e1A8SomeEnumOMf" = linkonce_odr hidden constant
80+
// A2: @"$e1A10SomeStructVMf" = linkonce_odr hidden constant
81+
// A2: @"$e1A9SomeClassCMf" = linkonce_odr hidden global
82+
83+
// A2: @"$e1A8SomeEnumON" = alias{{.*}}e1A8SomeEnumOMf
84+
// A2: @"$e1A10SomeStructVN" = alias{{.*}}e1A10SomeStructVMf
85+
// A2: @"$e1A9SomeClassCN" = alias{{.*}}e1A9SomeClassCMf
86+
87+
// B2: @"$e1A9SomeClassCN" = {{.*}}external{{.*}} global
88+
// B2: @"$e1A10SomeStructVN" = {{.*}}external{{.*}} global
89+
// B2: @"$e1A8SomeEnumON" = {{.*}}external{{.*}} global
90+
// B2: call {{.*}} @"$e1A9SomeClassCACycfC"(ptr swiftself @"$e1A9SomeClassCN")
91+
// B2: store{{.*}}e1A10SomeStructVN
92+
// B2: store{{.*}}e1A8SomeEnumON
93+
94+
// Test reference of metadata. Because we are the defining module metadata is
95+
// visible outside of the image per current policy.
96+
// In single llvm module per SIL module "Private" SIL linkage makes more
97+
// intuitive sense.
98+
// A3: @"$e1A8SomeEnumOMf" = internal constant
99+
// A3: @"$e1A10SomeStructVMf" = internal constant
100+
// A3: @"$e1A9SomeClassCMf" = internal global
101+
// A3: @"$e1A9SomeClassCN" = alias{{.*}}e1A9SomeClassCMf
102+
// A3: call {{.*}} @"$e1A9SomeClassCACycfC"({{.*}}getelementptr{{.*}}@"$e1A9SomeClassCMf"
103+
104+
105+
// Test "external" reference of metadata (defines metadata from another module
106+
// in current module as linkonce).
107+
// C4: @"$e1A8SomeEnumOMf" = linkonce_odr hidden constant
108+
// C4: @"$e1A10SomeStructVMf" = linkonce_odr hidden constant
109+
// C4: @"$e1A9SomeClassCMf" = linkonce_odr hidden global

0 commit comments

Comments
 (0)