@@ -645,8 +645,10 @@ void OpaqueValueVisitor::checkForIndirectApply(FullApplySite applySite) {
645645 }
646646 ++calleeArgIdx;
647647 }
648- if (applySite.getSubstCalleeType ()->hasIndirectFormalResults ())
648+
649+ if (applySite.getSubstCalleeType ()->hasIndirectFormalResults ()) {
649650 pass.indirectApplies .insert (applySite);
651+ }
650652}
651653
652654// / If `value` is address-only, add it to the `valueStorageMap`.
@@ -883,6 +885,16 @@ static SILValue getProjectedUseValue(Operand *operand) {
883885 return SILValue ();
884886}
885887
888+ static bool doesNotNeedStackAllocation (SILValue value) {
889+ auto *defInst = value->getDefiningInstruction ();
890+ if (!defInst)
891+ return false ;
892+
893+ if (isa<LoadBorrowInst>(defInst) || isa<BeginApplyInst>(defInst))
894+ return true ;
895+
896+ return false ;
897+ }
886898// ===----------------------------------------------------------------------===//
887899// OpaqueStorageAllocation
888900//
@@ -1042,11 +1054,15 @@ void OpaqueStorageAllocation::allocateValue(SILValue value) {
10421054 if (getReusedStorageOperand (value))
10431055 return ;
10441056
1057+ if (doesNotNeedStackAllocation (value))
1058+ return ;
1059+
10451060 // Check for values that inherently project storage from their operand.
10461061 if (auto *storageOper = getProjectedDefOperand (value)) {
10471062 pass.valueStorageMap .recordDefProjection (storageOper, value);
10481063 return ;
10491064 }
1065+
10501066 if (value->getOwnershipKind () == OwnershipKind::Guaranteed) {
10511067 value->dump ();
10521068 llvm::report_fatal_error (" ^^^ guaranteed values must reuse storage" );
@@ -1183,7 +1199,6 @@ void OpaqueStorageAllocation::removeAllocation(SILValue value) {
11831199AllocStackInst *OpaqueStorageAllocation::createStackAllocation (SILValue value) {
11841200 assert (value.getOwnershipKind () != OwnershipKind::Guaranteed &&
11851201 " creating storage for a guaranteed value implies a copy" );
1186-
11871202 // Instructions that produce an opened type never reach here because they
11881203 // have guaranteed ownership--they project their storage. We reach this
11891204 // point after the opened value has been copied.
@@ -1822,10 +1837,11 @@ class ApplyRewriter {
18221837 loweredCalleeConv(getLoweredCallConv(oldCall)) {}
18231838
18241839 void convertApplyWithIndirectResults ();
1840+ void convertBeginApplyWithOpaqueYield ();
18251841
18261842protected:
18271843 SILBasicBlock::iterator getCallResultInsertionPoint () {
1828- if (isa<ApplyInst>(apply))
1844+ if (isa<ApplyInst>(apply) || isa<BeginApplyInst>(apply) )
18291845 return std::next (SILBasicBlock::iterator (apply.getInstruction ()));
18301846
18311847 auto *bb = cast<TryApplyInst>(apply)->getNormalBB ();
@@ -2080,6 +2096,35 @@ void ApplyRewriter::rewriteApply(ArrayRef<SILValue> newCallArgs) {
20802096 // will be deleted with its destructure_tuple.
20812097}
20822098
2099+ void ApplyRewriter::convertBeginApplyWithOpaqueYield () {
2100+ auto *origCall = cast<BeginApplyInst>(apply.getInstruction ());
2101+ SmallVector<SILValue, 4 > opValues;
2102+
2103+ for (auto &oper : origCall->getArgumentOperands ()) {
2104+ opValues.push_back (oper.get ());
2105+ }
2106+
2107+ // Recreate the begin_apply so that the instruction results have the right
2108+ // ownership kind as per the lowered addresses convention.
2109+ auto *newCall = argBuilder.createBeginApply (
2110+ callLoc, apply.getCallee (), apply.getSubstitutionMap (), opValues,
2111+ origCall->getApplyOptions (), origCall->getSpecializationInfo ());
2112+ this ->apply = FullApplySite (newCall);
2113+
2114+ // Replace uses of orig begin_apply with the new begin_apply
2115+ auto oldResults = origCall->getAllResultsBuffer ();
2116+ auto newResults = newCall->getAllResultsBuffer ();
2117+ assert (oldResults.size () == newResults.size ());
2118+ for (auto i : indices (oldResults)) {
2119+ if (oldResults[i].getType ().isAddressOnly (*pass.function )) {
2120+ pass.valueStorageMap .setStorageAddress (&oldResults[i], &newResults[i]);
2121+ pass.valueStorageMap .getStorage (&oldResults[i]).markRewritten ();
2122+ } else {
2123+ oldResults[i].replaceAllUsesWith (&newResults[i]);
2124+ }
2125+ }
2126+ }
2127+
20832128// Replace \p tryApply with a new try_apply using \p newCallArgs.
20842129//
20852130// If the old result was a single opaque value, then create and return a
@@ -2545,6 +2590,16 @@ class UseRewriter : SILInstructionVisitor<UseRewriter> {
25452590 CallArgRewriter (applyInst, pass).rewriteIndirectArgument (use);
25462591 }
25472592
2593+ void visitBeginApplyInst (BeginApplyInst *bai) {
2594+ CallArgRewriter (bai, pass).rewriteIndirectArgument (use);
2595+ }
2596+
2597+ void visitYieldInst (YieldInst *yield) {
2598+ SILValue addr =
2599+ pass.valueStorageMap .getStorage (yield->getOperand (0 )).storageAddress ;
2600+ yield->setOperand (0 , addr);
2601+ }
2602+
25482603 void visitAssignInst (AssignInst *assignInst);
25492604
25502605 void visitBeginBorrowInst (BeginBorrowInst *borrow);
@@ -3039,6 +3094,11 @@ class DefRewriter : SILInstructionVisitor<DefRewriter> {
30393094 ApplyRewriter (applyInst, pass).convertApplyWithIndirectResults ();
30403095 }
30413096
3097+ void visitBeginApplyInst (BeginApplyInst *bai) {
3098+ CallArgRewriter (bai, pass).rewriteArguments ();
3099+ ApplyRewriter (bai, pass).convertBeginApplyWithOpaqueYield ();
3100+ }
3101+
30423102 // Rewrite the apply for an indirect result.
30433103 void visitDestructureTupleInst (DestructureTupleInst *destructure) {
30443104 SILValue srcVal = destructure->getOperand ();
@@ -3107,6 +3167,10 @@ class DefRewriter : SILInstructionVisitor<DefRewriter> {
31073167 }
31083168 }
31093169
3170+ void visitLoadBorrowInst (LoadBorrowInst *lbi) {
3171+ pass.valueStorageMap .setStorageAddress (lbi, lbi->getOperand ());
3172+ }
3173+
31103174 // Define an opaque struct.
31113175 void visitStructInst (StructInst *structInst) {
31123176 // For each element, initialize the operand's memory. Some struct elements
@@ -3159,8 +3223,9 @@ static void rewriteIndirectApply(FullApplySite apply,
31593223 // If all indirect args were loadable, then they still need to be rewritten.
31603224 CallArgRewriter (apply, pass).rewriteArguments ();
31613225
3162- if (!apply.getSubstCalleeType ()->hasIndirectFormalResults ())
3226+ if (!apply.getSubstCalleeType ()->hasIndirectFormalResults ()) {
31633227 return ;
3228+ }
31643229
31653230 // If the call has indirect results and wasn't already rewritten, rewrite it
31663231 // now. This handles try_apply, which is not rewritten when DefRewriter visits
0 commit comments