Skip to content

Commit 99c62ea

Browse files
committed
[silgenpattern] Extract out the large completion handler lambda into its own function.
This makes it easier to read/reason about SILGenPattern::emitSwitchStmt().
1 parent c8cdc46 commit 99c62ea

File tree

1 file changed

+78
-74
lines changed

1 file changed

+78
-74
lines changed

lib/SILGen/SILGenPattern.cpp

Lines changed: 78 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -2631,6 +2631,81 @@ static void emitDiagnoseOfUnexpectedEnumCase(SILGenFunction &SGF,
26312631
SGFContext());
26322632
}
26332633

2634+
static void switchCaseStmtSuccessCallback(SILGenFunction &SGF,
2635+
PatternMatchEmission &emission,
2636+
ArgArray argArray, ClauseRow &row) {
2637+
auto caseBlock = row.getClientData<CaseStmt>();
2638+
SGF.emitProfilerIncrement(caseBlock);
2639+
2640+
// Certain case statements can be entered along multiple paths, either
2641+
// because they have multiple labels or because of fallthrough. When we
2642+
// need multiple entrance path, we factor the paths with a shared block.
2643+
if (!caseBlock->hasBoundDecls()) {
2644+
// Don't emit anything yet, we emit it at the cleanup level of the switch
2645+
// statement.
2646+
JumpDest sharedDest = emission.getSharedCaseBlockDest(caseBlock);
2647+
SGF.Cleanups.emitBranchAndCleanups(sharedDest, caseBlock);
2648+
return;
2649+
}
2650+
2651+
// If we don't have a fallthrough or a multi-pattern 'case', we can just
2652+
// emit the body inline and save some dead blocks. Emit the statement here.
2653+
if (!row.hasFallthroughTo() && caseBlock->getCaseLabelItems().size() == 1) {
2654+
emission.emitCaseBody(caseBlock);
2655+
return;
2656+
}
2657+
2658+
JumpDest sharedDest = emission.getSharedCaseBlockDest(caseBlock);
2659+
2660+
// Generate the arguments from this row's pattern in the case block's
2661+
// expected order, and keep those arguments from being cleaned up, as
2662+
// we're passing the +1 along to the shared case block dest. (The
2663+
// cleanups still happen, as they are threaded through here messily,
2664+
// but the explicit retains here counteract them, and then the
2665+
// retain/release pair gets optimized out.)
2666+
ArrayRef<CaseLabelItem> labelItems = caseBlock->getCaseLabelItems();
2667+
SmallVector<SILValue, 4> args;
2668+
SmallVector<VarDecl *, 4> expectedVarOrder;
2669+
SmallVector<VarDecl *, 4> vars;
2670+
labelItems[0].getPattern()->collectVariables(expectedVarOrder);
2671+
row.getCasePattern()->collectVariables(vars);
2672+
2673+
SILModule &M = SGF.F.getModule();
2674+
for (auto expected : expectedVarOrder) {
2675+
if (!expected->hasName())
2676+
continue;
2677+
for (auto *var : vars) {
2678+
if (!var->hasName() || var->getName() != expected->getName())
2679+
continue;
2680+
2681+
SILValue value = SGF.VarLocs[var].value;
2682+
SILType type = value->getType();
2683+
2684+
// If we have an address-only type, initialize the temporary
2685+
// allocation. We're not going to pass the address as a block
2686+
// argument.
2687+
if (type.isAddressOnly(M)) {
2688+
emission.emitAddressOnlyInitialization(expected, value);
2689+
break;
2690+
}
2691+
2692+
// If we have a loadable address, perform a load [copy].
2693+
if (type.isAddress()) {
2694+
value = SGF.B.emitLoadValueOperation(SGF.CurrentSILLoc, value,
2695+
LoadOwnershipQualifier::Copy);
2696+
args.push_back(value);
2697+
break;
2698+
}
2699+
2700+
value = SGF.B.emitCopyValueOperation(SGF.CurrentSILLoc, value);
2701+
args.push_back(value);
2702+
break;
2703+
}
2704+
}
2705+
2706+
SGF.Cleanups.emitBranchAndCleanups(sharedDest, caseBlock, args);
2707+
}
2708+
26342709
void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
26352710
LLVM_DEBUG(llvm::dbgs() << "emitting switch stmt\n";
26362711
S->dump(llvm::dbgs());
@@ -2646,81 +2721,10 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
26462721
return;
26472722
}
26482723

