@@ -445,6 +445,12 @@ class PatternMatchEmission {
445
445
446
446
void emitCaseBody (CaseStmt *caseBlock);
447
447
448
+ SILValue getAddressOnlyTemporary (VarDecl *decl) {
449
+ auto found = Temporaries.find (decl);
450
+ assert (found != Temporaries.end ());
451
+ return found->second ;
452
+ }
453
+
448
454
private:
449
455
void emitWildcardDispatch (ClauseMatrix &matrix, ArgArray args, unsigned row,
450
456
const FailureHandler &failure);
@@ -2326,16 +2332,12 @@ void PatternMatchEmission::initSharedCaseBlockDest(CaseStmt *caseBlock,
2326
2332
auto *block = SGF.createBasicBlock ();
2327
2333
result.first ->second .first = block;
2328
2334
2329
- // If we do not have any bound decls, we do not need to setup any phi
2330
- // arguments for the shared case block. Just bail early.
2331
- if (!caseBlock-> hasBoundDecls ()) {
2335
+ // Add args for any pattern variables
2336
+ auto caseBodyVars = caseBlock-> getCaseBodyVariables ();
2337
+ if (!caseBodyVars)
2332
2338
return ;
2333
- }
2334
2339
2335
- auto pattern = caseBlock->getCaseLabelItems ()[0 ].getPattern ();
2336
- SmallVector<VarDecl *, 4 > patternVarDecls;
2337
- pattern->collectVariables (patternVarDecls);
2338
- for (auto *vd : patternVarDecls) {
2340
+ for (auto *vd : *caseBodyVars) {
2339
2341
if (!vd->hasName ())
2340
2342
continue ;
2341
2343
@@ -2363,39 +2365,18 @@ void PatternMatchEmission::emitAddressOnlyAllocations() {
2363
2365
for (auto &entry : SharedCases) {
2364
2366
CaseStmt *caseBlock = entry.first ;
2365
2367
2366
- // If we do not have any bound decls, we can bail early.
2367
- if (!caseBlock-> hasBoundDecls ()) {
2368
+ auto caseBodyVars = caseBlock-> getCaseBodyVariables ();
2369
+ if (!caseBodyVars)
2368
2370
continue ;
2369
- }
2370
2371
2371
- // If we have a shared case with bound decls, then the 0th pattern has the
2372
- // order of variables that are the incoming BB arguments. Setup the VarLocs
2373
- // to point to the incoming args and setup initialization so any args needing
2374
- // cleanup will get that as well.
2375
- auto pattern = caseBlock->getCaseLabelItems ()[0 ].getPattern ();
2376
- SmallVector<VarDecl *, 4 > patternVarDecls;
2377
- pattern->collectVariables (patternVarDecls);
2378
- for (auto *vd : patternVarDecls) {
2372
+ // If we have a shared case with bound decls, setup the arguments for the
2373
+ // shared block by emitting the temporary allocation used for the arguments
2374
+ // of the shared block.
2375
+ for (auto *vd : *caseBodyVars) {
2379
2376
if (!vd->hasName ())
2380
2377
continue ;
2381
2378
2382
2379
SILType ty = SGF.getLoweredType (vd->getType ());
2383
- if (ty.isNull ()) {
2384
- // If we're making the shared block on behalf of a previous case's
2385
- // fallthrough, caseBlock's VarDecl's won't be in the SGF yet, so
2386
- // determine phi types by using current vars of the same name.
2387
- for (auto var : SGF.VarLocs ) {
2388
- auto varDecl = dyn_cast<VarDecl>(var.getFirst ());
2389
- if (!varDecl || !varDecl->hasName () ||
2390
- varDecl->getName () != vd->getName ())
2391
- continue ;
2392
- ty = var.getSecond ().value ->getType ();
2393
- if (var.getSecond ().box ) {
2394
- ty = ty.getObjectType ();
2395
- }
2396
- }
2397
- }
2398
-
2399
2380
if (!ty.isAddressOnly (SGF.F .getModule ()))
2400
2381
continue ;
2401
2382
assert (!Temporaries[vd]);
@@ -2455,23 +2436,19 @@ void PatternMatchEmission::emitSharedCaseBlocks() {
2455
2436
assert (SGF.getCleanupsDepth () == PatternMatchStmtDepth);
2456
2437
SWIFT_DEFER { assert (SGF.getCleanupsDepth () == PatternMatchStmtDepth); };
2457
2438
2458
- // If we do not have any bound decls, just emit the case body since we do
2459
- // not need to setup any var locs.
2460
- if (!caseBlock->hasBoundDecls ()) {
2439
+ auto caseBodyVars = caseBlock->getCaseBodyVariables ();
2440
+ if (!caseBodyVars) {
2461
2441
emitCaseBody (caseBlock);
2462
2442
continue ;
2463
2443
}
2464
2444
2465
- // If we have a shared case with bound decls, then the 0th pattern has the
2466
- // order of variables that are the incoming BB arguments. Setup the VarLocs
2467
- // to point to the incoming args and setup initialization so any args
2468
- // needing cleanup will get that as well.
2445
+ // If we have a shared case with bound decls, then the case stmt pattern has
2446
+ // the order of variables that are the incoming BB arguments. Setup the
2447
+ // VarLocs to point to the incoming args and setup initialization so any
2448
+ // args needing Cleanup will get that as well.
2469
2449
Scope scope (SGF.Cleanups , CleanupLocation (caseBlock));
2470
- auto pattern = caseBlock->getCaseLabelItems ()[0 ].getPattern ();
2471
- SmallVector<VarDecl *, 4 > patternVarDecls;
2472
- pattern->collectVariables (patternVarDecls);
2473
2450
unsigned argIndex = 0 ;
2474
- for (auto *vd : patternVarDecls ) {
2451
+ for (auto *vd : *caseBodyVars ) {
2475
2452
if (!vd->hasName ())
2476
2453
continue ;
2477
2454
@@ -2622,10 +2599,33 @@ static void switchCaseStmtSuccessCallback(SILGenFunction &SGF,
2622
2599
2623
2600
// Certain case statements can be entered along multiple paths, either because
2624
2601
// they have multiple labels or because of fallthrough. When we need multiple
2625
- // entrance path, we factor the paths with a shared block. If we don't have a
2626
- // fallthrough or a multi-pattern 'case', we can just emit the body inline and
2627
- // save some dead blocks. Emit the statement here and bail early.
2602
+ // entrance path, we factor the paths with a shared block.
2603
+ //
2604
+ // If we don't have a fallthrough or a multi-pattern 'case', we can emit the
2605
+ // body inline. Emit the statement here and bail early.
2628
2606
if (!row.hasFallthroughTo () && caseBlock->getCaseLabelItems ().size () == 1 ) {
2607
+ // If we have case body vars, set them up to point at the matching var
2608
+ // decls.
2609
+ if (auto caseBodyVars = caseBlock->getCaseBodyVariables ()) {
2610
+ // Since we know that we only have one case label item, grab its pattern
2611
+ // vars and use that to update expected with the right SILValue.
2612
+ //
2613
+ // TODO: Do we need a copy here?
2614
+ SmallVector<VarDecl *, 4 > patternVars;
2615
+ row.getCasePattern ()->collectVariables (patternVars);
2616
+ for (auto *expected : *caseBodyVars) {
2617
+ if (!expected->hasName ())
2618
+ continue ;
2619
+ for (auto *vd : patternVars) {
2620
+ if (!vd->hasName () || vd->getName () != expected->getName ()) {
2621
+ continue ;
2622
+ }
2623
+
2624
+ // Ok, we found a match. Update the VarLocs for the case block.
2625
+ SGF.VarLocs [expected] = SGF.VarLocs [vd];
2626
+ }
2627
+ }
2628
+ }
2629
2629
emission.emitCaseBody (caseBlock);
2630
2630
return ;
2631
2631
}
@@ -2639,7 +2639,10 @@ static void switchCaseStmtSuccessCallback(SILGenFunction &SGF,
2639
2639
2640
2640
// If we do not have any bound decls, we do not need to setup any
2641
2641
// variables. Just jump to the shared destination.
2642
- if (!caseBlock->hasBoundDecls ()) {
2642
+ auto caseBodyVars = caseBlock->getCaseBodyVariables ();
2643
+ if (!caseBodyVars) {
2644
+ // Don't emit anything yet, we emit it at the cleanup level of the switch
2645
+ // statement.
2643
2646
JumpDest sharedDest = emission.getSharedCaseBlockDest (caseBlock);
2644
2647
SGF.Cleanups .emitBranchAndCleanups (sharedDest, caseBlock);
2645
2648
return ;
@@ -2650,18 +2653,14 @@ static void switchCaseStmtSuccessCallback(SILGenFunction &SGF,
2650
2653
// +1 along to the shared case block dest. (The cleanups still happen, as they
2651
2654
// are threaded through here messily, but the explicit retains here counteract
2652
2655
// them, and then the retain/release pair gets optimized out.)
2653
- ArrayRef<CaseLabelItem> labelItems = caseBlock->getCaseLabelItems ();
2654
2656
SmallVector<SILValue, 4 > args;
2655
- SmallVector<VarDecl *, 4 > expectedVarOrder;
2656
- SmallVector<VarDecl *, 4 > vars;
2657
- labelItems[0 ].getPattern ()->collectVariables (expectedVarOrder);
2658
- row.getCasePattern ()->collectVariables (vars);
2659
-
2660
2657
SILModule &M = SGF.F .getModule ();
2661
- for (auto expected : expectedVarOrder) {
2658
+ SmallVector<VarDecl *, 4 > patternVars;
2659
+ row.getCasePattern ()->collectVariables (patternVars);
2660
+ for (auto *expected : *caseBodyVars) {
2662
2661
if (!expected->hasName ())
2663
2662
continue ;
2664
- for (auto *var : vars ) {
2663
+ for (auto *var : patternVars ) {
2665
2664
if (!var->hasName () || var->getName () != expected->getName ())
2666
2665
continue ;
2667
2666
@@ -2690,6 +2689,7 @@ static void switchCaseStmtSuccessCallback(SILGenFunction &SGF,
2690
2689
}
2691
2690
}
2692
2691
2692
+ // Now that we have initialized our arguments, branch to the shared dest.
2693
2693
SGF.Cleanups .emitBranchAndCleanups (sharedDest, caseBlock, args);
2694
2694
}
2695
2695
@@ -2837,45 +2837,46 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
2837
2837
void SILGenFunction::emitSwitchFallthrough (FallthroughStmt *S) {
2838
2838
assert (!SwitchStack.empty () && " fallthrough outside of switch?!" );
2839
2839
PatternMatchContext *context = SwitchStack.back ();
2840
-
2840
+
2841
2841
// Get the destination block.
2842
- CaseStmt *caseStmt = S->getFallthroughDest ();
2843
- JumpDest sharedDest =
2844
- context->Emission .getSharedCaseBlockDest (caseStmt);
2842
+ CaseStmt *destCaseStmt = S->getFallthroughDest ();
2843
+ JumpDest sharedDest = context->Emission .getSharedCaseBlockDest (destCaseStmt);
2845
2844
2846
- if (!caseStmt->hasBoundDecls ()) {
2845
+ // If our destination case doesn't have any bound decls, there is no rebinding
2846
+ // to do. Just jump to the shared dest.
2847
+ auto destCaseBodyVars = destCaseStmt->getCaseBodyVariables ();
2848
+ if (!destCaseBodyVars) {
2847
2849
Cleanups.emitBranchAndCleanups (sharedDest, S);
2848
2850
return ;
2849
2851
}
2850
2852
2851
2853
// Generate branch args to pass along current vars to fallthrough case.
2852
2854
SILModule &M = F.getModule ();
2853
- ArrayRef<CaseLabelItem> labelItems = caseStmt->getCaseLabelItems ();
2854
2855
SmallVector<SILValue, 4 > args;
2855
- SmallVector<VarDecl *, 4 > expectedVarOrder;
2856
- labelItems[0 ].getPattern ()->collectVariables (expectedVarOrder);
2856
+ CaseStmt *fallthroughSourceStmt = S->getFallthroughSource ();
2857
2857
2858
- for (auto *expected : expectedVarOrder ) {
2858
+ for (auto *expected : *destCaseBodyVars ) {
2859
2859
if (!expected->hasName ())
2860
2860
continue ;
2861
- for (auto var : VarLocs) {
2862
- auto varDecl = dyn_cast<VarDecl>(var.getFirst ());
2863
- if (!varDecl || !varDecl->hasName () ||
2864
- varDecl->getName () != expected->getName ()) {
2861
+
2862
+ // The type checker enforces that if our destination case has variables then
2863
+ // our fallthrough source must as well.
2864
+ for (auto *var : *fallthroughSourceStmt->getCaseBodyVariables ()) {
2865
+ if (!var->hasName () || var->getName () != expected->getName ()) {
2865
2866
continue ;
2866
2867
}
2867
2868
2868
- SILValue value = var.getSecond ().value ;
2869
+ auto varLoc = VarLocs[var];
2870
+ SILValue value = varLoc.value ;
2869
2871
2870
2872
if (value->getType ().isAddressOnly (M)) {
2871
2873
context->Emission .emitAddressOnlyInitialization (expected, value);
2872
2874
break ;
2873
2875
}
2874
2876
2875
- if (var.getSecond ().box ) {
2876
- auto &lowering = getTypeLowering (value->getType ());
2877
- auto argValue = lowering.emitLoad (B, CurrentSILLoc, value,
2878
- LoadOwnershipQualifier::Copy);
2877
+ if (varLoc.box ) {
2878
+ SILValue argValue = B.emitLoadValueOperation (
2879
+ CurrentSILLoc, value, LoadOwnershipQualifier::Copy);
2879
2880
args.push_back (argValue);
2880
2881
break ;
2881
2882
}
0 commit comments