llvm/llvm/test/Transforms/Coroutines/coro-async.ll

; RUN: opt < %s -passes='default<O2>' -S | FileCheck --check-prefixes=CHECK %s
; RUN: opt < %s -O0 -S | FileCheck --check-prefixes=CHECK-O0 %s
target datalayout = "p:64:64:64"

%async.task = type { i64 }
%async.actor = type { i64 }
%async.fp = type <{ i32, i32 }>

%async.ctxt = type { ptr, ptr }

; The async callee.
@my_other_async_function_fp = external global <{ i32, i32 }>
declare void @my_other_async_function(ptr %async.ctxt)

; The current async function (the caller).
; This struct describes an async function. The first field is the
; relative offset to the async function implementation, the second field is the
; size needed for the async context of the current async function.

@my_async_function_fp = constant <{ i32, i32 }>
  <{ i32 trunc ( ; Relative pointer to async function
       i64 sub (
         i64 ptrtoint (ptr @my_async_function to i64),
         i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32 }>, ptr @my_async_function_fp, i32 0, i32 1) to i64)
       )
     to i32),
     i32 128    ; Initial async context size without space for frame
}>
@my_async_function_pa_fp = constant <{ i32, i32 }>
  <{ i32 trunc (
       i64 sub (
         i64 ptrtoint (ptr @my_async_function_pa to i64),
         i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32 }>, ptr @my_async_function_pa_fp, i32 0, i32 1) to i64)
       )
     to i32),
     i32 8
}>

; Function that implements the dispatch to the callee function.
define swiftcc void @my_async_function.my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt, ptr %task, ptr %actor) {
  tail call swiftcc void %fnPtr(ptr %async.ctxt, ptr %task, ptr %actor)
  ret void
}

declare void @some_user(i64)
declare void @some_may_write(ptr)

define ptr @__swift_async_resume_project_context(ptr %ctxt) {
entry:
  %resume_ctxt = load ptr, ptr %ctxt, align 8
  ret ptr %resume_ctxt
}

define ptr @resume_context_projection(ptr %ctxt) {
entry:
  %resume_ctxt = load ptr, ptr %ctxt, align 8
  ret ptr %resume_ctxt
}


define swiftcc void @my_async_function(ptr swiftasync %async.ctxt, ptr %task, ptr %actor) presplitcoroutine !dbg !1 {
entry:
  %tmp = alloca { i64, i64 }, align 8
  %vector = alloca <4 x double>, align 16
  %proj.1 = getelementptr inbounds { i64, i64 }, ptr %tmp, i64 0, i32 0
  %proj.2 = getelementptr inbounds { i64, i64 }, ptr %tmp, i64 0, i32 1

  %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
          ptr @my_async_function_fp)
  %hdl = call ptr @llvm.coro.begin(token %id, ptr null)
  store i64 0, ptr %proj.1, align 8
  store i64 1, ptr %proj.2, align 8
  call void @some_may_write(ptr %proj.1)

	; Begin lowering: apply %my_other_async_function(%args...)

  ; setup callee context
  %callee_context = call ptr @llvm.coro.async.context.alloc(ptr %task, ptr @my_other_async_function_fp)
  ; store arguments ...
  ; ... (omitted)

  ; store the return continuation
  %callee_context.return_to_caller.addr = getelementptr inbounds %async.ctxt, ptr %callee_context, i32 0, i32 1
  %resume.func_ptr = call ptr @llvm.coro.async.resume()
  store ptr %resume.func_ptr, ptr %callee_context.return_to_caller.addr

  ; store caller context into callee context
  store ptr %async.ctxt, ptr %callee_context
  %vector_spill = load <4 x double>, ptr %vector, align 16
  %res = call {ptr, ptr, ptr} (i32, ptr, ptr, ...) @llvm.coro.suspend.async(i32 0,
                                                  ptr %resume.func_ptr,
                                                  ptr @__swift_async_resume_project_context,
                                                  ptr @my_async_function.my_other_async_function_fp.apply,
                                                  ptr @asyncSuspend, ptr %callee_context, ptr %task, ptr %actor), !dbg !5

  call void @llvm.coro.async.context.dealloc(ptr %callee_context)
  %continuation_task_arg = extractvalue {ptr, ptr, ptr} %res, 1
  %val = load i64, ptr %proj.1
  call void @some_user(i64 %val)
  %val.2 = load i64, ptr %proj.2
  call void @some_user(i64 %val.2)
  store <4 x double> %vector_spill, ptr %vector, align 16
  tail call swiftcc void @asyncReturn(ptr %async.ctxt, ptr %continuation_task_arg, ptr %actor)
  call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %hdl, i1 0)
  unreachable
}

