Skip to content

Commit d424b3d

Browse files
niaowdeadprogram
authored andcommitted
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.
1 parent c203284 commit d424b3d

File tree

2 files changed

+11
-5
lines changed

2 files changed

+11
-5
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ tinygo-test:
188188
$(TINYGO) test encoding/base32
189189
$(TINYGO) test encoding/hex
190190
$(TINYGO) test hash/fnv
191+
$(TINYGO) test hash/crc64
191192
$(TINYGO) test math
192193
$(TINYGO) test text/scanner
193194
$(TINYGO) test unicode/utf8

transform/coroutines.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -735,10 +735,10 @@ func (c *coroutineLoweringPass) lowerFuncCoro(fn *asyncFunc) {
735735
task := c.builder.CreateCall(c.current, []llvm.Value{llvm.Undef(c.i8ptr), fn.rawTask}, "task")
736736
parentState := c.builder.CreateCall(c.setState, []llvm.Value{task, coroState, llvm.Undef(c.i8ptr), llvm.Undef(c.i8ptr)}, "task.state.parent")
737737
// Get return pointer if needed.
738-
var retPtr llvm.Value
739-
if fn.hasValueStoreReturn() {
740-
retPtr = c.builder.CreateCall(c.getRetPtr, []llvm.Value{task, llvm.Undef(c.i8ptr), llvm.Undef(c.i8ptr)}, "task.retPtr")
741-
retPtr = c.builder.CreateBitCast(retPtr, llvm.PointerType(fn.fn.Type().ElementType().ReturnType(), 0), "task.retPtr.bitcast")
738+
var retPtrRaw, retPtr llvm.Value
739+
if returnType.TypeKind() != llvm.VoidTypeKind {
740+
retPtrRaw = c.builder.CreateCall(c.getRetPtr, []llvm.Value{task, llvm.Undef(c.i8ptr), llvm.Undef(c.i8ptr)}, "task.retPtr")
741+
retPtr = c.builder.CreateBitCast(retPtrRaw, llvm.PointerType(fn.fn.Type().ElementType().ReturnType(), 0), "task.retPtr.bitcast")
742742
}
743743

744744
// Build suspend block.
@@ -802,8 +802,13 @@ func (c *coroutineLoweringPass) lowerFuncCoro(fn *asyncFunc) {
802802

803803
// Resume caller.
804804
c.builder.CreateCall(c.returnTo, []llvm.Value{task, parentState, llvm.Undef(c.i8ptr), llvm.Undef(c.i8ptr)}, "")
805-
case returnVoidTail, returnTail, returnDeadTail:
805+
case returnVoidTail, returnDeadTail:
806806
// Nothing to do.
807+
case returnTail:
808+
c.builder.SetInsertPointBefore(call)
809+
810+
// Restore the return pointer so that the caller can store into it.
811+
c.builder.CreateCall(c.setRetPtr, []llvm.Value{task, retPtrRaw, llvm.Undef(c.i8ptr), llvm.Undef(c.i8ptr)}, "")
807812
case returnAlternateTail:
808813
c.builder.SetInsertPointBefore(call)
809814

0 commit comments

Comments
 (0)