From d424b3d7ea6814f7b6de92d33574c78a8510746b Mon Sep 17 00:00:00 2001 From: Nia Weiss Date: Sat, 31 Oct 2020 11:37:50 -0400 Subject: [PATCH] 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. --- Makefile | 1 + transform/coroutines.go | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 4eb29fca..f78c5dbc 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/transform/coroutines.go b/transform/coroutines.go index 5700e64a..3756da25 100644 --- a/transform/coroutines.go +++ b/transform/coroutines.go @@ -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)