define void @my_async_function_pa(ptr %ctxt, ptr %task, ptr %actor) {
  call void @llvm.coro.async.size.replace(ptr @my_async_function_pa_fp, ptr @my_async_function_fp)
  call swiftcc void @my_async_function(ptr %ctxt, ptr %task, ptr %actor)
  ret void
}

; Make sure we update the async function pointer
; CHECK: @my_async_function_fp = constant <{ i32, i32 }> <{ {{.*}}, i32 176 }
; CHECK: @my_async_function_pa_fp = constant <{ i32, i32 }> <{ {{.*}}, i32 176 }
; CHECK: @my_async_function2_fp = constant <{ i32, i32 }> <{ {{.*}}, i32 176 }

; CHECK-LABEL: define swiftcc void @my_async_function(ptr swiftasync %async.ctxt, ptr %task, ptr %actor)
; CHECK-O0-LABEL: define swiftcc void @my_async_function(ptr swiftasync %async.ctxt, ptr %task, ptr %actor)
; CHECK-SAME: !dbg ![[SP1:[0-9]+]] {
; CHECK: coro.return:
; CHECK:   [[FRAMEPTR:%.*]] = getelementptr inbounds i8, ptr %async.ctxt, i64 128
; CHECK:   [[ACTOR_SPILL_ADDR:%.*]] = getelementptr inbounds i8, ptr %async.ctxt, i64 152
; CHECK:   store ptr %actor, ptr [[ACTOR_SPILL_ADDR]]
; CHECK:   [[ADDR1:%.*]]  = getelementptr inbounds i8, ptr %async.ctxt, i64 144
; CHECK:   store ptr %async.ctxt, ptr [[ADDR1]]
; CHECK:   [[ALLOCA_PRJ2:%.*]] = getelementptr inbounds i8, ptr %async.ctxt, i64 136
; CHECK:   store i64 0, ptr [[FRAMEPTR]]
; CHECK:   store i64 1, ptr [[ALLOCA_PRJ2]]
; CHECK:   tail call void @some_may_write(ptr nonnull [[FRAMEPTR]])
; CHECK:   [[CALLEE_CTXT:%.*]] = tail call ptr @llvm.coro.async.context.alloc(ptr %task, ptr nonnull @my_other_async_function_fp)
; CHECK:   [[CALLEE_CTXT_SPILL:%.*]] = getelementptr inbounds i8, ptr %async.ctxt, i64 160
; CHECK:   store ptr [[CALLEE_CTXT]], ptr [[CALLEE_CTXT_SPILL]]
; CHECK:   [[TYPED_RETURN_TO_CALLER_ADDR:%.*]] = getelementptr inbounds i8, ptr [[CALLEE_CTXT]], i64 8
; CHECK:   store ptr @my_async_functionTQ0_, ptr [[TYPED_RETURN_TO_CALLER_ADDR]]
; CHECK:   store ptr %async.ctxt, ptr [[CALLEE_CTXT]]
; Make sure the spill is underaligned to the max context alignment (16).
; CHECK-O0:   [[VECTOR_SPILL:%.*]] = load <4 x double>, ptr {{.*}}
; CHECK-O0:   [[VECTOR_SPILL_ADDR:%.*]] = getelementptr inbounds %my_async_function.Frame, ptr {{.*}}, i32 0, i32 1
; CHECK-O0:   store <4 x double> [[VECTOR_SPILL]], ptr [[VECTOR_SPILL_ADDR]], align 16
; CHECK:   tail call swiftcc void @asyncSuspend(ptr nonnull [[CALLEE_CTXT]], ptr %task, ptr %actor)
; CHECK:   ret void
; CHECK: }

