xref: /llvm-project/llvm/test/Transforms/Coroutines/coro-async.ll (revision 29441e4f5fa5f5c7709f7cf180815ba97f611297)
1; RUN: opt < %s -passes='default<O2>' -S | FileCheck --check-prefixes=CHECK %s
2; RUN: opt < %s -O0 -S | FileCheck --check-prefixes=CHECK-O0 %s
3target datalayout = "p:64:64:64"
4
5%async.task = type { i64 }
6%async.actor = type { i64 }
7%async.fp = type <{ i32, i32 }>
8
9%async.ctxt = type { ptr, ptr }
10
11; The async callee.
12@my_other_async_function_fp = external global <{ i32, i32 }>
13declare void @my_other_async_function(ptr %async.ctxt)
14
15; The current async function (the caller).
16; This struct describes an async function. The first field is the
17; relative offset to the async function implementation, the second field is the
18; size needed for the async context of the current async function.
19
20@my_async_function_fp = constant <{ i32, i32 }>
21  <{ i32 trunc ( ; Relative pointer to async function
22       i64 sub (
23         i64 ptrtoint (ptr @my_async_function to i64),
24         i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32 }>, ptr @my_async_function_fp, i32 0, i32 1) to i64)
25       )
26     to i32),
27     i32 128    ; Initial async context size without space for frame
28}>
29@my_async_function_pa_fp = constant <{ i32, i32 }>
30  <{ i32 trunc (
31       i64 sub (
32         i64 ptrtoint (ptr @my_async_function_pa to i64),
33         i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32 }>, ptr @my_async_function_pa_fp, i32 0, i32 1) to i64)
34       )
35     to i32),
36     i32 8
37}>
38
39; Function that implements the dispatch to the callee function.
40define swiftcc void @my_async_function.my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt, ptr %task, ptr %actor) {
41  tail call swiftcc void %fnPtr(ptr %async.ctxt, ptr %task, ptr %actor)
42  ret void
43}
44
45declare void @some_user(i64)
46declare void @some_may_write(ptr)
47
48define ptr @__swift_async_resume_project_context(ptr %ctxt) {
49entry:
50  %resume_ctxt = load ptr, ptr %ctxt, align 8
51  ret ptr %resume_ctxt
52}
53
54define ptr @resume_context_projection(ptr %ctxt) {
55entry:
56  %resume_ctxt = load ptr, ptr %ctxt, align 8
57  ret ptr %resume_ctxt
58}
59
60
61define swiftcc void @my_async_function(ptr swiftasync %async.ctxt, ptr %task, ptr %actor) presplitcoroutine !dbg !1 {
62entry:
63  %tmp = alloca { i64, i64 }, align 8
64  %vector = alloca <4 x double>, align 16
65  %proj.1 = getelementptr inbounds { i64, i64 }, ptr %tmp, i64 0, i32 0
66  %proj.2 = getelementptr inbounds { i64, i64 }, ptr %tmp, i64 0, i32 1
67
68  %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
69          ptr @my_async_function_fp)
70  %hdl = call ptr @llvm.coro.begin(token %id, ptr null)
71  store i64 0, ptr %proj.1, align 8
72  store i64 1, ptr %proj.2, align 8
73  call void @some_may_write(ptr %proj.1)
74
75	; Begin lowering: apply %my_other_async_function(%args...)
76
77  ; setup callee context
78  %callee_context = call ptr @llvm.coro.async.context.alloc(ptr %task, ptr @my_other_async_function_fp)
79  ; store arguments ...
80  ; ... (omitted)
81
82  ; store the return continuation
83  %callee_context.return_to_caller.addr = getelementptr inbounds %async.ctxt, ptr %callee_context, i32 0, i32 1
84  %resume.func_ptr = call ptr @llvm.coro.async.resume()
85  store ptr %resume.func_ptr, ptr %callee_context.return_to_caller.addr
86
87  ; store caller context into callee context
88  store ptr %async.ctxt, ptr %callee_context
89  %vector_spill = load <4 x double>, ptr %vector, align 16
90  %res = call {ptr, ptr, ptr} (i32, ptr, ptr, ...) @llvm.coro.suspend.async(i32 0,
91                                                  ptr %resume.func_ptr,
92                                                  ptr @__swift_async_resume_project_context,
93                                                  ptr @my_async_function.my_other_async_function_fp.apply,
94                                                  ptr @asyncSuspend, ptr %callee_context, ptr %task, ptr %actor), !dbg !5
95
96  call void @llvm.coro.async.context.dealloc(ptr %callee_context)
97  %continuation_task_arg = extractvalue {ptr, ptr, ptr} %res, 1
98  %val = load i64, ptr %proj.1
99  call void @some_user(i64 %val)
100  %val.2 = load i64, ptr %proj.2
101  call void @some_user(i64 %val.2)
102  store <4 x double> %vector_spill, ptr %vector, align 16
103  tail call swiftcc void @asyncReturn(ptr %async.ctxt, ptr %continuation_task_arg, ptr %actor)
104  call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %hdl, i1 0)
105  unreachable
106}
107
108define void @my_async_function_pa(ptr %ctxt, ptr %task, ptr %actor) {
109  call void @llvm.coro.async.size.replace(ptr @my_async_function_pa_fp, ptr @my_async_function_fp)
110  call swiftcc void @my_async_function(ptr %ctxt, ptr %task, ptr %actor)
111  ret void
112}
113
114; Make sure we update the async function pointer
115; CHECK: @my_async_function_fp = constant <{ i32, i32 }> <{ {{.*}}, i32 176 }
116; CHECK: @my_async_function_pa_fp = constant <{ i32, i32 }> <{ {{.*}}, i32 176 }
117; CHECK: @my_async_function2_fp = constant <{ i32, i32 }> <{ {{.*}}, i32 176 }
118
119; CHECK-LABEL: define swiftcc void @my_async_function(ptr swiftasync initializes((152, 160)) %async.ctxt, ptr %task, ptr %actor)
120; CHECK-O0-LABEL: define swiftcc void @my_async_function(ptr swiftasync %async.ctxt, ptr %task, ptr %actor)
121; CHECK-SAME: !dbg ![[SP1:[0-9]+]] {
122; CHECK: coro.return:
123; CHECK:   [[FRAMEPTR:%.*]] = getelementptr inbounds nuw i8, ptr %async.ctxt, i64 128
124; CHECK:   [[ACTOR_SPILL_ADDR:%.*]] = getelementptr inbounds nuw i8, ptr %async.ctxt, i64 152
125; CHECK:   store ptr %actor, ptr [[ACTOR_SPILL_ADDR]]
126; CHECK:   [[ADDR1:%.*]]  = getelementptr inbounds nuw i8, ptr %async.ctxt, i64 144
127; CHECK:   store ptr %async.ctxt, ptr [[ADDR1]]
128; CHECK:   [[ALLOCA_PRJ2:%.*]] = getelementptr inbounds nuw i8, ptr %async.ctxt, i64 136
129; CHECK:   store i64 0, ptr [[FRAMEPTR]]
130; CHECK:   store i64 1, ptr [[ALLOCA_PRJ2]]
131; CHECK:   tail call void @some_may_write(ptr nonnull [[FRAMEPTR]])
132; CHECK:   [[CALLEE_CTXT:%.*]] = tail call ptr @llvm.coro.async.context.alloc(ptr %task, ptr nonnull @my_other_async_function_fp)
133; CHECK:   [[CALLEE_CTXT_SPILL:%.*]] = getelementptr inbounds nuw i8, ptr %async.ctxt, i64 160
134; CHECK:   store ptr [[CALLEE_CTXT]], ptr [[CALLEE_CTXT_SPILL]]
135; CHECK:   [[TYPED_RETURN_TO_CALLER_ADDR:%.*]] = getelementptr inbounds nuw i8, ptr [[CALLEE_CTXT]], i64 8
136; CHECK:   store ptr @my_async_functionTQ0_, ptr [[TYPED_RETURN_TO_CALLER_ADDR]]
137; CHECK:   store ptr %async.ctxt, ptr [[CALLEE_CTXT]]
138; Make sure the spill is underaligned to the max context alignment (16).
139; CHECK-O0:   [[VECTOR_SPILL:%.*]] = load <4 x double>, ptr {{.*}}
140; CHECK-O0:   [[VECTOR_SPILL_ADDR:%.*]] = getelementptr inbounds %my_async_function.Frame, ptr {{.*}}, i32 0, i32 1
141; CHECK-O0:   store <4 x double> [[VECTOR_SPILL]], ptr [[VECTOR_SPILL_ADDR]], align 16
142; CHECK:   tail call swiftcc void @asyncSuspend(ptr nonnull [[CALLEE_CTXT]], ptr %task, ptr %actor)
143; CHECK:   ret void
144; CHECK: }
145
146; CHECK-LABEL: define internal swiftcc void @my_async_functionTQ0_(ptr readonly swiftasync captures(none) %0, ptr %1, ptr readnone captures(none) %2)
147; CHECK-O0-LABEL: define internal swiftcc void @my_async_functionTQ0_(ptr swiftasync %0, ptr %1, ptr %2)
148; CHECK-SAME: !dbg ![[SP2:[0-9]+]] {
149; CHECK: entryresume.0:
150; CHECK:   [[CALLER_CONTEXT:%.*]] = load ptr, ptr %0
151; CHECK:   [[FRAME_PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[CALLER_CONTEXT]], i64 128
152; CHECK-O0:   [[VECTOR_SPILL_ADDR:%.*]] = getelementptr inbounds %my_async_function.Frame, ptr {{.*}}, i32 0, i32 1
153; CHECK-O0:   load <4 x double>, ptr [[VECTOR_SPILL_ADDR]], align 16
154; CHECK:   [[CALLEE_CTXT_SPILL_ADDR:%.*]] = getelementptr inbounds nuw i8, ptr [[CALLER_CONTEXT]], i64 160
155; CHECK:   [[CALLEE_CTXT_RELOAD:%.*]] = load ptr, ptr [[CALLEE_CTXT_SPILL_ADDR]]
156; CHECK:   [[ACTOR_RELOAD_ADDR:%.*]] = getelementptr inbounds nuw i8, ptr [[CALLER_CONTEXT]], i64 152
157; CHECK:   [[ACTOR_RELOAD:%.*]] = load ptr, ptr [[ACTOR_RELOAD_ADDR]]
158; CHECK:   [[ADDR1:%.*]] = getelementptr inbounds nuw i8, ptr [[CALLER_CONTEXT]], i64 144
159; CHECK:   [[ASYNC_CTXT_RELOAD:%.*]] = load ptr, ptr [[ADDR1]]
160; CHECK:   [[ALLOCA_PRJ2:%.*]] = getelementptr inbounds nuw i8, ptr [[CALLER_CONTEXT]], i64 136
161; CHECK:   tail call void @llvm.coro.async.context.dealloc(ptr nonnull [[CALLEE_CTXT_RELOAD]])
162; CHECK:   [[VAL1:%.*]] = load i64, ptr [[FRAME_PTR]]
163; CHECK:   tail call void @some_user(i64 [[VAL1]])
164; CHECK:   [[VAL2:%.*]] = load i64, ptr [[ALLOCA_PRJ2]]
165; CHECK:   tail call void @some_user(i64 [[VAL2]])
166; CHECK:   tail call swiftcc void @asyncReturn(ptr [[ASYNC_CTXT_RELOAD]], ptr %1, ptr [[ACTOR_RELOAD]])
167; CHECK:   ret void
168; CHECK: }
169
170@my_async_function2_fp = constant <{ i32, i32 }>
171  <{ i32 trunc ( ; Relative pointer to async function
172       i64 sub (
173         i64 ptrtoint (ptr @my_async_function2 to i64),
174         i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32 }>, ptr @my_async_function2_fp, i32 0, i32 1) to i64)
175       )
176     to i32),
177     i32 128    ; Initial async context size without space for frame
178  }>
179
180define swiftcc void @my_async_function2(ptr %task, ptr %actor, ptr %async.ctxt) presplitcoroutine "frame-pointer"="all" !dbg !6 {
181entry:
182
183  %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 2, ptr @my_async_function2_fp)
184  %hdl = call ptr @llvm.coro.begin(token %id, ptr null)
185  ; setup callee context
186  %callee_context = call ptr @llvm.coro.async.context.alloc(ptr %task, ptr @my_other_async_function_fp)
187
188  %callee_context.return_to_caller.addr = getelementptr inbounds %async.ctxt, ptr %callee_context, i32 0, i32 1
189  %resume.func_ptr = call ptr @llvm.coro.async.resume()
190  store ptr %resume.func_ptr, ptr %callee_context.return_to_caller.addr
191  store ptr %async.ctxt, ptr %callee_context
192  %res = call {ptr, ptr, ptr} (i32, ptr, ptr, ...) @llvm.coro.suspend.async(i32 2,
193                                                  ptr %resume.func_ptr,
194                                                  ptr @resume_context_projection,
195                                                  ptr @my_async_function.my_other_async_function_fp.apply,
196                                                  ptr @asyncSuspend, ptr %callee_context, ptr %task, ptr %actor), !dbg !9
197
198  %continuation_task_arg = extractvalue {ptr, ptr, ptr} %res, 0
199
200  %callee_context.return_to_caller.addr.1 = getelementptr inbounds %async.ctxt, ptr %callee_context, i32 0, i32 1
201  %resume.func_ptr.1 = call ptr @llvm.coro.async.resume()
202  store ptr %resume.func_ptr.1, ptr %callee_context.return_to_caller.addr.1
203  store ptr %async.ctxt, ptr %callee_context
204  %res.2 = call {ptr, ptr, ptr} (i32, ptr, ptr, ...) @llvm.coro.suspend.async(i32 0,
205                                                  ptr %resume.func_ptr.1,
206                                                  ptr @resume_context_projection,
207                                                  ptr @my_async_function.my_other_async_function_fp.apply,
208                                                  ptr @asyncSuspend, ptr %callee_context, ptr %task, ptr %actor)
209
210  call void @llvm.coro.async.context.dealloc(ptr %callee_context)
211  %continuation_actor_arg = extractvalue {ptr, ptr, ptr} %res.2, 1
212
213  tail call swiftcc void @asyncReturn(ptr %async.ctxt, ptr %continuation_task_arg, ptr %continuation_actor_arg)
214  call i1 @llvm.coro.end(ptr %hdl, i1 0, token none)
215  unreachable
216}
217
218; CHECK-LABEL: define swiftcc void @my_async_function2(ptr %task, ptr %actor, ptr %async.ctxt)
219; CHECK-SAME: #[[FRAMEPOINTER:[0-9]+]]
220; CHECK-SAME: !dbg ![[SP3:[0-9]+]]
221; CHECK: store ptr %async.ctxt,
222; CHECK: store ptr %actor,
223; CHECK: store ptr %task,
224; CHECK: [[CALLEE_CTXT:%.*]] =  tail call ptr @llvm.coro.async.context.alloc(
225; CHECK: store ptr [[CALLEE_CTXT]],
226; CHECK: store ptr @my_async_function2.resume.0,
227; CHECK: store ptr %async.ctxt,
228; CHECK: tail call swiftcc void @asyncSuspend(ptr nonnull [[CALLEE_CTXT]], ptr %task, ptr %actor)
229; CHECK: ret void
230
231; CHECK-LABEL: define internal swiftcc void @my_async_function2.resume.0(ptr %0, ptr readnone captures(none) %1, ptr readonly captures(none) %2)
232; CHECK-SAME: #[[FRAMEPOINTER]]
233; CHECK-SAME: !dbg ![[SP4:[0-9]+]]
234; CHECK: [[CALLEE_CTXT:%.*]] = load ptr, ptr %2
235; CHECK: [[CALLEE_CTXT_SPILL_ADDR:%.*]] = getelementptr inbounds nuw i8, ptr [[CALLEE_CTXT]], i64 152
236; CHECK: store ptr @my_async_function2.resume.1,
237; CHECK: [[CALLLE_CTXT_RELOAD:%.*]] = load ptr, ptr [[CALLEE_CTXT_SPILL_ADDR]]
238; CHECK: tail call swiftcc void @asyncSuspend(ptr [[CALLEE_CTXT_RELOAD]]
239; CHECK: ret void
240
241; CHECK-LABEL: define internal swiftcc void @my_async_function2.resume.1(ptr readonly captures(none) %0, ptr %1, ptr readnone captures(none) %2)
242; CHECK-SAME: #[[FRAMEPOINTER]]
243; CHECK: tail call swiftcc void @asyncReturn({{.*}}%1)
244; CHECK: ret void
245
246define swiftcc void @top_level_caller(ptr %ctxt, ptr %task, ptr %actor) {
247  %prepare = call ptr @llvm.coro.prepare.async(ptr @my_async_function)
248  call swiftcc void %prepare(ptr %ctxt, ptr %task, ptr %actor)
249  ret void
250}
251
252; CHECK-LABEL: define swiftcc void @top_level_caller(ptr initializes((152, 160)) %ctxt, ptr %task, ptr %actor)
253; CHECK: store ptr @my_async_functionTQ0_
254; CHECK: store ptr %ctxt
255; CHECK: tail call swiftcc void @asyncSuspend
256; CHECK: ret void
257
258@dont_crash_on_cf_fp = constant <{ i32, i32 }>
259  <{ i32 trunc ( ; Relative pointer to async function
260       i64 sub (
261         i64 ptrtoint (ptr @my_async_function to i64),
262         i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32 }>, ptr @my_async_function_fp, i32 0, i32 1) to i64)
263       )
264     to i32),
265     i32 128    ; Initial async context size without space for frame
266}>
267
268
269define swiftcc void @dont_crash_on_cf_dispatch(ptr %fnPtr, ptr %async.ctxt, ptr %task, ptr %actor) {
270  %isNull = icmp eq ptr %task, null
271  br i1 %isNull, label %is_null, label %is_not_null
272
273is_null:
274  ret void
275
276is_not_null:
277  tail call swiftcc void %fnPtr(ptr %async.ctxt, ptr %task, ptr %actor)
278  ret void
279}
280
281define swiftcc void @dont_crash_on_cf(ptr %async.ctxt, ptr %task, ptr %actor) presplitcoroutine  {
282entry:
283  %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
284          ptr @dont_crash_on_cf_fp)
285  %hdl = call ptr @llvm.coro.begin(token %id, ptr null)
286  %callee_context = call ptr @llvm.coro.async.context.alloc(ptr %task, ptr @my_other_async_function_fp)
287  %callee_context.return_to_caller.addr = getelementptr inbounds %async.ctxt, ptr %callee_context, i32 0, i32 1
288  %resume.func_ptr = call ptr @llvm.coro.async.resume()
289  store ptr %resume.func_ptr, ptr %callee_context.return_to_caller.addr
290  store ptr %async.ctxt, ptr %callee_context
291  %res = call {ptr, ptr, ptr} (i32, ptr, ptr, ...) @llvm.coro.suspend.async(i32 0,
292                                                  ptr %resume.func_ptr,
293                                                  ptr @resume_context_projection,
294                                                  ptr @dont_crash_on_cf_dispatch,
295                                                  ptr @asyncSuspend, ptr %callee_context, ptr %task, ptr %actor)
296
297  call void @llvm.coro.async.context.dealloc(ptr %callee_context)
298  %continuation_task_arg = extractvalue {ptr, ptr, ptr} %res, 1
299  tail call swiftcc void @asyncReturn(ptr %async.ctxt, ptr %continuation_task_arg, ptr %actor)
300  call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %hdl, i1 0)
301  unreachable
302}
303
304@multiple_coro_end_async_fp = constant <{ i32, i32 }>
305  <{ i32 trunc ( ; Relative pointer to async function
306       i64 sub (
307         i64 ptrtoint (ptr @multiple_coro_end_async to i64),
308         i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32 }>, ptr @multiple_coro_end_async_fp, i32 0, i32 1) to i64)
309       )
310     to i32),
311     i32 128    ; Initial async context size without space for frame
312}>
313
314define swiftcc void @must_tail_call_return(ptr %async.ctxt, ptr %task, ptr %actor) {
315  musttail call swiftcc void @asyncReturn(ptr %async.ctxt, ptr %task, ptr %actor)
316  ret void
317}
318
319define swiftcc void @multiple_coro_end_async(ptr %async.ctxt, ptr %task, ptr %actor) presplitcoroutine {
320entry:
321  %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
322          ptr @dont_crash_on_cf_fp)
323  %hdl = call ptr @llvm.coro.begin(token %id, ptr null)
324  %callee_context = call ptr @llvm.coro.async.context.alloc(ptr %task, ptr @my_other_async_function_fp)
325  %callee_context.return_to_caller.addr = getelementptr inbounds %async.ctxt, ptr %callee_context, i32 0, i32 1
326  %resume.func_ptr = call ptr @llvm.coro.async.resume()
327  store ptr %resume.func_ptr, ptr %callee_context.return_to_caller.addr
328  store ptr %async.ctxt, ptr %callee_context
329  %res = call {ptr, ptr, ptr} (i32, ptr, ptr, ...) @llvm.coro.suspend.async(i32 0,
330                                                  ptr %resume.func_ptr,
331                                                  ptr @resume_context_projection,
332                                                  ptr @dont_crash_on_cf_dispatch,
333                                                  ptr @asyncSuspend, ptr %callee_context, ptr %task, ptr %actor)
334
335  call void @llvm.coro.async.context.dealloc(ptr %callee_context)
336  %continuation_task_arg = extractvalue {ptr, ptr, ptr} %res, 1
337  %eq = icmp eq ptr %continuation_task_arg, null
338  br i1 %eq, label %is_equal, label %is_not_equal
339
340is_equal:
341  tail call swiftcc void @asyncReturn(ptr %async.ctxt, ptr %continuation_task_arg, ptr %actor)
342  call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %hdl, i1 0)
343  unreachable
344
345is_not_equal:
346  call i1 (ptr, i1, ...) @llvm.coro.end.async(
347                           ptr %hdl, i1 0,
348                           ptr @must_tail_call_return,
349                           ptr %async.ctxt, ptr %continuation_task_arg, ptr null)
350  unreachable
351}
352
353; CHECK-LABEL: define internal swiftcc void @multiple_coro_end_async.resume.0(
354; CHECK: musttail call swiftcc void @asyncReturn(
355; CHECK: ret void
356
357@polymorphic_suspend_return_fp = constant <{ i32, i32 }>
358  <{ i32 trunc ( ; Relative pointer to async function
359       i64 sub (
360         i64 ptrtoint (ptr @polymorphic_suspend_return to i64),
361         i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32 }>, ptr @polymorphic_suspend_return_fp, i32 0, i32 1) to i64)
362       )
363     to i32),
364     i32 64    ; Initial async context size without space for frame
365}>
366
367define swiftcc void @polymorphic_suspend_return(ptr swiftasync %async.ctxt, ptr %task, ptr %actor) presplitcoroutine {
368entry:
369  %tmp = alloca { i64, i64 }, align 8
370  %proj.1 = getelementptr inbounds { i64, i64 }, ptr %tmp, i64 0, i32 0
371  %proj.2 = getelementptr inbounds { i64, i64 }, ptr %tmp, i64 0, i32 1
372
373  %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
374          ptr @polymorphic_suspend_return_fp)
375  %hdl = call ptr @llvm.coro.begin(token %id, ptr null)
376  store i64 0, ptr %proj.1, align 8
377  store i64 1, ptr %proj.2, align 8
378  call void @some_may_write(ptr %proj.1)
379
380	; Begin lowering: apply %my_other_async_function(%args...)
381
382  ; setup callee context
383  %callee_context = call ptr @llvm.coro.async.context.alloc(ptr %task, ptr @my_other_async_function_fp)
384  ; store arguments ...
385  ; ... (omitted)
386
387  ; store the return continuation
388  %callee_context.return_to_caller.addr = getelementptr inbounds %async.ctxt, ptr %callee_context, i32 0, i32 1
389  %resume.func_ptr = call ptr @llvm.coro.async.resume()
390  store ptr %resume.func_ptr, ptr %callee_context.return_to_caller.addr
391
392  ; store caller context into callee context
393  store ptr %async.ctxt, ptr %callee_context
394  %res = call {ptr, ptr, ptr, ptr} (i32, ptr, ptr, ...)
395         @llvm.coro.suspend.async.sl_p0i8p0i8p0i8p0i8s(i32 256, ;; swiftasync at 0 and swiftself at 1 in resume function
396                                                 ptr %resume.func_ptr,
397                                                 ptr @resume_context_projection,
398                                                 ptr @my_async_function.my_other_async_function_fp.apply,
399                                                 ptr @asyncSuspend, ptr %callee_context, ptr %task, ptr %actor)
400
401  call void @llvm.coro.async.context.dealloc(ptr %callee_context)
402  %continuation_task_arg = extractvalue {ptr, ptr, ptr, ptr} %res, 3
403  %val = load i64, ptr %proj.1
404  call void @some_user(i64 %val)
405  %val.2 = load i64, ptr %proj.2
406  call void @some_user(i64 %val.2)
407
408  tail call swiftcc void @asyncReturn(ptr %async.ctxt, ptr %continuation_task_arg, ptr %actor)
409  call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %hdl, i1 0)
410  unreachable
411}
412
413; CHECK-LABEL: define swiftcc void @polymorphic_suspend_return(ptr swiftasync initializes((152, 160)) %async.ctxt, ptr %task, ptr %actor)
414; CHECK-LABEL: define internal swiftcc void @polymorphic_suspend_return.resume.0(ptr {{.*}}swiftasync{{.*}} %0, ptr {{.*}}swiftself{{.*}} %1, ptr {{.*}}%2, ptr {{.*}}%3)
415; CHECK: }
416
417@no_coro_suspend_fp = constant <{ i32, i32 }>
418  <{ i32 trunc ( ; Relative pointer to async function
419       i64 sub (
420         i64 ptrtoint (ptr @no_coro_suspend to i64),
421         i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32 }>, ptr @no_coro_suspend_fp, i32 0, i32 1) to i64)
422       )
423     to i32),
424     i32 128    ; Initial async context size without space for frame
425}>
426
427define swiftcc void @no_coro_suspend(ptr %async.ctx) presplitcoroutine {
428entry:
429  %some_alloca = alloca i64
430  %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
431          ptr @no_coro_suspend_fp)
432  %hdl = call ptr @llvm.coro.begin(token %id, ptr null)
433  call void @some_may_write(ptr %some_alloca)
434  call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %hdl, i1 0)
435  unreachable
436}
437
438; CHECK-LABEL: define swiftcc void @no_coro_suspend
439; CHECK:   [[ALLOCA:%.*]] = alloca i64
440; CHECK:   call void @some_may_write(ptr {{.*}}[[ALLOCA]])
441
442@no_coro_suspend_swifterror_fp = constant <{ i32, i32 }>
443  <{ i32 trunc ( ; Relative pointer to async function
444       i64 sub (
445         i64 ptrtoint (ptr @no_coro_suspend_swifterror to i64),
446         i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32 }>, ptr @no_coro_suspend_swifterror_fp, i32 0, i32 1) to i64)
447       )
448     to i32),
449     i32 128    ; Initial async context size without space for frame
450}>
451
452declare void @do_with_swifterror(ptr swifterror)
453
454define swiftcc void @no_coro_suspend_swifterror(ptr %async.ctx) presplitcoroutine {
455entry:
456  %some_alloca = alloca swifterror ptr
457  %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
458          ptr @no_coro_suspend_swifterror_fp)
459  %hdl = call ptr @llvm.coro.begin(token %id, ptr null)
460  store ptr null, ptr %some_alloca, align 8
461  call void @do_with_swifterror(ptr swifterror %some_alloca)
462  call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %hdl, i1 0)
463  unreachable
464}
465
466 ; CHECK-LABEL: define swiftcc void @no_coro_suspend_swifterror
467 ; CHECK:  [[ALLOCA:%.*]] = alloca swifterror ptr
468 ; CHECK:   store ptr null, ptr [[ALLOCA]]
469 ; CHECK:   call void @do_with_swifterror(ptr {{.*}}swifterror{{.*}} [[ALLOCA]])
470
471@undefined_coro_async_resume_fp = constant <{ i32, i32 }>
472  <{ i32 trunc (
473       i64 sub (
474         i64 ptrtoint (ptr @undefined_coro_async_resume to i64),
475         i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32 }>, ptr @undefined_coro_async_resume_fp, i32 0, i32 1) to i64)
476       )
477     to i32),
478     i32 24
479}>
480
481declare void @crash()
482declare void @use(ptr)
483
484define swiftcc void @undefined_coro_async_resume(ptr %async.ctx) presplitcoroutine {
485entry:
486  %id = call token @llvm.coro.id.async(i32 24, i32 16, i32 0, ptr @undefined_coro_async_resume_fp)
487  %hdl = call ptr @llvm.coro.begin(token %id, ptr null)
488  %undefined_resume_pointer = call ptr @llvm.coro.async.resume()
489  call void @use(ptr %undefined_resume_pointer)
490  call void @crash()
491  %unused = call i1 (ptr, i1, ...) @llvm.coro.end.async(ptr %hdl, i1 false)
492  unreachable
493}
494; CHECK-LABEL: define swiftcc void @undefined_coro_async_resume
495; CHECK-NOT: @llvm.coro.async.resume
496; CHECK: call void @use(ptr null)
497; CHECK: ret
498
499declare { ptr, ptr, ptr, ptr } @llvm.coro.suspend.async.sl_p0i8p0i8p0i8p0i8s(i32, ptr, ptr, ...)
500declare ptr @llvm.coro.prepare.async(ptr)
501declare token @llvm.coro.id.async(i32, i32, i32, ptr)
502declare ptr @llvm.coro.begin(token, ptr)
503declare i1 @llvm.coro.end.async(ptr, i1, ...)
504declare i1 @llvm.coro.end(ptr, i1, token)
505declare {ptr, ptr, ptr} @llvm.coro.suspend.async(i32, ptr, ptr, ...)
506declare ptr @llvm.coro.async.context.alloc(ptr, ptr)
507declare void @llvm.coro.async.context.dealloc(ptr)
508declare swiftcc void @asyncReturn(ptr, ptr, ptr)
509declare swiftcc void @asyncSuspend(ptr, ptr, ptr)
510declare ptr @llvm.coro.async.resume()
511declare void @llvm.coro.async.size.replace(ptr, ptr)
512declare ptr @hide(ptr)
513
514!llvm.dbg.cu = !{!2}
515!llvm.module.flags = !{!0}
516
517!0 = !{i32 2, !"Debug Info Version", i32 3}
518; CHECK: ![[SP1]] = distinct !DISubprogram(name: "my_async_function",
519; CHECK-SAME:                              linkageName: "my_async_function",
520; CHECK-SAME:                              scopeLine: 1
521!1 = distinct !DISubprogram(name: "my_async_function",
522                            linkageName: "my_async_function",
523                            scope: !2, file: !3, line: 1, type: !4,
524                            scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2)
525; CHECK: ![[SP2]] = distinct !DISubprogram(name: "my_async_function",
526; CHECK-SAME:                              linkageName: "my_async_functionTQ0_",
527; CHECK-SAME:                              scopeLine: 2
528!2 = distinct !DICompileUnit(language: DW_LANG_Swift, file: !3, emissionKind: FullDebug)
529!3 = !DIFile(filename: "/tmp/1.swift", directory: "/")
530!4 = !DISubroutineType(types: !{})
531!5 = !DILocation(line: 2, column: 0, scope: !1)
532
533; CHECK: ![[SP3]] = distinct !DISubprogram(name: "my_async_function2",
534; CHECK-SAME:                              linkageName: "my_async_function2",
535; CHECK-SAME:                              scopeLine: 1
536!6 = distinct !DISubprogram(name: "my_async_function2",
537                            linkageName: "my_async_function2",
538                            scope: !2, file: !3, line: 1, type: !4,
539                            scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2)
540; CHECK: ![[SP4]] = distinct !DISubprogram(name: "my_async_function2",
541; CHECK-SAME:                              linkageName: "my_async_function2.resume.0",
542; CHECK-SAME:                              scopeLine: 1
543!7 = !DILexicalBlockFile(scope: !6, file: !8, discriminator: 0)
544!8 = !DIFile(filename: "/tmp/fake.cpp", directory: "/")
545!9 = !DILocation(line: 2, column: 0, scope: !7)
546