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

Gor Nishanov via llvm-dev llvm-dev at lists.llvm.org
Thu Jul 21 11:43:44 PDT 2016


Hi Vadim:

> Does you design support resumption with parameter(s)?  (such as Python's
> generator.send(x)).  I suppose the "promise" could be used for passing data
> both ways,

Correct.

The docs/Coroutines.rst states that:

   "A coroutine author or a frontend may designate a distinguished `alloca`
    that can be used to communicate with the coroutine."

What kind of communication happens is determined by the source language
coroutine constructs. An example later in the section shows how, as a consumer
of a coroutine, you can read the data from the promise. But that communication
can go the other way if you, instead, will be storing into the promise in main,
and loading from it in the coroutine.

coro.promise intrinsic gives you the address of the promise associated with a
particular coroutine instance and you (as frontend writer, or coroutine library
designer is free to do whatever you want with it).

> please mention this explicitly in the design doc.

Would you suggest changes to the exact wording to make it clearer? I put it up
for review at: https://reviews.llvm.org/D22603, so you can just mark up the
changes you would like to see.

> Also, how is loading/storing to promise going to be lowered?

The coro.promise intrinsics just gives you an address of the coroutine promise.
You, as frontend / library writer, know what is the promise and you emit
appropriate load or stores instructions.

If you have a synchronous scenario and a promise is plain int, you would use
plain loads and stores. If your promise is some complicated data structure
which has atomics and you use it from different threads, you would use
appropriate loads, stores, fences and synchronization primitives.

But all this is out of scope for docs/Coroutines.rst . It is up to the frontend,
library writer to decide how it wants to use the promise. The only special
handling that LLVM does for the coroutine promise is:

1) places the promise at deterministic offset in the coroutine frame
2) allows you to get an address of the promise given a coroutine handle and
   vice versa.

Cheers,
Gor

P.S. If you'd like to see a library implementation of a generator, please see:

Generator itself:
https://github.com/GorNishanov/clang/blob/coro-rfc/test/Coroutines/Inputs/generator.h

coroutine_handle (a C++ level abstraction mapping to llvm intrinsics)
https://github.com/GorNishanov/clang/blob/coro-rfc/test/Coroutines/Inputs/coroutine.h

and the use:

https://github.com/GorNishanov/clang/blob/coro-rfc/test/Coroutines/generator.cpp

Well, if start looking at those tests, you may enjoy coroutines in C via macros,
lowered to the same coroutine intrinsics :-).

https://github.com/GorNishanov/clang/blob/coro-rfc/test/Coroutines/coro.c

and

https://github.com/GorNishanov/clang/blob/coro-rfc/test/Coroutines/Inputs/coro.h


More information about the llvm-dev mailing list