; CHECK-LABEL: define internal swiftcc void @my_async_functionTQ0_(ptr nocapture readonly swiftasync %0, ptr %1, ptr nocapture readnone %2)
; CHECK-O0-LABEL: define internal swiftcc void @my_async_functionTQ0_(ptr swiftasync %0, ptr %1, ptr %2)
; CHECK-SAME: !dbg ![[SP2:[0-9]+]] {
; CHECK: entryresume.0:
; CHECK:   [[CALLER_CONTEXT:%.*]] = load ptr, ptr %0
; CHECK:   [[FRAME_PTR:%.*]] = getelementptr inbounds i8, ptr [[CALLER_CONTEXT]], i64 128
; CHECK-O0:   [[VECTOR_SPILL_ADDR:%.*]] = getelementptr inbounds %my_async_function.Frame, ptr {{.*}}, i32 0, i32 1
; CHECK-O0:   load <4 x double>, ptr [[VECTOR_SPILL_ADDR]], align 16
; CHECK:   [[CALLEE_CTXT_SPILL_ADDR:%.*]] = getelementptr inbounds i8, ptr [[CALLER_CONTEXT]], i64 160
; CHECK:   [[CALLEE_CTXT_RELOAD:%.*]] = load ptr, ptr [[CALLEE_CTXT_SPILL_ADDR]]
; CHECK:   [[ACTOR_RELOAD_ADDR:%.*]] = getelementptr inbounds i8, ptr [[CALLER_CONTEXT]], i64 152
; CHECK:   [[ACTOR_RELOAD:%.*]] = load ptr, ptr [[ACTOR_RELOAD_ADDR]]
; CHECK:   [[ADDR1:%.*]] = getelementptr inbounds i8, ptr [[CALLER_CONTEXT]], i64 144
; CHECK:   [[ASYNC_CTXT_RELOAD:%.*]] = load ptr, ptr [[ADDR1]]
; CHECK:   [[ALLOCA_PRJ2:%.*]] = getelementptr inbounds i8, ptr [[CALLER_CONTEXT]], i64 136
; CHECK:   tail call void @llvm.coro.async.context.dealloc(ptr nonnull [[CALLEE_CTXT_RELOAD]])
; CHECK:   [[VAL1:%.*]] = load i64, ptr [[FRAME_PTR]]
; CHECK:   tail call void @some_user(i64 [[VAL1]])
; CHECK:   [[VAL2:%.*]] = load i64, ptr [[ALLOCA_PRJ2]]
; CHECK:   tail call void @some_user(i64 [[VAL2]])
; CHECK:   tail call swiftcc void @asyncReturn(ptr [[ASYNC_CTXT_RELOAD]], ptr %1, ptr [[ACTOR_RELOAD]])
; CHECK:   ret void
; CHECK: }

@my_async_function2_fp = constant <{ i32, i32 }>
  <{ i32 trunc ( ; Relative pointer to async function
       i64 sub (
         i64 ptrtoint (ptr @my_async_function2 to i64),
         i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32 }>, ptr @my_async_function2_fp, i32 0, i32 1) to i64)
       )
     to i32),
     i32 128    ; Initial async context size without space for frame
  }>

