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.
Этот коммит содержится в:
Nia Weiss 2020-10-31 11:37:50 -04:00 коммит произвёл Ron Evans
родитель c20328472b
коммит d424b3d7ea
2 изменённых файлов: 11 добавлений и 5 удалений

Просмотреть файл

@ -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

Просмотреть файл

@ -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)