<div class="gmail_quote">On Mon, Apr 11, 2011 at 9:07 AM, Sanjoy Das <span dir="ltr"><<a href="mailto:sanjoy@playingwithpointers.com">sanjoy@playingwithpointers.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
Hi!<br>
<br>
Thanks for the feedback. For context, my implementation plan is here:<br>
<a href="http://pastebin.com/e9JMZNCE" target="_blank">http://pastebin.com/e9JMZNCE</a><br>
<br>
First, about unwinding:<br>
<br>
In architectures like x86-64, where unwinding based on DWARF info, there<br>
shouldn't be any problems; since the DWARF info will be emitted<br>
correctly. Otherwise, if the unwinding is done by following BP, it<br>
should still be possible to have BP de-reference correctly (ref. "Frame<br>
Pointers" section in the implementation plan). SP will not always have a<br>
correct value - I don't know if this is problem.<br>
<br>
About co-routines:<br>
<br>
Here is a sketch of how I think co-routines can be implemented (I'll<br>
merge this with the main implementation plan after I get some feedback):<br>
<br>
Have a new instruction, called "yield" to return a value from a<br>
co-routine, preserving the state. Thus, we immediately know which<br>
functions are co-routines. Each co-routine will have a new stack.<br>
Associate each co-routine with a thread-local global variable (called<br>
saved_stack here, will have to be mangled with the name of the<br>
co-routine) which points to the start stack block for that co-routine.<br>
This will be the first block in the chain of blocks to follow.<br>
<br>
The structure of the block will be similar to the structure of a regular<br>
stack block, except that it will also have space to store two registers<br>
- this_ip and this_sp.<br>
<br>
The prologue of a co-routine will jump to a function similar to<br>
setup_new_block (setup_new_block_coroutine) which will work like<br>
setup_new_block, except:<br>
<br>
1. It will first check if saved_stack is NULL. If it is NULL, it will<br>
allocate a new block and save it to saved_stack. It if isn't, it'll<br>
simply restore saved_sp, saved_ip.<br>
<br>
2. In case a new block was allocated, it will pretty much do what<br>
setup_block does, after which it will adjust the SP to make space for<br>
the saved registers.<br>
<br>
The destroy_block procedure will also have to be a little different<br>
(mentioned below).<br>
<br>
There are four things (relevant to this discussion) a co-routine can do:<br>
<br>
Yield<br>
<br>
This returns control to the calling function, without forgetting the<br>
current state of the function. To do this, we save saved_ip and<br>
saved_sp. Every yield be padded with instructions pushing and popping<br>
the registers live at that point. Then we set the return value (register<br>
or memory), and restore saved_sp and saved_ip from the current block. We<br>
can't simply return because the actual return value has been hijacked to<br>
provide for block cleanup.<br>
<br>
Call to regular function<br>
<br>
Just a simple call - the caller's prologue will handle setting up a it's<br>
own stack space etc.<br>
<br>
Call to Co-routine<br>
<br>
This too should "just work", since all the heavy-lifting is done in the<br>
co-routine's prologue. However, the above approach will not work for<br>
nested co-routines (i.e. calling the same co-routine body with one call<br>
is still active, recursively). I'm not sure if having support for nested<br>
co-routines will add any value.<br>
<br>
Return<br>
<br>
This will be a regular return. Since the return value has been hijacked<br>
to point to a another block of code (destroy_block_coroutine), control<br>
will jump there instead.<br>
<br>
destroy_block_coroutine will free the linked-list of stack blocks (we<br>
have to free this, since we will won't have a reference to this list<br>
anymore), set saved_stack for this co-routine to NULL, and restore<br>
saved_sp and saved_ip.<br></blockquote><div><br></div><div>I'm wondering how much of this should be implemented as new LLVM functionality, and how much should be left to the front-end compiler.  With some additional LLVM intrinsics (e.g. llvm.stack.new.block, llvm.stack.delete.block, etc.), a front-end could take care of the details of how co-routines are actually implemented.  This would also give the front-end freedom to implement whatever semantics/conventions are necessary/required for the source language.  I'm just not sure having LLVM dictate <i>how</i> co-routines are implemented is the best way to approach this.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<font color="#888888"><br>
--<br>
</font><div><div></div><div class="h5">Sanjoy Das<br>
<a href="http://playingwithpointers.com" target="_blank">http://playingwithpointers.com</a><br>
_______________________________________________<br>
LLVM Developers mailing list<br>
<a href="mailto:LLVMdev@cs.uiuc.edu">LLVMdev@cs.uiuc.edu</a>         <a href="http://llvm.cs.uiuc.edu" target="_blank">http://llvm.cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev</a><br>
</div></div></blockquote></div><br><br clear="all"><br>-- <br><br><div>Thanks,</div><div><br></div><div>Justin Holewinski</div><br>