Skip to content

Commit 249831f

Browse files
Merge pull request swiftlang#76942 from nate-chandler/general-coro/20240927/1
[CoroutineAccessors] SIL represents callee alloc.
2 parents 9c992a7 + 71239d6 commit 249831f

Some content is hidden

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

43 files changed

+744
-70
lines changed

docs/ABI/Mangling.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,7 @@ mangled in to disambiguate.
856856
FUNC-REPRESENTATION ::= 'W' // protocol witness
857857

858858
COROUTINE-KIND ::= 'A' // yield-once coroutine
859+
COROUTINE-KIND ::= 'I' // yield-once-2 coroutine
859860
COROUTINE-KIND ::= 'G' // yield-many coroutine
860861

861862
#if SWIFT_RUNTIME_VERSION >= 5.5

docs/SIL.rst

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -789,13 +789,16 @@ coroutine, where a normal function return would need to transfer ownership of
789789
its return value, since a normal function's context ceases to exist and be able
790790
to maintain ownership of the value after it returns.
791791

792-
To support these concepts, SIL supports two kinds of coroutine:
793-
``@yield_many`` and ``@yield_once``. Either of these attributes may be
792+
To support these concepts, SIL supports two flavors: single-yield and
793+
multi-yield. These two flavors correspond to three kinds. A multi-yield
794+
coroutine is of kind ``@yield_many``. A single-yield coroutine is of kind
795+
either ``@yield_once`` or ``@yield_once_2``. Any of these attributes may be
794796
written before a function type to indicate that it is a coroutine type.
795-
``@yield_many`` and ``@yield_once`` coroutines are allowed to also be
796-
``@async``. (Note that ``@async`` functions are not themselves modeled
797-
explicitly as coroutines in SIL, although the implementation may use a coroutine
798-
lowering strategy.)
797+
798+
Both single-yield and multi-yield coroutines are allowed to also be ``@async``.
799+
(Note that ``@async`` functions are not themselves modeled explicitly as
800+
coroutines in SIL, although the implementation may use a coroutine lowering
801+
strategy.)
799802

800803
A coroutine type may declare any number of *yielded values*, which is to
801804
say, values which are provided to the caller at a yield point. Yielded
@@ -816,9 +819,10 @@ calling a yield-many coroutine of any kind.
816819
Coroutines may contain the special ``yield`` and ``unwind``
817820
instructions.
818821

819-
A ``@yield_many`` coroutine may yield as many times as it desires.
820-
A ``@yield_once`` coroutine may yield exactly once before returning,
821-
although it may also ``throw`` before reaching that point.
822+
A multi-yield (``@yield_many``) coroutine may yield as many times as it desires.
823+
A single-yield (``@yield_once`` or ``@yield_once_2``) coroutine may yield
824+
exactly once before returning, although it may also ``throw`` before reaching
825+
that point.
822826

