Skip to content

Instantly share code, notes, and snippets.

@andrewrk
Last active July 23, 2019 19:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andrewrk/8db59a66ca8719d7b6297271bca754ca to your computer and use it in GitHub Desktop.
Save andrewrk/8db59a66ca8719d7b6297271bca754ca to your computer and use it in GitHub Desktop.
simple coroutine demo
var x: i32 = 1;
export fn entry() void {
const p = async simpleAsyncFn();
}
fn simpleAsyncFn() void {
x += 1;
suspend;
x += 1;
}
%"[]u8" = type { i8*, i64 }
%builtin.StackTrace = type { i64, %"[]usize" }
%"[]usize" = type { i64*, i64 }
%"@Frame(simpleAsyncFn)" = type { i64 }
@x = internal unnamed_addr global i32 1, align 4
@0 = internal unnamed_addr constant [32 x i8] c"invalid resume of async function", align 1
@1 = internal unnamed_addr constant %"[]u8" { i8* getelementptr inbounds ([32 x i8], [32 x i8]* @0, i64 0, i64 0), i64 32 }, align 8
@2 = internal unnamed_addr constant [16 x i8] c"integer overflow", align 1
@3 = internal unnamed_addr constant %"[]u8" { i8* getelementptr inbounds ([16 x i8], [16 x i8]* @2, i64 0, i64 0), i64 16 }, align 8
; Function Attrs: nobuiltin nounwind
define void @entry() #2 !dbg !35 {
Entry:
%p = alloca %"@Frame(simpleAsyncFn)", align 8
%0 = getelementptr inbounds %"@Frame(simpleAsyncFn)", %"@Frame(simpleAsyncFn)"* %p, i32 0, i32 0, !dbg !44
store i64 0, i64* %0, !dbg !44
%1 = call fastcc i64 @simpleAsyncFn(%"@Frame(simpleAsyncFn)"* %p), !dbg !44
call void @llvm.dbg.declare(metadata %"@Frame(simpleAsyncFn)"* %p, metadata !39, metadata !DIExpression()), !dbg !45
ret void, !dbg !46
}
; Function Attrs: nobuiltin nounwind
define internal fastcc i64 @simpleAsyncFn(%"@Frame(simpleAsyncFn)"* nonnull) unnamed_addr #2 !dbg !47 {
AsyncSwitch:
%1 = getelementptr inbounds %"@Frame(simpleAsyncFn)", %"@Frame(simpleAsyncFn)"* %0, i32 0, i32 0, !dbg !51
%2 = load i64, i64* %1, !dbg !51
switch i64 %2, label %BadResume [
i64 0, label %Entry
i64 1, label %GetSize
i64 2, label %Resume
], !dbg !51
Entry: ; preds = %AsyncSwitch
%3 = load i32, i32* @x, align 4, !dbg !52
%4 = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %3, i32 1), !dbg !54
%5 = extractvalue { i32, i1 } %4, 0, !dbg !54
%6 = extractvalue { i32, i1 } %4, 1, !dbg !54
br i1 %6, label %OverflowFail, label %OverflowOk, !dbg !54
Resume: ; preds = %AsyncSwitch
%7 = load i32, i32* @x, align 4, !dbg !55
%8 = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %7, i32 1), !dbg !56
%9 = extractvalue { i32, i1 } %8, 0, !dbg !56
%10 = extractvalue { i32, i1 } %8, 1, !dbg !56
br i1 %10, label %OverflowFail1, label %OverflowOk2, !dbg !56
BadResume: ; preds = %AsyncSwitch
tail call fastcc void @panic(%"[]u8"* @1, %builtin.StackTrace* null), !dbg !51
unreachable, !dbg !51
GetSize: ; preds = %AsyncSwitch
ret i64 8, !dbg !51
OverflowFail: ; preds = %Entry
tail call fastcc void @panic(%"[]u8"* @3, %builtin.StackTrace* null), !dbg !54
unreachable, !dbg !54
OverflowOk: ; preds = %Entry
store i32 %5, i32* @x, align 4, !dbg !54
%11 = getelementptr inbounds %"@Frame(simpleAsyncFn)", %"@Frame(simpleAsyncFn)"* %0, i32 0, i32 0, !dbg !57
store i64 2, i64* %11, !dbg !57
ret i64 undef, !dbg !57
OverflowFail1: ; preds = %Resume
tail call fastcc void @panic(%"[]u8"* @3, %builtin.StackTrace* null), !dbg !56
unreachable, !dbg !56
OverflowOk2: ; preds = %Resume
store i32 %9, i32* @x, align 4, !dbg !56
%12 = getelementptr inbounds %"@Frame(simpleAsyncFn)", %"@Frame(simpleAsyncFn)"* %0, i32 0, i32 0, !dbg !58
store i64 3, i64* %12, !dbg !58
ret i64 undef, !dbg !58
}
const std = @import("std");
var x: i32 = 1;
export fn entry() void {
const p = async<std.heap.direct_allocator> simpleAsyncFn();
}
async fn simpleAsyncFn() void {
x += 1;
suspend;
x += 1;
}
define void @entry() #0 !dbg !698 {
Entry:
%error_return_trace_addresses = alloca [32 x i64], align 8
%error_return_trace = alloca %builtin.StackTrace, align 8
%0 = alloca { i16, i8* }, align 8
%p = alloca { i16, i8* }, align 8
%1 = getelementptr inbounds %builtin.StackTrace, %builtin.StackTrace* %error_return_trace, i32 0, i32 0
store i64 0, i64* %1
%2 = getelementptr inbounds %builtin.StackTrace, %builtin.StackTrace* %error_return_trace, i32 0, i32 1
%3 = getelementptr inbounds %"[]usize", %"[]usize"* %2, i32 0, i32 0
%4 = getelementptr inbounds [32 x i64], [32 x i64]* %error_return_trace_addresses, i64 0, i64 0
store i64* %4, i64** %3, align 8
%5 = getelementptr inbounds %"[]usize", %"[]usize"* %2, i32 0, i32 1
store i64 32, i64* %5, align 8
%6 = getelementptr inbounds { i16, i8* }, { i16, i8* }* %0, i32 0, i32 0, !dbg !708
%7 = call fastcc i8* @simpleAsyncFn(%builtin.StackTrace* %error_return_trace, %std.mem.Allocator* @direct_allocator_state, i16* %6), !dbg !708
%8 = getelementptr inbounds { i16, i8* }, { i16, i8* }* %0, i32 0, i32 1, !dbg !708
store i8* %7, i8** %8, !dbg !708
%9 = bitcast { i16, i8* }* %0 to i8*, !dbg !708
%10 = bitcast { i16, i8* }* %p to i8*, !dbg !708
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %10, i8* align 8 %9, i64 16, i1 false), !dbg !708
call void @llvm.dbg.declare(metadata { i16, i8* }* %p, metadata !702, metadata !DIExpression()), !dbg !709
ret void, !dbg !710
}
; Function Attrs: nobuiltin noinline nounwind optnone
define internal fastcc i8* @simpleAsyncFn(%builtin.StackTrace* nonnull, %std.mem.Allocator*, i16*) unnamed_addr #3 !dbg !711 {
Entry:
%3 = alloca [6 x i64]
%promise = alloca %"AsyncFramePromise(void)", align 8
%await_handle = alloca i8*, align 8
%coro_size = alloca i64, align 8
%allocator = alloca %std.mem.Allocator*, align 8
%4 = alloca %"[]usize", align 8
%5 = alloca i8*, align 8
%6 = alloca %"[]u8", align 8
%7 = alloca %"[]u8", align 8
%8 = bitcast %"AsyncFramePromise(void)"* %promise to i8*, !dbg !729
call void @llvm.memset.p0i8.i64(i8* align 8 %8, i8 -86, i64 296, i1 false), !dbg !729
%9 = ptrtoint i8* %8 to i64, !dbg !729
%10 = getelementptr inbounds [6 x i64], [6 x i64]* %3, i64 0, i64 0
store i64 1296236545, i64* %10
%11 = getelementptr inbounds [6 x i64], [6 x i64]* %3, i64 0, i64 1
store i64 %9, i64* %11
%12 = getelementptr inbounds [6 x i64], [6 x i64]* %3, i64 0, i64 2
store i64 296, i64* %12
%13 = getelementptr inbounds [6 x i64], [6 x i64]* %3, i64 0, i64 3
store i64 0, i64* %13
%14 = getelementptr inbounds [6 x i64], [6 x i64]* %3, i64 0, i64 4
store i64 0, i64* %14
%15 = getelementptr inbounds [6 x i64], [6 x i64]* %3, i64 0, i64 5
store i64 0, i64* %15
%16 = ptrtoint [6 x i64]* %3 to i64
%17 = call i64 asm sideeffect "rolq $$3, %rdi ; rolq $$13, %rdi\0Arolq $$61, %rdi ; rolq $$51, %rdi\0Axchgq %rbx,%rbx\0A", "={rdx},{rax},0,~{cc},~{memory}"(i64 %16, i64 0)
call void @llvm.dbg.declare(metadata %"AsyncFramePromise(void)"* %promise, metadata !716, metadata !DIExpression()), !dbg !729
store i8* null, i8** %await_handle, align 8, !dbg !729
call void @llvm.dbg.declare(metadata i8** %await_handle, metadata !726, metadata !DIExpression()), !dbg !729
%18 = bitcast %"AsyncFramePromise(void)"* %promise to i8*, !dbg !729
%19 = call token @llvm.coro.id(i32 16, i8* %18, i8* null, i8* null), !dbg !729
%20 = call i64 @llvm.coro.size.i64(), !dbg !729
store i64 %20, i64* %coro_size, align 8, !dbg !729
call void @llvm.dbg.declare(metadata i64* %coro_size, metadata !727, metadata !DIExpression()), !dbg !729
store %std.mem.Allocator* %1, %std.mem.Allocator** %allocator, align 8, !dbg !729
call void @llvm.dbg.declare(metadata %std.mem.Allocator** %allocator, metadata !728, metadata !DIExpression()), !dbg !729
%21 = getelementptr inbounds %std.mem.Allocator, %std.mem.Allocator* %1, i32 0, i32 0, !dbg !729
%22 = load void ({ i16, %"[]u8" }*, %builtin.StackTrace*, %std.mem.Allocator*, %"[]u8"*, i29, i64, i29)*, void ({ i16, %"[]u8" }*, %builtin.StackTrace*, %std.mem.Allocator*, %"[]u8"*, i29, i64, i29)** %21, align 8, !dbg !729
%23 = call fastcc i8* @__zig_coro_alloc_helper(void ({ i16, %"[]u8" }*, %builtin.StackTrace*, %std.mem.Allocator*, %"[]u8"*, i29, i64, i29)* %22, %builtin.StackTrace* %0, %std.mem.Allocator* %1, i16* %2, i64 %20), !dbg !729
%24 = icmp ne i8* %23, null, !dbg !729
br i1 %24, label %AllocOk, label %AllocError, !dbg !729
AllocError: ; preds = %Entry
ret i8* undef, !dbg !729
AllocOk: ; preds = %Entry
%25 = call i8* @llvm.coro.begin(token %19, i8* %23), !dbg !729
%26 = getelementptr inbounds %"AsyncFramePromise(void)", %"AsyncFramePromise(void)"* %promise, i32 0, i32 0, !dbg !729
store i64 0, i64* %26, align 8, !dbg !729
%27 = getelementptr inbounds %"AsyncFramePromise(void)", %"AsyncFramePromise(void)"* %promise, i32 0, i32 3, !dbg !729
%28 = getelementptr inbounds %"AsyncFramePromise(void)", %"AsyncFramePromise(void)"* %promise, i32 0, i32 2, !dbg !729
%29 = getelementptr inbounds %builtin.StackTrace, %builtin.StackTrace* %28, i32 0, i32 0, !dbg !729
store i64 0, i64* %29, align 8, !dbg !729
%30 = getelementptr inbounds %builtin.StackTrace, %builtin.StackTrace* %28, i32 0, i32 1, !dbg !729
%31 = getelementptr inbounds %"[]usize", %"[]usize"* %4, i32 0, i32 0, !dbg !729
%32 = getelementptr inbounds [32 x i64], [32 x i64]* %27, i64 0, i64 0, !dbg !729
store i64* %32, i64** %31, !dbg !729
%33 = getelementptr inbounds %"[]usize", %"[]usize"* %4, i32 0, i32 1, !dbg !729
store i64 32, i64* %33, !dbg !729
%34 = bitcast %"[]usize"* %4 to i8*, !dbg !729
%35 = bitcast %"[]usize"* %30 to i8*, !dbg !729
call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %35, i8* align 8 %34, i64 16, i1 false), !dbg !729
%36 = load i32, i32* @x, align 4, !dbg !730
%37 = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %36, i32 1), !dbg !732
%38 = extractvalue { i32, i1 } %37, 0, !dbg !732
%39 = extractvalue { i32, i1 } %37, 1, !dbg !732
br i1 %39, label %OverflowFail, label %OverflowOk, !dbg !732
IsCanceled: ; preds = %NotAlreadySuspended, %OverflowOk
%40 = and i64 %84, -8, !dbg !733
%41 = icmp ne i64 %40, 0, !dbg !733
br i1 %41, label %CancelAwaiter, label %SuspendCleanup, !dbg !733
CancelAwaiter: ; preds = %IsCanceled
%42 = icmp eq i64 %40, 0, !dbg !733
br i1 %42, label %PtrToIntBad, label %PtrToIntOk, !dbg !733
NotCanceled: ; preds = %PtrToIntOk
%43 = and i64 %91, -8, !dbg !733
%44 = icmp eq i64 %43, -8, !dbg !733
br i1 %44, label %PostReturn, label %PreReturn, !dbg !733
PostReturn: ; preds = %NotCanceled
%45 = and i64 %91, 4, !dbg !733
%46 = icmp ne i64 %45, 0, !dbg !733
br i1 %46, label %CancelDone, label %DoCancel, !dbg !733
PreReturn: ; preds = %NotCanceled
br label %CancelDone, !dbg !733
DoCancel: ; preds = %PostReturn
call void @llvm.coro.destroy(i8* %87), !dbg !733
br label %CancelDone, !dbg !733
CancelDone: ; preds = %DoCancel, %PreReturn, %PostReturn, %PtrToIntOk
br label %SuspendCleanup, !dbg !733
NotCanceled1: ; preds = %OverflowOk
%47 = and i64 %84, 2, !dbg !733
%48 = icmp ne i64 %47, 0, !dbg !733
br i1 %48, label %AlreadySuspended, label %NotAlreadySuspended, !dbg !733
AlreadySuspended: ; preds = %NotCanceled1
tail call fastcc void @panic(%"[]u8"* @48, %builtin.StackTrace* null), !dbg !733
unreachable, !dbg !733
NotAlreadySuspended: ; preds = %NotCanceled1
%49 = call i8 @llvm.coro.suspend(token none, i1 false), !dbg !733
switch i8 %49, label %Suspend [
i8 0, label %SuspendResume
i8 1, label %IsCanceled
], !dbg !733
SuspendCleanup: ; preds = %CancelDone, %IsCanceled
%50 = phi i1 [ true, %IsCanceled ], [ false, %CancelDone ], !dbg !733
br i1 %50, label %FinalCleanup, label %CoroEarlyFinal, !dbg !733
SuspendResume: ; preds = %NotAlreadySuspended
%51 = load i32, i32* @x, align 4, !dbg !734
%52 = call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %51, i32 1), !dbg !735
%53 = extractvalue { i32, i1 } %52, 0, !dbg !735
%54 = extractvalue { i32, i1 } %52, 1, !dbg !735
br i1 %54, label %OverflowFail3, label %OverflowOk4, !dbg !735
Suspended: ; preds = %OverflowOk4
tail call fastcc void @panic(%"[]u8"* @48, %builtin.StackTrace* null), !dbg !729
unreachable, !dbg !729
NotSuspended: ; preds = %OverflowOk4
%55 = and i64 %94, -8, !dbg !729
%56 = icmp ne i64 %55, 0, !dbg !729
br i1 %56, label %StoreAwaiter, label %CheckCanceled, !dbg !729
StoreAwaiter: ; preds = %NotSuspended
%57 = icmp eq i64 %55, 0, !dbg !729
br i1 %57, label %PtrToIntBad5, label %PtrToIntOk6, !dbg !729
CheckCanceled: ; preds = %NotSuspended
%58 = and i64 %94, 1, !dbg !729
%59 = icmp ne i64 %58, 0, !dbg !729
br i1 %59, label %FinalCleanup, label %CoroEarlyFinal, !dbg !729
CoroEarlyFinal: ; preds = %CheckCanceled, %SuspendCleanup
%60 = call i8 @llvm.coro.suspend(token none, i1 true), !dbg !729
switch i8 %60, label %Suspend [
i8 0, label %InvalidResume
i8 1, label %FinalCleanup
], !dbg !729
Suspend: ; preds = %ResumeDone, %CheckFree, %CoroEarlyFinal, %NotAlreadySuspended
%61 = call i1 @llvm.coro.end(i8* null, i1 false), !dbg !729
ret i8* %25, !dbg !729
InvalidResume: ; preds = %CoroEarlyFinal
tail call fastcc void @panic(%"[]u8"* @48, %builtin.StackTrace* null), !dbg !729
unreachable, !dbg !729
CoroNormalFinal: ; preds = %PtrToIntOk6
%62 = getelementptr inbounds %"AsyncFramePromise(void)", %"AsyncFramePromise(void)"* %promise, i32 0, i32 1, !dbg !729
%63 = load i8*, i8** %await_handle, align 8, !dbg !729
br label %CheckFree, !dbg !729
FinalCleanup: ; preds = %CoroEarlyFinal, %CheckCanceled, %SuspendCleanup
br label %CheckFree, !dbg !729
CheckFree: ; preds = %FinalCleanup, %CoroNormalFinal
%64 = phi i1 [ false, %FinalCleanup ], [ true, %CoroNormalFinal ], !dbg !729
%65 = phi i8* [ undef, %FinalCleanup ], [ %63, %CoroNormalFinal ], !dbg !729
%66 = load %std.mem.Allocator*, %std.mem.Allocator** %allocator, align 8, !dbg !729
%67 = getelementptr inbounds %std.mem.Allocator, %std.mem.Allocator* %66, i32 0, i32 1, !dbg !729
%68 = load void (%"[]u8"*, %std.mem.Allocator*, %"[]u8"*, i29, i64, i29)*, void (%"[]u8"*, %std.mem.Allocator*, %"[]u8"*, i29, i64, i29)** %67, align 8, !dbg !729
%69 = call i8* @llvm.coro.free(token %19, i8* %25), !dbg !729
store i8* %69, i8** %5, !dbg !729
%70 = load i64, i64* %coro_size, align 8, !dbg !729
%71 = load i8*, i8** %5, align 8, !dbg !729
%72 = getelementptr inbounds %"[]u8", %"[]u8"* %6, i32 0, i32 0, !dbg !729
%73 = getelementptr inbounds i8, i8* %71, i64 0, !dbg !729
store i8* %73, i8** %72, !dbg !729
%74 = getelementptr inbounds %"[]u8", %"[]u8"* %6, i32 0, i32 1, !dbg !729
%75 = sub nsw i64 %70, 0, !dbg !729
store i64 %75, i64* %74, !dbg !729
call fastcc void %68(%"[]u8"* sret %7, %std.mem.Allocator* %66, %"[]u8"* %6, i29 8, i64 1, i29 1), !dbg !729
br i1 %64, label %Resume, label %Suspend, !dbg !729
Resume: ; preds = %CheckFree
%76 = call i8* @llvm.coro.promise(i8* %65, i32 16, i1 false), !dbg !729
%77 = bitcast i8* %76 to %"AsyncFramePromise(void)"*, !dbg !729
%78 = getelementptr inbounds %"AsyncFramePromise(void)", %"AsyncFramePromise(void)"* %77, i32 0, i32 0, !dbg !729
%79 = atomicrmw and i64* %78, i64 -3 seq_cst, !dbg !729
%80 = and i64 %79, 1, !dbg !729
%81 = icmp ne i64 %80, 0, !dbg !729
br i1 %81, label %ResumeDone, label %NotCanceled2, !dbg !729
NotCanceled2: ; preds = %Resume
%82 = and i64 %79, 2, !dbg !729
%83 = icmp ne i64 %82, 0, !dbg !729
br i1 %83, label %IsSuspended, label %IsNotSuspended, !dbg !729
IsNotSuspended: ; preds = %NotCanceled2
tail call fastcc void @panic(%"[]u8"* @48, %builtin.StackTrace* null), !dbg !729
unreachable, !dbg !729
IsSuspended: ; preds = %NotCanceled2
call void @llvm.coro.resume(i8* %65), !dbg !729
br label %ResumeDone, !dbg !729
ResumeDone: ; preds = %IsSuspended, %Resume
br label %Suspend, !dbg !729
OverflowFail: ; preds = %AllocOk
tail call fastcc void @panic(%"[]u8"* @40, %builtin.StackTrace* null), !dbg !732
unreachable, !dbg !732
OverflowOk: ; preds = %AllocOk
store i32 %38, i32* @x, align 4, !dbg !732
%84 = atomicrmw or i64* %26, i64 2 seq_cst, !dbg !733
%85 = and i64 %84, 1, !dbg !733
%86 = icmp ne i64 %85, 0, !dbg !733
br i1 %86, label %IsCanceled, label %NotCanceled1, !dbg !733
PtrToIntBad: ; preds = %CancelAwaiter
tail call fastcc void @panic(%"[]u8"* @42, %builtin.StackTrace* null), !dbg !733
unreachable, !dbg !733
PtrToIntOk: ; preds = %CancelAwaiter
%87 = inttoptr i64 %40 to i8*, !dbg !733
%88 = call i8* @llvm.coro.promise(i8* %87, i32 16, i1 false), !dbg !733
%89 = bitcast i8* %88 to %"AsyncFramePromise(void)"*, !dbg !733
%90 = getelementptr inbounds %"AsyncFramePromise(void)", %"AsyncFramePromise(void)"* %89, i32 0, i32 0, !dbg !733
%91 = atomicrmw or i64* %90, i64 1 seq_cst, !dbg !733
%92 = and i64 %91, 1, !dbg !733
%93 = icmp ne i64 %92, 0, !dbg !733
br i1 %93, label %CancelDone, label %NotCanceled, !dbg !733
OverflowFail3: ; preds = %SuspendResume
tail call fastcc void @panic(%"[]u8"* @40, %builtin.StackTrace* null), !dbg !735
unreachable, !dbg !735
OverflowOk4: ; preds = %SuspendResume
store i32 %53, i32* @x, align 4, !dbg !735
%94 = atomicrmw or i64* %26, i64 -8 seq_cst, !dbg !729
%95 = and i64 %94, 2, !dbg !729
%96 = icmp ne i64 %95, 0, !dbg !729
br i1 %96, label %Suspended, label %NotSuspended, !dbg !729
PtrToIntBad5: ; preds = %StoreAwaiter
tail call fastcc void @panic(%"[]u8"* @42, %builtin.StackTrace* null), !dbg !729
unreachable, !dbg !729
PtrToIntOk6: ; preds = %StoreAwaiter
%97 = inttoptr i64 %55 to i8*, !dbg !729
store i8* %97, i8** %await_handle, align 8, !dbg !729
br label %CoroNormalFinal, !dbg !729
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment