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::visitForStmt(ForStmt *S) { // Enter a new scope. LexicalScope ForScope(SGF.Cleanups, SGF, CleanupLocation(S)); // Emit any local 'var' variables declared in the initializer. for (auto D : S->getInitializerVarDecls()) { SGF.visit(D); } if (auto *Initializer = S->getInitializer().getPtrOrNull()) { SGF.emitIgnoredExpr(Initializer); } // If we ever reach an unreachable point, stop emitting statements. // This will need revision if we ever add goto. if (!SGF.B.hasValidInsertionPoint()) return; // Create a new basic block and jump into it. SILBasicBlock *loopBB = createBasicBlock(); SGF.B.emitBlock(loopBB, S); JumpDest endDest = createJumpDest(S->getBody()); // Evaluate the condition with the false edge leading directly // to the continuation block. Condition Cond = S->getCond().isNonNull() ? SGF.emitCondition(S->getCond().get(), /*hasFalseCode*/ false) : Condition(loopBB, 0, 0, S); // Infinite loop. // If there's a true edge, emit the body in it. if (Cond.hasTrue()) { Cond.enterTrue(SGF); SGF.emitProfilerIncrement(S->getBody()); // Set the destinations for 'break' and 'continue'. JumpDest incDest = createJumpDest(S->getBody()); SGF.BreakContinueDestStack.push_back({S, endDest, incDest}); visit(S->getBody()); SGF.BreakContinueDestStack.pop_back(); emitOrDeleteBlock(SGF, incDest, S); if (SGF.B.hasValidInsertionPoint() && S->getIncrement().isNonNull()) { FullExpr Scope(SGF.Cleanups, CleanupLocation(S->getIncrement().get())); // Ignore the result of the increment expression. SGF.emitIgnoredExpr(S->getIncrement().get()); } if (SGF.B.hasValidInsertionPoint()) { // Associate the loop body's closing brace with this branch. RegularLocation L(S->getBody()); L.pointToEnd(); SGF.B.createBranch(L, loopBB); } Cond.exitTrue(SGF); } // Complete the conditional execution. Cond.complete(SGF); emitOrDeleteBlock(SGF, endDest, S); }