823827
Variadic Generics
824828
`````````````````
@@ -6128,23 +6132,36 @@ begin_apply
61286132
// %float : $Float
61296133
// %token is a token
61306134

6135+
(%anyAddr, %float, %token, %allocation) = begin_apply %0() : $@yield_once_2 () -> (@yields @inout %Any, @yields Float)
6136+
// %anyAddr : $*Any
6137+
// %float : $Float
6138+
// %token is a token
6139+
// %allocation is a pointer to a token
6140+
61316141
Transfers control to coroutine ``%0``, passing it the given arguments.
61326142
The rules for the application generally follow the rules for ``apply``,
61336143
except:
61346144

6135-
- the callee value must have a ``yield_once`` coroutine type,
6145+
- the callee value must have be of single-yield coroutine type (``yield_once``
6146+
or ``yield_once_2``)
61366147

61376148
- control returns to this function not when the coroutine performs a
61386149
``return``, but when it performs a ``yield``, and
61396150

61406151
- the instruction results are derived from the yields of the coroutine
61416152
instead of its normal results.
61426153

6143-
The final result of a ``begin_apply`` is a "token", a special value which
6144-
can only be used as the operand of an ``end_apply`` or ``abort_apply``
6145-
instruction. Before this second instruction is executed, the coroutine
6146-
is said to be "suspended", and the token represents a reference to its
6147-
suspended activation record.
6154+
The final (in the case of ``@yield_once``) or penultimate (in the case of
6155+
``@yield_once_2``) result of a ``begin_apply`` is a "token", a special value
6156+
which can only be used as the operand of an ``end_apply`` or ``abort_apply``
6157+
instruction. Before this second instruction is executed, the coroutine is said
6158+
to be "suspended", and the token represents a reference to its suspended
6159+
activation record.
6160+
6161+
If the coroutine's kind ``yield_once_2``, its final result is an address of a
6162+
"token", representing the allocation done by the callee coroutine. It can only
6163+
be used as the operand of a ``dealloc_stack`` which must appear after the
6164+
coroutine is resumed.
61486165

61496166
The other results of the instruction correspond to the yields in the
61506167
coroutine type. In general, the rules of a yield are similar to the rules
@@ -8376,9 +8393,10 @@ the current function was invoked with a ``try_apply`` instruction, control
83768393
resumes at the normal destination, and the value of the basic block argument
83778394
will be the operand of this ``return`` instruction.
83788395

8379-
If the current function is a ``yield_once`` coroutine, there must not be
8380-
a path from the entry block to a ``return`` which does not pass through
8381-
a ``yield`` instruction. This rule does not apply in the ``raw`` SIL stage.
8396+
If the current function is a single-yield coroutine (``yield_once`` or
8397+
``yield_once_2``), there must not be a path from the entry block to a
8398+
``return`` which does not pass through a ``yield`` instruction. This rule does
8399+
not apply in the ``raw`` SIL stage.
83828400

83838401
``return`` does not retain or release its operand or any other values.
83848402

@@ -8446,9 +8464,10 @@ The ``resume`` and ``unwind`` destination blocks must be uniquely
84468464
referenced by the ``yield`` instruction. This prevents them from becoming
84478465
critical edges.
84488466

8449-
In a ``yield_once`` coroutine, there must not be a control flow path leading
8450-
from the ``resume`` edge to another ``yield`` instruction in this function.
8451-
This rule does not apply in the ``raw`` SIL stage.
8467+
In a single-yield coroutine (``yield_once`` or ``yield_once_2``), there must
8468+
not be a control flow path leading from the ``resume`` edge to another
8469+
``yield`` instruction in this function. This rule does not apply in the ``raw``
8470+
SIL stage.
84528471

84538472
There must not be a control flow path leading from the ``unwind`` edge to
84548473
a ``return`` instruction, to a ``throw`` instruction, or to any block

include/swift/AST/IRGenOptions.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ struct PointerAuthOptions : clang::PointerAuthOptions {
165165
/// Resumption functions from yield-once coroutines.
166166
PointerAuthSchema YieldOnceResumeFunctions;
167167

168+
/// Resumption functions from yield-once-2 coroutines.
169+
PointerAuthSchema YieldOnce2ResumeFunctions;
170+
168171
/// Resumption functions from yield-many coroutines.
169172
PointerAuthSchema YieldManyResumeFunctions;
170173

@@ -482,6 +485,9 @@ class IRGenOptions {
482485

483486
unsigned EmitAsyncFramePushPopMetadata : 1;
484487

488+
// Whether to use the yield_once ABI when emitting yield_once_2 coroutines.
489+
unsigned EmitYieldOnce2AsYieldOnce : 1;
490+
485491
// Whether to force emission of a frame for all async functions
486492
// (LLVM's 'frame-pointer=all').
487493
unsigned AsyncFramePointerAll : 1;
@@ -574,10 +580,10 @@ class IRGenOptions {
574580
EmitGenericRODatas(true), NoPreallocatedInstantiationCaches(false),
575581
DisableReadonlyStaticObjects(false), CollocatedMetadataFunctions(false),
576582
ColocateTypeDescriptors(true), UseRelativeProtocolWitnessTables(false),
577-
UseFragileResilientProtocolWitnesses(false),
578-
EnableHotColdSplit(false), EmitAsyncFramePushPopMetadata(false),
579-
AsyncFramePointerAll(false),
580-
CmdArgs(), SanitizeCoverage(llvm::SanitizerCoverageOptions()),
583+
UseFragileResilientProtocolWitnesses(false), EnableHotColdSplit(false),
584+
EmitAsyncFramePushPopMetadata(false), EmitYieldOnce2AsYieldOnce(true),
585+
AsyncFramePointerAll(false), CmdArgs(),
586+
SanitizeCoverage(llvm::SanitizerCoverageOptions()),
581587
TypeInfoFilter(TypeInfoDumpFilter::All),
582588
PlatformCCallingConvention(llvm::CallingConv::C), UseCASBackend(false),
583589
CASObjMode(llvm::CASBackendMode::Native) {

include/swift/AST/TypeAttr.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ SIMPLE_SIL_TYPE_ATTR(pseudogeneric, Pseudogeneric)
101101
SIMPLE_SIL_TYPE_ATTR(unimplementable, Unimplementable)
102102
SIMPLE_SIL_TYPE_ATTR(yields, Yields)
103103
SIMPLE_SIL_TYPE_ATTR(yield_once, YieldOnce)
104+
SIMPLE_SIL_TYPE_ATTR(yield_once_2, YieldOnce2)
104105
SIMPLE_SIL_TYPE_ATTR(yield_many, YieldMany)
105106
SIMPLE_SIL_TYPE_ATTR(captures_generics, CapturesGenerics)
106107
// Used at the SIL level to mark a type as moveOnly.

include/swift/AST/Types.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4823,11 +4823,18 @@ enum class SILCoroutineKind : uint8_t {
48234823
/// It must not have normal results and may have arbitrary yield results.
48244824
YieldOnce,
48254825

4826+
/// This function is a yield-once coroutine (used by read and modify
4827+
/// accessors). It has the following differences from YieldOnce:
4828+
/// - it does not observe errors thrown by its caller (unless the feature
4829+
/// CoroutineAccessorsUnwindOnCallerError is enabled)
4830+
/// - it uses the callee-allocated ABI
4831+
YieldOnce2,
4832+
48264833
/// This function is a yield-many coroutine (used by e.g. generators).
48274834
/// It must not have normal results and may have arbitrary yield results.
48284835
YieldMany,
48294836
};
4830-
4837+
48314838
class SILFunctionConventions;
48324839

48334840

@@ -5039,6 +5046,17 @@ class SILFunctionType final
50395046
SILCoroutineKind getCoroutineKind() const {
50405047
return SILCoroutineKind(Bits.SILFunctionType.CoroutineKind);
50415048
}
5049+
/// Whether this coroutine's ABI is callee-allocated.
5050+
bool isCalleeAllocatedCoroutine() const {
5051+
switch (getCoroutineKind()) {
5052+
case SILCoroutineKind::None:
5053+
case SILCoroutineKind::YieldOnce:
5054+
case SILCoroutineKind::YieldMany:
5055+
return false;
5056+
case SILCoroutineKind::YieldOnce2:
5057+
return true;
5058+
}
5059+
}
50425060

50435061
bool isSendable() const { return getExtInfo().isSendable(); }
50445062
bool isUnimplementable() const { return getExtInfo().isUnimplementable(); }

include/swift/Basic/Features.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,12 @@ EXPERIMENTAL_FEATURE(UnspecifiedMeansMainActorIsolated, false)
427427
/// modify/read single-yield coroutines
428428
SUPPRESSIBLE_EXPERIMENTAL_FEATURE(CoroutineAccessors, true)
429429

430+
/// modify/read single-yield coroutines always execute code post-yield code
431+
EXPERIMENTAL_FEATURE(CoroutineAccessorsUnwindOnCallerError, false)
432+
433+
/// modify/read coroutines use the callee-allocated ABI
434+
EXPERIMENTAL_FEATURE(CoroutineAccessorsAllocateInCallee, false)
435+
430436
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
431437
#undef EXPERIMENTAL_FEATURE
432438
#undef UPCOMING_FEATURE

include/swift/Demangling/TypeDecoder.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ enum class ImplMetatypeRepresentation {
5151
enum class ImplCoroutineKind {
5252
None,
5353
YieldOnce,
54+
YieldOnce2,
5455
YieldMany,
5556
};
5657

@@ -1097,6 +1098,8 @@ class TypeDecoder {
10971098
return MAKE_NODE_TYPE_ERROR0(child, "expected text");
10981099
if (child->getText() == "yield_once") {
10991100
coroutineKind = ImplCoroutineKind::YieldOnce;
1101+
} else if (child->getText() == "yield_once_2") {
1102+
coroutineKind = ImplCoroutineKind::YieldOnce2;
11001103
} else if (child->getText() == "yield_many") {
11011104
coroutineKind = ImplCoroutineKind::YieldMany;
11021105
} else

include/swift/SIL/SILInstruction.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,9 @@ class SILInstruction : public llvm::ilist_node<SILInstruction> {
847847
/// instruction.
848848
bool isAllocatingStack() const;
849849

850+
/// The stack allocation produced by the instruction, if any.
851+
SILValue getStackAllocation() const;
852+
850853
/// Returns true if this is the deallocation of a stack allocating instruction.
851854
/// The first operand must be the allocating instruction.
852855
bool isDeallocatingStack() const;
@@ -3251,13 +3254,25 @@ class BeginApplyInst final
32513254
public:
32523255
using MultipleValueInstructionTrailingObjects::totalSizeToAlloc;
32533256

3257+
bool isCalleeAllocated() const {
3258+
return getSubstCalleeType()->isCalleeAllocatedCoroutine();
3259+
}
3260+
32543261
MultipleValueInstructionResult *getTokenResult() const {
3262+
return const_cast<MultipleValueInstructionResult *>(
3263+
&getAllResultsBuffer().drop_back(isCalleeAllocated() ? 1 : 0).back());
3264+
}
3265+
3266+
MultipleValueInstructionResult *getCalleeAllocationResult() const {
3267+
if (!isCalleeAllocated()) {
3268+
return nullptr;
3269+
}
32553270
return const_cast<MultipleValueInstructionResult *>(
32563271
&getAllResultsBuffer().back());
32573272
}
32583273

32593274
SILInstructionResultArray getYieldedValues() const {
3260-
return getAllResultsBuffer().drop_back();
3275+
return getAllResultsBuffer().drop_back(isCalleeAllocated() ? 2 : 1);
32613276
}
32623277

32633278
void getCoroutineEndPoints(

lib/AST/ASTDemangler.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,8 @@ getCoroutineKind(ImplCoroutineKind kind) {
582582
return SILCoroutineKind::None;
583583
case ImplCoroutineKind::YieldOnce:
584584
return SILCoroutineKind::YieldOnce;
585+
case ImplCoroutineKind::YieldOnce2:
586+
return SILCoroutineKind::YieldOnce2;
585587
case ImplCoroutineKind::YieldMany:
586588
return SILCoroutineKind::YieldMany;
587589
}

lib/AST/ASTMangler.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2149,6 +2149,9 @@ void ASTMangler::appendImplFunctionType(SILFunctionType *fn,
21492149
case SILCoroutineKind::YieldOnce:
21502150
OpArgs.push_back('A');
21512151
break;
2152+
case SILCoroutineKind::YieldOnce2:
2153+
OpArgs.push_back('I');
2154+
break;
21522155
case SILCoroutineKind::YieldMany:
21532156
OpArgs.push_back('G');
21542157
break;

0 commit comments

Comments
 (0)