define swiftcc void @my_async_function2(ptr %task, ptr %actor, ptr %async.ctxt) presplitcoroutine "frame-pointer"="all" !dbg !6 {
entry:

  %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 2, ptr @my_async_function2_fp)
  %hdl = call ptr @llvm.coro.begin(token %id, ptr null)
  ; setup callee context
  %callee_context = call ptr @llvm.coro.async.context.alloc(ptr %task, ptr @my_other_async_function_fp)

  %callee_context.return_to_caller.addr = getelementptr inbounds %async.ctxt, ptr %callee_context, i32 0, i32 1
  %resume.func_ptr = call ptr @llvm.coro.async.resume()
  store ptr %resume.func_ptr, ptr %callee_context.return_to_caller.addr
  store ptr %async.ctxt, ptr %callee_context
  %res = call {ptr, ptr, ptr} (i32, ptr, ptr, ...) @llvm.coro.suspend.async(i32 2,
                                                  ptr %resume.func_ptr,
                                                  ptr @resume_context_projection,
                                                  ptr @my_async_function.my_other_async_function_fp.apply,
                                                  ptr @asyncSuspend, ptr %callee_context, ptr %task, ptr %actor), !dbg !9

  %continuation_task_arg = extractvalue {ptr, ptr, ptr} %res, 0

  %callee_context.return_to_caller.addr.1 = getelementptr inbounds %async.ctxt, ptr %callee_context, i32 0, i32 1
  %resume.func_ptr.1 = call ptr @llvm.coro.async.resume()
  store ptr %resume.func_ptr.1, ptr %callee_context.return_to_caller.addr.1
  store ptr %async.ctxt, ptr %callee_context
  %res.2 = call {ptr, ptr, ptr} (i32, ptr, ptr, ...) @llvm.coro.suspend.async(i32 0,
                                                  ptr %resume.func_ptr.1,
                                                  ptr @resume_context_projection,
                                                  ptr @my_async_function.my_other_async_function_fp.apply,
                                                  ptr @asyncSuspend, ptr %callee_context, ptr %task, ptr %actor)

  call void @llvm.coro.async.context.dealloc(ptr %callee_context)
  %continuation_actor_arg = extractvalue {ptr, ptr, ptr} %res.2, 1

  tail call swiftcc void @asyncReturn(ptr %async.ctxt, ptr %continuation_task_arg, ptr %continuation_actor_arg)
  call i1 @llvm.coro.end(ptr %hdl, i1 0, token none)
  unreachable
}

; CHECK-LABEL: define swiftcc void @my_async_function2(ptr %task, ptr %actor, ptr %async.ctxt)
; CHECK-SAME: #[[FRAMEPOINTER:[0-9]+]]
; CHECK-SAME: !dbg ![[SP3:[0-9]+]]
; CHECK: store ptr %async.ctxt,
; CHECK: store ptr %actor,
; CHECK: store ptr %task,
; CHECK: [[CALLEE_CTXT:%.*]] =  tail call ptr @llvm.coro.async.context.alloc(
; CHECK: store ptr [[CALLEE_CTXT]],
; CHECK: store ptr @my_async_function2.resume.0,
; CHECK: store ptr %async.ctxt,
; CHECK: tail call swiftcc void @asyncSuspend(ptr nonnull [[CALLEE_CTXT]], ptr %task, ptr %actor)
; CHECK: ret void

; CHECK-LABEL: define internal swiftcc void @my_async_function2.resume.0(ptr %0, ptr nocapture readnone %1, ptr nocapture readonly %2)
; CHECK-SAME: #[[FRAMEPOINTER]]
; CHECK-SAME: !dbg ![[SP4:[0-9]+]]
; CHECK: [[CALLEE_CTXT:%.*]] = load ptr, ptr %2
; CHECK: [[CALLEE_CTXT_SPILL_ADDR:%.*]] = getelementptr inbounds i8, ptr [[CALLEE_CTXT]], i64 152
; CHECK: store ptr @my_async_function2.resume.1,
; CHECK: [[CALLLE_CTXT_RELOAD:%.*]] = load ptr, ptr [[CALLEE_CTXT_SPILL_ADDR]]
; CHECK: tail call swiftcc void @asyncSuspend(ptr [[CALLEE_CTXT_RELOAD]]
; CHECK: ret void

; CHECK-LABEL: define internal swiftcc void @my_async_function2.resume.1(ptr nocapture readonly %0, ptr %1, ptr nocapture readnone %2)
; CHECK-SAME: #[[FRAMEPOINTER]]
; CHECK: tail call swiftcc void @asyncReturn({{.*}}%1)
; CHECK: ret void

define swiftcc void @top_level_caller(ptr %ctxt, ptr %task, ptr %actor) {
  %prepare = call ptr @llvm.coro.prepare.async(ptr @my_async_function)
  call swiftcc void %prepare(ptr %ctxt, ptr %task, ptr %actor)
  ret void
}

; CHECK-LABEL: define swiftcc void @top_level_caller(ptr %ctxt, ptr %task, ptr %actor)
; CHECK: store ptr @my_async_functionTQ0_
; CHECK: store ptr %ctxt
; CHECK: tail call swiftcc void @asyncSuspend
; CHECK: ret void

@dont_crash_on_cf_fp = constant <{ i32, i32 }>
  <{ i32 trunc ( ; Relative pointer to async function
       i64 sub (
         i64 ptrtoint (ptr @my_async_function to i64),
         i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32 }>, ptr @my_async_function_fp, i32 0, i32 1) to i64)
       )
     to i32),
     i32 128    ; Initial async context size without space for frame
}>


