void SILGenFunction::emitReturnExpr(SILLocation branchLoc, Expr *ret) { SmallVector<SILValue, 4> directResults; if (F.getLoweredFunctionType()->hasIndirectResults()) { // Indirect return of an address-only value. FullExpr scope(Cleanups, CleanupLocation(ret)); // Build an initialization which recursively destructures the tuple. SmallVector<CleanupHandle, 4> resultCleanups; InitializationPtr resultInit = prepareIndirectResultInit(*this, ret->getType()->getCanonicalType(), directResults, resultCleanups); // Emit the result expression into the initialization. emitExprInto(ret, resultInit.get()); // Deactivate all the cleanups for the result values. for (auto cleanup : resultCleanups) { Cleanups.forwardCleanup(cleanup); } } else { // SILValue return. FullExpr scope(Cleanups, CleanupLocation(ret)); emitRValue(ret).forwardAll(*this, directResults); } Cleanups.emitBranchAndCleanups(ReturnDest, branchLoc, directResults); }
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::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(); }