Skip to content

Commit ada0f09

Browse files
committed
SILGen: Implement 'complete' unavailable decl optimization.
Avoid SIL lowering for declarations marked unavailable when `-unavailable-decl-optimiation=complete` is specified. Part of rdar://106674022
1 parent 7d1d7a3 commit ada0f09

File tree

7 files changed

+268
-4
lines changed

7 files changed

+268
-4
lines changed

include/swift/SIL/SILModule.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,8 +1078,22 @@ namespace Lowering {
10781078
/// Determine whether the given class will be allocated/deallocated using the
10791079
/// Objective-C runtime, i.e., +alloc and -dealloc.
10801080
LLVM_LIBRARY_VISIBILITY bool usesObjCAllocator(ClassDecl *theClass);
1081+
1082+
/// Returns true if SIL/IR lowering for the given declaration should be skipped.
1083+
/// A declaration may not require lowering if, for example, it is annotated as
1084+
/// unavailable and optimization settings allow it to be omitted.
1085+
LLVM_LIBRARY_VISIBILITY bool shouldSkipLowering(Decl *D);
10811086
} // namespace Lowering
10821087

1088+
/// Apply the given function to each ABI member of \c D skipping the members
1089+
/// that should be skipped according to \c shouldSkipLowering()
1090+
template <typename F>
1091+
void forEachMemberToLower(IterableDeclContext *D, F &&f) {
1092+
for (auto *member : D->getABIMembers()) {
1093+
if (!Lowering::shouldSkipLowering(member))
1094+
f(member);
1095+
}
1096+
}
10831097
} // namespace swift
10841098

10851099
#endif

include/swift/SIL/SILVTableVisitor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,9 @@ template <class T> class SILVTableVisitor {
141141
if (!theClass->hasKnownSwiftImplementation())
142142
return;
143143

144-
for (auto member : theClass->getABIMembers())
144+
forEachMemberToLower(theClass, [&](Decl *member) {
145145
maybeAddMember(member);
146+
});
146147
}
147148
};
148149

lib/SIL/IR/SILModule.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,3 +955,13 @@ bool Lowering::usesObjCAllocator(ClassDecl *theClass) {
955955
// allocation methods because they may have been overridden.
956956
return theClass->getObjectModel() == ReferenceCounting::ObjC;
957957
}
958+
959+
bool Lowering::shouldSkipLowering(Decl *D) {
960+
if (D->getASTContext().LangOpts.UnavailableDeclOptimizationMode !=
961+
UnavailableDeclOptimization::Complete)
962+
return false;
963+
964+
// Unavailable declarations should be skipped if
965+
// -unavailable-decl-optimization=complete is specified.
966+
return D->getSemanticUnavailableAttr() != None;
967+
}

lib/SILGen/SILGen.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,13 @@ bool SILGenModule::hasFunction(SILDeclRef constant) {
770770
return emittedFunctions.count(constant);
771771
}
772772

773+
void SILGenModule::visit(Decl *D) {
774+
if (Lowering::shouldSkipLowering(D))
775+
return;
776+
777+
ASTVisitor::visit(D);
778+
}
779+
773780
void SILGenModule::visitFuncDecl(FuncDecl *fd) { emitFunction(fd); }
774781

