1; RUN: opt < %s -passes='cgscc(coro-split),simplifycfg,early-cse' -S | FileCheck %s 2 3%"struct.std::coroutine_handle" = type { ptr } 4%"struct.std::coroutine_handle.0" = type { %"struct.std::coroutine_handle" } 5%"struct.lean_future<int>::Awaiter" = type { i32, %"struct.std::coroutine_handle.0" } 6 7declare ptr @malloc(i64) 8 9%i8.array = type { [100 x i8] } 10declare void @consume.i8.array(ptr) 11 12; The lifetime of testval starts and ends before coro.suspend. Even though consume.i8.array 13; might capture it, we can safely say it won't live across suspension. 14define void @foo() presplitcoroutine { 15entry: 16 %testval = alloca %i8.array 17 %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null) 18 %alloc = call ptr @malloc(i64 16) #3 19 %vFrame = call noalias nonnull ptr @llvm.coro.begin(token %id, ptr %alloc) 20 21 call void @llvm.lifetime.start.p0(i64 100, ptr %testval) 22 call void @consume.i8.array(ptr %testval) 23 call void @llvm.lifetime.end.p0(i64 100, ptr %testval) 24 25 %save = call token @llvm.coro.save(ptr null) 26 %suspend = call i8 @llvm.coro.suspend(token %save, i1 false) 27 switch i8 %suspend, label %exit [ 28 i8 0, label %await.ready 29 i8 1, label %exit 30 ] 31await.ready: 32 %StrayCoroSave = call token @llvm.coro.save(ptr null) 33 br label %exit 34exit: 35 call i1 @llvm.coro.end(ptr null, i1 false, token none) 36 ret void 37} 38 39; The lifetime of testval starts after coro.suspend. So it will never live across suspension 40; points. 41define void @bar() presplitcoroutine { 42entry: 43 %testval = alloca %i8.array 44 %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null) 45 %alloc = call ptr @malloc(i64 16) #3 46 %vFrame = call noalias nonnull ptr @llvm.coro.begin(token %id, ptr %alloc) 47 %save = call token @llvm.coro.save(ptr null) 48 %suspend = call i8 @llvm.coro.suspend(token %save, i1 false) 49 switch i8 %suspend, label %exit [ 50 i8 0, label %await.ready 51 i8 1, label %exit 52 ] 53await.ready: 54 %StrayCoroSave = call token @llvm.coro.save(ptr null) 55 56 call void @llvm.lifetime.start.p0(i64 100, ptr %testval) 57 call void @consume.i8.array(ptr %testval) 58 call void @llvm.lifetime.end.p0(i64 100, ptr %testval) 59 60 br label %exit 61exit: 62 call i1 @llvm.coro.end(ptr null, i1 false, token none) 63 ret void 64} 65 66; Verify that for both foo and bar, testval isn't put on the frame. 67; CHECK: %foo.Frame = type { ptr, ptr, i1 } 68; CHECK: %bar.Frame = type { ptr, ptr, i1 } 69 70declare token @llvm.coro.id(i32, ptr readnone, ptr nocapture readonly, ptr) 71declare i1 @llvm.coro.alloc(token) #3 72declare i64 @llvm.coro.size.i64() #5 73declare ptr @llvm.coro.begin(token, ptr writeonly) #3 74declare token @llvm.coro.save(ptr) #3 75declare ptr @llvm.coro.frame() #5 76declare i8 @llvm.coro.suspend(token, i1) #3 77declare ptr @llvm.coro.free(token, ptr nocapture readonly) #2 78declare i1 @llvm.coro.end(ptr, i1, token) #3 79declare void @llvm.lifetime.start.p0(i64, ptr nocapture) #4 80declare void @llvm.lifetime.end.p0(i64, ptr nocapture) #4 81