[DAGCombiner] Add target hook function to decide folding (mul (add x, c1), c2)
[llvm-project.git] / llvm / test / Transforms / Coroutines / coro-async.ll
blob58aaa0efb12e83f55fe685ac18cf987205d3ed5d
1 ; RUN: opt < %s -enable-coroutines -passes='default<O2>' -S | FileCheck --check-prefixes=CHECK %s
2 ; RUN: opt < %s -enable-coroutines -O0 -S | FileCheck --check-prefixes=CHECK-O0 %s
3 target datalayout = "p:64:64:64"
5 %async.task = type { i64 }
6 %async.actor = type { i64 }
7 %async.fp = type <{ i32, i32 }>
9 %async.ctxt = type { i8*, void (i8*, %async.task*, %async.actor*)* }
11 ; The async callee.
12 @my_other_async_function_fp = external global <{ i32, i32 }>
13 declare void @my_other_async_function(i8* %async.ctxt)
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.
20 @my_async_function_fp = constant <{ i32, i32 }>
21   <{ i32 trunc ( ; Relative pointer to async function
22        i64 sub (
23          i64 ptrtoint (void (i8*, %async.task*, %async.actor*)* @my_async_function to i64),
24          i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32 }>, <{ i32, i32 }>* @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
29 @my_async_function_pa_fp = constant <{ i32, i32 }>
30   <{ i32 trunc (
31        i64 sub (
32          i64 ptrtoint (void (i8*, %async.task*, %async.actor*)* @my_async_function_pa to i64),
33          i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32 }>, <{ i32, i32 }>* @my_async_function_pa_fp, i32 0, i32 1) to i64)
34        )
35      to i32),
36      i32 8
39 ; Function that implements the dispatch to the callee function.
40 define swiftcc void @my_async_function.my_other_async_function_fp.apply(i8* %fnPtr, i8* %async.ctxt, %async.task* %task, %async.actor* %actor) {
41   %callee = bitcast i8* %fnPtr to void(i8*, %async.task*, %async.actor*)*
42   tail call swiftcc void %callee(i8* %async.ctxt, %async.task* %task, %async.actor* %actor)
43   ret void
46 declare void @some_user(i64)
47 declare void @some_may_write(i64*)
49 define i8* @__swift_async_resume_project_context(i8* %ctxt) {
50 entry:
51   %resume_ctxt_addr = bitcast i8* %ctxt to i8**
52   %resume_ctxt = load i8*, i8** %resume_ctxt_addr, align 8
53   ret i8* %resume_ctxt
56 define i8* @resume_context_projection(i8* %ctxt) {
57 entry:
58   %resume_ctxt_addr = bitcast i8* %ctxt to i8**
59   %resume_ctxt = load i8*, i8** %resume_ctxt_addr, align 8
60   ret i8* %resume_ctxt
64 define swiftcc void @my_async_function(i8* swiftasync %async.ctxt, %async.task* %task, %async.actor* %actor) !dbg !1 {
65 entry:
66   %tmp = alloca { i64, i64 }, align 8
67   %vector = alloca <4 x double>, align 16
68   %proj.1 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %tmp, i64 0, i32 0
69   %proj.2 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %tmp, i64 0, i32 1
71   %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
72           i8* bitcast (<{i32, i32}>* @my_async_function_fp to i8*))
73   %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
74   store i64 0, i64* %proj.1, align 8
75   store i64 1, i64* %proj.2, align 8
76   call void @some_may_write(i64* %proj.1)
78         ; Begin lowering: apply %my_other_async_function(%args...)
80   ; setup callee context
81   %arg0 = bitcast %async.task* %task to i8*
82   %arg1 = bitcast <{ i32, i32}>* @my_other_async_function_fp to i8*
83   %callee_context = call i8* @llvm.coro.async.context.alloc(i8* %arg0, i8* %arg1)
84         %callee_context.0 = bitcast i8* %callee_context to %async.ctxt*
85   ; store arguments ...
86   ; ... (omitted)
88   ; store the return continuation
89   %callee_context.return_to_caller.addr = getelementptr inbounds %async.ctxt, %async.ctxt* %callee_context.0, i32 0, i32 1
90   %return_to_caller.addr = bitcast void(i8*, %async.task*, %async.actor*)** %callee_context.return_to_caller.addr to i8**
91   %resume.func_ptr = call i8* @llvm.coro.async.resume()
92   store i8* %resume.func_ptr, i8** %return_to_caller.addr
94   ; store caller context into callee context
95   %callee_context.caller_context.addr = getelementptr inbounds %async.ctxt, %async.ctxt* %callee_context.0, i32 0, i32 0
96   store i8* %async.ctxt, i8** %callee_context.caller_context.addr
97   %resume_proj_fun = bitcast i8*(i8*)* @__swift_async_resume_project_context to i8*
98   %callee = bitcast void(i8*, %async.task*, %async.actor*)* @asyncSuspend to i8*
99   %vector_spill = load <4 x double>, <4 x double>* %vector, align 16
100   %res = call {i8*, i8*, i8*} (i32, i8*, i8*, ...) @llvm.coro.suspend.async(i32 0,
101                                                   i8* %resume.func_ptr,
102                                                   i8* %resume_proj_fun,
103                                                   void (i8*, i8*, %async.task*, %async.actor*)* @my_async_function.my_other_async_function_fp.apply,
104                                                   i8* %callee, i8* %callee_context, %async.task* %task, %async.actor *%actor), !dbg !5
106   call void @llvm.coro.async.context.dealloc(i8* %callee_context)
107   %continuation_task_arg = extractvalue {i8*, i8*, i8*} %res, 1
108   %task.2 =  bitcast i8* %continuation_task_arg to %async.task*
109   %val = load i64, i64* %proj.1
110   call void @some_user(i64 %val)
111   %val.2 = load i64, i64* %proj.2
112   call void @some_user(i64 %val.2)
113   store <4 x double> %vector_spill, <4 x double>* %vector, align 16
114   tail call swiftcc void @asyncReturn(i8* %async.ctxt, %async.task* %task.2, %async.actor* %actor)
115   call i1 (i8*, i1, ...) @llvm.coro.end.async(i8* %hdl, i1 0)
116   unreachable
119 define void @my_async_function_pa(i8* %ctxt, %async.task* %task, %async.actor* %actor) {
120   call void @llvm.coro.async.size.replace(i8* bitcast (<{i32, i32}>* @my_async_function_pa_fp to i8*), i8* bitcast (<{i32, i32}>* @my_async_function_fp to i8*))
121   call swiftcc void @my_async_function(i8* %ctxt, %async.task* %task, %async.actor* %actor)
122   ret void
125 ; Make sure we update the async function pointer
126 ; CHECK: @my_async_function_fp = constant <{ i32, i32 }> <{ {{.*}}, i32 176 }
127 ; CHECK: @my_async_function_pa_fp = constant <{ i32, i32 }> <{ {{.*}}, i32 176 }
128 ; CHECK: @my_async_function2_fp = constant <{ i32, i32 }> <{ {{.*}}, i32 176 }
130 ; CHECK-LABEL: define swiftcc void @my_async_function(i8* swiftasync %async.ctxt, %async.task* %task, %async.actor* %actor)
131 ; CHECK-O0-LABEL: define swiftcc void @my_async_function(i8* swiftasync %async.ctxt, %async.task* %task, %async.actor* %actor)
132 ; CHECK-SAME: !dbg ![[SP1:[0-9]+]] {
133 ; CHECK: coro.return:
134 ; CHECK:   [[FRAMEPTR:%.*]] = getelementptr inbounds i8, i8* %async.ctxt, i64 128
135 ; CHECK:   [[ACTOR_SPILL_ADDR:%.*]] = getelementptr inbounds i8, i8* %async.ctxt, i64 152
136 ; CHECK:   [[CAST1:%.*]] = bitcast i8* [[ACTOR_SPILL_ADDR]] to %async.actor**
137 ; CHECK:   store %async.actor* %actor, %async.actor** [[CAST1]]
138 ; CHECK:   [[ADDR1:%.*]]  = getelementptr inbounds i8, i8* %async.ctxt, i64 144
139 ; CHECK:   [[ASYNC_CTXT_SPILL_ADDR:%.*]] = bitcast i8* [[ADDR1]] to i8**
140 ; CHECK:   store i8* %async.ctxt, i8** [[ASYNC_CTXT_SPILL_ADDR]]
141 ; CHECK:   [[ALLOCA_PRJ1:%.*]] = bitcast i8* [[FRAMEPTR]] to i64*
142 ; CHECK:   [[ALLOCA_PRJ2:%.*]] = getelementptr inbounds i8, i8* %async.ctxt, i64 136
143 ; CHECK:   [[ADDR2:%.*]] = bitcast i8* [[ALLOCA_PRJ2]] to i64*
144 ; CHECK:   store i64 0, i64* [[ALLOCA_PRJ1]]
145 ; CHECK:   store i64 1, i64* [[ADDR2]]
146 ; CHECK:   tail call void @some_may_write(i64* nonnull %proj.1)
147 ; CHECK:   [[TASK:%.*]] = bitcast %async.task* %task to i8*
148 ; CHECK:   [[CALLEE_CTXT:%.*]] = tail call i8* @llvm.coro.async.context.alloc(i8* [[TASK]], i8* bitcast (<{ i32, i32 }>* @my_other_async_function_fp to i8*))
149 ; CHECK:   [[CALLEE_CTXT_SPILL:%.*]] = getelementptr inbounds i8, i8* %async.ctxt, i64 160
150 ; CHECK:   [[CAST2:%.*]] = bitcast i8* [[CALLEE_CTXT_SPILL]] to i8**
151 ; CHECK:   store i8* [[CALLEE_CTXT]], i8** [[CAST2]]
152 ; CHECK:   [[TYPED_RETURN_TO_CALLER_ADDR:%.*]] = getelementptr inbounds i8, i8* [[CALLEE_CTXT]], i64 8
153 ; CHECK:   [[RETURN_TO_CALLER_ADDR:%.*]] = bitcast i8* [[TYPED_RETURN_TO_CALLER_ADDR]] to i8**
154 ; CHECK:   store i8* bitcast (void (i8*, i8*, i8*)* @my_async_functionTQ0_ to i8*), i8** [[RETURN_TO_CALLER_ADDR]]
155 ; CHECK:   [[CALLER_CONTEXT_ADDR:%.*]] = bitcast i8* [[CALLEE_CTXT]] to i8**
156 ; CHECK:   store i8* %async.ctxt, i8** [[CALLER_CONTEXT_ADDR]]
157 ; Make sure the spill is underaligned to the max context alignment (16).
158 ; CHECK-O0:   [[VECTOR_SPILL:%.*]] = load <4 x double>, <4 x double>* {{.*}}
159 ; CHECK-O0:   [[VECTOR_SPILL_ADDR:%.*]] = getelementptr inbounds %my_async_function.Frame, %my_async_function.Frame* {{.*}}, i32 0, i32 1
160 ; CHECK-O0:   store <4 x double> [[VECTOR_SPILL]], <4 x double>* [[VECTOR_SPILL_ADDR]], align 16
161 ; CHECK:   tail call swiftcc void @asyncSuspend(i8* [[CALLEE_CTXT]], %async.task* %task, %async.actor* %actor)
162 ; CHECK:   ret void
163 ; CHECK: }
165 ; CHECK-LABEL: define internal swiftcc void @my_async_functionTQ0_(i8* nocapture readonly swiftasync %0, i8* %1, i8* nocapture readnone %2)
166 ; CHECK-O0-LABEL: define internal swiftcc void @my_async_functionTQ0_(i8* swiftasync %0, i8* %1, i8* %2)
167 ; CHECK-SAME: !dbg ![[SP2:[0-9]+]] {
168 ; CHECK: entryresume.0:
169 ; CHECK:   [[CALLER_CONTEXT_ADDR:%.*]] = bitcast i8* %0 to i8**
170 ; CHECK:   [[CALLER_CONTEXT:%.*]] = load i8*, i8** [[CALLER_CONTEXT_ADDR]]
171 ; CHECK:   [[FRAME_PTR:%.*]] = getelementptr inbounds i8, i8* [[CALLER_CONTEXT]], i64 128
172 ; CHECK-O0:   [[VECTOR_SPILL_ADDR:%.*]] = getelementptr inbounds %my_async_function.Frame, %my_async_function.Frame* {{.*}}, i32 0, i32 1
173 ; CHECK-O0:   load <4 x double>, <4 x double>* [[VECTOR_SPILL_ADDR]], align 16
174 ; CHECK:   [[CALLEE_CTXT_SPILL_ADDR:%.*]] = getelementptr inbounds i8, i8* [[CALLER_CONTEXT]], i64 160
175 ; CHECK:   [[CAST1:%.*]] = bitcast i8* [[CALLEE_CTXT_SPILL_ADDR]] to i8**
176 ; CHECK:   [[CALLEE_CTXT_RELOAD:%.*]] = load i8*, i8** [[CAST1]]
177 ; CHECK:   [[ACTOR_RELOAD_ADDR:%.*]] = getelementptr inbounds i8, i8* [[CALLER_CONTEXT]], i64 152
178 ; CHECK:   [[CAST2:%.*]] = bitcast i8* [[ACTOR_RELOAD_ADDR]] to %async.actor**
179 ; CHECK:   [[ACTOR_RELOAD:%.*]] = load %async.actor*, %async.actor** [[CAST2]]
180 ; CHECK:   [[ADDR1:%.*]] = getelementptr inbounds i8, i8* [[CALLER_CONTEXT]], i64 144
181 ; CHECK:   [[ASYNC_CTXT_RELOAD_ADDR:%.*]] = bitcast i8* [[ADDR1]] to i8**
182 ; CHECK:   [[ASYNC_CTXT_RELOAD:%.*]] = load i8*, i8** [[ASYNC_CTXT_RELOAD_ADDR]]
183 ; CHECK:   [[ALLOCA_PRJ2:%.*]] = getelementptr inbounds i8, i8* [[CALLER_CONTEXT]], i64 136
184 ; CHECK:   [[ADDR2:%.*]] = bitcast i8* [[ALLOCA_PRJ2]] to i64*
185 ; CHECK:   [[ALLOCA_PRJ1:%.*]] = bitcast i8* [[FRAME_PTR]] to i64*
186 ; CHECK:   tail call void @llvm.coro.async.context.dealloc(i8* [[CALLEE_CTXT_RELOAD]])
187 ; CHECK:   [[TASK_ARG:%.*]] = bitcast i8* %1 to %async.task*
188 ; CHECK:   [[VAL1:%.*]] = load i64, i64* [[ALLOCA_PRJ1]]
189 ; CHECK:   tail call void @some_user(i64 [[VAL1]])
190 ; CHECK:   [[VAL2:%.*]] = load i64, i64* [[ADDR2]]
191 ; CHECK:   tail call void @some_user(i64 [[VAL2]])
192 ; CHECK:   tail call swiftcc void @asyncReturn(i8* [[ASYNC_CTXT_RELOAD]], %async.task* [[TASK_ARG]], %async.actor* [[ACTOR_RELOAD]])
193 ; CHECK:   ret void
194 ; CHECK: }
196 @my_async_function2_fp = constant <{ i32, i32 }>
197   <{ i32 trunc ( ; Relative pointer to async function
198        i64 sub (
199          i64 ptrtoint (void (%async.task*, %async.actor*, i8*)* @my_async_function2 to i64),
200          i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32 }>, <{ i32, i32 }>* @my_async_function2_fp, i32 0, i32 1) to i64)
201        )
202      to i32),
203      i32 128    ; Initial async context size without space for frame
204   }>
206 define swiftcc void @my_async_function2(%async.task* %task, %async.actor* %actor, i8* %async.ctxt) "frame-pointer"="all" !dbg !6 {
207 entry:
209   %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 2, i8* bitcast (<{i32, i32}>* @my_async_function2_fp to i8*))
210   %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
211   ; setup callee context
212   %arg0 = bitcast %async.task* %task to i8*
213   %arg1 = bitcast <{ i32, i32}>* @my_other_async_function_fp to i8*
214   %callee_context = call i8* @llvm.coro.async.context.alloc(i8* %arg0, i8* %arg1)
216         %callee_context.0 = bitcast i8* %callee_context to %async.ctxt*
217   %callee_context.return_to_caller.addr = getelementptr inbounds %async.ctxt, %async.ctxt* %callee_context.0, i32 0, i32 1
218   %return_to_caller.addr = bitcast void(i8*, %async.task*, %async.actor*)** %callee_context.return_to_caller.addr to i8**
219   %resume.func_ptr = call i8* @llvm.coro.async.resume()
220   store i8* %resume.func_ptr, i8** %return_to_caller.addr
221   %callee_context.caller_context.addr = getelementptr inbounds %async.ctxt, %async.ctxt* %callee_context.0, i32 0, i32 0
222   store i8* %async.ctxt, i8** %callee_context.caller_context.addr
223   %resume_proj_fun = bitcast i8*(i8*)* @resume_context_projection to i8*
224   %callee = bitcast void(i8*, %async.task*, %async.actor*)* @asyncSuspend to i8*
225   %task.casted = bitcast i8* %arg0 to %async.task*
226   %res = call {i8*, i8*, i8*} (i32, i8*, i8*, ...) @llvm.coro.suspend.async(i32 2,
227                                                   i8* %resume.func_ptr,
228                                                   i8* %resume_proj_fun,
229                                                   void (i8*, i8*, %async.task*, %async.actor*)* @my_async_function.my_other_async_function_fp.apply,
230                                                   i8* %callee, i8* %callee_context, %async.task* %task.casted, %async.actor *%actor), !dbg !9
232   %continuation_task_arg = extractvalue {i8*, i8*, i8*} %res, 0
233   %task.2 =  bitcast i8* %continuation_task_arg to %async.task*
235         %callee_context.0.1 = bitcast i8* %callee_context to %async.ctxt*
236   %callee_context.return_to_caller.addr.1 = getelementptr inbounds %async.ctxt, %async.ctxt* %callee_context.0.1, i32 0, i32 1
237   %return_to_caller.addr.1 = bitcast void(i8*, %async.task*, %async.actor*)** %callee_context.return_to_caller.addr.1 to i8**
238   %resume.func_ptr.1 = call i8* @llvm.coro.async.resume()
239   store i8* %resume.func_ptr.1, i8** %return_to_caller.addr.1
240   %callee_context.caller_context.addr.1 = getelementptr inbounds %async.ctxt, %async.ctxt* %callee_context.0.1, i32 0, i32 0
241   store i8* %async.ctxt, i8** %callee_context.caller_context.addr.1
242   %resume_proj_fun.2 = bitcast i8*(i8*)* @resume_context_projection to i8*
243   %callee.2 = bitcast void(i8*, %async.task*, %async.actor*)* @asyncSuspend to i8*
244   %res.2 = call {i8*, i8*, i8*} (i32, i8*, i8*, ...) @llvm.coro.suspend.async(i32 0,
245                                                   i8* %resume.func_ptr.1,
246                                                   i8* %resume_proj_fun.2,
247                                                   void (i8*, i8*, %async.task*, %async.actor*)* @my_async_function.my_other_async_function_fp.apply,
248                                                   i8* %callee.2, i8* %callee_context, %async.task* %task.casted, %async.actor *%actor)
250   call void @llvm.coro.async.context.dealloc(i8* %callee_context)
251   %continuation_actor_arg = extractvalue {i8*, i8*, i8*} %res.2, 1
252   %actor.2 =  bitcast i8* %continuation_actor_arg to %async.actor*
254   tail call swiftcc void @asyncReturn(i8* %async.ctxt, %async.task* %task.2, %async.actor* %actor.2)
255   call i1 @llvm.coro.end(i8* %hdl, i1 0)
256   unreachable
259 ; CHECK-LABEL: define swiftcc void @my_async_function2(%async.task* %task, %async.actor* %actor, i8* %async.ctxt)
260 ; CHECK-SAME: #[[FRAMEPOINTER:[0-9]+]]
261 ; CHECK-SAME: !dbg ![[SP3:[0-9]+]]
262 ; CHECK: store i8* %async.ctxt,
263 ; CHECK: store %async.actor* %actor,
264 ; CHECK: store %async.task* %task,
265 ; CHECK: [[CALLEE_CTXT:%.*]] =  tail call i8* @llvm.coro.async.context.alloc(
266 ; CHECK: store i8* [[CALLEE_CTXT]],
267 ; CHECK: store i8* bitcast (void (i8*, i8*, i8*)* @my_async_function2.resume.0 to i8*),
268 ; CHECK: store i8* %async.ctxt,
269 ; CHECK: tail call swiftcc void @asyncSuspend(i8* [[CALLEE_CTXT]], %async.task* %task, %async.actor* %actor)
270 ; CHECK: ret void
272 ; CHECK-LABEL: define internal swiftcc void @my_async_function2.resume.0(i8* %0, i8* nocapture readnone %1, i8* nocapture readonly %2)
273 ; CHECK-SAME: #[[FRAMEPOINTER]]
274 ; CHECK-SAME: !dbg ![[SP4:[0-9]+]]
275 ; CHECK: [[CALLEE_CTXT_ADDR:%.*]] = bitcast i8* %2 to i8**
276 ; CHECK: [[CALLEE_CTXT:%.*]] = load i8*, i8** [[CALLEE_CTXT_ADDR]]
277 ; CHECK: [[CALLEE_CTXT_SPILL_ADDR:%.*]] = getelementptr inbounds i8, i8* [[CALLEE_CTXT]], i64 152
278 ; CHECK: [[CALLEE_CTXT_SPILL_ADDR2:%.*]] = bitcast i8* [[CALLEE_CTXT_SPILL_ADDR]] to i8**
279 ; CHECK: store i8* bitcast (void (i8*, i8*, i8*)* @my_async_function2.resume.1 to i8*),
280 ; CHECK: [[CALLLE_CTXT_RELOAD:%.*]] = load i8*, i8** [[CALLEE_CTXT_SPILL_ADDR2]]
281 ; CHECK: tail call swiftcc void @asyncSuspend(i8* [[CALLEE_CTXT_RELOAD]]
282 ; CHECK: ret void
284 ; CHECK-LABEL: define internal swiftcc void @my_async_function2.resume.1(i8* nocapture readonly %0, i8* %1, i8* nocapture readnone %2)
285 ; CHECK-SAME: #[[FRAMEPOINTER]]
286 ; CHECK: bitcast i8* %0 to i8**
287 ; CHECK: [[ACTOR_ARG:%.*]] = bitcast i8* %1
288 ; CHECK: tail call swiftcc void @asyncReturn({{.*}}[[ACTOR_ARG]])
289 ; CHECK: ret void
291 define swiftcc void @top_level_caller(i8* %ctxt, i8* %task, i8* %actor) {
292   %prepare = call i8* @llvm.coro.prepare.async(i8* bitcast (void (i8*, %async.task*,  %async.actor*)* @my_async_function to i8*))
293   %f = bitcast i8* %prepare to void (i8*, i8*, i8*)*
294   call swiftcc void %f(i8* %ctxt, i8* %task, i8* %actor)
295   ret void
298 ; CHECK-LABEL: define swiftcc void @top_level_caller(i8* %ctxt, i8* %task, i8* %actor)
299 ; CHECK: store i8* bitcast (void (i8*, i8*, i8*)* @my_async_functionTQ0_
300 ; CHECK: store i8* %ctxt
301 ; CHECK: tail call swiftcc void @asyncSuspend
302 ; CHECK: ret void
304 @dont_crash_on_cf_fp = constant <{ i32, i32 }>
305   <{ i32 trunc ( ; Relative pointer to async function
306        i64 sub (
307          i64 ptrtoint (void (i8*, %async.task*, %async.actor*)* @my_async_function to i64),
308          i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32 }>, <{ i32, i32 }>* @my_async_function_fp, i32 0, i32 1) to i64)
309        )
310      to i32),
311      i32 128    ; Initial async context size without space for frame
315 define swiftcc void @dont_crash_on_cf_dispatch(i8* %fnPtr, i8* %async.ctxt, %async.task* %task, %async.actor* %actor) {
316   %isNull = icmp eq %async.task* %task, null
317   br i1 %isNull, label %is_null, label %is_not_null
319 is_null:
320   ret void
322 is_not_null:
323   %callee = bitcast i8* %fnPtr to void(i8*, %async.task*, %async.actor*)*
324   tail call swiftcc void %callee(i8* %async.ctxt, %async.task* %task, %async.actor* %actor)
325   ret void
328 define swiftcc void @dont_crash_on_cf(i8* %async.ctxt, %async.task* %task, %async.actor* %actor)  {
329 entry:
330   %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
331           i8* bitcast (<{i32, i32}>* @dont_crash_on_cf_fp to i8*))
332   %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
333   %arg0 = bitcast %async.task* %task to i8*
334   %arg1 = bitcast <{ i32, i32}>* @my_other_async_function_fp to i8*
335   %callee_context = call i8* @llvm.coro.async.context.alloc(i8* %arg0, i8* %arg1)
336         %callee_context.0 = bitcast i8* %callee_context to %async.ctxt*
337   %callee_context.return_to_caller.addr = getelementptr inbounds %async.ctxt, %async.ctxt* %callee_context.0, i32 0, i32 1
338   %return_to_caller.addr = bitcast void(i8*, %async.task*, %async.actor*)** %callee_context.return_to_caller.addr to i8**
339   %resume.func_ptr = call i8* @llvm.coro.async.resume()
340   store i8* %resume.func_ptr, i8** %return_to_caller.addr
341   %callee_context.caller_context.addr = getelementptr inbounds %async.ctxt, %async.ctxt* %callee_context.0, i32 0, i32 0
342   store i8* %async.ctxt, i8** %callee_context.caller_context.addr
343   %resume_proj_fun = bitcast i8*(i8*)* @resume_context_projection to i8*
344   %callee = bitcast void(i8*, %async.task*, %async.actor*)* @asyncSuspend to i8*
345   %res = call {i8*, i8*, i8*} (i32, i8*, i8*, ...) @llvm.coro.suspend.async(i32 0,
346                                                   i8* %resume.func_ptr,
347                                                   i8* %resume_proj_fun,
348                                                   void (i8*, i8*, %async.task*, %async.actor*)* @dont_crash_on_cf_dispatch,
349                                                   i8* %callee, i8* %callee_context, %async.task* %task, %async.actor *%actor)
351   call void @llvm.coro.async.context.dealloc(i8* %callee_context)
352   %continuation_task_arg = extractvalue {i8*, i8*, i8*} %res, 1
353   %task.2 =  bitcast i8* %continuation_task_arg to %async.task*
354   tail call swiftcc void @asyncReturn(i8* %async.ctxt, %async.task* %task.2, %async.actor* %actor)
355   call i1 (i8*, i1, ...) @llvm.coro.end.async(i8* %hdl, i1 0)
356   unreachable
359 @multiple_coro_end_async_fp = constant <{ i32, i32 }>
360   <{ i32 trunc ( ; Relative pointer to async function
361        i64 sub (
362          i64 ptrtoint (void (i8*, %async.task*, %async.actor*)* @multiple_coro_end_async to i64),
363          i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32 }>, <{ i32, i32 }>* @multiple_coro_end_async_fp, i32 0, i32 1) to i64)
364        )
365      to i32),
366      i32 128    ; Initial async context size without space for frame
369 define swiftcc void @must_tail_call_return(i8* %async.ctxt, %async.task* %task, %async.actor* %actor) {
370   musttail call swiftcc void @asyncReturn(i8* %async.ctxt, %async.task* %task, %async.actor* %actor)
371   ret void
374 define swiftcc void @multiple_coro_end_async(i8* %async.ctxt, %async.task* %task, %async.actor* %actor)  {
375 entry:
376   %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
377           i8* bitcast (<{i32, i32}>* @dont_crash_on_cf_fp to i8*))
378   %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
379   %arg0 = bitcast %async.task* %task to i8*
380   %arg1 = bitcast <{ i32, i32}>* @my_other_async_function_fp to i8*
381   %callee_context = call i8* @llvm.coro.async.context.alloc(i8* %arg0, i8* %arg1)
382         %callee_context.0 = bitcast i8* %callee_context to %async.ctxt*
383   %callee_context.return_to_caller.addr = getelementptr inbounds %async.ctxt, %async.ctxt* %callee_context.0, i32 0, i32 1
384   %return_to_caller.addr = bitcast void(i8*, %async.task*, %async.actor*)** %callee_context.return_to_caller.addr to i8**
385   %resume.func_ptr = call i8* @llvm.coro.async.resume()
386   store i8* %resume.func_ptr, i8** %return_to_caller.addr
387   %callee_context.caller_context.addr = getelementptr inbounds %async.ctxt, %async.ctxt* %callee_context.0, i32 0, i32 0
388   store i8* %async.ctxt, i8** %callee_context.caller_context.addr
389   %resume_proj_fun = bitcast i8*(i8*)* @resume_context_projection to i8*
390   %callee = bitcast void(i8*, %async.task*, %async.actor*)* @asyncSuspend to i8*
391   %res = call {i8*, i8*, i8*} (i32, i8*, i8*, ...) @llvm.coro.suspend.async(i32 0,
392                                                   i8* %resume.func_ptr,
393                                                   i8* %resume_proj_fun,
394                                                   void (i8*, i8*, %async.task*, %async.actor*)* @dont_crash_on_cf_dispatch,
395                                                   i8* %callee, i8* %callee_context, %async.task* %task, %async.actor *%actor)
397   call void @llvm.coro.async.context.dealloc(i8* %callee_context)
398   %continuation_task_arg = extractvalue {i8*, i8*, i8*} %res, 1
399   %task.2 =  bitcast i8* %continuation_task_arg to %async.task*
400   %eq = icmp eq i8 * %continuation_task_arg, null
401   br i1 %eq, label %is_equal, label %is_not_equal
403 is_equal:
404   tail call swiftcc void @asyncReturn(i8* %async.ctxt, %async.task* %task.2, %async.actor* %actor)
405   call i1 (i8*, i1, ...) @llvm.coro.end.async(i8* %hdl, i1 0)
406   unreachable
408 is_not_equal:
409   call i1 (i8*, i1, ...) @llvm.coro.end.async(
410                            i8* %hdl, i1 0,
411                            void (i8*, %async.task*, %async.actor*)* @must_tail_call_return,
412                            i8* %async.ctxt, %async.task* %task.2, %async.actor* null)
413   unreachable
416 ; CHECK-LABEL: define internal swiftcc void @multiple_coro_end_async.resume.0(
417 ; CHECK: musttail call swiftcc void @asyncReturn(
418 ; CHECK: ret void
420 @polymorphic_suspend_return_fp = constant <{ i32, i32 }>
421   <{ i32 trunc ( ; Relative pointer to async function
422        i64 sub (
423          i64 ptrtoint (void (i8*, %async.task*, %async.actor*)* @polymorphic_suspend_return to i64),
424          i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32 }>, <{ i32, i32 }>* @polymorphic_suspend_return_fp, i32 0, i32 1) to i64)
425        )
426      to i32),
427      i32 64    ; Initial async context size without space for frame
430 define swiftcc void @polymorphic_suspend_return(i8* swiftasync %async.ctxt, %async.task* %task, %async.actor* %actor)  {
431 entry:
432   %tmp = alloca { i64, i64 }, align 8
433   %proj.1 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %tmp, i64 0, i32 0
434   %proj.2 = getelementptr inbounds { i64, i64 }, { i64, i64 }* %tmp, i64 0, i32 1
436   %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
437           i8* bitcast (<{i32, i32}>* @polymorphic_suspend_return_fp to i8*))
438   %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
439   store i64 0, i64* %proj.1, align 8
440   store i64 1, i64* %proj.2, align 8
441   call void @some_may_write(i64* %proj.1)
443         ; Begin lowering: apply %my_other_async_function(%args...)
445   ; setup callee context
446   %arg0 = bitcast %async.task* %task to i8*
447   %arg1 = bitcast <{ i32, i32}>* @my_other_async_function_fp to i8*
448   %callee_context = call i8* @llvm.coro.async.context.alloc(i8* %arg0, i8* %arg1)
449         %callee_context.0 = bitcast i8* %callee_context to %async.ctxt*
450   ; store arguments ...
451   ; ... (omitted)
453   ; store the return continuation
454   %callee_context.return_to_caller.addr = getelementptr inbounds %async.ctxt, %async.ctxt* %callee_context.0, i32 0, i32 1
455   %return_to_caller.addr = bitcast void(i8*, %async.task*, %async.actor*)** %callee_context.return_to_caller.addr to i8**
456   %resume.func_ptr = call i8* @llvm.coro.async.resume()
457   store i8* %resume.func_ptr, i8** %return_to_caller.addr
459   ; store caller context into callee context
460   %callee_context.caller_context.addr = getelementptr inbounds %async.ctxt, %async.ctxt* %callee_context.0, i32 0, i32 0
461   store i8* %async.ctxt, i8** %callee_context.caller_context.addr
462   %resume_proj_fun = bitcast i8*(i8*)* @resume_context_projection to i8*
463   %callee = bitcast void(i8*, %async.task*, %async.actor*)* @asyncSuspend to i8*
464   %res = call {i8*, i8*, i8*, i8*} (i32, i8*, i8*, ...)
465          @llvm.coro.suspend.async.sl_p0i8p0i8p0i8p0i8s(i32 256, ;; swiftasync at 0 and swiftself at 1 in resume function
466                                                  i8* %resume.func_ptr,
467                                                  i8* %resume_proj_fun,
468                                                  void (i8*, i8*, %async.task*, %async.actor*)* @my_async_function.my_other_async_function_fp.apply,
469                                                  i8* %callee, i8* %callee_context, %async.task* %task, %async.actor *%actor)
471   call void @llvm.coro.async.context.dealloc(i8* %callee_context)
472   %continuation_task_arg = extractvalue {i8*, i8*, i8*, i8*} %res, 3
473   %task.2 =  bitcast i8* %continuation_task_arg to %async.task*
474   %val = load i64, i64* %proj.1
475   call void @some_user(i64 %val)
476   %val.2 = load i64, i64* %proj.2
477   call void @some_user(i64 %val.2)
479   tail call swiftcc void @asyncReturn(i8* %async.ctxt, %async.task* %task.2, %async.actor* %actor)
480   call i1 (i8*, i1, ...) @llvm.coro.end.async(i8* %hdl, i1 0)
481   unreachable
484 ; CHECK-LABEL: define swiftcc void @polymorphic_suspend_return(i8* swiftasync %async.ctxt, %async.task* %task, %async.actor* %actor)
485 ; CHECK-LABEL: define internal swiftcc void @polymorphic_suspend_return.resume.0(i8* {{.*}}swiftasync{{.*}} %0, i8* {{.*}}swiftself{{.*}} %1, i8* {{.*}}%2, i8* {{.*}}%3)
486 ; CHECK: bitcast i8* %3 to %async.task*
487 ; CHECK: }
489 @no_coro_suspend_fp = constant <{ i32, i32 }>
490   <{ i32 trunc ( ; Relative pointer to async function
491        i64 sub (
492          i64 ptrtoint (void (i8*)* @no_coro_suspend to i64),
493          i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32 }>, <{ i32, i32 }>* @no_coro_suspend_fp, i32 0, i32 1) to i64)
494        )
495      to i32),
496      i32 128    ; Initial async context size without space for frame
499 define swiftcc void @no_coro_suspend(i8* %async.ctx) {
500 entry:
501   %some_alloca = alloca i64
502   %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
503           i8* bitcast (<{i32, i32}>* @no_coro_suspend_fp to i8*))
504   %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
505   call void @some_may_write(i64* %some_alloca)
506   call i1 (i8*, i1, ...) @llvm.coro.end.async(i8* %hdl, i1 0)
507   unreachable
510 ; CHECK-LABEL: define swiftcc void @no_coro_suspend
511 ; CHECK:   [[ALLOCA:%.*]] = alloca i64
512 ; CHECK:   call void @some_may_write(i64* {{.*}}[[ALLOCA]])
514 @no_coro_suspend_swifterror_fp = constant <{ i32, i32 }>
515   <{ i32 trunc ( ; Relative pointer to async function
516        i64 sub (
517          i64 ptrtoint (void (i8*)* @no_coro_suspend_swifterror to i64),
518          i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32 }>, <{ i32, i32 }>* @no_coro_suspend_swifterror_fp, i32 0, i32 1) to i64)
519        )
520      to i32),
521      i32 128    ; Initial async context size without space for frame
524 declare void @do_with_swifterror(i64** swifterror)
526 define swiftcc void @no_coro_suspend_swifterror(i8* %async.ctx) {
527 entry:
528   %some_alloca = alloca swifterror i64*
529   %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,
530           i8* bitcast (<{i32, i32}>* @no_coro_suspend_swifterror_fp to i8*))
531   %hdl = call i8* @llvm.coro.begin(token %id, i8* null)
532   store i64* null, i64** %some_alloca, align 8
533   call void @do_with_swifterror(i64** swifterror %some_alloca)
534   call i1 (i8*, i1, ...) @llvm.coro.end.async(i8* %hdl, i1 0)
535   unreachable
538  ; CHECK-LABEL: define swiftcc void @no_coro_suspend_swifterror
539  ; CHECK:  [[ALLOCA:%.*]] = alloca swifterror i64*
540  ; CHECK:   store i64* null, i64** [[ALLOCA]]
541  ; CHECK:   call void @do_with_swifterror(i64** {{.*}}swifterror{{.*}} [[ALLOCA]])
543 declare { i8*, i8*, i8*, i8* } @llvm.coro.suspend.async.sl_p0i8p0i8p0i8p0i8s(i32, i8*, i8*, ...)
544 declare i8* @llvm.coro.prepare.async(i8*)
545 declare token @llvm.coro.id.async(i32, i32, i32, i8*)
546 declare i8* @llvm.coro.begin(token, i8*)
547 declare i1 @llvm.coro.end.async(i8*, i1, ...)
548 declare i1 @llvm.coro.end(i8*, i1)
549 declare {i8*, i8*, i8*} @llvm.coro.suspend.async(i32, i8*, i8*, ...)
550 declare i8* @llvm.coro.async.context.alloc(i8*, i8*)
551 declare void @llvm.coro.async.context.dealloc(i8*)
552 declare swiftcc void @asyncReturn(i8*, %async.task*, %async.actor*)
553 declare swiftcc void @asyncSuspend(i8*, %async.task*, %async.actor*)
554 declare i8* @llvm.coro.async.resume()
555 declare void @llvm.coro.async.size.replace(i8*, i8*)
556 declare i8* @hide(i8*)
558 !llvm.dbg.cu = !{!2}
559 !llvm.module.flags = !{!0}
561 !0 = !{i32 2, !"Debug Info Version", i32 3}
562 ; CHECK: ![[SP1]] = distinct !DISubprogram(name: "my_async_function",
563 ; CHECK-SAME:                              linkageName: "my_async_function",
564 ; CHECK-SAME:                              scopeLine: 1
565 !1 = distinct !DISubprogram(name: "my_async_function",
566                             linkageName: "my_async_function",
567                             scope: !2, file: !3, line: 1, type: !4,
568                             scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2)
569 ; CHECK: ![[SP2]] = distinct !DISubprogram(name: "my_async_function",
570 ; CHECK-SAME:                              linkageName: "my_async_functionTQ0_",
571 ; CHECK-SAME:                              scopeLine: 2
572 !2 = distinct !DICompileUnit(language: DW_LANG_Swift, file: !3, emissionKind: FullDebug)
573 !3 = !DIFile(filename: "/tmp/1.swift", directory: "/")
574 !4 = !DISubroutineType(types: !{})
575 !5 = !DILocation(line: 2, column: 0, scope: !1)
577 ; CHECK: ![[SP3]] = distinct !DISubprogram(name: "my_async_function2",
578 ; CHECK-SAME:                              linkageName: "my_async_function2",
579 ; CHECK-SAME:                              scopeLine: 1
580 !6 = distinct !DISubprogram(name: "my_async_function2",
581                             linkageName: "my_async_function2",
582                             scope: !2, file: !3, line: 1, type: !4,
583                             scopeLine: 1, spFlags: DISPFlagDefinition, unit: !2)
584 ; CHECK: ![[SP4]] = distinct !DISubprogram(name: "my_async_function2",
585 ; CHECK-SAME:                              linkageName: "my_async_function2.resume.0",
586 ; CHECK-SAME:                              scopeLine: 1
587 !7 = !DILexicalBlockFile(scope: !6, file: !8, discriminator: 0)
588 !8 = !DIFile(filename: "/tmp/fake.cpp", directory: "/")
589 !9 = !DILocation(line: 2, column: 0, scope: !7)