775782
void SILGenModule::emitFunctionDefinition(SILDeclRef constant, SILFunction *f) {

lib/SILGen/SILGen.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
266266
// Visitors for top-level forms
267267
//===--------------------------------------------------------------------===//
268268

269+
void visit(Decl *D);
270+
269271
// These are either not allowed at global scope or don't require
270272
// code emission.
271273
void visitImportDecl(ImportDecl *d) {}

lib/SILGen/SILGenType.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,8 +1085,9 @@ class SILGenType : public TypeMemberVisitor<SILGenType> {
10851085
void emitType() {
10861086
SGM.emitLazyConformancesForType(theType);
10871087

1088-
for (Decl *member : theType->getABIMembers())
1088+
forEachMemberToLower(theType, [&](Decl *member) {
10891089
visit(member);
1090+
});
10901091

10911092
// Build a vtable if this is a class.
10921093
if (auto theClass = dyn_cast<ClassDecl>(theType)) {
@@ -1252,9 +1253,10 @@ class SILGenExtension : public TypeMemberVisitor<SILGenExtension> {
12521253
// @_objcImplementation extension, but we don't actually need to do any of
12531254
// the stuff that it currently does.
12541255

1255-
for (Decl *member : e->getABIMembers())
1256+
forEachMemberToLower(e, [&](Decl *member) {
12561257
visit(member);
1257-
1258+
});
1259+
12581260
// If this is a main-interface @_objcImplementation extension and the class
12591261
// has a synthesized destructor, emit it now.
12601262
if (auto cd = dyn_cast_or_null<ClassDecl>(e->getImplementedObjCDecl())) {
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
// RUN: %target-swift-emit-silgen -module-name Test -parse-as-library %s -verify | %FileCheck %s --check-prefixes=CHECK,CHECK-NO-STRIP
2+
// RUN: %target-swift-emit-silgen -module-name Test -parse-as-library %s -verify -unavailable-decl-optimization=none | %FileCheck %s --check-prefixes=CHECK,CHECK-NO-STRIP
3+
// RUN: %target-swift-emit-silgen -module-name Test -parse-as-library %s -verify -unavailable-decl-optimization=complete | %FileCheck %s --check-prefixes=CHECK,CHECK-STRIP
4+
5+
// CHECK-NO-STRIP: s4Test14globalConstant_Wz
6+
// CHECK-NO-STRIP: s4Test14globalConstantSbvp
7+
// CHECK-NO-STRIP: s4Test14globalConstant_WZ
8+
// CHECK-NO-STRIP: s4Test14globalConstantSbvau
9+
// FIXME: global var isn't stripped
10+
// HECK-STRIP-NOT: s4Test14globalConstant_Wz
11+
// HECK-STRIP-NOT: s4Test14globalConstantSbvp
12+
// HECK-STRIP-NOT: s4Test14globalConstant_WZ
13+
// HECK-STRIP-NOT: s4Test14globalConstantSbvau
14+
@available(*, unavailable)
15+
public let globalConstant = true
16+
17+
// CHECK-NO-STRIP: s4Test15unavailableFuncyyF
18+
// CHECK-STRIP-NOT: s4Test15unavailableFuncyyF
19+
@available(*, unavailable)
20+
public func unavailableFunc() {}
21+
22+
@available(*, unavailable)
23+
public struct UnavailableStruct<T> {
24+
// CHECK-NO-STRIP: s4Test17UnavailableStructV8propertyxvg
25+
// CHECK-NO-STRIP: s4Test17UnavailableStructV8propertyxvs
26+
// CHECK-NO-STRIP: s4Test17UnavailableStructV8propertyxvM
27+
// CHECK-STRIP-NOT: s4Test17UnavailableStructV8propertyxvg
28+
// CHECK-STRIP-NOT: s4Test17UnavailableStructV8propertyxvs
29+
// CHECK-STRIP-NOT: s4Test17UnavailableStructV8propertyxvM
30+
public var property: T
31+
32+
// CHECK-NO-STRIP: s4Test17UnavailableStructVyACyxGxcfC
33+
// CHECK-STRIP-NOT: s4Test17UnavailableStructVyACyxGxcfC
34+
public init(_ t: T) {
35+
self.property = t
36+
}
37+
38+
// CHECK-NO-STRIP: s4Test17UnavailableStructV6methodyyF
39+
// CHECK-STRIP-NOT: s4Test17UnavailableStructV6methodyyF
40+
public func method() {}
41+
}
42+
43+
@available(*, unavailable)
44+
extension UnavailableStruct {
45+
// CHECK-NO-STRIP: s4Test17UnavailableStructV15extensionMethodyyF
46+
// CHECK-STRIP-NOT: s4Test17UnavailableStructV15extensionMethodyyF
47+
public func extensionMethod() {}
48+
}
49+
50+
@available(*, unavailable)
51+
public enum UnavailableEnum {
52+
case a, b
53+
54+
// CHECK-NO-STRIP: s4Test15UnavailableEnumO6methodyyF
55+
// CHECK-STRIP-NOT: s4Test15UnavailableEnumO6methodyyF
56+
public func method() {}
57+
}
58+
59+
@available(*, unavailable)
60+
public class UnavailableClass<T> {
61+
// CHECK-NO-STRIP: s4Test16UnavailableClassC8propertyxvg
62+
// CHECK-NO-STRIP: s4Test16UnavailableClassC8propertyxvs
63+
// CHECK-NO-STRIP: s4Test16UnavailableClassC8propertyxvM
64+
// CHECK-STRIP-NOT: s4Test16UnavailableClassC8propertyxvg
65+
// CHECK-STRIP-NOT: s4Test16UnavailableClassC8propertyxvs
66+
// CHECK-STRIP-NOT: s4Test16UnavailableClassC8propertyxvM
67+
public var property: T
68+
69+
// CHECK-NO-STRIP: s4Test16UnavailableClassCyACyxGxcfC
70+
// CHECK-NO-STRIP: s4Test16UnavailableClassCyACyxGxcfc
71+
// CHECK-STRIP-NOT: s4Test16UnavailableClassCyACyxGxcfC
72+
// CHECK-STRIP-NOT: s4Test16UnavailableClassCyACyxGxcfc
73+
public init(_ t: T) {
74+
self.property = t
75+
}
76+
77+
// CHECK-NO-STRIP: s4Test16UnavailableClassCfd
78+
// CHECK-NO-STRIP: s4Test16UnavailableClassCfD
79+
// CHECK-STRIP-NOT: s4Test16UnavailableClassCfd
80+
// CHECK-STRIP-NOT: s4Test16UnavailableClassCfD
81+
deinit {}
82+
}
83+
84+
public struct S<T> {
85+
// CHECK-NO-STRIP: s4Test1SV19unavailablePropertyxvg
86+
// CHECK-NO-STRIP: s4Test1SV19unavailablePropertyxvs
87+
// CHECK-NO-STRIP: s4Test1SV19unavailablePropertyxvM
88+
// CHECK-STRIP-NOT: s4Test1SV19unavailablePropertyxvg
89+
// CHECK-STRIP-NOT: s4Test1SV19unavailablePropertyxvs
90+
// CHECK-STRIP-NOT: s4Test1SV19unavailablePropertyxvM
91+
@available(*, unavailable)
92+
public var unavailableProperty: T
93+
94+
// CHECK-NO-STRIP: s4Test1SVyACyxGxcfC
95+
// CHECK-STRIP-NOT: s4Test1SVyACyxGxcfC
96+
@available(*, unavailable)
97+
public init(_ t: T) {}
98+
99+
// CHECK-NO-STRIP: s4Test1SV17unavailableMethodyyF
100+
// CHECK-STRIP-NOT: s4Test1SV17unavailableMethodyyF
101+
@available(*, unavailable)
102+
public func unavailableMethod() {}
103+
}
104+
105+
@available(*, unavailable)
106+
extension S {
107+
// CHECK-NO-STRIP: s4Test1SV28methodInUnavailableExtensionyyF
108+
// CHECK-STRIP-NOT: s4Test1SV28methodInUnavailableExtensionyyF
109+
public func methodInUnavailableExtension() {}
110+
}
111+
112+
public enum E {
113+
case a
114+
115+
@available(*, unavailable)
116+
case b
117+
118+
// CHECK-NO-STRIP: s4Test1EO17unavailableMethodyyF
119+
// CHECK-STRIP-NOT: s4Test1EO17unavailableMethodyyF
120+
@available(*, unavailable)
121+
public func unavailableMethod() {}
122+
}
123+
124+
public class C<T> {
125+
// CHECK-NO-STRIP: s4Test1CC19unavailablePropertyxvg
126+
// CHECK-NO-STRIP: s4Test1CC19unavailablePropertyxvs
127+
// CHECK-NO-STRIP: s4Test1CC19unavailablePropertyxvM
128+
// CHECK-STRIP-NOT: s4Test1CC19unavailablePropertyxvg
129+
// CHECK-STRIP-NOT: s4Test1CC19unavailablePropertyxvs
130+
// CHECK-STRIP-NOT: s4Test1CC19unavailablePropertyxvM
131+
@available(*, unavailable)
132+
public var unavailableProperty: T
133+
134+
// CHECK-NO-STRIP: s4Test1CCyACyxGxcfC
135+
// CHECK-NO-STRIP: s4Test1CCyACyxGxcfc
136+
// CHECK-STRIP-NOT: s4Test1CCyACyxGxcfC
137+
// CHECK-STRIP-NOT: s4Test1CCyACyxGxcfc
138+
@available(*, unavailable)
139+
public init(_ t: T) {}
140+
141+
// CHECK: s4Test1CCfd
142+
// CHECK: s4Test1CCfD
143+
deinit {}
144+
}
145+
146+
public protocol P {
147+
func requirement()
148+
}
149+
150+
@available(*, unavailable)
151+
extension S: P {
152+
// CHECK-NO-STRIP: s4Test1SV11requirementyyF
153+
// CHECK-STRIP-NOT: s4Test1SV11requirementyyF
154+
public func requirement() {}
155+
}
156+
157+
// CHECK-NO-STRIP: s4Test29unavailableFuncWithNestedTypeyyF
158+
// CHECK-STRIP-NOT: s4Test29unavailableFuncWithNestedTypeyyF
159+
@available(*, unavailable)
160+
public func unavailableFuncWithNestedType() {
161+
// NOTE: Check lines for this decl are below since local types are emitted
162+
// after top level decls.
163+
struct Nested {
164+
// s4Test29unavailableFuncWithNestedTypeyyF0E0L_V6methodyyF
165+
public func method() {}
166+
}
167+
}
168+
169+
170+
// MARK: Local types SIL
171+
172+
// CHECK-NO-STRIP: s4Test29unavailableFuncWithNestedTypeyyF0E0L_V6methodyyF
173+
// CHECK-STRIP-NOT: s4Test29unavailableFuncWithNestedTypeyyF0E0L_V6methodyyF
174+
175+
// MARK: SIL vtables
176+
177+
// CHECK-NO-STRIP: sil_vtable [serialized] UnavailableClass
178+
// CHECK-STRIP-NOT: sil_vtable [serialized] UnavailableClass
179+
180+
// CHECK-NO-STRIP: sil_vtable [serialized] C {
181+
// CHECK-NO-STRIP-NEXT: #C.unavailableProperty!getter:
182+
// CHECK-NO-STRIP-NEXT: #C.unavailableProperty!setter:
183+
// CHECK-NO-STRIP-NEXT: #C.unavailableProperty!modify:
184+
// CHECK-NO-STRIP-NEXT: #C.init!allocator:
185+
// CHECK-NO-STRIP-NEXT: #C.deinit!deallocator:
186+
// CHECK-NO-STRIP-NEXT: }
187+
188+
// CHECK-STRIP: sil_vtable [serialized] C {
189+
// CHECK-STRIP-NOT: #C.unavailableProperty!getter:
190+
// CHECK-STRIP-NOT: #C.unavailableProperty!setter:
191+
// CHECK-STRIP-NOT: #C.unavailableProperty!modify:
192+
// CHECK-STRIP-NOT: #C.init!allocator:
193+
// CHECK-STRIP: #C.deinit!deallocator:
194+
// CHECK-STRIP: }
195+
196+
// MARK: SIL witness tables
197+
198+
// CHECK-NO-STRIP: sil_witness_table [serialized] UnavailableEnum: Equatable module Test
199+
// CHECK-STRIP-NOT: sil_witness_table [serialized] UnavailableEnum: Equatable module Test
200+
201+
// CHECK-NO-STRIP: sil_witness_table [serialized] UnavailableEnum: Hashable module Test
202+
// CHECK-STRIP-NOT: sil_witness_table [serialized] UnavailableEnum: Hashable module Test
203+
204+
// CHECK: sil_witness_table [serialized] E: Equatable module Test
205+
206+
// CHECK: sil_witness_table [serialized] E: Hashable module Test
207+
208+
// CHECK-NO-STRIP: sil_witness_table [serialized] <T> S<T>: P module Test
209+
// CHECK-STRIP-NOT: sil_witness_table [serialized] <T> S<T>: P module Test
210+
211+
// MARK: SIL properties
212+
213+
// CHECK-NO-STRIP: sil_property #UnavailableStruct.property<τ_0_0> ()
214+
// CHECK-STRIP-NOT: sil_property #UnavailableStruct.property<τ_0_0> ()
215+
216+
// CHECK-NO-STRIP: sil_property #UnavailableEnum.hashValue ()
217+
// CHECK-STRIP-NOT: sil_property #UnavailableEnum.hashValue ()
218+
219+
// CHECK-NO-STRIP: sil_property #UnavailableClass.property<τ_0_0> ()
220+
// CHECK-STRIP-NOT: sil_property #UnavailableClass.property<τ_0_0> ()
221+
222+
// CHECK-NO-STRIP: sil_property #S.unavailableProperty<τ_0_0> ()
223+
// CHECK-STRIP-NOT: sil_property #S.unavailableProperty<τ_0_0> ()
224+
225+
// CHECK: sil_property #E.hashValue ()
226+
227+
// CHECK-NO-STRIP: sil_property #C.unavailableProperty<τ_0_0> ()
228+
// CHECK-STRIP-NOT: sil_property #C.unavailableProperty<τ_0_0> ()

0 commit comments

Comments
 (0)