Skip to content

Commit 8a74e52

Browse files
committed
SILGen: Add post-processing pass to lazily emit ClangImproter-synthesized conformances
1 parent d24bc38 commit 8a74e52

File tree

9 files changed

+277
-35
lines changed

9 files changed

+277
-35
lines changed

lib/SILGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ add_swift_host_library(swiftSILGen STATIC
2323
SILGenForeignError.cpp
2424
SILGenFunction.cpp
2525
SILGenGlobalVariable.cpp
26+
SILGenLazyConformance.cpp
2627
SILGenLValue.cpp
2728
SILGenPattern.cpp
2829
SILGenPoly.cpp

lib/SILGen/SILGen.cpp

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,8 @@ void SILGenModule::preEmitFunction(SILDeclRef constant,
757757

758758
void SILGenModule::postEmitFunction(SILDeclRef constant,
759759
SILFunction *F) {
760+
emitLazyConformancesForFunction(F);
761+
760762
assert(!F->isExternalDeclaration() && "did not emit any function body?!");
761763
LLVM_DEBUG(llvm::dbgs() << "lowered sil:\n";
762764
F->print(llvm::dbgs()));
@@ -1161,6 +1163,7 @@ SILFunction *SILGenModule::emitLazyGlobalInitializer(StringRef funcName,
11611163
f->setDebugScope(new (M) SILDebugScope(RegularLocation(binding), f));
11621164
auto dc = binding->getDeclContext();
11631165
SILGenFunction(*this, *f, dc).emitLazyGlobalInitializer(binding, pbdEntry);
1166+
emitLazyConformancesForFunction(f);
11641167
f->verify();
11651168

11661169
return f;
@@ -1518,40 +1521,6 @@ void SILGenModule::visitTopLevelCodeDecl(TopLevelCodeDecl *td) {
15181521
}
15191522
}
15201523

1521-
void SILGenModule::useConformance(ProtocolConformanceRef conformanceRef) {
1522-
// We don't need to emit dependent conformances.
1523-
if (conformanceRef.isAbstract())
1524-
return;
1525-
1526-
auto conformance = conformanceRef.getConcrete();
1527-
auto normal = dyn_cast<NormalProtocolConformance>(
1528-
conformance->getRootConformance());
1529-
if (normal == nullptr)
1530-
return;
1531-
1532-
// If we already emitted this witness table, we don't need to track the fact
1533-
// we need it.
1534-
if (emittedWitnessTables.count(normal))
1535-
return;
1536-
1537-
// If we delayed emitting this witness table, force it.
1538-
auto foundDelayed = delayedConformances.find(normal);
1539-
if (foundDelayed != delayedConformances.end()) {
1540-
forcedConformances.push_back(*foundDelayed);
1541-
delayedConformances.erase(foundDelayed);
1542-
return;
1543-
}
1544-
1545-
// Otherwise, just remember the fact we used this conformance.
1546-
usedConformances.insert(normal);
1547-
}
1548-
1549-
void SILGenModule::useConformancesFromSubstitutions(
1550-
const SubstitutionMap subs) {
1551-
for (auto conf : subs.getConformances())
1552-
useConformance(conf);
1553-
}
1554-
15551524
namespace {
15561525

15571526
/// An RAII class to scope source file codegen.

lib/SILGen/SILGen.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,10 +428,16 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
428428
SILGlobalVariable *getSILGlobalVariable(VarDecl *gDecl,
429429
ForDefinition_t forDef);
430430

431+
/// Emit all lazy conformances referenced from this function body.
432+
void emitLazyConformancesForFunction(SILFunction *F);
433+
431434
/// Mark a protocol conformance as used, so we know we need to emit it if
432435
/// it's in our TU.
433436
void useConformance(ProtocolConformanceRef conformance);
434437

438+
/// Mark protocol conformances from the given type as used.
439+
void useConformancesFromType(CanType type);
440+
435441
/// Mark protocol conformances from the given set of substitutions as used.
436442
void useConformancesFromSubstitutions(SubstitutionMap subs);
437443

lib/SILGen/SILGenBridging.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,7 @@ ManagedValue SILGenFunction::emitFuncToBlock(SILLocation loc,
589589
buildFuncToBlockInvokeBody(thunkSGF, loc, funcType, blockType,
590590
loweredFuncTy, loweredBlockTy, storageTy,
591591
useWithoutEscapingVerification);
592+
SGM.emitLazyConformancesForFunction(thunk);
592593
}
593594

594595
// Form the block on the stack.
@@ -946,6 +947,7 @@ SILGenFunction::emitBlockToFunc(SILLocation loc,
946947
auto loc = RegularLocation::getAutoGeneratedLocation();
947948
buildBlockToFuncThunkBody(thunkSGF, loc, blockType, funcType,
948949
loweredBlockTy, loweredFuncTyWithoutNoEscape);
950+
SGM.emitLazyConformancesForFunction(thunk);
949951
}
950952

951953
CanSILFunctionType substFnTy = thunkTy;

lib/SILGen/SILGenExpr.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2620,7 +2620,8 @@ static SILFunction *getOrCreateKeyPathGetter(SILGenModule &SGM,
26202620
scope.pop();
26212621

26222622
subSGF.B.createReturn(loc, subSGF.emitEmptyTuple(loc));
2623-
2623+
2624+
SGM.emitLazyConformancesForFunction(thunk);
26242625
return thunk;
26252626
}
26262627

@@ -2794,6 +2795,7 @@ static SILFunction *getOrCreateKeyPathSetter(SILGenModule &SGM,
27942795

27952796
subSGF.B.createReturn(loc, subSGF.emitEmptyTuple(loc));
27962797

2798+
SGM.emitLazyConformancesForFunction(thunk);
27972799
return thunk;
27982800
}
27992801

@@ -3015,6 +3017,8 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM,
30153017
auto returnBoolVal = subSGF.B.createStruct(loc,
30163018
SILType::getPrimitiveObjectType(boolTy), returnVal);
30173019
subSGF.B.createReturn(loc, returnBoolVal);
3020+
3021+
SGM.emitLazyConformancesForFunction(equals);
30183022
}();
30193023

30203024
// Get or create the hash witness
@@ -3112,6 +3116,7 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM,
31123116
}
31133117

31143118
subSGF.B.createReturn(loc, hashCode);
3119+
SGM.emitLazyConformancesForFunction(hash);
31153120
}();
31163121

31173122
return;

lib/SILGen/SILGenLazyConformance.cpp

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
//===--- SILGenLazyConformance.cpp ----------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "SILGen.h"
14+
#include "swift/AST/Decl.h"
15+
#include "swift/AST/ProtocolConformance.h"
16+
#include "swift/SIL/SILInstruction.h"
17+
#include "swift/SIL/SILVisitor.h"
18+
19+
using namespace swift;
20+
using namespace swift::Lowering;
21+
22+
void SILGenModule::useConformance(ProtocolConformanceRef conformanceRef) {
23+
// We don't need to emit dependent conformances.
24+
if (conformanceRef.isAbstract())
25+
return;
26+
27+
auto conformance = conformanceRef.getConcrete();
28+
auto normal = dyn_cast<NormalProtocolConformance>(
29+
conformance->getRootConformance());
30+
if (normal == nullptr)
31+
return;
32+
33+
// If we already emitted this witness table, we don't need to track the fact
34+
// we need it.
35+
if (emittedWitnessTables.count(normal))
36+
return;
37+
38+
// If we delayed emitting this witness table, force it.
39+
auto foundDelayed = delayedConformances.find(normal);
40+
if (foundDelayed != delayedConformances.end()) {
41+
forcedConformances.push_back(*foundDelayed);
42+
delayedConformances.erase(foundDelayed);
43+
return;
44+
}
45+
46+
// Otherwise, just remember the fact we used this conformance.
47+
usedConformances.insert(normal);
48+
}
49+
50+
void SILGenModule::useConformancesFromSubstitutions(
51+
const SubstitutionMap subs) {
52+
for (auto conf : subs.getConformances())
53+
useConformance(conf);
54+
}
55+
56+
void SILGenModule::useConformancesFromType(CanType type) {
57+
type.findIf([&](Type t) -> bool {
58+
auto *decl = t->getAnyNominal();
59+
if (!decl)
60+
return false;
61+
62+
if (isa<ProtocolDecl>(decl))
63+
return false;
64+
65+
auto *genericSig = decl->getGenericSignature();
66+
if (!genericSig)
67+
return false;
68+
69+
auto subMap = t->getContextSubstitutionMap(SwiftModule, decl);
70+
useConformancesFromSubstitutions(subMap);
71+
return false;
72+
});
73+
}
74+
75+
/// A visitor class that tries to guess which SIL instructions can cause
76+
/// IRGen to emit references to witness tables. This is used to emit
77+
/// ClangImporter-synthesized conformances lazily.
78+
///
79+
/// In the long run, we'll instead have IRGen directly ask SILGen to
80+
/// generate a witness table when needed, so that we don't have to do
81+
/// any "guessing" here.
82+
class LazyConformanceEmitter : public SILInstructionVisitor<LazyConformanceEmitter> {
83+
SILGenModule &SGM;
84+
85+
public:
86+
LazyConformanceEmitter(SILGenModule &SGM) : SGM(SGM) {}
87+
88+
void visitAllocExistentialBoxInst(AllocExistentialBoxInst *AEBI) {
89+
SGM.useConformancesFromType(AEBI->getFormalConcreteType());
90+
for (auto conformance : AEBI->getConformances())
91+
SGM.useConformance(conformance);
92+
}
93+
94+
void visitAllocGlobalInst(AllocGlobalInst *AGI) {
95+
SGM.useConformancesFromType(
96+
AGI->getReferencedGlobal()->getLoweredType().getASTType());
97+
}
98+
99+
void visitAllocRefInst(AllocRefInst *ARI) {
100+
SGM.useConformancesFromType(ARI->getType().getASTType());
101+
}
102+
103+
void visitAllocStackInst(AllocStackInst *ASI) {
104+
SGM.useConformancesFromType(ASI->getType().getASTType());
105+
}
106+
107+
void visitAllocValueBufferInst(AllocValueBufferInst *AVBI) {
108+
SGM.useConformancesFromType(AVBI->getType().getASTType());
109+
}
110+
111+
void visitApplyInst(ApplyInst *AI) {
112+
SGM.useConformancesFromSubstitutions(AI->getSubstitutionMap());
113+
}
114+
115+
void visitBeginApplyInst(BeginApplyInst *BAI) {
116+
SGM.useConformancesFromSubstitutions(BAI->getSubstitutionMap());
117+
}
118+
119+
void visitBuiltinInst(BuiltinInst *BI) {
120+
SGM.useConformancesFromSubstitutions(BI->getSubstitutions());
121+
}
122+
123+
void visitCheckedCastBranchInst(CheckedCastBranchInst *CCBI) {
124+
SGM.useConformancesFromType(CCBI->getSourceType());
125+
SGM.useConformancesFromType(CCBI->getTargetType());
126+
}
127+
128+
void visitCheckedCastAddrBranchInst(CheckedCastAddrBranchInst *CCABI) {
129+
SGM.useConformancesFromType(CCABI->getSourceType());
130+
SGM.useConformancesFromType(CCABI->getTargetType());
131+
}
132+
133+
void visitCheckedCastValueBranchInst(CheckedCastValueBranchInst *CCVBI) {
134+
SGM.useConformancesFromType(CCVBI->getSourceType());
135+
SGM.useConformancesFromType(CCVBI->getTargetType());
136+
}
137+
138+
void visitCopyAddrInst(CopyAddrInst *CAI) {
139+
SGM.useConformancesFromType(CAI->getSrc()->getType().getASTType());
140+
SGM.useConformancesFromType(CAI->getDest()->getType().getASTType());
141+
}
142+
143+
void visitCopyValueInst(CopyValueInst *CVI) {
144+
SGM.useConformancesFromType(CVI->getOperand()->getType().getASTType());
145+
}
146+
147+
void visitDestroyAddrInst(DestroyAddrInst *DAI) {
148+
SGM.useConformancesFromType(DAI->getOperand()->getType().getASTType());
149+
}
150+
151+
void visitDestroyValueInst(DestroyValueInst *DVI) {
152+
SGM.useConformancesFromType(DVI->getOperand()->getType().getASTType());
153+
}
154+
155+
void visitGlobalAddrInst(GlobalAddrInst *GAI) {
156+
SGM.useConformancesFromType(
157+
GAI->getReferencedGlobal()->getLoweredType().getASTType());
158+
}
159+
160+
void visitGlobalValueInst(GlobalValueInst *GVI) {
161+
SGM.useConformancesFromType(
162+
GVI->getReferencedGlobal()->getLoweredType().getASTType());
163+
}
164+
165+
void visitKeyPathInst(KeyPathInst *KPI) {
166+
SGM.useConformancesFromSubstitutions(KPI->getSubstitutions());
167+
}
168+
169+
void visitInitEnumDataAddrInst(InitEnumDataAddrInst *IEDAI) {
170+
SGM.useConformancesFromType(
171+
IEDAI->getOperand()->getType().getASTType());
172+
}
173+
174+
void visitInjectEnumAddrInst(InjectEnumAddrInst *IEAI) {
175+
SGM.useConformancesFromType(IEAI->getOperand()->getType().getASTType());
176+
}
177+
178+
void visitInitExistentialAddrInst(InitExistentialAddrInst *IEAI) {
179+
SGM.useConformancesFromType(IEAI->getFormalConcreteType());
180+
for (auto conformance : IEAI->getConformances())
181+
SGM.useConformance(conformance);
182+
}
183+
184+
void visitInitExistentialMetatypeInst(InitExistentialMetatypeInst *IEMI) {
185+
SGM.useConformancesFromType(IEMI->getOperand()->getType().getASTType());
186+
for (auto conformance : IEMI->getConformances())
187+
SGM.useConformance(conformance);
188+
}
189+
190+
void visitInitExistentialRefInst(InitExistentialRefInst *IERI) {
191+
SGM.useConformancesFromType(IERI->getFormalConcreteType());
192+
for (auto conformance : IERI->getConformances())
193+
SGM.useConformance(conformance);
194+
}
195+
196+
void visitInitExistentialValueInst(InitExistentialValueInst *IEVI) {
197+
SGM.useConformancesFromType(IEVI->getFormalConcreteType());
198+
for (auto conformance : IEVI->getConformances())
199+
SGM.useConformance(conformance);
200+
}
201+
202+
void visitMetatypeInst(MetatypeInst *MI) {
203+
SGM.useConformancesFromType(MI->getType().getASTType());
204+
}
205+
206+
void visitPartialApplyInst(PartialApplyInst *PAI) {
207+
SGM.useConformancesFromSubstitutions(PAI->getSubstitutionMap());
208+
}
209+
210+
void visitSelectEnumAddrInst(SelectEnumAddrInst *SEAI) {
211+
SGM.useConformancesFromType(
212+
SEAI->getEnumOperand()->getType().getASTType());
213+
}
214+
215+
void visitStructElementAddrInst(StructElementAddrInst *SEAI) {
216+
SGM.useConformancesFromType(SEAI->getOperand()->getType().getASTType());
217+
}
218+
219+
void visitTryApplyInst(TryApplyInst *TAI) {
220+
SGM.useConformancesFromSubstitutions(TAI->getSubstitutionMap());
221+
}
222+
223+
void visitTupleElementAddrInst(TupleElementAddrInst *TEAI) {
224+
SGM.useConformancesFromType(TEAI->getOperand()->getType().getASTType());
225+
}
226+
227+
void visitUnconditionalCheckedCastInst(UnconditionalCheckedCastInst *UCCI) {
228+
SGM.useConformancesFromType(UCCI->getSourceType());
229+
SGM.useConformancesFromType(UCCI->getTargetType());
230+
}
231+
232+
void visitUnconditionalCheckedCastAddrInst(UnconditionalCheckedCastAddrInst *UCCAI) {
233+
SGM.useConformancesFromType(UCCAI->getSourceType());
234+
SGM.useConformancesFromType(UCCAI->getTargetType());
235+
}
236+
237+
void visitUncheckedTakeEnumDataAddrInst(UncheckedTakeEnumDataAddrInst *UTEDAI) {}
238+
239+
void visitWitnessMethodInst(WitnessMethodInst *WMI) {
240+
SGM.useConformance(WMI->getConformance());
241+
}
242+
243+
void visitSILInstruction(SILInstruction *I) {}
244+
};
245+
246+
void SILGenModule::emitLazyConformancesForFunction(SILFunction *F) {
247+
LazyConformanceEmitter emitter(*this);
248+
249+
for (auto &BB : *F)
250+
for (auto &I : BB)
251+
emitter.visit(&I);
252+
}

0 commit comments

Comments
 (0)