110 lines · plain
1; RUN: opt < %s -O0 -S | FileCheck --check-prefixes=CHECK %s2 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@my_async_function_fp = constant <{ i32, i32 }>16 <{ i32 trunc ( ; Relative pointer to async function17 i64 sub (18 i64 ptrtoint (ptr @my_async_function to i64),19 i64 ptrtoint (ptr getelementptr inbounds (<{ i32, i32 }>, ptr @my_async_function_fp, i32 0, i32 1) to i64)20 )21 to i32),22 i32 128 ; Initial async context size without space for frame23}>24 25define swiftcc void @my_other_async_function_fp.apply(ptr %fnPtr, ptr %async.ctxt) {26 tail call swiftcc void %fnPtr(ptr %async.ctxt)27 ret void28}29 30declare void @escape(ptr)31declare void @store_resume(ptr)32declare i1 @exitLoop()33define ptr @resume_context_projection(ptr %ctxt) {34entry:35 %resume_ctxt = load ptr, ptr %ctxt, align 836 ret ptr %resume_ctxt37}38 39define swiftcc void @my_async_function(ptr swiftasync %async.ctxt) {40entry:41 %escaped_addr = alloca i6442 43 %id = call token @llvm.coro.id.async(i32 128, i32 16, i32 0,44 ptr @my_async_function_fp)45 %hdl = call ptr @llvm.coro.begin(token %id, ptr null)46 call void @llvm.lifetime.start.p0(ptr %escaped_addr)47 br label %callblock48 49 50callblock:51 52 %callee_context = call ptr @context_alloc()53 54 %resume.func_ptr = call ptr @llvm.coro.async.resume()55 call void @store_resume(ptr %resume.func_ptr)56 %res = call {ptr, ptr, ptr} (i32, ptr, ptr, ...) @llvm.coro.suspend.async(i32 0,57 ptr %resume.func_ptr,58 ptr @resume_context_projection,59 ptr @my_other_async_function_fp.apply,60 ptr @asyncSuspend, ptr %callee_context)61 call void @escape(ptr %escaped_addr)62 %exitCond = call i1 @exitLoop()63 64;; We used to move the lifetime.start intrinsic here =>65;; This exposes two bugs:66; 1.) The code should use the basic block start not end as insertion point67; More problematically:68; 2.) The code marks the stack object as not alive for part of the loop.69 70 br i1 %exitCond, label %loop_exit, label %loop71 %res2 = call {ptr, ptr, ptr} (i32, ptr, ptr, ...) @llvm.coro.suspend.async(i32 0,72 ptr %resume.func_ptr,73 ptr @resume_context_projection,74 ptr @my_other_async_function_fp.apply,75 ptr @asyncSuspend, ptr %callee_context)76 77 %exitCond2 = call i1 @exitLoop()78 br i1 %exitCond2, label %loop_exit, label %loop79 80loop:81 br label %callblock82 83loop_exit:84 call void @llvm.lifetime.end.p0(ptr %escaped_addr)85 call void (ptr, i1, ...) @llvm.coro.end.async(ptr %hdl, i1 false)86 unreachable87}88 89; CHECK: define {{.*}} void @my_async_function.resume.0(90; CHECK-NOT: llvm.lifetime91; CHECK: br i1 %exitCond, label %common.ret, label %loop92; CHECK-NOT: llvm.lifetime93; CHECK: }94 95declare { ptr, ptr, ptr, ptr } @llvm.coro.suspend.async.sl_p0i8p0i8p0i8p0i8s(i32, ptr, ptr, ...)96declare ptr @llvm.coro.prepare.async(ptr)97declare token @llvm.coro.id.async(i32, i32, i32, ptr)98declare ptr @llvm.coro.begin(token, ptr)99declare void @llvm.coro.end.async(ptr, i1, ...)100declare void @llvm.coro.end(ptr, i1, token)101declare {ptr, ptr, ptr} @llvm.coro.suspend.async(i32, ptr, ptr, ...)102declare ptr @context_alloc()103declare void @llvm.coro.async.context.dealloc(ptr)104declare swiftcc void @asyncSuspend(ptr)105declare ptr @llvm.coro.async.resume()106declare void @llvm.coro.async.size.replace(ptr, ptr)107declare void @llvm.lifetime.start.p0(ptr nocapture) #0108declare void @llvm.lifetime.end.p0(ptr nocapture) #0109attributes #0 = { argmemonly nofree nosync nounwind willreturn }110