add missing return pointer restore for regular coroutine tail calls

This fixes an issue where a normal suspending call followed by a plain tail call would result in the tail return value being written to the return pointer of the normal suspending call.
This is fixed by saving the return pointer at the start of the function and restoring it before initiating a plain tail call.
This commit is contained in:
Nia Weiss
2020-10-31 11:37:50 -04:00
committed by Ron Evans
parent c20328472b
commit d424b3d7ea
2 changed files with 11 additions and 5 deletions
+1
View File
@@ -188,6 +188,7 @@ tinygo-test:
$(TINYGO) test encoding/base32
$(TINYGO) test encoding/hex
$(TINYGO) test hash/fnv
$(TINYGO) test hash/crc64
$(TINYGO) test math
$(TINYGO) test text/scanner
$(TINYGO) test unicode/utf8
+10 -5
View File
@@ -735,10 +735,10 @@ func (c *coroutineLoweringPass) lowerFuncCoro(fn *asyncFunc) {
task := c.builder.CreateCall(c.current, []llvm.Value{llvm.Undef(c.i8ptr), fn.rawTask}, "task")
parentState := c.builder.CreateCall(c.setState, []llvm.Value{task, coroState, llvm.Undef(c.i8ptr), llvm.Undef(c.i8ptr)}, "task.state.parent")
// Get return pointer if needed.
var retPtr llvm.Value
if fn.hasValueStoreReturn() {
retPtr = c.builder.CreateCall(c.getRetPtr, []llvm.Value{task, llvm.Undef(c.i8ptr), llvm.Undef(c.i8ptr)}, "task.retPtr")
retPtr = c.builder.CreateBitCast(retPtr, llvm.PointerType(fn.fn.Type().ElementType().ReturnType(), 0), "task.retPtr.bitcast")
var retPtrRaw, retPtr llvm.Value
if returnType.TypeKind() != llvm.VoidTypeKind {
retPtrRaw = c.builder.CreateCall(c.getRetPtr, []llvm.Value{task, llvm.Undef(c.i8ptr), llvm.Undef(c.i8ptr)}, "task.retPtr")
retPtr = c.builder.CreateBitCast(retPtrRaw, llvm.PointerType(fn.fn.Type().ElementType().ReturnType(), 0), "task.retPtr.bitcast")
}
// Build suspend block.
@@ -802,8 +802,13 @@ func (c *coroutineLoweringPass) lowerFuncCoro(fn *asyncFunc) {
// Resume caller.
c.builder.CreateCall(c.returnTo, []llvm.Value{task, parentState, llvm.Undef(c.i8ptr), llvm.Undef(c.i8ptr)}, "")
case returnVoidTail, returnTail, returnDeadTail:
case returnVoidTail, returnDeadTail:
// Nothing to do.
case returnTail:
c.builder.SetInsertPointBefore(call)
// Restore the return pointer so that the caller can store into it.
c.builder.CreateCall(c.setRetPtr, []llvm.Value{task, retPtrRaw, llvm.Undef(c.i8ptr), llvm.Undef(c.i8ptr)}, "")
case returnAlternateTail:
c.builder.SetInsertPointBefore(call)