[llvm-dev] RFC: LLVM Coroutine Representation, Round 2

Gor Nishanov via llvm-dev llvm-dev at lists.llvm.org
Wed Jul 20 14:23:29 PDT 2016


Hi Antoine:

> - As the caller of a coroutine, how do I know whether a coroutine
>   reached its cleanup point or not?  This seems essential for
>   implementing iterators and looping on them, yet @llvm.coro.done only
>   works if a particular suspend point was designated as "final" (which
>   doesn't sound possible to do in the general case, i.e. halting
>   problem).

Whether a suspend point is final or not is a property of the a suspend point.
The second parameter of the coro.suspend intrinsic is a Boolean constant that
indicates whether it is final suspend point or not. The frontend decides which
suspend is final (if any).

For example, for C++ generator that looks like this:

   genenerator<int> f(int n) {
      yield 1;
      yield 2;
   }

Compiler synthesizes additional initial and final suspend points, the latter
is marked as final in LLVM IR. So, the actual coroutine looks like:

   genenerator<int> f(int n) {
      <initial-suspend>
      yield 1;
      yield 2;
      <final-suspend> // marked as final suspend
  }

When you pull from a generator, you resume the coroutine and then check, whether
coro.done is true or false. If false, coroutine is not at final
suspend and the user
of a generator can consume the current value. If it is at final suspend point
there is no value to consume, thus, you know that you are at the end
of the sequence.

If you have a coroutine that looks like this:

   genenerator<int> g(int n) {
      <initial-suspend>
      for (int i = 0;;) yield ++i;
      <final-suspend> // marked as final suspend
  }

It will never reach the final suspend and thus coro.done will never evaluate
to true. Thus, coroutine will produce an infinite sequence of values.

> - Is the promise type restricted to atomic LLVM types, or can I use
>   @llvm.coro.promise.p0i8 (together with a bitcast) if the promise is an
>   arbitrary complex structure?

A promise could be an arbitrary type. It does not have to be atomic.
A promise for a generator probably will only contain the current value or the
pointer to the current value depending if it is cheap or expensive to copy.

A promise for an asynchronous coroutine would probably contain a room to store
an eventual value produced by that task and, possibly, an atomic flag you can
set while coroutine is running to indicate that you would like it to cancel and
a reference count tracking number of users holding the reference to a coroutine
so that it won't go away until the number of users drops down to zero.

> - Is the promise allocated/copied inside the coroutine frame?  If not,
>   how does the sharing work even if the coroutine is passed to different
>   callers?

Yes. Coroutine promise, if specified, will be always part of the coroutine frame
and will be placed at deterministic location. So that coro.promise and
coro.from.promise intrinsics can work.

Cheers,
Gor


More information about the llvm-dev mailing list