Skip to content

Commit d84847a

Browse files
authored
Reland Allow normal function results of @yield_once coroutines (#71645)
* Allow normal function results of @yield_once coroutines * Address review comments * Workaround LLVM coroutine codegen problem: it assumes that unwind path never returns. This is not true to Swift coroutines as unwind path should end with error result.
1 parent b6348b0 commit d84847a

File tree

71 files changed

+667
-278
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+667
-278
lines changed

docs/SIL.rst

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6100,6 +6100,14 @@ executing the ``begin_apply``) were being "called" by the ``yield``:
61006100
or move the value from that position before ending or aborting the
61016101
coroutine.
61026102

6103+
A coroutine optionally may produce normal results. These do not have
6104+
``@yields`` annotation in the result type tuple.
6105+
::
6106+
(%float, %token) = begin_apply %0() : $@yield_once () -> (@yields Float, Int)
6107+
6108+
Normal results of a coroutine are produced by the corresponding ``end_apply``
6109+
instruction.
6110+
61036111
A ``begin_apply`` must be uniquely either ended or aborted before
61046112
exiting the function or looping to an earlier portion of the function.
61056113

@@ -6129,9 +6137,9 @@ end_apply
61296137
`````````
61306138
::
61316139

6132-
sil-instruction ::= 'end_apply' sil-value
6140+
sil-instruction ::= 'end_apply' sil-value 'as' sil-type
61336141

6134-
end_apply %token
6142+
end_apply %token as $()
61356143

61366144
Ends the given coroutine activation, which is currently suspended at
61376145
a ``yield`` instruction. Transfers control to the coroutine and takes
@@ -6141,8 +6149,8 @@ when the coroutine reaches a ``return`` instruction.
61416149
The operand must always be the token result of a ``begin_apply``
61426150
instruction, which is why it need not specify a type.
61436151

6144-
``end_apply`` currently has no instruction results. If coroutines were
6145-
allowed to have normal results, they would be producted by ``end_apply``.
6152+
The result of ``end_apply`` is the normal result of the coroutine function (the
6153+
operand of the ``return`` instruction)."
61466154

61476155
When throwing coroutines are supported, there will need to be a
61486156
``try_end_apply`` instruction.

include/swift/AST/Types.h

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4789,24 +4789,27 @@ class SILFunctionType final
47894789
using Representation = SILExtInfoBuilder::Representation;
47904790

47914791
private:
4792-
unsigned NumParameters;
4792+
unsigned NumParameters = 0;
47934793

4794-
// These are *normal* results if this is not a coroutine and *yield* results
4795-
// otherwise.
4796-
unsigned NumAnyResults; // Not including the ErrorResult.
4797-
unsigned NumAnyIndirectFormalResults; // Subset of NumAnyResults.
4798-
unsigned NumPackResults; // Subset of NumAnyIndirectFormalResults.
4794+
// These are *normal* results
4795+
unsigned NumAnyResults = 0; // Not including the ErrorResult.
4796+
unsigned NumAnyIndirectFormalResults = 0; // Subset of NumAnyResults.
4797+
unsigned NumPackResults = 0; // Subset of NumAnyIndirectFormalResults.
4798+
// These are *yield* results
4799+
unsigned NumAnyYieldResults = 0; // Not including the ErrorResult.
4800+
unsigned NumAnyIndirectFormalYieldResults = 0; // Subset of NumAnyYieldResults.
4801+
unsigned NumPackYieldResults = 0; // Subset of NumAnyIndirectFormalYieldResults.
47994802

48004803
// [NOTE: SILFunctionType-layout]
48014804
// The layout of a SILFunctionType in memory is:
48024805
// SILFunctionType
48034806
// SILParameterInfo[NumParameters]
4804-
// SILResultInfo[isCoroutine() ? 0 : NumAnyResults]
4807+
// SILResultInfo[NumAnyResults]
48054808
// SILResultInfo? // if hasErrorResult()
4806-
// SILYieldInfo[isCoroutine() ? NumAnyResults : 0]
4809+
// SILYieldInfo[NumAnyYieldResults]
48074810
// SubstitutionMap[HasPatternSubs + HasInvocationSubs]
4808-
// CanType? // if !isCoro && NumAnyResults > 1, formal result cache
4809-
// CanType? // if !isCoro && NumAnyResults > 1, all result cache
4811+
// CanType? // if NumAnyResults > 1, formal result cache
4812+
// CanType? // if NumAnyResults > 1, all result cache
48104813

48114814
CanGenericSignature InvocationGenericSig;
48124815
ProtocolConformanceRef WitnessMethodConformance;
@@ -4845,7 +4848,7 @@ class SILFunctionType final
48454848

48464849
/// Do we have slots for caches of the normal-result tuple type?
48474850
bool hasResultCache() const {
4848-
return NumAnyResults > 1 && !isCoroutine();
4851+
return NumAnyResults > 1;
48494852
}
48504853

48514854
CanType &getMutableFormalResultsCache() const {
@@ -4945,14 +4948,14 @@ class SILFunctionType final
49454948
ArrayRef<SILYieldInfo> getYields() const {
49464949
return const_cast<SILFunctionType *>(this)->getMutableYields();
49474950
}
4948-
unsigned getNumYields() const { return isCoroutine() ? NumAnyResults : 0; }
4951+
unsigned getNumYields() const { return NumAnyYieldResults; }
49494952

49504953
/// Return the array of all result information. This may contain inter-mingled
49514954
/// direct and indirect results.
49524955
ArrayRef<SILResultInfo> getResults() const {
49534956
return const_cast<SILFunctionType *>(this)->getMutableResults();
49544957
}
4955-
unsigned getNumResults() const { return isCoroutine() ? 0 : NumAnyResults; }
4958+
unsigned getNumResults() const { return NumAnyResults; }
49564959

49574960
ArrayRef<SILResultInfo> getResultsWithError() const {
49584961
return const_cast<SILFunctionType *>(this)->getMutableResultsWithError();
@@ -4989,17 +4992,17 @@ class SILFunctionType final
49894992
// indirect property, not the SIL indirect property, should be consulted to
49904993
// determine whether function reabstraction is necessary.
49914994
unsigned getNumIndirectFormalResults() const {
4992-
return isCoroutine() ? 0 : NumAnyIndirectFormalResults;
4995+
return NumAnyIndirectFormalResults;
49934996
}
49944997
/// Does this function have any formally indirect results?
49954998
bool hasIndirectFormalResults() const {
49964999
return getNumIndirectFormalResults() != 0;
49975000
}
49985001
unsigned getNumDirectFormalResults() const {
4999-
return isCoroutine() ? 0 : NumAnyResults - NumAnyIndirectFormalResults;
5002+
return NumAnyResults - NumAnyIndirectFormalResults;
50005003
}
50015004
unsigned getNumPackResults() const {
5002-
return isCoroutine() ? 0 : NumPackResults;
5005+
return NumPackResults;
50035006
}
50045007
bool hasIndirectErrorResult() const {
50055008
return hasErrorResult() && getErrorResult().isFormalIndirect();
@@ -5057,17 +5060,17 @@ class SILFunctionType final
50575060
TypeExpansionContext expansion);
50585061

50595062
unsigned getNumIndirectFormalYields() const {
5060-
return isCoroutine() ? NumAnyIndirectFormalResults : 0;
5063+
return NumAnyIndirectFormalYieldResults;
50615064
}
50625065
/// Does this function have any formally indirect yields?
50635066
bool hasIndirectFormalYields() const {
50645067
return getNumIndirectFormalYields() != 0;
50655068
}
50665069
unsigned getNumDirectFormalYields() const {
5067-
return isCoroutine() ? NumAnyResults - NumAnyIndirectFormalResults : 0;
5070+
return NumAnyYieldResults - NumAnyIndirectFormalYieldResults;
50685071
}
50695072
unsigned getNumPackYields() const {
5070-
return isCoroutine() ? NumPackResults : 0;
5073+
return NumPackYieldResults;
50715074
}
50725075

50735076
struct IndirectFormalYieldFilter {

include/swift/SIL/SILBuilder.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -589,11 +589,11 @@ class SILBuilder {
589589
beginApply));
590590
}
591591

592-
EndApplyInst *createEndApply(SILLocation loc, SILValue beginApply) {
592+
EndApplyInst *createEndApply(SILLocation loc, SILValue beginApply, SILType ResultType) {
593593
return insert(new (getModule()) EndApplyInst(getSILDebugLocation(loc),
594-
beginApply));
594+
beginApply, ResultType));
595595
}
596-
596+
597597
BuiltinInst *createBuiltin(SILLocation Loc, Identifier Name, SILType ResultTy,
598598
SubstitutionMap Subs,
599599
ArrayRef<SILValue> Args) {

include/swift/SIL/SILCloner.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1077,7 +1077,8 @@ SILCloner<ImplClass>::visitEndApplyInst(EndApplyInst *Inst) {
10771077
getBuilder().setCurrentDebugScope(getOpScope(Inst->getDebugScope()));
10781078
recordClonedInstruction(
10791079
Inst, getBuilder().createEndApply(getOpLocation(Inst->getLoc()),
1080-
getOpValue(Inst->getOperand())));
1080+
getOpValue(Inst->getOperand()),
1081+
getOpType(Inst->getType())));
10811082
}
10821083

10831084
template<typename ImplClass>

include/swift/SIL/SILInstruction.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3253,11 +3253,12 @@ class AbortApplyInst
32533253
/// normally.
32543254
class EndApplyInst
32553255
: public UnaryInstructionBase<SILInstructionKind::EndApplyInst,
3256-
NonValueInstruction> {
3256+
SingleValueInstruction> {
32573257
friend SILBuilder;
32583258

3259-
EndApplyInst(SILDebugLocation debugLoc, SILValue beginApplyToken)
3260-
: UnaryInstructionBase(debugLoc, beginApplyToken) {
3259+
EndApplyInst(SILDebugLocation debugLoc, SILValue beginApplyToken,
3260+
SILType Ty)
3261+
: UnaryInstructionBase(debugLoc, beginApplyToken, Ty) {
32613262
assert(isaResultOf<BeginApplyInst>(beginApplyToken) &&
32623263
isaResultOf<BeginApplyInst>(beginApplyToken)->isBeginApplyToken());
32633264
}

include/swift/SIL/SILNodes.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,8 @@ ABSTRACT_VALUE_AND_INST(SingleValueInstruction, ValueBase, SILInstruction)
568568
SingleValueInstruction, MayHaveSideEffects, MayRelease)
569569
SINGLE_VALUE_INST(PartialApplyInst, partial_apply,
570570
SingleValueInstruction, MayHaveSideEffects, DoesNotRelease)
571+
SINGLE_VALUE_INST(EndApplyInst, end_apply,
572+
SILInstruction, MayHaveSideEffects, MayRelease)
571573
SINGLE_VALUE_INST(FunctionExtractIsolationInst, function_extract_isolation,
572574
SingleValueInstruction, None, DoesNotRelease)
573575

@@ -873,8 +875,6 @@ NON_VALUE_INST(UncheckedRefCastAddrInst, unchecked_ref_cast_addr,
873875
SILInstruction, MayHaveSideEffects, DoesNotRelease)
874876
NON_VALUE_INST(AllocGlobalInst, alloc_global,
875877
SILInstruction, MayHaveSideEffects, DoesNotRelease)
876-
NON_VALUE_INST(EndApplyInst, end_apply,
877-
SILInstruction, MayHaveSideEffects, MayRelease)
878878
NON_VALUE_INST(AbortApplyInst, abort_apply,
879879
SILInstruction, MayHaveSideEffects, MayRelease)
880880
NON_VALUE_INST(PackElementSetInst, pack_element_set,

lib/AST/ASTContext.cpp

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4546,29 +4546,29 @@ SILFunctionType::SILFunctionType(
45464546
!ext.getLifetimeDependenceInfo().empty();
45474547
Bits.SILFunctionType.CoroutineKind = unsigned(coroutineKind);
45484548
NumParameters = params.size();
4549-
if (coroutineKind == SILCoroutineKind::None) {
4550-
assert(yields.empty());
4551-
NumAnyResults = normalResults.size();
4552-
NumAnyIndirectFormalResults = 0;
4553-
NumPackResults = 0;
4554-
for (auto &resultInfo : normalResults) {
4555-
if (resultInfo.isFormalIndirect())
4556-
NumAnyIndirectFormalResults++;
4557-
if (resultInfo.isPack())
4558-
NumPackResults++;
4559-
}
4560-
memcpy(getMutableResults().data(), normalResults.data(),
4561-
normalResults.size() * sizeof(SILResultInfo));
4562-
} else {
4563-
assert(normalResults.empty());
4564-
NumAnyResults = yields.size();
4565-
NumAnyIndirectFormalResults = 0;
4549+
assert((coroutineKind == SILCoroutineKind::None && yields.empty()) ||
4550+
coroutineKind != SILCoroutineKind::None);
4551+
4552+
NumAnyResults = normalResults.size();
4553+
NumAnyIndirectFormalResults = 0;
4554+
NumPackResults = 0;
4555+
for (auto &resultInfo : normalResults) {
4556+
if (resultInfo.isFormalIndirect())
4557+
NumAnyIndirectFormalResults++;
4558+
if (resultInfo.isPack())
4559+
NumPackResults++;
4560+
}
4561+
memcpy(getMutableResults().data(), normalResults.data(),
4562+
normalResults.size() * sizeof(SILResultInfo));
4563+
if (coroutineKind != SILCoroutineKind::None) {
4564+
NumAnyYieldResults = yields.size();
4565+
NumAnyIndirectFormalYieldResults = 0;
45664566
NumPackResults = 0;
45674567
for (auto &yieldInfo : yields) {
45684568
if (yieldInfo.isFormalIndirect())
4569-
NumAnyIndirectFormalResults++;
4569+
NumAnyIndirectFormalYieldResults++;
45704570
if (yieldInfo.isPack())
4571-
NumPackResults++;
4571+
NumPackYieldResults++;
45724572
}
45734573
memcpy(getMutableYields().data(), yields.data(),
45744574
yields.size() * sizeof(SILYieldInfo));
@@ -4740,7 +4740,6 @@ CanSILFunctionType SILFunctionType::get(
47404740
std::optional<SILResultInfo> errorResult, SubstitutionMap patternSubs,
47414741
SubstitutionMap invocationSubs, const ASTContext &ctx,
47424742
ProtocolConformanceRef witnessMethodConformance) {
4743-
assert(coroutineKind == SILCoroutineKind::None || normalResults.empty());
47444743
assert(coroutineKind != SILCoroutineKind::None || yields.empty());
47454744
assert(!ext.isPseudogeneric() || genericSig ||
47464745
coroutineKind != SILCoroutineKind::None);

0 commit comments

Comments
 (0)