define swiftcc void @dont_crash_on_cf_dispatch(ptr %fnPtr, ptr %async.ctxt, ptr %task, ptr %actor) {
  %isNull = icmp eq ptr %task, null
  br i1 %isNull, label %is_null, label %is_not_null

is_null:
  ret void

is_not_null:
  tail call swiftcc void %fnPtr(ptr %async.ctxt, ptr %task, ptr %actor)
  ret void
}

define swiftcc void @dont_crash_on_cf(ptr %async.ctxt, ptr %task, ptr %actor) presplitcoroutine  {
entry:
  %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
          ptr @dont_crash_on_cf_fp)
  %hdl = call ptr @llvm.coro.begin(token %id, ptr null)
  %callee_context = call ptr @llvm.coro.async.context.alloc(ptr %task, ptr @my_other_async_function_fp)
  %callee_context.return_to_caller.addr = getelementptr inbounds %async.ctxt, ptr %callee_context, i32 0, i32 1
  %resume.func_ptr = call ptr @llvm.coro.async.resume()
  store ptr %resume.func_ptr, ptr %callee_context.return_to_caller.addr
  store ptr %async.ctxt, ptr %callee_context
  %res = call {ptr, ptr, ptr} (i32, ptr, ptr, ...) @llvm.coro.suspend.async(i32 0,
                                                  ptr %resume.func_ptr,
                                                  ptr @resume_context_projection,
                                                  ptr @dont_crash_on_cf_dispatch,
                                                  ptr @asyncSuspend, ptr %callee_context, ptr %task, ptr %actor)

  call void @llvm.coro.async.context.dealloc(ptr %callee_context)
  %continuation_task_arg = extractvalue {ptr, ptr, ptr} %res, 1
  tail call swiftcc void @asyncReturn(ptr %async.ctxt, ptr %continuation_task_arg, ptr %actor)
  call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %hdl, i1 0)
  unreachable
}

@multiple_coro_end_async_fp = constant <{ i32, i32 }>
  <{ i32 trunc ( ; Relative pointer to async function
       i64 sub (
         i64 ptrtoint (ptr @multiple_coro_end_async to i64),
         i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32 }>, ptr @multiple_coro_end_async_fp, i32 0, i32 1) to i64)
       )
     to i32),
     i32 128    ; Initial async context size without space for frame
}>

define swiftcc void @must_tail_call_return(ptr %async.ctxt, ptr %task, ptr %actor) {
  musttail call swiftcc void @asyncReturn(ptr %async.ctxt, ptr %task, ptr %actor)
  ret void
}

