[llvm-dev] [RFC] LLVM Coroutines

Eli Friedman via llvm-dev llvm-dev at lists.llvm.org
Sat Jun 11 14:27:12 PDT 2016


On Fri, Jun 10, 2016 at 10:32 PM, Gor Nishanov <gornishanov at gmail.com>
wrote:

> Okay. New intrinsics:
>
> declare void coro.barrier(i64); // will get a unique number for every
> insertion
>
> >>   x = alloca...
> >>
> >> block1:
> >>   suspend
> >>   ; nothing can sneak in here???, Right?
> >>   switch (resume, destroy, return)
> >>
> >> resume:
> >>   coro.barrier(0)
> >>   x += 1 ; load + inc + store
> >>   [...]
> >>
> >> destroy:
> >>   coro.barrier(1)
> >>   x += 1 ; load + inc + store
> >>   [...]
> >>
> >> return:
> >>   coro.barrier(2)
> >>   (don't touch x)
> >>   [...]
>
> Now we are good, right?
> I am still not giving up hope for an intrinsic approach.
>

coro.barrier() doesn't work: if the address of the alloca doesn't escape,
alias analysis will assume the barrier can't read or write the value of the
alloca, so the barrier doesn't actually block code movement.

There is always a backup plan to go to your "two function" idea with a
> slight
> twist.
>
>
> Almost two functions (coro.fork(), coro.suspendO() same as in original
> proposal)
>
> ================================================================================
>
> CoroEarly pass which runs at EP_EarlyAsPossible will extract f.start using
> coro.fork as a guide (since false branch bypasses the coroutine body).
>
> Coroutine will now travel as two functions until CoroSplit gets to f.start
> (Probably will use 'coroutine' attribute on a function to indicate that it
> requires CoroSplit to munge on it.)
>
> I am still hoping we can find a solution without requiring to separate
> f.start
> out. Seems like a huge hammer to avoid undesirable code motion / hoisting.
>
> (I really hope that @coro.barrier(i64) approach can work)
>


If you really don't want two functions, you could probably do something
like this:

block1:
%first_time = load...
br i1 %first_time, label return, label suspend1

suspend1:
suspend
switch (resume1, destroy1)

block2:
%first_time = load...
br i1 %first_time, label return, label suspend2

suspend2:
suspend
switch (resume2, destroy2)

label return:
%cont = phi i32 [(block1, 1), (block2, 2)]
; do stuff
switch %cont... (1, label suspend1), (2, label suspend2)

It's a little awkward to generate the return block, but otherwise it's
reasonably clean. Also, if some non-C++ language wants to generate
coroutines, it might not have to generate the return block at all.

-Eli
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20160611/8a77eb6a/attachment.html>


More information about the llvm-dev mailing list