Skip to content

Commit 55ace24

Browse files
committed
[+0-all-args] Teach SwitchEnumBuilder how to handle cases with a jump dest continuation.
1 parent 9e969d2 commit 55ace24

File tree

2 files changed

+88
-35
lines changed

2 files changed

+88
-35
lines changed

lib/SILGen/SwitchEnumBuilder.cpp

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,47 @@ using namespace Lowering;
2121
// SwitchCaseFullExpr Implementation
2222
//===----------------------------------------------------------------------===//
2323

24+
SwitchCaseFullExpr::SwitchCaseFullExpr(SILGenFunction &SGF, CleanupLocation loc)
25+
: SGF(SGF), scope(SGF.Cleanups, loc), loc(loc), branchDest() {}
26+
2427
SwitchCaseFullExpr::SwitchCaseFullExpr(SILGenFunction &SGF, CleanupLocation loc,
25-
SILBasicBlock *contBlock)
26-
: SGF(SGF), scope(SGF.Cleanups, loc), loc(loc), contBlock(contBlock) {}
28+
SwitchCaseBranchDest branchDest)
29+
: SGF(SGF), scope(SGF.Cleanups, loc), loc(loc), branchDest(branchDest) {}
2730

2831
void SwitchCaseFullExpr::exitAndBranch(SILLocation loc,
2932
ArrayRef<SILValue> branchArgs) {
30-
assert(contBlock &&
31-
"Should not call this if we do not have a continuation block");
33+
assert(bool(branchDest) && "Must have a branch destination!");
3234
assert(SGF.B.hasValidInsertionPoint());
3335
scope.pop();
34-
SGF.B.createBranch(loc, contBlock.get(), branchArgs);
36+
37+
// Then either do a direct branch or a branch + cleanups.
38+
if (SILBasicBlock *block = branchDest.getBlock()) {
39+
SGF.B.createBranch(loc, block, branchArgs);
40+
return;
41+
}
42+
43+
SGF.Cleanups.emitBranchAndCleanups(branchDest.getJumpDest(), loc, branchArgs);
3544
}
3645

