<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Fri, Jun 10, 2016 at 6:36 AM, Gor Nishanov <span dir="ltr"><<a href="mailto:gornishanov@gmail.com" target="_blank">gornishanov@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class="">>> If you're going down that route, that still leaves the question of the<br>
>> semantics of the fork intrinsic... thinking about it a bit more, I think<br>
>> you're going to run into problems with trying to keep around a return block<br>
>> through optimizations:<br>
<br>
</span>Thinking about it a bit more, it is even simpler, I don't have to involve<br>
coro.end in this case at all and should not worry about branches, RAUW-ing<br>
coro.suspend with an appropriate constant takes care of it all.<br>
<br>
Here is an updated version.<br>
1) coro.fork is gone, gone gone!!!!<br>
2) coro.suspend is changed as follows:<br>
<span class=""><br>
    declare i8 coro.suspend([...])<br>
<br>
    returns:<br>
</span>      0 - in resume clone<br>
      1 - in destroy clone<br>
      -1 - in the original function<br>
<br>
Usage:<br>
<span class=""><br>
    [...]<br>
    %0 = call i8 @llvm.coro.suspend([...])<br>
</span>    switch i8 %0, label %return [ i32 0, label %resume,<br>
                                  i32 1, label %cleanup]<br>
<br>
Lowering of coro.suspend X<br>
<br>
  In the original function:<br>
    * RAUW coro.suspend to -1<br>
    * Remove coro.suspend<br>
<br>
  In both clones:<br>
    * RAUW coro.suspend to 0 in `f.resume` and 1 in `f.destroy`<br>
    * Split block after coro.suspend, new block becomes the resume label X<br>
    * replace coro.suspend with<br>
      - `ret void` in resume clone<br>
      - @llvm.trap() in destroy clone<br>
        (in destroy clone none of the suspends points should be reachable,<br>
         if they are it is a front end bug)<br>
<br>
Much prettier than before :-)<br>
<span class=""><font color="#888888"><br><br></font></span></blockquote><div><br></div><div>I'm not sure this quite works the way you want it to in terms of the optimizer.  For example:<br><span class=""><br></span></div><div><span class="">block1:<br></span></div><div><span class="">suspend<br></span></div><div><span class="">switch (resume, destroy, return)<br><br></span></div><div><span class="">resume:</span><br><span class=""><span class="">store </span></span><span class=""><span class=""><span class="">zero </span> to global @g</span><br>[...]<br><br></span></div><div><span class="">destroy:</span><br><span class="">store </span><span class=""><span class="">zero </span> to global @g<br>[...]<br><br></span></div><div><span class="">return:<br></span><span class="">store zero to global @g<br>[...]</span><br></div><div><span class=""><br></span></div><div>Naively, you would expect that it would be legal to hoist the store... but that breaks your coroutine semantics because the global could be mutated <span class="">between the first return and the resume.<br></span></div><div><span class=""><br></span></div><div><span class="">Probably the most natural way to solve this is the two-function approach I suggested earlier... that way, the first call to suspend isn't special, so everything just works.<br><br>There might be some other way to solve it, but I think it just becomes more awkward. For example, you could add a boolean that tracks whether the function has been suspended yet, and explicitly reroute the control flow to conditionally perform one-time operations before each call to suspend.  But then you need a giant switch statement or a separate one-time cleanup function to actually route the control flow correctly.<br><br></span></div><div><span class="">-Eli<br></span></div></div></div></div>