define swiftcc void @multiple_coro_end_async(ptr %async.ctxt, ptr %task, ptr %actor) presplitcoroutine {
entry:
  %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
          ptr @dont_crash_on_cf_fp)
  %hdl = call ptr @llvm.coro.begin(token %id, ptr null)
  %callee_context = call ptr @llvm.coro.async.context.alloc(ptr %task, ptr @my_other_async_function_fp)
  %callee_context.return_to_caller.addr = getelementptr inbounds %async.ctxt, ptr %callee_context, i32 0, i32 1
  %resume.func_ptr = call ptr @llvm.coro.async.resume()
  store ptr %resume.func_ptr, ptr %callee_context.return_to_caller.addr
  store ptr %async.ctxt, ptr %callee_context
  %res = call {ptr, ptr, ptr} (i32, ptr, ptr, ...) @llvm.coro.suspend.async(i32 0,
                                                  ptr %resume.func_ptr,
                                                  ptr @resume_context_projection,
                                                  ptr @dont_crash_on_cf_dispatch,
                                                  ptr @asyncSuspend, ptr %callee_context, ptr %task, ptr %actor)

  call void @llvm.coro.async.context.dealloc(ptr %callee_context)
  %continuation_task_arg = extractvalue {ptr, ptr, ptr} %res, 1
  %eq = icmp eq ptr %continuation_task_arg, null
  br i1 %eq, label %is_equal, label %is_not_equal

is_equal:
  tail call swiftcc void @asyncReturn(ptr %async.ctxt, ptr %continuation_task_arg, ptr %actor)
  call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %hdl, i1 0)
  unreachable

is_not_equal:
  call i1 (ptr, i1, ...) @llvm.coro.end.async(
                           ptr %hdl, i1 0,
                           ptr @must_tail_call_return,
                           ptr %async.ctxt, ptr %continuation_task_arg, ptr null)
  unreachable
}

; CHECK-LABEL: define internal swiftcc void @multiple_coro_end_async.resume.0(
; CHECK: musttail call swiftcc void @asyncReturn(
; CHECK: ret void

@polymorphic_suspend_return_fp = constant <{ i32, i32 }>
  <{ i32 trunc ( ; Relative pointer to async function
       i64 sub (
         i64 ptrtoint (ptr @polymorphic_suspend_return to i64),
         i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32 }>, ptr @polymorphic_suspend_return_fp, i32 0, i32 1) to i64)
       )
     to i32),
     i32 64    ; Initial async context size without space for frame
}>

define swiftcc void @polymorphic_suspend_return(ptr swiftasync %async.ctxt, ptr %task, ptr %actor) presplitcoroutine {
entry:
  %tmp = alloca { i64, i64 }, align 8
  %proj.1 = getelementptr inbounds { i64, i64 }, ptr %tmp, i64 0, i32 0
  %proj.2 = getelementptr inbounds { i64, i64 }, ptr %tmp, i64 0, i32 1

  %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
          ptr @polymorphic_suspend_return_fp)
  %hdl = call ptr @llvm.coro.begin(token %id, ptr null)
  store i64 0, ptr %proj.1, align 8
  store i64 1, ptr %proj.2, align 8
  call void @some_may_write(ptr %proj.1)

	; Begin lowering: apply %my_other_async_function(%args...)

  ; setup callee context
  %callee_context = call ptr @llvm.coro.async.context.alloc(ptr %task, ptr @my_other_async_function_fp)
  ; store arguments ...
  ; ... (omitted)

  ; store the return continuation
  %callee_context.return_to_caller.addr = getelementptr inbounds %async.ctxt, ptr %callee_context, i32 0, i32 1
  %resume.func_ptr = call ptr @llvm.coro.async.resume()
  store ptr %resume.func_ptr, ptr %callee_context.return_to_caller.addr

  ; store caller context into callee context
  store ptr %async.ctxt, ptr %callee_context
  %res = call {ptr, ptr, ptr, ptr} (i32, ptr, ptr, ...)
         @llvm.coro.suspend.async.sl_p0i8p0i8p0i8p0i8s(i32 256, ;; swiftasync at 0 and swiftself at 1 in resume function
                                                 ptr %resume.func_ptr,
                                                 ptr @resume_context_projection,
                                                 ptr @my_async_function.my_other_async_function_fp.apply,
                                                 ptr @asyncSuspend, ptr %callee_context, ptr %task, ptr %actor)

  call void @llvm.coro.async.context.dealloc(ptr %callee_context)
  %continuation_task_arg = extractvalue {ptr, ptr, ptr, ptr} %res, 3
  %val = load i64, ptr %proj.1
  call void @some_user(i64 %val)
  %val.2 = load i64, ptr %proj.2
  call void @some_user(i64 %val.2)

  tail call swiftcc void @asyncReturn(ptr %async.ctxt, ptr %continuation_task_arg, ptr %actor)
  call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %hdl, i1 0)
  unreachable
}

