[llvm-dev] [RFC] LLVM Coroutines
Sanjoy Das via llvm-dev
llvm-dev at lists.llvm.org
Sat Jun 11 18:09:26 PDT 2016
Hi Gor,
How will you handle (potentially variably sized) alloca instructions
that cannot be elided by promotion to SSA? E.g.
void cor() {
int a = 0;
escape(&a);
for (;;) yield(a++);
}
-- Sanjoy
On Sat, Jun 11, 2016 at 5:43 PM, Gor Nishanov via llvm-dev
<llvm-dev at lists.llvm.org> wrote:
> (Dropped llvm-dev by accident. Putting it back)
>
>
> HI Eli:
>
>>> 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.
>
> Got it. I am new to this and learning a lot over the course
> of this thread. Thank you for being patient with me.
>
> Two questions and one clarification:
>
> Q1: Do we have to have a load here?
> ===================================
>
>>> block1:
>>> %first_time = load... <--- What are we loading here?
>>> br i1 %first_time, label return, label suspend1
>>>
>>> supend1:
>>> %0 = coro.suspend()
>>> switch %0 (resume1, destroy1)
>
> Can we use three way coro.suspend instead?
>
> Block1:
> %0 = call i8 coro.suspend()
> switch i8 %0, label suspend1 [i8 0 %return] ; or icmp + br i1
> Suspend1:
> switch i8 %0, label %resume1 [i8 1 %destroy1] ; or icmp + br i1
>
> One problem I can see is that someone can write a pass that might merge
> two branches / switches into one switch and we are back where we were.
> I guess what you meant by load, is to call some coro.is.first.time() intrinsic.
> So it looks like:
>
>>> block1:
>>> %first_time = call i1 coro.is.first.time()
>>> br i1 %first_time, label return, label suspend1
>>>
>>> supend1:
>>> %0 = coro.suspend()
>>> switch %0 (resume1, destroy1)
>
> This looks fine, there may be more uses for this intrinsic in the frontend.
> Killing two birds with one stone. Good.
>
> Question 2: Why the switch in the return block?
> ===============================================
>
> I would think that **pre-split** return block would be simply:
>
> return:
> <run dtors for parameters, if required>
> <conversion ops for ret value, if required>
> <ret void> or <ret whatever>
>
> Where and why I should put a switch that you mentioned in this return block?
>
> BTW, I am speaking of the return block as if it is one block,
> but, it could be a dominating block over all the blocks that together
> run the destructors, do return value conversion, etc.
>
> Clarification:
> ==============
>
>>> Also, if some non-C++ language wants to generate coroutines,
>>> it might not have to generate the return block at all.
>
> C++ coroutines are flexible. The semantic of a coroutine is defined via
> traits, so you may define a coroutine that returns void. It does not have
> to return coroutine handle or some struct that wraps the coroutine handle.
>
> For example, a developer may have a queue of suspended coroutines that is
> processed by a scheduler, so a coroutine can queue its handle on suspension
> either into a global queue or thread_local queue. If there are no destructors
> to run for parameters, the return block would be simply:
>
> return:
> ret void
>
>
> Cheers,
> Gor
> _______________________________________________
> LLVM Developers mailing list
> llvm-dev at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
--
Sanjoy Das
http://playingwithpointers.com
More information about the llvm-dev
mailing list