tinygo/transform/testdata/coroutines.out.ll
Ayke van Laethem a21a039ac7 arm: automatically determine stack sizes
This is a big change that will determine the stack size for many
goroutines automatically. Functions that aren't recursive and don't call
function pointers can in many cases have an automatically determined
worst case stack size. This is useful, as the stack size is usually much
lower than the previous hardcoded default of 1024 bytes: somewhere
around 200-500 bytes is common.

A side effect of this change is that the default stack sizes (including
the stack size for other architectures such as AVR) can now be changed
in the config JSON file, making it tunable per application.
2020-08-27 19:23:22 +02:00

197 строки
7,7 КиБ
LLVM

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*, i32, 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 %0, i8* %1, 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 %0, i64 %1, i8* %2, 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* %0, i8* %parentHandle) {
entry:
%task.current = bitcast i8* %parentHandle to %"internal/task.Task"*
ret void
}
define i32 @tail(i32 %0, i64 %1, i8* %2, 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 %0, i64 %1, i8* %2, 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 %0, i64 %1, i8* %2, 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 %0, i32 %1, i64 %2, i8* %3, 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 %0, i64 %1, i8* %2, 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* %0, i8* %1) {
entry:
ret void
}
define void @sleepGoroutine(i8* %0, 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* %0, 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
}
; Function Attrs: argmemonly nounwind readonly
declare token @llvm.coro.id(i32, i8* readnone, i8* nocapture readonly, i8*) #0
; Function Attrs: nounwind readnone
declare i32 @llvm.coro.size.i32() #1
; Function Attrs: nounwind
declare i8* @llvm.coro.begin(token, i8* writeonly) #2
; Function Attrs: nounwind
declare i8 @llvm.coro.suspend(token, i1) #2
; Function Attrs: nounwind
declare i1 @llvm.coro.end(i8*, i1) #2
; Function Attrs: argmemonly nounwind readonly
declare i8* @llvm.coro.free(token, i8* nocapture readonly) #0
; Function Attrs: nounwind
declare token @llvm.coro.save(i8*) #2
; Function Attrs: argmemonly nounwind willreturn
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #3
; Function Attrs: argmemonly nounwind willreturn
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 willreturn }