; CHECK-LABEL: define swiftcc void @polymorphic_suspend_return(ptr swiftasync %async.ctxt, ptr %task, ptr %actor)
; CHECK-LABEL: define internal swiftcc void @polymorphic_suspend_return.resume.0(ptr {{.*}}swiftasync{{.*}} %0, ptr {{.*}}swiftself{{.*}} %1, ptr {{.*}}%2, ptr {{.*}}%3)
; CHECK: }

@no_coro_suspend_fp = constant <{ i32, i32 }>
  <{ i32 trunc ( ; Relative pointer to async function
       i64 sub (
         i64 ptrtoint (ptr @no_coro_suspend to i64),
         i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32 }>, ptr @no_coro_suspend_fp, i32 0, i32 1) to i64)
       )
     to i32),
     i32 128    ; Initial async context size without space for frame
}>

define swiftcc void @no_coro_suspend(ptr %async.ctx) presplitcoroutine {
entry:
  %some_alloca = alloca i64
  %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
          ptr @no_coro_suspend_fp)
  %hdl = call ptr @llvm.coro.begin(token %id, ptr null)
  call void @some_may_write(ptr %some_alloca)
  call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %hdl, i1 0)
  unreachable
}

; CHECK-LABEL: define swiftcc void @no_coro_suspend
; CHECK:   [[ALLOCA:%.*]] = alloca i64
; CHECK:   call void @some_may_write(ptr {{.*}}[[ALLOCA]])

@no_coro_suspend_swifterror_fp = constant <{ i32, i32 }>
  <{ i32 trunc ( ; Relative pointer to async function
       i64 sub (
         i64 ptrtoint (ptr @no_coro_suspend_swifterror to i64),
         i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32 }>, ptr @no_coro_suspend_swifterror_fp, i32 0, i32 1) to i64)
       )
     to i32),
     i32 128    ; Initial async context size without space for frame
}>

declare void @do_with_swifterror(ptr swifterror)

define swiftcc void @no_coro_suspend_swifterror(ptr %async.ctx) presplitcoroutine {
entry:
  %some_alloca = alloca swifterror ptr
  %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
          ptr @no_coro_suspend_swifterror_fp)
  %hdl = call ptr @llvm.coro.begin(token %id, ptr null)
  store ptr null, ptr %some_alloca, align 8
  call void @do_with_swifterror(ptr swifterror %some_alloca)
  call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %hdl, i1 0)
  unreachable
}

 ; CHECK-LABEL: define swiftcc void @no_coro_suspend_swifterror
 ; CHECK:  [[ALLOCA:%.*]] = alloca swifterror ptr
 ; CHECK:   store ptr null, ptr [[ALLOCA]]
 ; CHECK:   call void @do_with_swifterror(ptr {{.*}}swifterror{{.*}} [[ALLOCA]])

@undefined_coro_async_resume_fp = constant <{ i32, i32 }>
  <{ i32 trunc (
       i64 sub (
         i64 ptrtoint (ptr @undefined_coro_async_resume to i64),
         i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32 }>, ptr @undefined_coro_async_resume_fp, i32 0, i32 1) to i64)
       )
     to i32),
     i32 24
}>

declare void @crash()
declare void @use(ptr)

define swiftcc void @undefined_coro_async_resume(ptr %async.ctx) presplitcoroutine {
entry:
  %id = call token @llvm.coro.id.async(i32 24, i32 16, i32 0, ptr @undefined_coro_async_resume_fp)
  %hdl = call ptr @llvm.coro.begin(token %id, ptr null)
  %undefined_resume_pointer = call ptr @llvm.coro.async.resume()
  call void @use(ptr %undefined_resume_pointer)
  call void @crash()
  %unused = call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %hdl, i1 false)
  unreachable
}
; CHECK-LABEL: define swiftcc void @undefined_coro_async_resume
; CHECK-NOT: @llvm.coro.async.resume
; CHECK: call void @use(ptr null)
; CHECK: ret

declare { ptr, ptr, ptr, ptr } @llvm.coro.suspend.async.sl_p0i8p0i8p0i8p0i8s(i32, ptr, ptr, ...)
declare ptr @llvm.coro.prepare.async(ptr)
declare token @llvm.coro.id.async(i32, i32, i32, ptr)
declare ptr @llvm.coro.begin(token, ptr)
declare i1 @llvm.coro.end.async(ptr, i1, ...)
declare i1 @llvm.coro.end(ptr, i1, token)
declare {ptr, ptr, ptr} @llvm.coro.suspend.async(i32, ptr, ptr, ...)
declare ptr @llvm.coro.async.context.alloc(ptr, ptr)
declare void @llvm.coro.async.context.dealloc(ptr)
declare swiftcc void @asyncReturn(ptr, ptr, ptr)
declare swiftcc void @asyncSuspend(ptr, ptr, ptr)
declare ptr @llvm.coro.async.resume()
declare void @llvm.coro.async.size.replace(ptr, ptr)
declare ptr @hide(ptr)

!llvm.dbg.cu = !{!2}
!llvm.module.flags = !{!0}

!0 = !{i32 2, !"Debug Info Version", i32 3}
; CHECK: ![[SP1]] = distinct !DISubprogram(name: "my_async_function",
; CHECK-SAME:                              linkageName: "my_async_function",
; CHECK-SAME:                              scopeLine: 1
!1 = distinct !DISubprogram(name: "my_async_function",
                            linkageName: "my_async_function",
                            scope: !2, file: !3, line: 1, type: !4,
                            scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2)
; CHECK: ![[SP2]] = distinct !DISubprogram(name: "my_async_function",
; CHECK-SAME:                              linkageName: "my_async_functionTQ0_",
; CHECK-SAME:                              scopeLine: 2
!2 = distinct !DICompileUnit(language: DW_LANG_Swift, file: !3, emissionKind: FullDebug)
!3 = !DIFile(filename: "/tmp/1.swift", directory: "/")
!4 = !DISubroutineType(types: !{})
!5 = !DILocation(line: 2, column: 0, scope: !1)

; CHECK: ![[SP3]] = distinct !DISubprogram(name: "my_async_function2",
; CHECK-SAME:                              linkageName: "my_async_function2",
; CHECK-SAME:                              scopeLine: 1
!6 = distinct !DISubprogram(name: "my_async_function2",
                            linkageName: "my_async_function2",
                            scope: !2, file: !3, line: 1, type: !4,
                            scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2)
; CHECK: ![[SP4]] = distinct !DISubprogram(name: "my_async_function2",
; CHECK-SAME:                              linkageName: "my_async_function2.resume.0",
; CHECK-SAME:                              scopeLine: 1
!7 = !DILexicalBlockFile(scope: !6, file: !8, discriminator: 0)
!8 = !DIFile(filename: "/tmp/fake.cpp", directory: "/")
!9 = !DILocation(line: 2, column: 0, scope: !7)