Skip to content

Commit 8c95abb

Browse files
authored
Merge pull request #23132 from gottesmm/pr-3ed566dc0f1adb6be65627cc8b34ba8e5e3ebe39
2 parents b6517c5 + 4fefea5 commit 8c95abb

File tree

1 file changed

+155
-140
lines changed

1 file changed

+155
-140
lines changed

lib/SILGen/SILGenPattern.cpp

Lines changed: 155 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -2320,19 +2320,21 @@ void PatternMatchEmission::initSharedCaseBlockDest(CaseStmt *caseBlock,
23202320
result.first->second.first = block;
23212321

23222322
// Add args for any pattern variables
2323-
if (caseBlock->hasBoundDecls()) {
2324-
auto pattern = caseBlock->getCaseLabelItems()[0].getPattern();
2325-
pattern->forEachVariable([&](VarDecl *V) {
2326-
if (!V->hasName())
2327-
return;
2328-
2329-
// We don't pass address-only values in basic block arguments.
2330-
SILType ty = SGF.getLoweredType(V->getType());
2331-
if (ty.isAddressOnly(SGF.F.getModule()))
2332-
return;
2333-
block->createPhiArgument(ty, ValueOwnershipKind::Owned, V);
2334-
});
2323+
if (!caseBlock->hasBoundDecls()) {
2324+
return;
23352325
}
2326+
2327+
auto pattern = caseBlock->getCaseLabelItems()[0].getPattern();
2328+
pattern->forEachVariable([&](VarDecl *V) {
2329+
if (!V->hasName())
2330+
return;
2331+
2332+
// We don't pass address-only values in basic block arguments.
2333+
SILType ty = SGF.getLoweredType(V->getType());
2334+
if (ty.isAddressOnly(SGF.F.getModule()))
2335+
return;
2336+
block->createPhiArgument(ty, ValueOwnershipKind::Owned, V);
2337+
});
23362338
}
23372339

23382340
/// Retrieve the jump destination for a shared case block.
@@ -2403,7 +2405,7 @@ emitAddressOnlyInitialization(VarDecl *dest, SILValue value) {
24032405

24042406
/// Emit all the shared case statements.
24052407
void PatternMatchEmission::emitSharedCaseBlocks() {
2406-
for (auto &entry: SharedCases) {
2408+
for (auto &entry : SharedCases) {
24072409
CaseStmt *caseBlock = entry.first;
24082410
SILBasicBlock *caseBB = entry.second.first;
24092411
bool hasFallthroughTo = entry.second.second;
@@ -2437,64 +2439,73 @@ void PatternMatchEmission::emitSharedCaseBlocks() {
24372439
// Then emit the case body into the caseBB.
24382440
SGF.B.setInsertionPoint(caseBB);
24392441
}
2440-
2442+
2443+
// Make sure that before/after we emit the case body we have emitted all
2444+
// cleanups we created within.
24412445
assert(SGF.getCleanupsDepth() == PatternMatchStmtDepth);
2446+
SWIFT_DEFER { assert(SGF.getCleanupsDepth() == PatternMatchStmtDepth); };
2447+
2448+
// If we do not have any bound decls, just emit the case body since we do
2449+
// not need to setup any var locs.
2450+
if (!caseBlock->hasBoundDecls()) {
2451+
emitCaseBody(caseBlock);
2452+
continue;
2453+
}
24422454

24432455
// If we have a shared case with bound decls, then the 0th pattern has the
24442456
// order of variables that are the incoming BB arguments. Setup the VarLocs
2445-
// to point to the incoming args and setup initialization so any args needing
2446-
// cleanup will get that as well.
2447-
if (caseBlock->hasBoundDecls()) {
2448-
Scope scope(SGF.Cleanups, CleanupLocation(caseBlock));
2449-
auto pattern = caseBlock->getCaseLabelItems()[0].getPattern();
2450-
unsigned argIndex = 0;
2451-
pattern->forEachVariable([&](VarDecl *V) {
2452-
if (!V->hasName())
2453-
return;
2454-
2455-
SILType ty = SGF.getLoweredType(V->getType());
2456-
2457-
// Initialize mv at +1. We always pass values in at +1 for today into
2458-
// shared blocks.
2459-
ManagedValue mv;
2460-
if (ty.isAddressOnly(SGF.F.getModule())) {
2461-
// There's no basic block argument, since we don't allow basic blocks
2462-
// to have address arguments.
2463-
//
2464-
// Instead, we map the variable to a temporary alloc_stack in
2465-
// emitAddressOnlyAllocations(), and store into it at each
2466-
// predecessor block.
2467-
//
2468-
// There's nothing to do here, since the value should already have
2469-
// been initialized on entry.
2470-
auto found = Temporaries.find(V);
2471-
assert(found != Temporaries.end());
2472-
mv = SGF.emitManagedRValueWithCleanup(found->second);
2473-
} else {
2474-
SILValue arg = caseBB->getArgument(argIndex++);
2475-
assert(arg.getOwnershipKind() == ValueOwnershipKind::Owned ||
2476-
arg.getOwnershipKind() == ValueOwnershipKind::Any);
2477-
mv = SGF.emitManagedRValueWithCleanup(arg);
2478-
}
2457+
// to point to the incoming args and setup initialization so any args
2458+
// needing cleanup will get that as well.
2459+
Scope scope(SGF.Cleanups, CleanupLocation(caseBlock));
2460+
auto pattern = caseBlock->getCaseLabelItems()[0].getPattern();
2461+
unsigned argIndex = 0;
2462+
pattern->forEachVariable([&](VarDecl *V) {
2463+
if (!V->hasName())
2464+
return;
24792465

2480-
if (V->isLet()) {
2481-
// Just emit a let and leave the cleanup alone.
2482-
SGF.VarLocs[V].value = mv.getValue();
2483-
} else {
2484-
// The pattern variables were all emitted as lets and one got passed in,
2485-
// now we finally alloc a box for the var and forward in the chosen value.
2486-
SGF.VarLocs.erase(V);
2487-
auto newVar = SGF.emitInitializationForVarDecl(V, V->isLet());
2488-
newVar->copyOrInitValueInto(SGF, V, mv, /*isInit*/ true);
2489-
newVar->finishInitialization(SGF);
2490-
}
2491-
});
2492-
emitCaseBody(caseBlock);
2493-
} else {
2494-
emitCaseBody(caseBlock);
2495-
}
2496-
2497-
assert(SGF.getCleanupsDepth() == PatternMatchStmtDepth);
2466+
SILType ty = SGF.getLoweredType(V->getType());
2467+
2468+
// Initialize mv at +1. We always pass values in at +1 for today into
2469+
// shared blocks.
2470+
ManagedValue mv;
2471+
if (ty.isAddressOnly(SGF.F.getModule())) {
2472+
// There's no basic block argument, since we don't allow basic blocks
2473+
// to have address arguments.
2474+
//
2475+
// Instead, we map the variable to a temporary alloc_stack in
2476+
// emitAddressOnlyAllocations(), and store into it at each
2477+
// predecessor block.
2478+
//
2479+
// There's nothing to do here, since the value should already have
2480+
// been initialized on entry.
2481+
auto found = Temporaries.find(V);
2482+
assert(found != Temporaries.end());
2483+
mv = SGF.emitManagedRValueWithCleanup(found->second);
2484+
} else {
2485+
SILValue arg = caseBB->getArgument(argIndex++);
2486+
assert(arg.getOwnershipKind() == ValueOwnershipKind::Owned ||
2487+
arg.getOwnershipKind() == ValueOwnershipKind::Any);
2488+
mv = SGF.emitManagedRValueWithCleanup(arg);
2489+
}
2490+
2491+
if (V->isLet()) {
2492+
// Just emit a let and leave the cleanup alone.
2493+
SGF.VarLocs[V].value = mv.getValue();
2494+
return;
2495+
}
2496+
2497+
// Otherwise, the pattern variables were all emitted as lets and one got
2498+
// passed in. Since we have a var, alloc a box for the var and forward in
2499+
// the chosen value.
2500+
SGF.VarLocs.erase(V);
2501+
auto newVar = SGF.emitInitializationForVarDecl(V, V->isLet());
2502+
newVar->copyOrInitValueInto(SGF, V, mv, /*isInit*/ true);
2503+
newVar->finishInitialization(SGF);
2504+
});
2505+
2506+
// Now that we have setup all of the VarLocs correctly, emit the shared case
2507+
// body.
2508+
emitCaseBody(caseBlock);
24982509
}
24992510
}
25002511

@@ -2629,6 +2640,81 @@ static void emitDiagnoseOfUnexpectedEnumCase(SILGenFunction &SGF,
26292640
SGFContext());
26302641
}
26312642

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

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

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

0 commit comments

Comments
 (0)