void StmtEmitter::visitWhileStmt(WhileStmt *S) { LexicalScope condBufferScope(SGF, S); // Create a new basic block and jump into it. JumpDest loopDest = createJumpDest(S->getBody()); SGF.B.emitBlock(loopDest.getBlock(), S); // Create a break target (at this level in the cleanup stack) in case it is // needed. JumpDest breakDest = createJumpDest(S->getBody()); // Set the destinations for any 'break' and 'continue' statements inside the // body. SGF.BreakContinueDestStack.push_back({S, breakDest, loopDest}); // Evaluate the condition, the body, and a branch back to LoopBB when the // condition is true. On failure, jump to BreakBB. { // Enter a scope for any bound pattern variables. Scope conditionScope(SGF.Cleanups, S); auto NumTrueTaken = SGF.loadProfilerCount(S->getBody()); auto NumFalseTaken = SGF.loadProfilerCount(S); SGF.emitStmtCondition(S->getCond(), breakDest, S, NumTrueTaken, NumFalseTaken); // In the success path, emit the body of the while. SGF.emitProfilerIncrement(S->getBody()); SGF.emitStmt(S->getBody()); // Finish the "true part" by cleaning up any temporaries and jumping to the // continuation block. if (SGF.B.hasValidInsertionPoint()) { RegularLocation L(S->getBody()); L.pointToEnd(); SGF.Cleanups.emitBranchAndCleanups(loopDest, L); } } SGF.BreakContinueDestStack.pop_back(); // Handle break block. If it was used, we link it up with the cleanup chain, // otherwise we just remove it. SILBasicBlock *breakBB = breakDest.getBlock(); if (breakBB->pred_empty()) { SGF.eraseBasicBlock(breakBB); } else { SGF.B.emitBlock(breakBB); } }
void StmtEmitter::visitDoStmt(DoStmt *S) { // We don't need to do anything fancy if we don't have a label. // Otherwise, assume we might break or continue. bool hasLabel = (bool) S->getLabelInfo(); JumpDest endDest = JumpDest::invalid(); if (hasLabel) { // Create the end dest first so that the loop dest comes in-between. endDest = createJumpDest(S->getBody()); // Create a new basic block and jump into it. JumpDest loopDest = createJumpDest(S->getBody()); SGF.B.emitBlock(loopDest.getBlock(), S); // Set the destinations for 'break' and 'continue'. SGF.BreakContinueDestStack.push_back({S, endDest, loopDest}); } // Emit the body. visit(S->getBody()); if (hasLabel) { SGF.BreakContinueDestStack.pop_back(); emitOrDeleteBlock(SGF, endDest, CleanupLocation(S)); } }
void StmtEmitter::visitGuardStmt(GuardStmt *S) { // Create a block for the body and emit code into it before processing any of // the patterns, because none of the bound variables will be in scope in the // 'body' context. JumpDest bodyBB = JumpDest(createBasicBlock(), SGF.getCleanupsDepth(), CleanupLocation(S)); { // Move the insertion point to the 'body' block temporarily and emit it. // Note that we don't push break/continue locations since they aren't valid // in this statement. SavedInsertionPoint savedIP(SGF, bodyBB.getBlock()); SGF.emitProfilerIncrement(S->getBody()); SGF.emitStmt(S->getBody()); // The body block must end in a noreturn call, return, break etc. It // isn't valid to fall off into the normal flow. To model this, we emit // an unreachable instruction and then have SIL diagnostic check this. if (SGF.B.hasValidInsertionPoint()) SGF.B.createUnreachable(S); } // Emit the condition bindings, branching to the bodyBB if they fail. Since // we didn't push a scope, the bound variables are live after this statement. SGF.emitStmtCondition(S->getCond(), bodyBB, S); }
/// emitBranchAndCleanups - Emit a branch to the given jump destination, /// threading out through any cleanups we might need to run. This does not /// pop the cleanup stack. void CleanupManager::emitBranchAndCleanups(JumpDest Dest, SILLocation BranchLoc, ArrayRef<SILValue> Args) { SILGenBuilder &B = Gen.getBuilder(); assert(B.hasValidInsertionPoint() && "Emitting branch in invalid spot"); emitCleanups(Dest.getDepth(), Dest.getCleanupLocation(), /*popCleanups=*/false); B.createBranch(BranchLoc, Dest.getBlock(), Args); }
static bool prepareExtraEpilog(SILGenFunction &SGF, JumpDest &dest, SILLocation &loc, SILValue *arg) { assert(!SGF.B.hasValidInsertionPoint()); // If we don't have a destination, we don't need to emit the epilog. if (!dest.isValid()) return false; // If the destination isn't used, we don't need to emit the epilog. SILBasicBlock *epilogBB = dest.getBlock(); auto pi = epilogBB->pred_begin(), pe = epilogBB->pred_end(); if (pi == pe) { dest = JumpDest::invalid(); SGF.eraseBasicBlock(epilogBB); return false; } assert(epilogBB->getNumArguments() <= 1); assert((epilogBB->getNumArguments() == 1) == (arg != nullptr)); if (arg) *arg = epilogBB->args_begin()[0]; bool reposition = true; // If the destination has a single branch predecessor, // consider emitting the epilog into it. SILBasicBlock *predBB = *pi; if (++pi == pe) { if (auto branch = dyn_cast<BranchInst>(predBB->getTerminator())) { assert(branch->getArgs().size() == epilogBB->getNumArguments()); // Save the location and operand information from the branch, // then destroy it. loc = branch->getLoc(); if (arg) *arg = branch->getArgs()[0]; predBB->erase(branch); // Erase the rethrow block. SGF.eraseBasicBlock(epilogBB); epilogBB = predBB; reposition = false; } } // Reposition the block to the end of the postmatter section // unless we're emitting into a single predecessor. if (reposition) { SGF.B.moveBlockTo(epilogBB, SGF.F.end()); } SGF.B.setInsertionPoint(epilogBB); return true; }
/// Terminate the current block by emitting a branch which might leave /// the current cleanup-protected scope. The target scope may not yet /// be known, in which case this will require a fixup. /// /// As a side-effect, this method clears the insertion point. void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) { assert(Dest.getScopeDepth().encloses(EHStack.stable_begin()) && "stale jump destination"); if (!HaveInsertPoint()) return; // Create the branch. llvm::BranchInst *BI = Builder.CreateBr(Dest.getBlock()); // Calculate the innermost active normal cleanup. EHScopeStack::stable_iterator TopCleanup = EHStack.getInnermostActiveNormalCleanup(); // If we're not in an active normal cleanup scope, or if the // destination scope is within the innermost active normal cleanup // scope, we don't need to worry about fixups. if (TopCleanup == EHStack.stable_end() || TopCleanup.encloses(Dest.getScopeDepth())) { // works for invalid Builder.ClearInsertionPoint(); return; } // If we can't resolve the destination cleanup scope, just add this // to the current cleanup scope as a branch fixup. if (!Dest.getScopeDepth().isValid()) { BranchFixup &Fixup = EHStack.addBranchFixup(); Fixup.Destination = Dest.getBlock(); Fixup.DestinationIndex = Dest.getDestIndex(); Fixup.InitialBranch = BI; Fixup.OptimisticBranchBlock = nullptr; Builder.ClearInsertionPoint(); return; } // Otherwise, thread through all the normal cleanups in scope. // Store the index at the start. llvm::ConstantInt *Index = Builder.getInt32(Dest.getDestIndex()); new llvm::StoreInst(Index, getNormalCleanupDestSlot(), BI); // Adjust BI to point to the first cleanup block. { EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.find(TopCleanup)); BI->setSuccessor(0, CreateNormalEntry(*this, Scope)); } // Add this destination to all the scopes involved. EHScopeStack::stable_iterator I = TopCleanup; EHScopeStack::stable_iterator E = Dest.getScopeDepth(); if (E.strictlyEncloses(I)) { while (true) { EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.find(I)); assert(Scope.isNormalCleanup()); I = Scope.getEnclosingNormalCleanup(); // If this is the last cleanup we're propagating through, tell it // that there's a resolved jump moving through it. if (!E.strictlyEncloses(I)) { Scope.addBranchAfter(Index, Dest.getBlock()); break; } // Otherwise, tell the scope that there's a jump propoagating // through it. If this isn't new information, all the rest of // the work has been done before. if (!Scope.addBranchThrough(Dest.getBlock())) break; } } Builder.ClearInsertionPoint(); }
void StmtEmitter::visitForEachStmt(ForEachStmt *S) { // Emit the 'iterator' variable that we'll be using for iteration. LexicalScope OuterForScope(SGF.Cleanups, SGF, CleanupLocation(S)); SGF.visitPatternBindingDecl(S->getIterator()); // If we ever reach an unreachable point, stop emitting statements. // This will need revision if we ever add goto. if (!SGF.B.hasValidInsertionPoint()) return; // If generator's optional result is address-only, create a stack allocation // to hold the results. This will be initialized on every entry into the loop // header and consumed by the loop body. On loop exit, the terminating value // will be in the buffer. auto optTy = S->getIteratorNext()->getType()->getCanonicalType(); auto &optTL = SGF.getTypeLowering(optTy); SILValue nextBufOrValue; if (optTL.isAddressOnly()) nextBufOrValue = SGF.emitTemporaryAllocation(S, optTL.getLoweredType()); // Create a new basic block and jump into it. JumpDest loopDest = createJumpDest(S->getBody()); SGF.B.emitBlock(loopDest.getBlock(), S); // Set the destinations for 'break' and 'continue'. JumpDest endDest = createJumpDest(S->getBody()); SGF.BreakContinueDestStack.push_back({ S, endDest, loopDest }); // Advance the generator. Use a scope to ensure that any temporary stack // allocations in the subexpression are immediately released. if (optTL.isAddressOnly()) { Scope InnerForScope(SGF.Cleanups, CleanupLocation(S->getIteratorNext())); auto nextInit = SGF.useBufferAsTemporary(nextBufOrValue, optTL); SGF.emitExprInto(S->getIteratorNext(), nextInit.get()); nextInit->getManagedAddress().forward(SGF); } else { Scope InnerForScope(SGF.Cleanups, CleanupLocation(S->getIteratorNext())); nextBufOrValue = SGF.emitRValueAsSingleValue(S->getIteratorNext()).forward(SGF); } // Continue if the value is present. Condition Cond = SGF.emitCondition( SGF.emitDoesOptionalHaveValue(S, nextBufOrValue), S, /*hasFalseCode=*/false, /*invertValue=*/false); if (Cond.hasTrue()) { Cond.enterTrue(SGF); SGF.emitProfilerIncrement(S->getBody()); // Emit the loop body. // The declared variable(s) for the current element are destroyed // at the end of each loop iteration. { Scope InnerForScope(SGF.Cleanups, CleanupLocation(S->getBody())); // Emit the initialization for the pattern. If any of the bound patterns // fail (because this is a 'for case' pattern with a refutable pattern, // the code should jump to the continue block. InitializationPtr initLoopVars = SGF.emitPatternBindingInitialization(S->getPattern(), loopDest); ManagedValue val; // If we had a loadable "next" generator value, we know it is present. // Get the value out of the optional, and wrap it up with a cleanup so // that any exits out of this scope properly clean it up. if (optTL.isLoadable()) { val = SGF.emitManagedRValueWithCleanup(nextBufOrValue); } else { val = SGF.emitManagedBufferWithCleanup(nextBufOrValue); } val = SGF.emitUncheckedGetOptionalValueFrom(S, val, optTL, SGFContext(initLoopVars.get())); if (!val.isInContext()) RValue(SGF, S, optTy.getAnyOptionalObjectType(), val) .forwardInto(SGF, S, initLoopVars.get()); // Now that the pattern has been initialized, check any where condition. // If it fails, loop around as if 'continue' happened. if (auto *Where = S->getWhere()) { auto cond = SGF.emitCondition(Where, /*hasFalse*/false, /*invert*/true); // If self is null, branch to the epilog. cond.enterTrue(SGF); SGF.Cleanups.emitBranchAndCleanups(loopDest, Where, { }); cond.exitTrue(SGF); cond.complete(SGF); } visit(S->getBody()); } // Loop back to the header. if (SGF.B.hasValidInsertionPoint()) { // Associate the loop body's closing brace with this branch. RegularLocation L(S->getBody()); L.pointToEnd(); SGF.B.createBranch(L, loopDest.getBlock()); } Cond.exitTrue(SGF); } // Complete the conditional execution. Cond.complete(SGF); emitOrDeleteBlock(SGF, endDest, S); SGF.BreakContinueDestStack.pop_back(); // We do not need to destroy the value in the 'nextBuf' slot here, because // either the 'for' loop finished naturally and the buffer contains '.None', // or we exited by 'break' and the value in the buffer was consumed. }
void StmtEmitter::visitDoCatchStmt(DoCatchStmt *S) { Type formalExnType = S->getCatches().front()->getErrorPattern()->getType(); auto &exnTL = SGF.getTypeLowering(formalExnType); // Create the throw destination at the end of the function. JumpDest throwDest = createJumpDest(S->getBody(), FunctionSection::Postmatter); SILArgument *exnArg = throwDest.getBlock()->createBBArg(exnTL.getLoweredType()); // We always need a continuation block because we might fall out of // a catch block. But we don't need a loop block unless the 'do' // statement is labeled. JumpDest endDest = createJumpDest(S->getBody()); // We don't need to do anything too fancy about emission if we don't // have a label. Otherwise, assume we might break or continue. bool hasLabel = (bool) S->getLabelInfo(); if (hasLabel) { // Create a new basic block and jump into it. JumpDest loopDest = createJumpDest(S->getBody()); SGF.B.emitBlock(loopDest.getBlock(), S); // Set the destinations for 'break' and 'continue'. SGF.BreakContinueDestStack.push_back({S, endDest, loopDest}); } // Emit the body. { // Push the new throw destination. llvm::SaveAndRestore<JumpDest> savedThrowDest(SGF.ThrowDest, throwDest); visit(S->getBody()); // We emit the counter for exiting the do-block here, as we may not have a // valid insertion point when falling out. SGF.emitProfilerIncrement(S); } // Emit the catch clauses, but only if the body of the function // actually throws. This is a consequence of the fact that a // DoCatchStmt with a non-throwing body will type check even in // a non-throwing lexical context. In this case, our local throwDest // has no predecessors, and SGF.ThrowDest may not be valid either. if (auto *BB = getOrEraseBlock(SGF, throwDest)) { // Move the insertion point to the throw destination. SavedInsertionPoint savedIP(SGF, BB, FunctionSection::Postmatter); // The exception cleanup should be getting forwarded around // correctly anyway, but push a scope to ensure it gets popped. Scope exnScope(SGF.Cleanups, CleanupLocation(S)); // Take ownership of the exception. ManagedValue exn = SGF.emitManagedRValueWithCleanup(exnArg, exnTL); // Emit all the catch clauses, branching to the end destination if // we fall out of one. SGF.emitCatchDispatch(S, exn, S->getCatches(), endDest); } if (hasLabel) { SGF.BreakContinueDestStack.pop_back(); } // Handle falling out of the do-block. // // It's important for good code layout that the insertion point be // left in the original function section after this. So if // emitOrDeleteBlock ever learns to just continue in the // predecessor, we'll need to suppress that here. emitOrDeleteBlock(SGF, endDest, CleanupLocation(S->getBody())); }
void StmtEmitter::visitIfStmt(IfStmt *S) { Scope condBufferScope(SGF.Cleanups, S); // Create a continuation block. We need it if there is a labeled break out // of the if statement or if there is an if/then/else. JumpDest contDest = createJumpDest(S->getThenStmt()); auto contBB = contDest.getBlock(); // Set the destinations for any 'break' and 'continue' statements inside the // body. Note that "continue" is not valid out of a labeled 'if'. SGF.BreakContinueDestStack.push_back( { S, contDest, JumpDest(CleanupLocation(S)) }); // Set up the block for the false case. If there is an 'else' block, we make // a new one, otherwise it is our continue block. JumpDest falseDest = contDest; if (S->getElseStmt()) falseDest = createJumpDest(S); // Emit the condition, along with the "then" part of the if properly guarded // by the condition and a jump to ContBB. If the condition fails, jump to // the CondFalseBB. { // Enter a scope for any bound pattern variables. LexicalScope trueScope(SGF.Cleanups, SGF, S); SGF.emitStmtCondition(S->getCond(), falseDest, S); // In the success path, emit the 'then' part if the if. SGF.emitProfilerIncrement(S->getThenStmt()); SGF.emitStmt(S->getThenStmt()); // Finish the "true part" by cleaning up any temporaries and jumping to the // continuation block. if (SGF.B.hasValidInsertionPoint()) { RegularLocation L(S->getThenStmt()); L.pointToEnd(); SGF.Cleanups.emitBranchAndCleanups(contDest, L); } } // If there is 'else' logic, then emit it. if (S->getElseStmt()) { SGF.B.emitBlock(falseDest.getBlock()); visit(S->getElseStmt()); if (SGF.B.hasValidInsertionPoint()) { RegularLocation L(S->getElseStmt()); L.pointToEnd(); SGF.B.createBranch(L, contBB); } } // If the continuation block was used, emit it now, otherwise remove it. if (contBB->pred_empty()) { SGF.eraseBasicBlock(contBB); } else { RegularLocation L(S->getThenStmt()); L.pointToEnd(); SGF.B.emitBlock(contBB, L); } SGF.BreakContinueDestStack.pop_back(); }
void CodeGenFunction::EmitUPCForAllStmt(const UPCForAllStmt &S) { JumpDest LoopExit = getJumpDestInCurrentScope("upc_forall.end"); RunCleanupsScope ForScope(*this); llvm::Value *Depth = 0; if (S.getAfnty()) { Address DepthAddr = getUPCForAllDepth(CGM); Depth = Builder.CreateLoad(DepthAddr); Builder.CreateStore(Builder.CreateNUWAdd(Depth, llvm::ConstantInt::get(IntTy, 1), "upc_forall.inc_depth"), DepthAddr); EHStack.pushCleanup<UPCForAllCleanup>(NormalAndEHCleanup, Depth); } CGDebugInfo *DI = getDebugInfo(); if (DI) DI->EmitLexicalBlockStart(Builder, S.getSourceRange().getBegin()); // Evaluate the first part before the loop. if (S.getInit()) EmitStmt(S.getInit()); // Start the loop with a block that tests the condition. // If there's an increment, the continue scope will be overwritten // later. JumpDest Continue = getJumpDestInCurrentScope("upc_forall.cond"); llvm::BasicBlock *CondBlock = Continue.getBlock(); EmitBlock(CondBlock); // Create a cleanup scope for the condition variable cleanups. RunCleanupsScope ConditionScope(*this); llvm::Value *BoolCondVal = 0; if (S.getCond()) { // If the for statement has a condition scope, emit the local variable // declaration. llvm::BasicBlock *ExitBlock = LoopExit.getBlock(); if (S.getConditionVariable()) { EmitAutoVarDecl(*S.getConditionVariable()); } // If there are any cleanups between here and the loop-exit scope, // create a block to stage a loop exit along. if (ForScope.requiresCleanups()) ExitBlock = createBasicBlock("upcforall.cond.cleanup"); // As long as the condition is true, iterate the loop. llvm::BasicBlock *ForBody = createBasicBlock("upc_forall.filter"); // C99 6.8.5p2/p4: The first substatement is executed if the expression // compares unequal to 0. The condition must be a scalar type. BoolCondVal = EvaluateExprAsBool(S.getCond()); Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock); if (ExitBlock != LoopExit.getBlock()) { EmitBlock(ExitBlock); EmitBranchThroughCleanup(LoopExit); } EmitBlock(ForBody); } else { // Treat it as a non-zero constant. Don't even create a new block for the // body, just fall into it. } // If the for loop doesn't have an increment we can just use the // condition as the continue block. Otherwise we'll need to create // a block for it (in the current scope, i.e. in the scope of the // condition), and that we will become our continue block. if (S.getInc()) Continue = getJumpDestInCurrentScope("upc_forall.inc"); // Store the blocks to use for break and continue. BreakContinueStack.push_back(BreakContinue(LoopExit, Continue)); if (const Expr *Afnty = S.getAfnty()) { llvm::Value *Affinity = EmitScalarExpr(Afnty); if (Afnty->getType()->hasPointerToSharedRepresentation()) { // get threadof Affinity = EmitUPCPointerGetThread(Affinity); } else { assert(Affinity->getType()->isIntegerTy()); llvm::Value *Threads = EmitUPCThreads(); if (cast<llvm::IntegerType>(Threads->getType())->getBitWidth() < cast<llvm::IntegerType>(Affinity->getType())->getBitWidth()) { Threads = Builder.CreateIntCast(Threads, Affinity->getType(), false); } else { Affinity = Builder.CreateIntCast(Affinity, Threads->getType(), Afnty->getType()->hasSignedIntegerRepresentation()); } if (Afnty->getType()->hasSignedIntegerRepresentation()) { Affinity = Builder.CreateSRem(Affinity, Threads); llvm::Value *Zero = llvm::ConstantInt::get(Affinity->getType(), 0); Affinity = Builder.CreateSelect(Builder.CreateICmpSLT(Affinity, Zero), Builder.CreateAdd(Affinity, Threads), Affinity); } else { Affinity = Builder.CreateURem(Affinity, Threads); } } Affinity = Builder.CreateIntCast(Affinity, IntTy, false); llvm::Value *MyThread = EmitUPCMyThread(); llvm::Value *Test = Builder.CreateOr(Builder.CreateICmpUGT(Depth, llvm::ConstantInt::get(IntTy, 0)), Builder.CreateICmpEQ(Affinity, MyThread)); llvm::BasicBlock *RealBody = createBasicBlock("upc_forall.body"); Builder.CreateCondBr(Test, RealBody, Continue.getBlock()); EmitBlock(RealBody); } { // Create a separate cleanup scope for the body, in case it is not // a compound statement. RunCleanupsScope BodyScope(*this); EmitStmt(S.getBody()); } // If there is an increment, emit it next. if (S.getInc()) { EmitBlock(Continue.getBlock()); EmitStmt(S.getInc()); } BreakContinueStack.pop_back(); ConditionScope.ForceCleanup(); EmitBranch(CondBlock); ForScope.ForceCleanup(); if (DI) DI->EmitLexicalBlockEnd(Builder, S.getSourceRange().getEnd()); // Emit the fall-through block. EmitBlock(LoopExit.getBlock(), true); }
void StmtEmitter::visitForEachStmt(ForEachStmt *S) { // Emit the 'iterator' variable that we'll be using for iteration. LexicalScope OuterForScope(SGF, CleanupLocation(S)); SGF.visitPatternBindingDecl(S->getIterator()); // If we ever reach an unreachable point, stop emitting statements. // This will need revision if we ever add goto. if (!SGF.B.hasValidInsertionPoint()) return; // If generator's optional result is address-only, create a stack allocation // to hold the results. This will be initialized on every entry into the loop // header and consumed by the loop body. On loop exit, the terminating value // will be in the buffer. auto optTy = S->getIteratorNext()->getType()->getCanonicalType(); auto &optTL = SGF.getTypeLowering(optTy); SILValue addrOnlyBuf; ManagedValue nextBufOrValue; if (optTL.isAddressOnly() && SGF.silConv.useLoweredAddresses()) addrOnlyBuf = SGF.emitTemporaryAllocation(S, optTL.getLoweredType()); // Create a new basic block and jump into it. JumpDest loopDest = createJumpDest(S->getBody()); SGF.B.emitBlock(loopDest.getBlock(), S); // Set the destinations for 'break' and 'continue'. JumpDest endDest = createJumpDest(S->getBody()); SGF.BreakContinueDestStack.push_back({ S, endDest, loopDest }); // Then emit the loop destination block. // // Advance the generator. Use a scope to ensure that any temporary stack // allocations in the subexpression are immediately released. if (optTL.isAddressOnly() && SGF.silConv.useLoweredAddresses()) { // Create the initialization outside of the innerForScope so that the // innerForScope doesn't clean it up. auto nextInit = SGF.useBufferAsTemporary(addrOnlyBuf, optTL); { Scope innerForScope(SGF.Cleanups, CleanupLocation(S->getIteratorNext())); SGF.emitExprInto(S->getIteratorNext(), nextInit.get()); } nextBufOrValue = nextInit->getManagedAddress(); } else { Scope innerForScope(SGF.Cleanups, CleanupLocation(S->getIteratorNext())); nextBufOrValue = innerForScope.popPreservingValue( SGF.emitRValueAsSingleValue(S->getIteratorNext())); } SILBasicBlock *failExitingBlock = createBasicBlock(); SwitchEnumBuilder switchEnumBuilder(SGF.B, S, nextBufOrValue); switchEnumBuilder.addOptionalSomeCase( createBasicBlock(), loopDest.getBlock(), [&](ManagedValue inputValue, SwitchCaseFullExpr &&scope) { SGF.emitProfilerIncrement(S->getBody()); // Emit the loop body. // The declared variable(s) for the current element are destroyed // at the end of each loop iteration. { Scope innerForScope(SGF.Cleanups, CleanupLocation(S->getBody())); // Emit the initialization for the pattern. If any of the bound // patterns // fail (because this is a 'for case' pattern with a refutable // pattern, // the code should jump to the continue block. InitializationPtr initLoopVars = SGF.emitPatternBindingInitialization(S->getPattern(), loopDest); // If we had a loadable "next" generator value, we know it is present. // Get the value out of the optional, and wrap it up with a cleanup so // that any exits out of this scope properly clean it up. // // *NOTE* If we do not have an address only value, then inputValue is // *already properly unwrapped. if (optTL.isAddressOnly() && SGF.silConv.useLoweredAddresses()) { inputValue = SGF.emitUncheckedGetOptionalValueFrom( S, inputValue, optTL, SGFContext(initLoopVars.get())); } if (!inputValue.isInContext()) RValue(SGF, S, optTy.getOptionalObjectType(), inputValue) .forwardInto(SGF, S, initLoopVars.get()); // Now that the pattern has been initialized, check any where // condition. // If it fails, loop around as if 'continue' happened. if (auto *Where = S->getWhere()) { auto cond = SGF.emitCondition(Where, /*hasFalse*/ false, /*invert*/ true); // If self is null, branch to the epilog. cond.enterTrue(SGF); SGF.Cleanups.emitBranchAndCleanups(loopDest, Where, {}); cond.exitTrue(SGF); cond.complete(SGF); } visit(S->getBody()); } // If we emitted an unreachable in the body, we will not have a valid // insertion point. Just return early. if (!SGF.B.hasValidInsertionPoint()) { scope.unreachableExit(); return; } // Otherwise, associate the loop body's closing brace with this branch. RegularLocation L(S->getBody()); L.pointToEnd(); scope.exitAndBranch(L); }, SGF.loadProfilerCount(S->getBody())); // We add loop fail block, just to be defensive about intermediate // transformations performing cleanups at scope.exit(). We still jump to the // contBlock. switchEnumBuilder.addOptionalNoneCase( createBasicBlock(), failExitingBlock, [&](ManagedValue inputValue, SwitchCaseFullExpr &&scope) { assert(!inputValue && "None should not be passed an argument!"); scope.exitAndBranch(S); }, SGF.loadProfilerCount(S)); std::move(switchEnumBuilder).emit(); SGF.B.emitBlock(failExitingBlock); emitOrDeleteBlock(SGF, endDest, S); SGF.BreakContinueDestStack.pop_back(); }