2649-
auto completionHandler = [&](PatternMatchEmission &emission,
2650-
ArgArray argArray,
2651-
ClauseRow &row) {
2652-
auto caseBlock = row.getClientData<CaseStmt>();
2653-
emitProfilerIncrement(caseBlock);
2654-
2655-
// Certain case statements can be entered along multiple paths, either
2656-
// because they have multiple labels or because of fallthrough. When we
2657-
// need multiple entrance path, we factor the paths with a shared block.
2658-
if (!caseBlock->hasBoundDecls()) {
2659-
// Don't emit anything yet, we emit it at the cleanup level of the switch
2660-
// statement.
2661-
JumpDest sharedDest = emission.getSharedCaseBlockDest(caseBlock);
2662-
Cleanups.emitBranchAndCleanups(sharedDest, caseBlock);
2663-
return;
2664-
}
2665-
2666-
// If we don't have a fallthrough or a multi-pattern 'case', we can just
2667-
// emit the body inline and save some dead blocks. Emit the statement here.
2668-
if (!row.hasFallthroughTo() && caseBlock->getCaseLabelItems().size() == 1) {
2669-
emission.emitCaseBody(caseBlock);
2670-
return;
2671-
}
2672-
2673-
JumpDest sharedDest = emission.getSharedCaseBlockDest(caseBlock);
2674-
2675-
// Generate the arguments from this row's pattern in the case block's
2676-
// expected order, and keep those arguments from being cleaned up, as
2677-
// we're passing the +1 along to the shared case block dest. (The
2678-
// cleanups still happen, as they are threaded through here messily,
2679-
// but the explicit retains here counteract them, and then the
2680-
// retain/release pair gets optimized out.)
2681-
ArrayRef<CaseLabelItem> labelItems = caseBlock->getCaseLabelItems();
2682-
SmallVector<SILValue, 4> args;
2683-
SmallVector<VarDecl *, 4> expectedVarOrder;
2684-
SmallVector<VarDecl *, 4> vars;
2685-
labelItems[0].getPattern()->collectVariables(expectedVarOrder);
2686-
row.getCasePattern()->collectVariables(vars);
2687-
2688-
SILModule &M = F.getModule();
2689-
for (auto expected : expectedVarOrder) {
2690-
if (!expected->hasName())
2691-
continue;
2692-
for (auto *var : vars) {
2693-
if (!var->hasName() || var->getName() != expected->getName())
2694-
continue;
2695-
2696-
SILValue value = VarLocs[var].value;
2697-
SILType type = value->getType();
2698-
2699-
// If we have an address-only type, initialize the temporary
2700-
// allocation. We're not going to pass the address as a block
2701-
// argument.
2702-
if (type.isAddressOnly(M)) {
2703-
emission.emitAddressOnlyInitialization(expected, value);
2704-
break;
2705-
}
2706-
2707-
// If we have a loadable address, perform a load [copy].
2708-
if (type.isAddress()) {
2709-
value = B.emitLoadValueOperation(CurrentSILLoc, value,
2710-
LoadOwnershipQualifier::Copy);
2711-
args.push_back(value);
2712-
break;
2713-
}
2714-
2715-
value = B.emitCopyValueOperation(CurrentSILLoc, value);
2716-
args.push_back(value);
2717-
break;
2718-
}
2719-
}
2720-
2721-
Cleanups.emitBranchAndCleanups(sharedDest, caseBlock, args);
2724+
auto completionHandler = [this](PatternMatchEmission &emission,
2725+
ArgArray argArray, ClauseRow &row) {
2726+
return switchCaseStmtSuccessCallback(*this, emission, argArray, row);
27222727
};
2723-
27242728
PatternMatchEmission emission(*this, S, completionHandler);
27252729

27262730
// Add a row for each label of each case.

0 commit comments

Comments
 (0)