Skip to content

Commit 1840724

Browse files
committed
[SILGen] Unify handling of for-in and async for-in statements
1 parent 40a7856 commit 1840724

File tree

1 file changed

+0
-169
lines changed

1 file changed

+0
-169
lines changed

lib/SILGen/SILGenStmt.cpp

Lines changed: 0 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,6 @@ namespace {
189189
#define STMT(ID, BASE) void visit##ID##Stmt(ID##Stmt *S);
190190
#include "swift/AST/StmtNodes.def"
191191

192-
void visitAsyncForEachStmt(ForEachStmt *S);
193-
194192
ASTContext &getASTContext() { return SGF.getASTContext(); }
195193

196194
SILBasicBlock *createBasicBlock() { return SGF.createBasicBlock(); }
@@ -1020,174 +1018,7 @@ void StmtEmitter::visitRepeatWhileStmt(RepeatWhileStmt *S) {
10201018
SGF.BreakContinueDestStack.pop_back();
10211019
}
10221020

1023-
void StmtEmitter::visitAsyncForEachStmt(ForEachStmt *S) {
1024-
// Emit the 'generator' variable that we'll be using for iteration.
1025-
LexicalScope OuterForScope(SGF, CleanupLocation(S));
1026-
{
1027-
SGF.emitPatternBinding(S->getIteratorVar()->getParentPatternBinding(),
1028-
/*index=*/0);
1029-
}
1030-
1031-
// If we ever reach an unreachable point, stop emitting statements.
1032-
// This will need revision if we ever add goto.
1033-
if (!SGF.B.hasValidInsertionPoint()) return;
1034-
1035-
// If generator's optional result is address-only, create a stack allocation
1036-
// to hold the results. This will be initialized on every entry into the loop
1037-
// header and consumed by the loop body. On loop exit, the terminating value
1038-
// will be in the buffer.
1039-
CanType optTy;
1040-
if (S->getConvertElementExpr()) {
1041-
optTy = S->getConvertElementExpr()->getType()->getCanonicalType();
1042-
} else {
1043-
optTy = S->getNextCall()->getType()->getCanonicalType();
1044-
}
1045-
auto &optTL = SGF.getTypeLowering(optTy);
1046-
SILValue addrOnlyBuf;
1047-
ManagedValue nextBufOrValue;
1048-
1049-
if (optTL.isAddressOnly() && SGF.silConv.useLoweredAddresses())
1050-
addrOnlyBuf = SGF.emitTemporaryAllocation(S, optTL.getLoweredType());
1051-
1052-
// Create a new basic block and jump into it.
1053-
JumpDest loopDest = createJumpDest(S->getBody());
1054-
SGF.B.emitBlock(loopDest.getBlock(), S);
1055-
1056-
// Set the destinations for 'break' and 'continue'.
1057-
JumpDest endDest = createJumpDest(S->getBody());
1058-
SGF.BreakContinueDestStack.push_back({ S, endDest, loopDest });
1059-
1060-
auto buildElementRValue = [&](SILLocation loc, SGFContext ctx) {
1061-
RValue result;
1062-
Expr *nextCall = S->getNextCall();
1063-
result = SGF.emitApplyExpr(
1064-
cast<ApplyExpr>(nextCall->getSemanticsProvidingExpr()),
1065-
S->getElementExpr() ? SGFContext() : ctx);
1066-
if (S->getElementExpr()) {
1067-
SILGenFunction::OpaqueValueRAII pushOpaqueValue(
1068-
SGF, S->getElementExpr(),
1069-
std::move(result).getAsSingleValue(SGF, loc));
1070-
result = SGF.emitRValue(S->getConvertElementExpr(), ctx);
1071-
}
1072-
return result;
1073-
};
1074-
1075-
// Then emit the loop destination block.
1076-
//
1077-
// Advance the generator. Use a scope to ensure that any temporary stack
1078-
// allocations in the subexpression are immediately released.
1079-
if (optTL.isAddressOnly() && SGF.silConv.useLoweredAddresses()) {
1080-
// Create the initialization outside of the innerForScope so that the
1081-
// innerForScope doesn't clean it up.
1082-
auto nextInit = SGF.useBufferAsTemporary(addrOnlyBuf, optTL);
1083-
{
1084-
ArgumentScope innerForScope(SGF, SILLocation(S));
1085-
SILLocation loc = SILLocation(S);
1086-
RValue result = buildElementRValue(loc, SGFContext(nextInit.get()));
1087-
if (!result.isInContext()) {
1088-
ArgumentSource(SILLocation(S->getSequence()),
1089-
std::move(result).ensurePlusOne(SGF, loc))
1090-
.forwardInto(SGF, nextInit.get());
1091-
}
1092-
innerForScope.pop();
1093-
}
1094-
nextBufOrValue = nextInit->getManagedAddress();
1095-
} else {
1096-
ArgumentScope innerForScope(SGF, SILLocation(S));
1097-
nextBufOrValue = innerForScope.popPreservingValue(
1098-
buildElementRValue(SILLocation(S), SGFContext())
1099-
.getAsSingleValue(SGF, SILLocation(S)));
1100-
}
1101-
1102-
SILBasicBlock *failExitingBlock = createBasicBlock();
1103-
SwitchEnumBuilder switchEnumBuilder(SGF.B, S, nextBufOrValue);
1104-
1105-
switchEnumBuilder.addOptionalSomeCase(
1106-
createBasicBlock(), loopDest.getBlock(),
1107-
[&](ManagedValue inputValue, SwitchCaseFullExpr &&scope) {
1108-
SGF.emitProfilerIncrement(S->getBody());
1109-
1110-
// Emit the loop body.
1111-
// The declared variable(s) for the current element are destroyed
1112-
// at the end of each loop iteration.
1113-
{
1114-
Scope innerForScope(SGF.Cleanups, CleanupLocation(S->getBody()));
1115-
// Emit the initialization for the pattern. If any of the bound
1116-
// patterns
1117-
// fail (because this is a 'for case' pattern with a refutable
1118-
// pattern,
1119-
// the code should jump to the continue block.
1120-
InitializationPtr initLoopVars =
1121-
SGF.emitPatternBindingInitialization(S->getPattern(), loopDest);
1122-
1123-
// If we had a loadable "next" generator value, we know it is present.
1124-
// Get the value out of the optional, and wrap it up with a cleanup so
1125-
// that any exits out of this scope properly clean it up.
1126-
//
1127-
// *NOTE* If we do not have an address only value, then inputValue is
1128-
// *already properly unwrapped.
1129-
if (optTL.isAddressOnly() && SGF.silConv.useLoweredAddresses()) {
1130-
inputValue = SGF.emitUncheckedGetOptionalValueFrom(
1131-
S, inputValue, optTL, SGFContext(initLoopVars.get()));
1132-
}
1133-
1134-
if (!inputValue.isInContext())
1135-
RValue(SGF, S, optTy.getOptionalObjectType(), inputValue)
1136-
.forwardInto(SGF, S, initLoopVars.get());
1137-
1138-
// Now that the pattern has been initialized, check any where
1139-
// condition.
1140-
// If it fails, loop around as if 'continue' happened.
1141-
if (auto *Where = S->getWhere()) {
1142-
auto cond = SGF.emitCondition(Where, /*invert*/ true);
1143-
// If self is null, branch to the epilog.
1144-
cond.enterTrue(SGF);
1145-
SGF.Cleanups.emitBranchAndCleanups(loopDest, Where, {});
1146-
cond.exitTrue(SGF);
1147-
cond.complete(SGF);
1148-
}
1149-
1150-
visit(S->getBody());
1151-
}
1152-
1153-
// If we emitted an unreachable in the body, we will not have a valid
1154-
// insertion point. Just return early.
1155-
if (!SGF.B.hasValidInsertionPoint()) {
1156-
scope.unreachableExit();
1157-
return;
1158-
}
1159-
1160-
// Otherwise, associate the loop body's closing brace with this branch.
1161-
RegularLocation L(S->getBody());
1162-
L.pointToEnd();
1163-
scope.exitAndBranch(L);
1164-
},
1165-
SGF.loadProfilerCount(S->getBody()));
1166-
1167-
// We add loop fail block, just to be defensive about intermediate
1168-
// transformations performing cleanups at scope.exit(). We still jump to the
1169-
// contBlock.
1170-
switchEnumBuilder.addOptionalNoneCase(
1171-
createBasicBlock(), failExitingBlock,
1172-
[&](ManagedValue inputValue, SwitchCaseFullExpr &&scope) {
1173-
assert(!inputValue && "None should not be passed an argument!");
1174-
scope.exitAndBranch(S);
1175-
},
1176-
SGF.loadProfilerCount(S));
1177-
1178-
std::move(switchEnumBuilder).emit();
1179-
1180-
SGF.B.emitBlock(failExitingBlock);
1181-
emitOrDeleteBlock(SGF, endDest, S);
1182-
SGF.BreakContinueDestStack.pop_back();
1183-
}
1184-
11851021
void StmtEmitter::visitForEachStmt(ForEachStmt *S) {
1186-
if (S->getAwaitLoc().isValid()) {
1187-
visitAsyncForEachStmt(S);
1188-
return;
1189-
}
1190-
11911022
// Emit the 'iterator' variable that we'll be using for iteration.
11921023
LexicalScope OuterForScope(SGF, CleanupLocation(S));
11931024
{

0 commit comments

Comments
 (0)