Skip to content

[Coroutines] Documentation for custom ABIs #111781

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions llvm/docs/Coroutines.rst
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ lowered to a constant representing the size required for the coroutine frame.
The `coro.begin`_ intrinsic initializes the coroutine frame and returns the
coroutine handle. The second parameter of `coro.begin` is given a block of memory
to be used if the coroutine frame needs to be allocated dynamically.

The `coro.id`_ intrinsic serves as coroutine identity useful in cases when the
`coro.begin`_ intrinsic get duplicated by optimization passes such as
jump-threading.
Expand Down Expand Up @@ -749,6 +750,65 @@ and python iterator `__next__` would look like:
return *(int*)coro.promise(hdl, 4, false);
}

Custom ABIs and Plugin Libraries
--------------------------------

Plugin libraries can extend coroutine lowering enabling a wide variety of users
to utilize the coroutine transformation passes. An existing coroutine lowering
is extended by:

#. defining custom ABIs that inherit from the existing ABIs,
#. give a list of generators for the custom ABIs when constructing the `CoroSplit`_ pass, and
#. use `coro.begin.custom.abi`_ in place of `coro.begin`_ that has an additional parameter for the index of the generator/ABI to be used for the coroutine.

A custom ABI overriding the SwitchABI's materialization looks like:

.. code-block:: c++

class CustomSwitchABI : public coro::SwitchABI {
public:
CustomSwitchABI(Function &F, coro::Shape &S)
: coro::SwitchABI(F, S, ExtraMaterializable) {}
};

Giving a list of custom ABI generators while constructing the `CoroSplit`
pass looks like:

.. code-block:: c++

CoroSplitPass::BaseABITy GenCustomABI = [](Function &F, coro::Shape &S) {
return std::make_unique<CustomSwitchABI>(F, S);
};

CGSCCPassManager CGPM;
CGPM.addPass(CoroSplitPass({GenCustomABI}));

The LLVM IR for a coroutine using a Coroutine with a custom ABI looks like:

.. code-block:: llvm

define ptr @f(i32 %n) presplitcoroutine_custom_abi {
entry:
%id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)
%size = call i32 @llvm.coro.size.i32()
%alloc = call ptr @malloc(i32 %size)
%hdl = call noalias ptr @llvm.coro.begin.custom.abi(token %id, ptr %alloc, i32 0)
br label %loop
loop:
%n.val = phi i32 [ %n, %entry ], [ %inc, %loop ]
%inc = add nsw i32 %n.val, 1
call void @print(i32 %n.val)
%0 = call i8 @llvm.coro.suspend(token none, i1 false)
switch i8 %0, label %suspend [i8 0, label %loop
i8 1, label %cleanup]
cleanup:
%mem = call ptr @llvm.coro.free(token %id, ptr %hdl)
call void @free(ptr %mem)
br label %suspend
suspend:
%unused = call i1 @llvm.coro.end(ptr %hdl, i1 false, token none)
ret ptr %hdl
}

Intrinsics
==========
Expand Down Expand Up @@ -1007,6 +1067,36 @@ with small positive and negative offsets).

A frontend should emit exactly one `coro.begin` intrinsic per coroutine.

.. _coro.begin.custom.abi:

'llvm.coro.begin.custom.abi' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
::

declare ptr @llvm.coro.begin.custom.abi(token <id>, ptr <mem>, i32)

Overview:
"""""""""

The '``llvm.coro.begin.custom.abi``' intrinsic is used in place of the
`coro.begin` intrinsic that has an additional parameter to specify the custom
ABI for the coroutine. The return is identical to that of the `coro.begin`
intrinsic.

Arguments:
""""""""""

The first and second arguments are identical to those of the `coro.begin`
intrinsic.

The third argument is an i32 index of the generator list given to the
`CoroSplit` pass specifying the custom ABI generator lor this coroutine.

Semantics:
""""""""""

The semantics are identical to those of the `coro.begin` intrinsic.

.. _coro.free:

'llvm.coro.free' Intrinsic
Expand Down
Loading