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*)* }
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
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)
27 i32 128 ; Initial async context size without space for frame
29 @my_async_function_pa_fp = constant <{ i32, i32 }>
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)
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)
46 declare void @some_user(i64)
47 declare void @some_may_write(i64*)
49 define i8* @__swift_async_resume_project_context(i8* %ctxt) {
51 %resume_ctxt_addr = bitcast i8* %ctxt to i8**
52 %resume_ctxt = load i8*, i8** %resume_ctxt_addr, align 8
56 define i8* @resume_context_projection(i8* %ctxt) {
58 %resume_ctxt_addr = bitcast i8* %ctxt to i8**
59 %resume_ctxt = load i8*, i8** %resume_ctxt_addr, align 8
64 define swiftcc void @my_async_function(i8* swiftasync %async.ctxt, %async.task* %task, %async.actor* %actor) !dbg !1 {
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*
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)
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)
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)
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]])
196 @my_async_function2_fp = constant <{ i32, i32 }>
197 <{ i32 trunc ( ; Relative pointer to async function
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)
203 i32 128 ; Initial async context size without space for frame
206 define swiftcc void @my_async_function2(%async.task* %task, %async.actor* %actor, i8* %async.ctxt) "frame-pointer"="all" !dbg !6 {
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)
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)
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]]
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]])
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)
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
304 @dont_crash_on_cf_fp = constant <{ i32, i32 }>
305 <{ i32 trunc ( ; Relative pointer to async function
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)
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
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)
328 define swiftcc void @dont_crash_on_cf(i8* %async.ctxt, %async.task* %task, %async.actor* %actor) {
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)
359 @multiple_coro_end_async_fp = constant <{ i32, i32 }>
360 <{ i32 trunc ( ; Relative pointer to async function
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)
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)
374 define swiftcc void @multiple_coro_end_async(i8* %async.ctxt, %async.task* %task, %async.actor* %actor) {
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
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)
409 call i1 (i8*, i1, ...) @llvm.coro.end.async(
411 void (i8*, %async.task*, %async.actor*)* @must_tail_call_return,
412 i8* %async.ctxt, %async.task* %task.2, %async.actor* null)
416 ; CHECK-LABEL: define internal swiftcc void @multiple_coro_end_async.resume.0(
417 ; CHECK: musttail call swiftcc void @asyncReturn(
420 @polymorphic_suspend_return_fp = constant <{ i32, i32 }>
421 <{ i32 trunc ( ; Relative pointer to async function
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)
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) {
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 ...
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)
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*
489 @no_coro_suspend_fp = constant <{ i32, i32 }>
490 <{ i32 trunc ( ; Relative pointer to async function
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)
496 i32 128 ; Initial async context size without space for frame
499 define swiftcc void @no_coro_suspend(i8* %async.ctx) {
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)
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
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)
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) {
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)
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*)
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)