3746
void SwitchCaseFullExpr::exit() {
38-
assert(!contBlock &&
47+
assert(!bool(branchDest) &&
3948
"Should not call this if we do have a continuation block");
4049
assert(SGF.B.hasValidInsertionPoint());
4150
scope.pop();
4251
}
4352

53+
SwitchCaseFullExpr::~SwitchCaseFullExpr() {
54+
assert(!scope.isValid() && "Did not pop scope?!");
55+
}
56+
57+
void SwitchCaseFullExpr::unreachableExit() {
58+
// This is important to ensure that we do not actually emit any cleanups since
59+
// we already know that an unreachable was emitted.
60+
assert(!SGF.B.hasValidInsertionPoint() && "Expected to pop scope without a "
61+
"valid insertion point!");
62+
scope.pop();
63+
}
64+
4465
//===----------------------------------------------------------------------===//
4566
// SwitchEnumBuilder Implementation
4667
//===----------------------------------------------------------------------===//
@@ -93,13 +114,12 @@ void SwitchEnumBuilder::emit() && {
93114
defaultBlockData->dispatchTime ==
94115
DefaultDispatchTime::BeforeNormalCases) {
95116
SILBasicBlock *defaultBlock = defaultBlockData->block;
96-
NullablePtr<SILBasicBlock> contBB = defaultBlockData->contBlock;
117+
SwitchCaseBranchDest branchDest = defaultBlockData->branchDest;
97118
DefaultCaseHandler handler = defaultBlockData->handler;
98119

99120
// Don't allow cleanups to escape the conditional block.
100121
SwitchCaseFullExpr presentScope(builder.getSILGenFunction(),
101-
CleanupLocation::get(loc),
102-
contBB.getPtrOrNull());
122+
CleanupLocation::get(loc), branchDest);
103123
builder.emitBlock(defaultBlock);
104124
ManagedValue input = optional;
105125
if (!isAddressOnly) {
@@ -112,13 +132,12 @@ void SwitchEnumBuilder::emit() && {
112132
for (NormalCaseData &caseData : caseDataArray) {
113133
EnumElementDecl *decl = caseData.decl;
114134
SILBasicBlock *caseBlock = caseData.block;
115-
NullablePtr<SILBasicBlock> contBlock = caseData.contBlock;
135+
SwitchCaseBranchDest branchDest = caseData.branchDest;
116136
NormalCaseHandler handler = caseData.handler;
117137

118138
// Don't allow cleanups to escape the conditional block.
119139
SwitchCaseFullExpr presentScope(builder.getSILGenFunction(),
120-
CleanupLocation::get(loc),
121-
contBlock.getPtrOrNull());
140+
CleanupLocation::get(loc), branchDest);
122141

123142
builder.emitBlock(caseBlock);
124143

@@ -141,13 +160,12 @@ void SwitchEnumBuilder::emit() && {
141160
if (defaultBlockData &&
142161
defaultBlockData->dispatchTime == DefaultDispatchTime::AfterNormalCases) {
143162
SILBasicBlock *defaultBlock = defaultBlockData->block;
144-
NullablePtr<SILBasicBlock> contBB = defaultBlockData->contBlock;
163+
auto branchDest = defaultBlockData->branchDest;
145164
DefaultCaseHandler handler = defaultBlockData->handler;
146165

147166
// Don't allow cleanups to escape the conditional block.
148167
SwitchCaseFullExpr presentScope(builder.getSILGenFunction(),
149-
CleanupLocation::get(loc),
150-
contBB.getPtrOrNull());
168+
CleanupLocation::get(loc), branchDest);
151169
builder.emitBlock(defaultBlock);
152170
ManagedValue input = optional;
153171
if (!isAddressOnly) {

lib/SILGen/SwitchEnumBuilder.h

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,30 @@ namespace Lowering {
2020

2121
class SILGenFunction;
2222

23+
/// TODO: std::variant.
24+
struct SwitchCaseBranchDest {
25+
Optional<JumpDest> jumpDest;
26+
NullablePtr<SILBasicBlock> block;
27+
28+
SwitchCaseBranchDest() : jumpDest(), block() {}
29+
30+
/// Implicit conversion.
31+
SwitchCaseBranchDest(JumpDest jumpDest) : jumpDest(jumpDest), block() {}
32+
33+
/// Implicit conversion.
34+
SwitchCaseBranchDest(SILBasicBlock *block) : jumpDest(), block(block) {}
35+
36+
explicit operator bool() const {
37+
return jumpDest.hasValue() || block.isNonNull();
38+
}
39+
40+
bool hasJumpDest() const { return jumpDest.hasValue(); }
41+
bool hasBlock() const { return bool(block); }
42+
43+
SILBasicBlock *getBlock() { return block.getPtrOrNull(); }
44+
JumpDest &getJumpDest() { return jumpDest.getValue(); }
45+
};
46+
2347
/// A cleanup scope RAII object, like FullExpr, that comes with a JumpDest for a
2448
/// continuation block. It is intended to be used to handle switch cases.
2549
///
@@ -30,23 +54,31 @@ class SwitchCaseFullExpr {
3054
SILGenFunction &SGF;
3155
Scope scope;
3256
CleanupLocation loc;
33-
NullablePtr<SILBasicBlock> contBlock;
57+
SwitchCaseBranchDest branchDest;
3458

3559
public:
3660
SwitchCaseFullExpr(SILGenFunction &SGF, CleanupLocation loc);
3761
SwitchCaseFullExpr(SILGenFunction &SGF, CleanupLocation loc,
38-
SILBasicBlock *contBlock);
62+
SwitchCaseBranchDest branchDest);
3963

40-
~SwitchCaseFullExpr() = default;
64+
~SwitchCaseFullExpr();
4165

4266
SwitchCaseFullExpr(const SwitchCaseFullExpr &) = delete;
4367
SwitchCaseFullExpr &operator=(const SwitchCaseFullExpr &) = delete;
4468

45-
/// Pop the scope and branch to the cont block.
69+
/// Pop the scope and branch to the branch destination. If this case has an
70+
/// associated JumpDest as its branch destination, then this will cause
71+
/// cleanups associated with the jump dest to be emitted.
4672
void exitAndBranch(SILLocation loc, ArrayRef<SILValue> result = {});
4773

48-
/// Pop the scope and do not branch to the cont block.
74+
/// Pop the scope and do not branch to the branch destination. This is
75+
/// intended to be used in situations where one wants to model a switch region
76+
/// that ends midway through one of the case blocks.
4977
void exit();
78+
79+
/// Do not pop the scope and do not branch to the branch destination. But do
80+
/// invalidate the scope. This can occur when emitting unreachables.
81+
void unreachableExit();
5082
};
5183

5284
/// A class for building switch enums that handles all of the ownership
@@ -55,6 +87,9 @@ class SwitchCaseFullExpr {
5587
/// It assumes that the user passes in a block that takes in a ManagedValue and
5688
/// returns a ManagedValue for the blocks exit argument. Should return an empty
5789
/// ManagedValue to signal no result.
90+
///
91+
/// TODO: Allow cases to take JumpDest as continuation blocks and then
92+
/// force exitBranchAndCleanup to be run.
5893
class SwitchEnumBuilder {
5994
public:
6095
using NormalCaseHandler =
@@ -68,29 +103,29 @@ class SwitchEnumBuilder {
68103
struct NormalCaseData {
69104
EnumElementDecl *decl;
70105
SILBasicBlock *block;
71-
NullablePtr<SILBasicBlock> contBlock;
106+
SwitchCaseBranchDest branchDest;
72107
NormalCaseHandler handler;
73108
ProfileCounter count;
74109

75110
NormalCaseData(EnumElementDecl *decl, SILBasicBlock *block,
76-
NullablePtr<SILBasicBlock> contBlock,
77-
NormalCaseHandler handler, ProfileCounter count)
78-
: decl(decl), block(block), contBlock(contBlock), handler(handler),
111+
SwitchCaseBranchDest branchDest, NormalCaseHandler handler,
112+
ProfileCounter count)
113+
: decl(decl), block(block), branchDest(branchDest), handler(handler),
79114
count(count) {}
80115
~NormalCaseData() = default;
81116
};
82117

83118
struct DefaultCaseData {
84119
SILBasicBlock *block;
85-
NullablePtr<SILBasicBlock> contBlock;
120+
SwitchCaseBranchDest branchDest;
86121
DefaultCaseHandler handler;
87122
DefaultDispatchTime dispatchTime;
88123
ProfileCounter count;
89124

90-
DefaultCaseData(SILBasicBlock *block, NullablePtr<SILBasicBlock> contBlock,
125+
DefaultCaseData(SILBasicBlock *block, SwitchCaseBranchDest branchDest,
91126
DefaultCaseHandler handler,
92127
DefaultDispatchTime dispatchTime, ProfileCounter count)
93-
: block(block), contBlock(contBlock), handler(handler),
128+
: block(block), branchDest(branchDest), handler(handler),
94129
dispatchTime(dispatchTime), count(count) {}
95130
~DefaultCaseData() = default;
96131
};
@@ -107,18 +142,18 @@ class SwitchEnumBuilder {
107142
: builder(builder), loc(loc), optional(optional) {}
108143

109144
void addDefaultCase(
110-
SILBasicBlock *defaultBlock, NullablePtr<SILBasicBlock> contBlock,
145+
SILBasicBlock *defaultBlock, SwitchCaseBranchDest branchDest,
111146
DefaultCaseHandler handle,
112147
DefaultDispatchTime dispatchTime = DefaultDispatchTime::AfterNormalCases,
113148
ProfileCounter count = ProfileCounter()) {
114-
defaultBlockData.emplace(defaultBlock, contBlock, handle, dispatchTime,
149+
defaultBlockData.emplace(defaultBlock, branchDest, handle, dispatchTime,
115150
count);
116151
}
117152

118153
void addCase(EnumElementDecl *decl, SILBasicBlock *caseBlock,
119-
NullablePtr<SILBasicBlock> contBlock, NormalCaseHandler handle,
154+
SwitchCaseBranchDest branchDest, NormalCaseHandler handle,
120155
ProfileCounter count = ProfileCounter()) {
121-
caseDataArray.emplace_back(decl, caseBlock, contBlock, handle, count);
156+
caseDataArray.emplace_back(decl, caseBlock, branchDest, handle, count);
122157
}
123158

124159
void addOptionalSomeCase(SILBasicBlock *caseBlock) {
@@ -138,19 +173,19 @@ class SwitchEnumBuilder {
138173
}
139174

140175
void addOptionalSomeCase(SILBasicBlock *caseBlock,
141-
NullablePtr<SILBasicBlock> contBlock,
176+
SwitchCaseBranchDest branchDest,
142177
NormalCaseHandler handle,
143178
ProfileCounter count = ProfileCounter()) {
144179
auto *decl = getSGF().getASTContext().getOptionalSomeDecl();
145-
caseDataArray.emplace_back(decl, caseBlock, contBlock, handle, count);
180+
caseDataArray.emplace_back(decl, caseBlock, branchDest, handle, count);
146181
}
147182

148183
void addOptionalNoneCase(SILBasicBlock *caseBlock,
149-
NullablePtr<SILBasicBlock> contBlock,
184+
SwitchCaseBranchDest branchDest,
150185
NormalCaseHandler handle,
151186
ProfileCounter count = ProfileCounter()) {
152187
auto *decl = getSGF().getASTContext().getOptionalNoneDecl();
153-
caseDataArray.emplace_back(decl, caseBlock, contBlock, handle, count);
188+
caseDataArray.emplace_back(decl, caseBlock, branchDest, handle, count);
154189
}
155190

156191
void emit() &&;

0 commit comments

Comments
 (0)