Skip to content

Commit a0197b3

Browse files
committed
SILGen: Some fixes for lazy conformance emission
- Don't forget to walk the top-level 'main' function - Force _ObjectiveCBridgeable and _BridgedStoredNSError conformances for types mentioned in apply instructions, existential erasure and casts - Only walk each unique CanType once, and skip non-ClangImporter synthesized conformances completely - Add a few missing cases
1 parent cf60ed5 commit a0197b3

File tree

3 files changed

+93
-6
lines changed

3 files changed

+93
-6
lines changed

lib/SILGen/SILGen.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1647,6 +1647,7 @@ class SourceFileScope {
16471647
LLVM_DEBUG(llvm::dbgs() << "lowered toplevel sil:\n";
16481648
toplevel->print(llvm::dbgs()));
16491649
toplevel->verify();
1650+
sgm.emitLazyConformancesForFunction(toplevel);
16501651
}
16511652

16521653
// If the source file contains an artificial main, emit the implicit

lib/SILGen/SILGen.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
8080
/// Set of used conformances for which witness tables need to be emitted.
8181
llvm::DenseSet<RootProtocolConformance *> usedConformances;
8282

83+
/// Bookkeeping to ensure that useConformancesFrom{ObjectiveC,}Type() is
84+
/// only called once for each unique type, as an optimization.
85+
llvm::DenseSet<TypeBase *> usedConformancesFromTypes;
86+
llvm::DenseSet<TypeBase *> usedConformancesFromObjectiveCTypes;
87+
8388
struct DelayedWitnessTable {
8489
NormalProtocolConformance *insertAfter;
8590
};
@@ -445,6 +450,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
445450
/// Mark protocol conformances from the given set of substitutions as used.
446451
void useConformancesFromSubstitutions(SubstitutionMap subs);
447452

