@@ -631,16 +631,98 @@ autorelease in the callee.
631631 type behaves like a non-generic type, as if the substitutions were
632632 actually applied to the underlying function type.
633633
634+ Async Functions
635+ ```````````````
636+
637+ SIL function types may be ``@async ``. ``@async `` functions run inside async
638+ tasks, and can have explicit *suspend points * where they suspend execution.
639+ ``@async `` functions can only be called from other ``@async `` functions, but
640+ otherwise can be invoked with the normal ``apply `` and ``try_apply ``
641+ instructions (or ``begin_apply `` if they are coroutines).
642+
643+ In Swift, the ``withUnsafeContinuation `` primitive is used to implement
644+ primitive suspend points. In SIL, ``@async `` functions represent this
645+ abstraction using the ``get_async_continuation[_addr] `` and
646+ ``await_async_continuation `` instructions. ``get_async_continuation[_addr] ``
647+ accesses a *continuation * value that can be used to resume the coroutine after
648+ it suspends. The resulting continuation value can then be passed into a
649+ completion handler, registered with an event loop, or scheduled by some other
650+ mechanism. Operations on the continuation can resume the async function's
651+ execution by passing a value back to the async function, or passing in an error
652+ that propagates as an error in the async function's context.
653+ The ``await_async_continuation `` instruction suspends execution of
654+ the coroutine until the continuation is invoked to resume it. A use of
655+ ``withUnsafeContinuation `` in Swift::
656+
657+ func waitForCallback() async -> Int {
658+ return await withUnsafeContinuation { cc in
659+ registerCallback { cc.resume($0) }
660+ }
661+ }
662+
663+ might lower to the following SIL::
664+
665+ sil @waitForCallback : $@convention(thin) @async () -> Int {
666+ entry:
667+ %cc = get_async_continuation $Int
668+ %closure = function_ref @waitForCallback_closure
669+ : $@convention(thin) (UnsafeContinuation<Int>) -> ()
670+ apply %closure(%cc)
671+ await_async_continuation %cc, resume resume_cc
672+
673+ resume_cc(%result : $Int):
674+ return %result
675+ }
676+
677+ The closure may then be inlined into the ``waitForCallback `` function::
678+
679+ sil @waitForCallback : $@convention(thin) @async () -> Int {
680+ entry:
681+ %cc = get_async_continuation $Int
682+ %registerCallback = function_ref @registerCallback
683+ : $@convention(thin) (@convention(thick) () -> ()) -> ()
684+ %callback_fn = function_ref @waitForCallback_callback
685+ %callback = partial_apply %callback_fn(%cc)
686+ apply %registerCallback(%callback)
687+ await_async_continuation %cc, resume resume_cc
688+
689+ resume_cc(%result : $Int):
690+ return %result
691+ }
692+
693+ Every continuation value must be used exactly once to resume its associated
694+ async coroutine once. It is undefined behavior to attempt to resume the same
695+ continuation more than once. On the flip side, failing to resume a continuation
696+ will leave the async task stuck in the suspended state, leaking any memory or
697+ other resources it owns.
698+
634699Coroutine Types
635700```````````````
636701
637702A coroutine is a function which can suspend itself and return control to
638703its caller without terminating the function. That is, it does not need to
639- obey a strict stack discipline.
640-
641- SIL supports two kinds of coroutine: ``@yield_many `` and ``@yield_once ``.
642- Either of these attributes may be written before a function type to
643- indicate that it is a coroutine type.
704+ obey a strict stack discipline. SIL coroutines have control flow that is
705+ tightly integrated with their callers, and they pass information back and forth
706+ between caller and callee in a structured way through yield points.
707+ *Generalized accessors * and *generators * in Swift fit this description: a
708+ ``read `` or ``modify `` accessor coroutine projects a single value, yields
709+ ownership of that one value temporarily to the caller, and then takes ownership
710+ back when resumed, allowing the coroutine to clean up resources or otherwise
711+ react to mutations done by the caller. *Generators * similarly yield a stream of
712+ values one at a time to their caller, temporarily yielding ownership of each
713+ value in turn to the caller. The tight coupling of the caller's control flow
714+ with these coroutines allows the caller to *borrow * values produced by the
715+ coroutine, where a normal function return would need to transfer ownership of
716+ its return value, since a normal function's context ceases to exist and be able
717+ to maintain ownership of the value after it returns.
718+
719+ To support these concepts, SIL supports two kinds of coroutine:
720+ ``@yield_many `` and ``@yield_once ``. Either of these attributes may be
721+ written before a function type to indicate that it is a coroutine type.
722+ ``@yield_many `` and ``@yield_once `` coroutines are allowed to also be
723+ ``@async ``. (Note that ``@async `` functions are not themselves modeled
724+ explicitly as coroutines in SIL, although the implementation may use a coroutine
725+ lowering strategy.)
644726
645727A coroutine type may declare any number of *yielded values *, which is to
646728say, values which are provided to the caller at a yield point. Yielded
@@ -658,19 +740,13 @@ coroutine can be called with the ``begin_apply`` instruction. There
658740is no support yet for calling a throwing yield-once coroutine or for
659741calling a yield-many coroutine of any kind.
660742
661- Coroutines may contain the special ``yield `` and ``unwind `` instructions.
743+ Coroutines may contain the special ``yield `` and ``unwind ``
744+ instructions.
662745
663746A ``@yield_many `` coroutine may yield as many times as it desires.
664747A ``@yield_once `` coroutine may yield exactly once before returning,
665748although it may also ``throw `` before reaching that point.
666749
667- This coroutine representation is well-suited to coroutines whose control
668- flow is tightly integrated with their callers and which intend to pass
669- information back and forth. This matches the needs of generalized
670- accessor and generator features in Swift. It is not a particularly good
671- match for ``async ``/``await ``-style features; a simpler representation
672- would probably do fine for that.
673-
674750Properties of Types
675751```````````````````
676752
@@ -2608,6 +2684,76 @@ undefined behavior if the global variable has already been initialized.
26082684
26092685The type operand must be a lowered object type.
26102686
2687+ get_async_continuation
2688+ ``````````````````````
2689+
2690+ ::
2691+
2692+ sil-instruction ::= 'get_async_continuation' '[throws]'? sil-type
2693+
2694+ %0 = get_async_continuation $T
2695+ %0 = get_async_continuation [throws] $U
2696+
2697+ Begins a suspension of an ``@async `` function. This instruction can only be
2698+ used inside an ``@async `` function. The result of the instruction is an
2699+ ``UnsafeContinuation<T> `` value, where ``T `` is the formal type argument to the
2700+ instruction, or an ``UnsafeThrowingContinuation<T> `` if the instruction
2701+ carries the ``[throws] `` attribute. ``T `` must be a loadable type.
2702+ The continuation must be consumed by a ``await_async_continuation `` terminator
2703+ on all paths. Between ``get_async_continuation `` and
2704+ ``await_async_continuation ``, the following restrictions apply:
2705+
2706+ - The function cannot ``return ``, ``throw ``, ``yield ``, or ``unwind ``.
2707+ - There cannot be nested suspend points; namely, the function cannot call
2708+ another ``@async `` function, nor can it initiate another suspend point with
2709+ ``get_async_continuation ``.
2710+
2711+ The function suspends execution when the matching ``await_async_continuation ``
2712+ terminator is reached, and resumes execution when the continuation is resumed.
2713+ The continuation resumption operation takes a value of type ``T `` which is
2714+ passed back into the function when it resumes execution in the ``await_async_continuation `` instruction's
2715+ ``resume `` successor block. If the instruction
2716+ has the ``[throws] `` attribute, it can also be resumed in an error state, in
2717+ which case the matching ``await_async_continuation `` instruction must also
2718+ have an ``error `` successor.
2719+
2720+ Within the enclosing SIL function, the result continuation is consumed by the
2721+ ``await_async_continuation ``, and cannot be referenced after the
2722+ ``await_async_continuation `` executes. Dynamically, the continuation value must
2723+ be resumed exactly once in the course of the program's execution; it is
2724+ undefined behavior to resume the continuation more than once. Conversely,
2725+ failing to resume the continuation will leave the suspended async coroutine
2726+ hung in its suspended state, leaking any resources it may be holding.
2727+
2728+ get_async_continuation_addr
2729+ ```````````````````````````
2730+
2731+ ::
2732+
2733+ sil-instruction ::= 'get_async_continuation_addr' '[throws]'? sil-type ',' sil-operand
2734+
2735+ %1 = get_async_continuation_addr $T, %0 : $*T
2736+ %1 = get_async_continuation_addr [throws] $U, %0 : $*U
2737+
2738+ Begins a suspension of an ``@async `` function, like ``get_async_continuation ``,
2739+ additionally binding a specific memory location for receiving the value
2740+ when the result continuation is resumed. The operand must be an address whose
2741+ type is the maximally-abstracted lowered type of the formal resume type. The
2742+ memory must be uninitialized, and must remain allocated until the matching
2743+ ``await_async_continuation `` instruction(s) consuming the result continuation
2744+ have executed. The behavior is otherwise the same as
2745+ ``get_async_continuation ``, and the same restrictions apply on code appearing
2746+ between ``get_async_continuation_addr `` and ``await_async_continuation `` as
2747+ apply between ``get_async_continuation `` and ``await_async_continuation ``.
2748+ Additionally, the state of the memory referenced by the operand is indefinite
2749+ between the execution of ``get_async_continuation_addr `` and
2750+ ``await_async_continuation ``, and it is undefined behavior to read or modify
2751+ the memory during this time. After the ``await_async_continuation `` resumes
2752+ normally to its ``resume `` successor, the memory referenced by the operand is
2753+ initialized with the resume value, and that value is then owned by the current
2754+ function. If ``await_async_continuation `` instead resumes to its ``error ``
2755+ successor, then the memory remains uninitialized.
2756+
26112757dealloc_stack
26122758`````````````
26132759::
@@ -6230,6 +6376,55 @@ destination (if it returns with ``throw``).
62306376
62316377The rules on generic substitutions are identical to those of ``apply ``.
62326378
6379+ await_async_continuation
6380+ ````````````````````````
6381+
6382+ ::
6383+
6384+ sil-terminator ::= 'await_async_continuation' sil-value
6385+ ',' 'resume' sil-identifier
6386+ (',' 'error' sil-identifier)?
6387+
6388+ await_async_continuation %0 : $UnsafeContinuation<T>, resume bb1
6389+ await_async_continuation %0 : $UnsafeThrowingContinuation<T>, resume bb1, error bb2
6390+
6391+ bb1(%1 : @owned $T):
6392+ bb2(%2 : @owned $Error):
6393+
6394+ Suspends execution of an ``@async `` function until the continuation
6395+ is resumed. The continuation must be the result of a
6396+ ``get_async_continuation `` or ``get_async_continuation_addr ``
6397+ instruction within the same function; see the documentation for
6398+ ``get_async_continuation `` for discussion of further constraints on the
6399+ IR between ``get_async_continuation[_addr] `` and ``await_async_continuation ``.
6400+ This terminator can only appear inside an ``@async `` function. The
6401+ instruction must always have a ``resume `` successor, but must have an
6402+ ``error `` successor if and only if the operand is an
6403+ ``UnsafeThrowingContinuation<T> ``.
6404+
6405+ If the operand is the result of a ``get_async_continuation `` instruction,
6406+ then the ``resume `` successor block must take an argument whose type is the
6407+ maximally-abstracted lowered type of ``T ``, matching the type argument of the
6408+ ``Unsafe[Throwing]Continuation<T> `` operand. The value of the ``resume ``
6409+ argument is owned by the current function. If the operand is the result of a
6410+ ``get_async_continuation_addr `` instruction, then the ``resume `` successor
6411+ block must *not * take an argument; the resume value will be written to the
6412+ memory referenced by the operand to the ``get_async_continuation_addr ``
6413+ instruction, after which point the value in that memory becomes owned by the
6414+ current function. With either variant, if the ``await_async_continuation ``
6415+ instruction has an ``error `` successor block, the ``error `` block must take a
6416+ single ``Error `` argument, and that argument is owned by the enclosing
6417+ function. The memory referenced by a ``get_async_continuation_addr ``
6418+ instruction remains uninitialized when ``await_async_continuation `` resumes on
6419+ the ``error `` successor.
6420+
6421+ It is possible for a continuation to be resumed before
6422+ ``await_async_continuation ``. In this case, the resume operation returns
6423+ immediately to its caller. When the ``await_async_continuation `` instruction
6424+ later executes, it then immediately transfers control to
6425+ its ``resume `` or ``error `` successor block, using the resume or error value
6426+ that the continuation was already resumed with.
6427+
62336428Differentiable Programming
62346429~~~~~~~~~~~~~~~~~~~~~~~~~~
62356430
0 commit comments