@@ -2320,19 +2320,21 @@ void PatternMatchEmission::initSharedCaseBlockDest(CaseStmt *caseBlock,
2320
2320
result.first ->second .first = block;
2321
2321
2322
2322
// 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 ;
2335
2325
}
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
+ });
2336
2338
}
2337
2339
2338
2340
// / Retrieve the jump destination for a shared case block.
@@ -2403,7 +2405,7 @@ emitAddressOnlyInitialization(VarDecl *dest, SILValue value) {
2403
2405
2404
2406
// / Emit all the shared case statements.
2405
2407
void PatternMatchEmission::emitSharedCaseBlocks () {
2406
- for (auto &entry: SharedCases) {
2408
+ for (auto &entry : SharedCases) {
2407
2409
CaseStmt *caseBlock = entry.first ;
2408
2410
SILBasicBlock *caseBB = entry.second .first ;
2409
2411
bool hasFallthroughTo = entry.second .second ;
@@ -2437,64 +2439,73 @@ void PatternMatchEmission::emitSharedCaseBlocks() {
2437
2439
// Then emit the case body into the caseBB.
2438
2440
SGF.B .setInsertionPoint (caseBB);
2439
2441
}
2440
-
2442
+
2443
+ // Make sure that before/after we emit the case body we have emitted all
2444
+ // cleanups we created within.
2441
2445
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
+ }
2442
2454
2443
2455
// If we have a shared case with bound decls, then the 0th pattern has the
2444
2456
// 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 ;
2479
2465
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);
2498
2509
}
2499
2510
}
2500
2511
@@ -2629,6 +2640,81 @@ static void emitDiagnoseOfUnexpectedEnumCase(SILGenFunction &SGF,
2629
2640
SGFContext ());
2630
2641
}
2631
2642
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
+
2632
2718
void SILGenFunction::emitSwitchStmt (SwitchStmt *S) {
2633
2719
LLVM_DEBUG (llvm::dbgs () << " emitting switch stmt\n " ;
2634
2720
S->dump (llvm::dbgs ());
@@ -2644,81 +2730,10 @@ void SILGenFunction::emitSwitchStmt(SwitchStmt *S) {
2644
2730
return ;
2645
2731
}
2646
2732
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);
2720
2736
};
2721
-
2722
2737
PatternMatchEmission emission (*this , S, completionHandler);
2723
2738
2724
2739
// Add a row for each label of each case.
0 commit comments