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 }