Gor Nishanov via llvm-dev
2016-Jul-20 21:23 UTC
[llvm-dev] RFC: LLVM Coroutine Representation, Round 2
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
Antoine Pitrou via llvm-dev
2016-Jul-20 21:44 UTC
[llvm-dev] RFC: LLVM Coroutine Representation, Round 2
On Wed, 20 Jul 2016 14:23:29 -0700 Gor Nishanov via llvm-dev <llvm-dev at lists.llvm.org> wrote:> > 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.I don't think this answers my question. Say I have (Python notation): def coroutine(n): for i in range(n): yield i def consumer(n): for val in coroutine(n): # do something with val How does consumer() know the coroutine has exited after the n'th iteration? It can't call @coro.done() as there is a single suspend point... Regards Antoine.