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