453+
/// Mark _ObjectiveCBridgeable conformances as used for any imported types
454+
/// mentioned by the given type.
455+
void useConformancesFromObjectiveCType(CanType type);
456+
448457
/// Emit a `mark_function_escape` instruction for top-level code when a
449458
/// function or closure at top level refers to script globals.
450459
void emitMarkFunctionEscapeForTopLevelCodeGlobals(SILLocation loc,

lib/SILGen/SILGenLazyConformance.cpp

Lines changed: 83 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "SILGen.h"
1414
#include "swift/AST/Decl.h"
1515
#include "swift/AST/ProtocolConformance.h"
16+
#include "swift/ClangImporter/ClangModule.h"
1617
#include "swift/SIL/SILInstruction.h"
1718
#include "swift/SIL/SILVisitor.h"
1819

@@ -25,11 +26,28 @@ void SILGenModule::useConformance(ProtocolConformanceRef conformanceRef) {
2526
return;
2627

2728
auto conformance = conformanceRef.getConcrete();
29+
30+
// Always look through inherited conformances.
31+
if (auto *inherited = dyn_cast<InheritedProtocolConformance>(conformance))
32+
conformance = inherited->getInheritedConformance();
33+
34+
// Get the normal conformance. If we don't have one, this is a self
35+
// conformance, which we can ignore.
2836
auto normal = dyn_cast<NormalProtocolConformance>(
2937
conformance->getRootConformance());
3038
if (normal == nullptr)
3139
return;
3240

41+
// Emit any conformances implied by conditional requirements.
42+
if (auto *specialized = dyn_cast<SpecializedProtocolConformance>(conformance))
43+
useConformancesFromSubstitutions(specialized->getSubstitutionMap());
44+
45+
// If this conformance was not synthesized by the ClangImporter, we're not
46+
// going to be emitting it lazily either, so we can avoid doing anything
47+
// below.
48+
if (!isa<ClangModuleUnit>(normal->getDeclContext()->getModuleScopeContext()))
49+
return;
50+
3351
// If we already emitted this witness table, we don't need to track the fact
3452
// we need it.
3553
if (emittedWitnessTables.count(normal))
@@ -54,21 +72,60 @@ void SILGenModule::useConformancesFromSubstitutions(
5472
}
5573

5674
void SILGenModule::useConformancesFromType(CanType type) {
57-
type.findIf([&](Type t) -> bool {
75+
if (!usedConformancesFromTypes.insert(type.getPointer()).second)
76+
return;
77+
78+
type.visit([&](Type t) {
5879
auto *decl = t->getAnyNominal();
5980
if (!decl)
60-
return false;
81+
return;
6182

6283
if (isa<ProtocolDecl>(decl))
63-
return false;
84+
return;
6485

6586
auto *genericSig = decl->getGenericSignature();
6687
if (!genericSig)
67-
return false;
88+
return;
6889

6990
auto subMap = t->getContextSubstitutionMap(SwiftModule, decl);
7091
useConformancesFromSubstitutions(subMap);
71-
return false;
92+
return;
93+
});
94+
}
95+
96+
void SILGenModule::useConformancesFromObjectiveCType(CanType type) {
97+
if (!usedConformancesFromObjectiveCTypes.insert(type.getPointer()).second)
98+
return;
99+
100+
auto &ctx = getASTContext();
101+
auto objectiveCBridgeable = ctx.getProtocol(
102+
KnownProtocolKind::ObjectiveCBridgeable);
103+
auto bridgedStoredNSError = ctx.getProtocol(
104+
KnownProtocolKind::BridgedStoredNSError);
105+
if (!objectiveCBridgeable && !bridgedStoredNSError)
106+
return;
107+
108+
type.visit([&](Type t) {
109+
auto *decl = t->getAnyNominal();
110+
if (!decl)
111+
return;
112+
113+
if (!isa<ClangModuleUnit>(decl->getModuleScopeContext()))
114+
return;
115+
116+
if (objectiveCBridgeable) {
117+
auto subConformance = SwiftModule->lookupConformance(
118+
t, objectiveCBridgeable);
119+
if (subConformance)
120+
useConformance(*subConformance);
121+
}
122+
123+
if (bridgedStoredNSError) {
124+
auto subConformance = SwiftModule->lookupConformance(
125+
t, bridgedStoredNSError);
126+
if (subConformance)
127+
useConformance(*subConformance);
128+
}
72129
});
73130
}
74131

@@ -87,6 +144,7 @@ class LazyConformanceEmitter : public SILInstructionVisitor<LazyConformanceEmitt
87144

88145
void visitAllocExistentialBoxInst(AllocExistentialBoxInst *AEBI) {
89146
SGM.useConformancesFromType(AEBI->getFormalConcreteType());
147+
SGM.useConformancesFromObjectiveCType(AEBI->getFormalConcreteType());
90148
for (auto conformance : AEBI->getConformances())
91149
SGM.useConformance(conformance);
92150
}
@@ -109,10 +167,12 @@ class LazyConformanceEmitter : public SILInstructionVisitor<LazyConformanceEmitt
109167
}
110168

111169
void visitApplyInst(ApplyInst *AI) {
170+
SGM.useConformancesFromObjectiveCType(AI->getSubstCalleeType());
112171
SGM.useConformancesFromSubstitutions(AI->getSubstitutionMap());
113172
}
114173

115174
void visitBeginApplyInst(BeginApplyInst *BAI) {
175+
SGM.useConformancesFromObjectiveCType(BAI->getSubstCalleeType());
116176
SGM.useConformancesFromSubstitutions(BAI->getSubstitutionMap());
117177
}
118178

@@ -123,16 +183,22 @@ class LazyConformanceEmitter : public SILInstructionVisitor<LazyConformanceEmitt
123183
void visitCheckedCastBranchInst(CheckedCastBranchInst *CCBI) {
124184
SGM.useConformancesFromType(CCBI->getSourceType());
125185
SGM.useConformancesFromType(CCBI->getTargetType());
186+
SGM.useConformancesFromObjectiveCType(CCBI->getSourceType());
187+
SGM.useConformancesFromObjectiveCType(CCBI->getTargetType());
126188
}
127189

128190
void visitCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *CCABI) {
129191
SGM.useConformancesFromType(CCABI->getSourceType());
130192
SGM.useConformancesFromType(CCABI->getTargetType());
193+
SGM.useConformancesFromObjectiveCType(CCABI->getSourceType());
194+
SGM.useConformancesFromObjectiveCType(CCABI->getTargetType());
131195
}
132196

133197
void visitCheckedCastValueBranchInst(CheckedCastValueBranchInst *CCVBI) {
134198
SGM.useConformancesFromType(CCVBI->getSourceType());
135199
SGM.useConformancesFromType(CCVBI->getTargetType());
200+
SGM.useConformancesFromObjectiveCType(CCVBI->getSourceType());
201+
SGM.useConformancesFromObjectiveCType(CCVBI->getTargetType());
136202
}
137203

138204
void visitCopyAddrInst(CopyAddrInst *CAI) {
@@ -177,6 +243,7 @@ class LazyConformanceEmitter : public SILInstructionVisitor<LazyConformanceEmitt
177243

178244
void visitInitExistentialAddrInst(InitExistentialAddrInst *IEAI) {
179245
SGM.useConformancesFromType(IEAI->getFormalConcreteType());
246+
SGM.useConformancesFromObjectiveCType(IEAI->getFormalConcreteType());
180247
for (auto conformance : IEAI->getConformances())
181248
SGM.useConformance(conformance);
182249
}
@@ -189,12 +256,14 @@ class LazyConformanceEmitter : public SILInstructionVisitor<LazyConformanceEmitt
189256

190257
void visitInitExistentialRefInst(InitExistentialRefInst *IERI) {
191258
SGM.useConformancesFromType(IERI->getFormalConcreteType());
259+
SGM.useConformancesFromObjectiveCType(IERI->getFormalConcreteType());
192260
for (auto conformance : IERI->getConformances())
193261
SGM.useConformance(conformance);
194262
}
195263

196264
void visitInitExistentialValueInst(InitExistentialValueInst *IEVI) {
197265
SGM.useConformancesFromType(IEVI->getFormalConcreteType());
266+
SGM.useConformancesFromObjectiveCType(IEVI->getFormalConcreteType());
198267
for (auto conformance : IEVI->getConformances())
199268
SGM.useConformance(conformance);
200269
}
@@ -204,6 +273,7 @@ class LazyConformanceEmitter : public SILInstructionVisitor<LazyConformanceEmitt
204273
}
205274

206275
void visitPartialApplyInst(PartialApplyInst *PAI) {
276+
SGM.useConformancesFromObjectiveCType(PAI->getSubstCalleeType());
207277
SGM.useConformancesFromSubstitutions(PAI->getSubstitutionMap());
208278
}
209279

@@ -217,6 +287,7 @@ class LazyConformanceEmitter : public SILInstructionVisitor<LazyConformanceEmitt
217287
}
218288

219289
void visitTryApplyInst(TryApplyInst *TAI) {
290+
SGM.useConformancesFromObjectiveCType(TAI->getSubstCalleeType());
220291
SGM.useConformancesFromSubstitutions(TAI->getSubstitutionMap());
221292
}
222293

@@ -227,14 +298,20 @@ class LazyConformanceEmitter : public SILInstructionVisitor<LazyConformanceEmitt
227298
void visitUnconditionalCheckedCastInst(UnconditionalCheckedCastInst *UCCI) {
228299
SGM.useConformancesFromType(UCCI->getSourceType());
229300
SGM.useConformancesFromType(UCCI->getTargetType());
301+
SGM.useConformancesFromObjectiveCType(UCCI->getSourceType());
302+
SGM.useConformancesFromObjectiveCType(UCCI->getTargetType());
230303
}
231304

232305
void visitUnconditionalCheckedCastAddrInst(UnconditionalCheckedCastAddrInst *UCCAI) {
233306
SGM.useConformancesFromType(UCCAI->getSourceType());
234307
SGM.useConformancesFromType(UCCAI->getTargetType());
308+
SGM.useConformancesFromObjectiveCType(UCCAI->getSourceType());
309+
SGM.useConformancesFromObjectiveCType(UCCAI->getTargetType());
235310
}
236311

237-
void visitUncheckedTakeEnumDataAddrInst(UncheckedTakeEnumDataAddrInst *UTEDAI) {}
312+
void visitUncheckedTakeEnumDataAddrInst(UncheckedTakeEnumDataAddrInst *UTEDAI) {
313+
SGM.useConformancesFromType(UTEDAI->getOperand()->getType().getASTType());
314+
}
238315

239316
void visitWitnessMethodInst(WitnessMethodInst *WMI) {
240317
SGM.useConformance(WMI->getConformance());

0 commit comments

Comments
 (0)