@@ -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.
24052407void 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+
26322718void 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