Skip to content

Commit 53f0d81

Browse files
committed
[AddressLowering] Rewrite indirect yields.
When a coroutine yields a value via an indirect convention, an address must be yielded. For address-only types, AddressLowering was already handling this. Here, support is added for all loadable, indirect operands.
1 parent 65fe910 commit 53f0d81

File tree

2 files changed

+393
-1
lines changed

2 files changed

+393
-1
lines changed

lib/SILOptimizer/Mandatory/AddressLowering.cpp

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@
145145
#include "swift/SIL/PrunedLiveness.h"
146146
#include "swift/SIL/SILArgument.h"
147147
#include "swift/SIL/SILBuilder.h"
148+
#include "swift/SIL/SILInstruction.h"
149+
#include "swift/SIL/SILValue.h"
148150
#include "swift/SIL/SILVisitor.h"
149151
#include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h"
150152
#include "swift/SILOptimizer/PassManager/Transforms.h"
@@ -432,6 +434,9 @@ struct AddressLoweringState {
432434
// All function-exiting terminators (return or throw instructions).
433435
SmallVector<TermInst *, 8> exitingInsts;
434436

437+
// All instructions that yield values to callees.
438+
TinyPtrVector<YieldInst *> yieldInsts;
439+
435440
// Handle moves from a phi's operand storage to the phi storage.
436441
std::unique_ptr<PhiRewriter> phiRewriter;
437442

@@ -616,6 +621,10 @@ void OpaqueValueVisitor::mapValueStorage() {
616621
if (auto apply = FullApplySite::isa(&inst))
617622
checkForIndirectApply(apply);
618623

624+
if (auto *yieldInst = dyn_cast<YieldInst>(&inst)) {
625+
pass.yieldInsts.push_back(yieldInst);
626+
}
627+
619628
for (auto result : inst.getResults()) {
620629
if (isPseudoCallResult(result) || isPseudoReturnValue(result))
621630
continue;
@@ -2130,7 +2139,7 @@ static void emitEndBorrows(SILValue value, AddressLoweringState &pass);
21302139
void ApplyRewriter::convertBeginApplyWithOpaqueYield() {
21312140
// Avoid revisiting this apply.
21322141
bool erased = pass.indirectApplies.erase(apply);
2133-
assert(erased && "all yields should be rewritten at the same time");
2142+
assert(erased && "all begin_applies should be rewritten at the same time");
21342143
(void)erased;
21352144

21362145
auto *origCall = cast<BeginApplyInst>(apply.getInstruction());
@@ -2591,6 +2600,119 @@ void ReturnRewriter::rewriteElement(SILValue oldResult,
25912600
}
25922601
}
25932602

2603+
//===----------------------------------------------------------------------===//
2604+
// YieldRewriter
2605+
//
2606+
// Rewrite return instructions for indirect results.
2607+
//===----------------------------------------------------------------------===//
2608+
2609+
class YieldRewriter {
2610+
AddressLoweringState &pass;
2611+
SILFunctionConventions opaqueFnConv;
2612+
2613+
public:
2614+
YieldRewriter(AddressLoweringState &pass)
2615+
: pass(pass), opaqueFnConv(pass.function->getConventions()) {}
2616+
2617+
void rewriteYields();
2618+
2619+
void rewriteYield(YieldInst *yieldInst);
2620+
2621+
protected:
2622+
void rewriteOperand(YieldInst *yieldInst, unsigned index);
2623+
};
2624+
2625+
void YieldRewriter::rewriteYields() {
2626+
for (auto *yield : pass.yieldInsts) {
2627+
rewriteYield(yield);
2628+
}
2629+
}
2630+
2631+
void YieldRewriter::rewriteYield(YieldInst *yieldInst) {
2632+
for (unsigned index = 0, count = yieldInst->getNumOperands(); index < count;
2633+
++index) {
2634+
rewriteOperand(yieldInst, index);
2635+
}
2636+
}
2637+
void YieldRewriter::rewriteOperand(YieldInst *yieldInst, unsigned index) {
2638+
auto info = opaqueFnConv.getYieldInfoForOperandIndex(index);
2639+
auto convention = info.getConvention();
2640+
auto ty =
2641+
opaqueFnConv.getSILType(info, pass.function->getTypeExpansionContext());
2642+
if (ty.isAddressOnly(*pass.function)) {
2643+
assert(yieldInst->getOperand(index)->getType().isAddress() &&
2644+
"rewriting yield of of address-only value after use rewriting!?");
2645+
return;
2646+
}
2647+
2648+
OwnershipKind ownership = OwnershipKind::None;
2649+
switch (convention) {
2650+
case ParameterConvention::Direct_Unowned:
2651+
case ParameterConvention::Direct_Guaranteed:
2652+
case ParameterConvention::Direct_Owned:
2653+
return;
2654+
case ParameterConvention::Indirect_Inout:
2655+
case ParameterConvention::Indirect_InoutAliasable:
2656+
return;
2657+
case ParameterConvention::Indirect_In:
2658+
case ParameterConvention::Indirect_In_Constant:
2659+
ownership = OwnershipKind::Owned;
2660+
break;
2661+
case ParameterConvention::Indirect_In_Guaranteed:
2662+
ownership = OwnershipKind::Guaranteed;
2663+
}
2664+
2665+
if (ty.isTrivial(*pass.function))
2666+
ownership = OwnershipKind::None;
2667+
2668+
auto operand = yieldInst->getOperand(index);
2669+
2670+
auto builder = pass.getBuilder(yieldInst->getIterator());
2671+
2672+
auto *asi = builder.createAllocStack(yieldInst->getLoc(), ty);
2673+
2674+
auto withSuccessorBuilders = [&](auto perform) {
2675+
auto *resumeBB = &yieldInst->getResumeBB()->front();
2676+
auto *unwindBB = &yieldInst->getUnwindBB()->front();
2677+
auto resumeBuilder = pass.getBuilder(resumeBB->getIterator());
2678+
auto unwindBuilder = pass.getBuilder(unwindBB->getIterator());
2679+
perform(resumeBuilder, resumeBB->getLoc());
2680+
perform(unwindBuilder, unwindBB->getLoc());
2681+
};
2682+
2683+
switch (ownership) {
2684+
case OwnershipKind::Owned:
2685+
case OwnershipKind::None:
2686+
builder.createStore(yieldInst->getLoc(), operand, asi,
2687+
ownership == OwnershipKind::None
2688+
? StoreOwnershipQualifier::Trivial
2689+
: StoreOwnershipQualifier::Init);
2690+
yieldInst->setOperand(index, asi);
2691+
withSuccessorBuilders(
2692+
[&](auto builder, auto loc) { builder.createDeallocStack(loc, asi); });
2693+
break;
2694+
case OwnershipKind::Guaranteed: {
2695+
BeginBorrowInst *bbi = nullptr;
2696+
if (operand->getOwnershipKind() == OwnershipKind::Owned) {
2697+
bbi = builder.createBeginBorrow(yieldInst->getLoc(), operand);
2698+
}
2699+
auto *storeBorrow = builder.createStoreBorrow(yieldInst->getLoc(),
2700+
bbi ? bbi : operand, asi);
2701+
yieldInst->setOperand(index, storeBorrow);
2702+
withSuccessorBuilders([&](auto builder, auto loc) {
2703+
builder.createEndBorrow(loc, storeBorrow);
2704+
if (bbi)
2705+
builder.createEndBorrow(loc, bbi);
2706+
builder.createDeallocStack(loc, asi);
2707+
});
2708+
break;
2709+
}
2710+
case OwnershipKind::Unowned:
2711+
case OwnershipKind::Any:
2712+
llvm_unreachable("unexpected ownership kind!?");
2713+
}
2714+
}
2715+
25942716
//===----------------------------------------------------------------------===//
25952717
// UseRewriter
25962718
//
@@ -3522,6 +3644,8 @@ static void rewriteFunction(AddressLoweringState &pass) {
35223644
// projection operands.
35233645
if (pass.function->getLoweredFunctionType()->hasIndirectFormalResults())
35243646
ReturnRewriter(pass).rewriteReturns();
3647+
if (pass.function->getLoweredFunctionType()->hasIndirectFormalYields())
3648+
YieldRewriter(pass).rewriteYields();
35253649
}
35263650

35273651
// Given an array of terminator operand values, produce an array of

0 commit comments

Comments
 (0)