refactor coroutine lowering and tasks

This commit is contained in:
Jaden Weiss
2020-01-03 00:23:37 -05:00
committed by Ayke
parent 2521cacb51
commit 6a50f25a48
40 changed files with 1830 additions and 1515 deletions
+120
View File
@@ -0,0 +1,120 @@
target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
target triple = "armv7m-none-eabi"
%"internal/task.state" = type { i8* }
%"internal/task.Task" = type { %"internal/task.Task", i8*, i32, %"internal/task.state" }
declare void @"internal/task.start"(i32, i8*, i8*, i8*)
declare void @"internal/task.Pause"(i8*, i8*)
declare void @runtime.scheduler(i8*, i8*)
declare i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.free(i8*, i8*, i8*)
declare %"internal/task.Task"* @"internal/task.Current"(i8*, i8*)
declare i8* @"(*internal/task.Task).setState"(%"internal/task.Task"*, i8*, i8*, i8*)
declare void @"(*internal/task.Task).setReturnPtr"(%"internal/task.Task"*, i8*, i8*, i8*)
declare i8* @"(*internal/task.Task).getReturnPtr"(%"internal/task.Task"*, i8*, i8*)
declare void @"(*internal/task.Task).returnTo"(%"internal/task.Task"*, i8*, i8*, i8*)
declare void @"(*internal/task.Task).returnCurrent"(%"internal/task.Task"*, i8*, i8*)
declare %"internal/task.Task"* @"internal/task.createTask"(i8*, i8*)
declare void @callMain(i8*, i8*)
; Test a simple sleep-like scenario.
declare void @enqueueTimer(%"internal/task.Task"*, i64, i8*, i8*)
define void @sleep(i64, i8*, i8* %parentHandle) {
entry:
%2 = call %"internal/task.Task"* @"internal/task.Current"(i8* undef, i8* null)
call void @enqueueTimer(%"internal/task.Task"* %2, i64 %0, i8* undef, i8* null)
call void @"internal/task.Pause"(i8* undef, i8* null)
ret void
}
; Test a delayed value return.
define i32 @delayedValue(i32, i64, i8*, i8* %parentHandle) {
entry:
call void @sleep(i64 %1, i8* undef, i8* null)
ret i32 %0
}
; Test a deadlocking async func.
define void @deadlock(i8*, i8* %parentHandle) {
entry:
call void @"internal/task.Pause"(i8* undef, i8* null)
unreachable
}
; Test a regular tail call.
define i32 @tail(i32, i64, i8*, i8* %parentHandle) {
entry:
%3 = call i32 @delayedValue(i32 %0, i64 %1, i8* undef, i8* null)
ret i32 %3
}
; Test a ditching tail call.
define void @ditchTail(i32, i64, i8*, i8* %parentHandle) {
entry:
%3 = call i32 @delayedValue(i32 %0, i64 %1, i8* undef, i8* null)
ret void
}
; Test a void tail call.
define void @voidTail(i32, i64, i8*, i8* %parentHandle) {
entry:
call void @ditchTail(i32 %0, i64 %1, i8* undef, i8* null)
ret void
}
; Test a tail call returning an alternate value.
define i32 @alternateTail(i32, i32, i64, i8*, i8* %parentHandle) {
entry:
%4 = call i32 @delayedValue(i32 %1, i64 %2, i8* undef, i8* null)
ret i32 %0
}
; Test a normal return from a coroutine.
; This must be turned into a coroutine.
define i1 @coroutine(i32, i64, i8*, i8* %parentHandle) {
entry:
%3 = call i32 @delayedValue(i32 %0, i64 %1, i8* undef, i8* null)
%4 = icmp eq i32 %3, 0
ret i1 %4
}
; Normal function which should not be transformed.
define void @doNothing(i8*, i8*) {
entry:
ret void
}
; Goroutine that sleeps and does nothing.
; Should be a void tail call.
define void @sleepGoroutine(i8*, i8* %parentHandle) {
call void @sleep(i64 1000000, i8* undef, i8* null)
ret void
}
; Program main function.
define void @progMain(i8*, i8* %parentHandle) {
entry:
; Call a sync func in a goroutine.
call void @"internal/task.start"(i32 ptrtoint (void (i8*, i8*)* @doNothing to i32), i8* undef, i8* undef, i8* null)
; Call an async func in a goroutine.
call void @"internal/task.start"(i32 ptrtoint (void (i8*, i8*)* @sleepGoroutine to i32), i8* undef, i8* undef, i8* null)
; Sleep a bit.
call void @sleep(i64 2000000, i8* undef, i8* null)
; Done.
ret void
}
; Entrypoint of runtime.
define void @main() {
entry:
call void @"internal/task.start"(i32 ptrtoint (void (i8*, i8*)* @progMain to i32), i8* undef, i8* undef, i8* null)
call void @runtime.scheduler(i8* undef, i8* null)
ret void
}
+176
View File
@@ -0,0 +1,176 @@
target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
target triple = "armv7m-none-eabi"
%"internal/task.Task" = type { %"internal/task.Task", i8*, i32, %"internal/task.state" }
%"internal/task.state" = type { i8* }
declare void @"internal/task.start"(i32, i8*, i8*, i8*)
declare void @"internal/task.Pause"(i8*, i8*)
declare void @runtime.scheduler(i8*, i8*)
declare i8* @runtime.alloc(i32, i8*, i8*)
declare void @runtime.free(i8*, i8*, i8*)
declare %"internal/task.Task"* @"internal/task.Current"(i8*, i8*)
declare i8* @"(*internal/task.Task).setState"(%"internal/task.Task"*, i8*, i8*, i8*)
declare void @"(*internal/task.Task).setReturnPtr"(%"internal/task.Task"*, i8*, i8*, i8*)
declare i8* @"(*internal/task.Task).getReturnPtr"(%"internal/task.Task"*, i8*, i8*)
declare void @"(*internal/task.Task).returnTo"(%"internal/task.Task"*, i8*, i8*, i8*)
declare void @"(*internal/task.Task).returnCurrent"(%"internal/task.Task"*, i8*, i8*)
declare %"internal/task.Task"* @"internal/task.createTask"(i8*, i8*)
declare void @callMain(i8*, i8*)
declare void @enqueueTimer(%"internal/task.Task"*, i64, i8*, i8*)
define void @sleep(i64, i8*, i8* %parentHandle) {
entry:
%task.current = bitcast i8* %parentHandle to %"internal/task.Task"*
%task.current1 = bitcast i8* %parentHandle to %"internal/task.Task"*
call void @enqueueTimer(%"internal/task.Task"* %task.current1, i64 %0, i8* undef, i8* null)
ret void
}
define i32 @delayedValue(i32, i64, i8*, i8* %parentHandle) {
entry:
%task.current = bitcast i8* %parentHandle to %"internal/task.Task"*
%ret.ptr = call i8* @"(*internal/task.Task).getReturnPtr"(%"internal/task.Task"* %task.current, i8* undef, i8* undef)
%ret.ptr.bitcast = bitcast i8* %ret.ptr to i32*
store i32 %0, i32* %ret.ptr.bitcast
call void @sleep(i64 %1, i8* undef, i8* %parentHandle)
ret i32 undef
}
define void @deadlock(i8*, i8* %parentHandle) {
entry:
%task.current = bitcast i8* %parentHandle to %"internal/task.Task"*
ret void
}
define i32 @tail(i32, i64, i8*, i8* %parentHandle) {
entry:
%task.current = bitcast i8* %parentHandle to %"internal/task.Task"*
%3 = call i32 @delayedValue(i32 %0, i64 %1, i8* undef, i8* %parentHandle)
ret i32 undef
}
define void @ditchTail(i32, i64, i8*, i8* %parentHandle) {
entry:
%task.current = bitcast i8* %parentHandle to %"internal/task.Task"*
%ret.ditch = call i8* @runtime.alloc(i32 4, i8* undef, i8* undef)
call void @"(*internal/task.Task).setReturnPtr"(%"internal/task.Task"* %task.current, i8* %ret.ditch, i8* undef, i8* undef)
%3 = call i32 @delayedValue(i32 %0, i64 %1, i8* undef, i8* %parentHandle)
ret void
}
define void @voidTail(i32, i64, i8*, i8* %parentHandle) {
entry:
%task.current = bitcast i8* %parentHandle to %"internal/task.Task"*
call void @ditchTail(i32 %0, i64 %1, i8* undef, i8* %parentHandle)
ret void
}
define i32 @alternateTail(i32, i32, i64, i8*, i8* %parentHandle) {
entry:
%task.current = bitcast i8* %parentHandle to %"internal/task.Task"*
%ret.ptr = call i8* @"(*internal/task.Task).getReturnPtr"(%"internal/task.Task"* %task.current, i8* undef, i8* undef)
%ret.ptr.bitcast = bitcast i8* %ret.ptr to i32*
store i32 %0, i32* %ret.ptr.bitcast
%ret.alternate = call i8* @runtime.alloc(i32 4, i8* undef, i8* undef)
call void @"(*internal/task.Task).setReturnPtr"(%"internal/task.Task"* %task.current, i8* %ret.alternate, i8* undef, i8* undef)
%4 = call i32 @delayedValue(i32 %1, i64 %2, i8* undef, i8* %parentHandle)
ret i32 undef
}
define i1 @coroutine(i32, i64, i8*, i8* %parentHandle) {
entry:
%call.return = alloca i32
%coro.id = call token @llvm.coro.id(i32 0, i8* null, i8* null, i8* null)
%coro.size = call i32 @llvm.coro.size.i32()
%coro.alloc = call i8* @runtime.alloc(i32 %coro.size, i8* undef, i8* undef)
%coro.state = call i8* @llvm.coro.begin(token %coro.id, i8* %coro.alloc)
%task.current2 = bitcast i8* %parentHandle to %"internal/task.Task"*
%task.state.parent = call i8* @"(*internal/task.Task).setState"(%"internal/task.Task"* %task.current2, i8* %coro.state, i8* undef, i8* undef)
%task.retPtr = call i8* @"(*internal/task.Task).getReturnPtr"(%"internal/task.Task"* %task.current2, i8* undef, i8* undef)
%task.retPtr.bitcast = bitcast i8* %task.retPtr to i1*
%call.return.bitcast = bitcast i32* %call.return to i8*
call void @llvm.lifetime.start.p0i8(i64 4, i8* %call.return.bitcast)
%task.current = bitcast i8* %parentHandle to %"internal/task.Task"*
%call.return.bitcast1 = bitcast i32* %call.return to i8*
call void @"(*internal/task.Task).setReturnPtr"(%"internal/task.Task"* %task.current, i8* %call.return.bitcast1, i8* undef, i8* undef)
%3 = call i32 @delayedValue(i32 %0, i64 %1, i8* undef, i8* %parentHandle)
%coro.save = call token @llvm.coro.save(i8* %coro.state)
%call.suspend = call i8 @llvm.coro.suspend(token %coro.save, i1 false)
switch i8 %call.suspend, label %suspend [
i8 0, label %wakeup
i8 1, label %cleanup
]
wakeup: ; preds = %entry
%4 = load i32, i32* %call.return
call void @llvm.lifetime.end.p0i8(i64 4, i8* %call.return.bitcast)
%5 = icmp eq i32 %4, 0
store i1 %5, i1* %task.retPtr.bitcast
call void @"(*internal/task.Task).returnTo"(%"internal/task.Task"* %task.current2, i8* %task.state.parent, i8* undef, i8* undef)
br label %cleanup
suspend: ; preds = %entry, %cleanup
%unused = call i1 @llvm.coro.end(i8* %coro.state, i1 false)
ret i1 undef
cleanup: ; preds = %entry, %wakeup
%coro.memFree = call i8* @llvm.coro.free(token %coro.id, i8* %coro.state)
call void @runtime.free(i8* %coro.memFree, i8* undef, i8* undef)
br label %suspend
}
define void @doNothing(i8*, i8*) {
entry:
ret void
}
define void @sleepGoroutine(i8*, i8* %parentHandle) {
%task.current = bitcast i8* %parentHandle to %"internal/task.Task"*
call void @sleep(i64 1000000, i8* undef, i8* %parentHandle)
ret void
}
define void @progMain(i8*, i8* %parentHandle) {
entry:
%task.current = bitcast i8* %parentHandle to %"internal/task.Task"*
call void @doNothing(i8* undef, i8* undef)
%start.task = call %"internal/task.Task"* @"internal/task.createTask"(i8* undef, i8* undef)
%start.task.bitcast = bitcast %"internal/task.Task"* %start.task to i8*
call void @sleepGoroutine(i8* undef, i8* %start.task.bitcast)
call void @sleep(i64 2000000, i8* undef, i8* %parentHandle)
ret void
}
define void @main() {
entry:
%start.task = call %"internal/task.Task"* @"internal/task.createTask"(i8* undef, i8* undef)
%start.task.bitcast = bitcast %"internal/task.Task"* %start.task to i8*
call void @progMain(i8* undef, i8* %start.task.bitcast)
call void @runtime.scheduler(i8* undef, i8* null)
ret void
}
declare token @llvm.coro.id(i32, i8* readnone, i8* nocapture readonly, i8*) #0
declare i32 @llvm.coro.size.i32() #1
declare i8* @llvm.coro.begin(token, i8* writeonly) #2
declare i8 @llvm.coro.suspend(token, i1) #2
declare i1 @llvm.coro.end(i8*, i1) #2
declare i8* @llvm.coro.free(token, i8* nocapture readonly) #0
declare token @llvm.coro.save(i8*) #2
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #3
declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #3
attributes #0 = { argmemonly nounwind readonly }
attributes #1 = { nounwind readnone }
attributes #2 = { nounwind }
attributes #3 = { argmemonly nounwind }
+3 -6
View File
@@ -15,7 +15,7 @@ target triple = "wasm32-unknown-unknown-wasm"
declare i32 @runtime.getFuncPtr(i8*, i32, %runtime.typecodeID*, i8*, i8*)
declare i32 @runtime.makeGoroutine(i32, i8*, i8*)
declare void @"internal/task.start"(i32, i8*, i8*, i8*)
declare void @runtime.nilPanic(i8*, i8*)
@@ -71,13 +71,10 @@ fpcall.next:
ret void
}
; Special case for runtime.makeGoroutine.
; Special case for internal/task.start.
define void @sleepFuncValue(i8*, i32, i8* nocapture readnone %context, i8* nocapture readnone %parentHandle) {
entry:
%2 = call i32 @runtime.getFuncPtr(i8* %0, i32 %1, %runtime.typecodeID* @"reflect/types.type:func:{basic:int}{}", i8* undef, i8* null)
%3 = call i32 @runtime.makeGoroutine(i32 %2, i8* undef, i8* null)
%4 = inttoptr i32 %3 to void (i32, i8*, i8*)*
call void %4(i32 8, i8* %0, i8* null)
call void @"internal/task.start"(i32 %2, i8* null, i8* undef, i8* null)
ret void
}
+3 -7
View File
@@ -15,7 +15,7 @@ target triple = "wasm32-unknown-unknown-wasm"
declare i32 @runtime.getFuncPtr(i8*, i32, %runtime.typecodeID*, i8*, i8*)
declare i32 @runtime.makeGoroutine(i32, i8*, i8*)
declare void @"internal/task.start"(i32, i8*, i8*, i8*)
declare void @runtime.nilPanic(i8*, i8*)
@@ -102,15 +102,11 @@ func.nil:
unreachable
func.call1:
%2 = call i32 @runtime.makeGoroutine(i32 ptrtoint (void (i32, i8*, i8*)* @"main$1" to i32), i8* undef, i8* null)
%3 = inttoptr i32 %2 to void (i32, i8*, i8*)*
call void %3(i32 8, i8* %0, i8* null)
call void @"internal/task.start"(i32 ptrtoint (void (i32, i8*, i8*)* @"main$1" to i32), i8* null, i8* undef, i8* null)
br label %func.next
func.call2:
%4 = call i32 @runtime.makeGoroutine(i32 ptrtoint (void (i32, i8*, i8*)* @"main$2" to i32), i8* undef, i8* null)
%5 = inttoptr i32 %4 to void (i32, i8*, i8*)*
call void %5(i32 8, i8* %0, i8* null)
call void @"internal/task.start"(i32 ptrtoint (void (i32, i8*, i8*)* @"main$2" to i32), i8* null, i8* undef, i8* null)
br label %func.next
func.next: