1; Tests that coro-split will optimize the lifetime.start maker of each local variable, 2; sink them to the places after the suspend block. 3; RUN: opt < %s -passes='cgscc(coro-split),simplifycfg,early-cse,simplifycfg' -S | FileCheck %s 4 5; CHECK: %a.Frame = type { ptr, ptr, i1 } 6; CHECK: %a_optnone.Frame = type { ptr, ptr, i32, i1 } 7 8%"struct.std::coroutine_handle" = type { ptr } 9%"struct.std::coroutine_handle.0" = type { %"struct.std::coroutine_handle" } 10%"struct.lean_future<int>::Awaiter" = type { i32, %"struct.std::coroutine_handle.0" } 11 12declare ptr @malloc(i64) 13declare void @print(i32) 14 15define void @a() presplitcoroutine { 16entry: 17 %ref.tmp7 = alloca %"struct.lean_future<int>::Awaiter", align 8 18 %testval = alloca i32 19 ; lifetime of %testval starts here, but not used until await.ready. 20 call void @llvm.lifetime.start.p0(i64 4, ptr %testval) 21 %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null) 22 %alloc = call ptr @malloc(i64 16) #3 23 %vFrame = call noalias nonnull ptr @llvm.coro.begin(token %id, ptr %alloc) 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 %val = load i32, ptr %ref.tmp7 34 %test = load i32, ptr %testval 35 call void @print(i32 %test) 36 call void @llvm.lifetime.end.p0(i64 4, ptr %testval) 37 call void @print(i32 %val) 38 br label %exit 39exit: 40 call i1 @llvm.coro.end(ptr null, i1 false, token none) 41 ret void 42} 43 44; CHECK-LABEL: @a.resume( 45; CHECK: %testval = alloca i32, align 4 46; CHECK: call void @llvm.lifetime.start.p0(i64 4, ptr %testval) 47; CHECK-NEXT: %val = load i32, ptr %ref.tmp7 48; CHECK-NEXT: %test = load i32, ptr %testval 49; CHECK-NEXT: call void @print(i32 %test) 50; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr %testval) 51; CHECK-NEXT: call void @print(i32 %val) 52; CHECK-NEXT: ret void 53 54define void @a_optnone() presplitcoroutine optnone noinline { 55entry: 56 %ref.tmp7 = alloca %"struct.lean_future<int>::Awaiter", align 8 57 %testval = alloca i32 58 ; lifetime of %testval starts here, but not used until await.ready. 59 call void @llvm.lifetime.start.p0(i64 4, ptr %testval) 60 %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null) 61 %alloc = call ptr @malloc(i64 16) #3 62 %vFrame = call noalias nonnull ptr @llvm.coro.begin(token %id, ptr %alloc) 63 64 %save = call token @llvm.coro.save(ptr null) 65 %suspend = call i8 @llvm.coro.suspend(token %save, i1 false) 66 switch i8 %suspend, label %exit [ 67 i8 0, label %await.ready 68 i8 1, label %exit 69 ] 70await.ready: 71 %StrayCoroSave = call token @llvm.coro.save(ptr null) 72 %val = load i32, ptr %ref.tmp7 73 %test = load i32, ptr %testval 74 call void @print(i32 %test) 75 call void @llvm.lifetime.end.p0(i64 4, ptr %testval) 76 call void @print(i32 %val) 77 br label %exit 78exit: 79 call i1 @llvm.coro.end(ptr null, i1 false, token none) 80 ret void 81} 82 83declare token @llvm.coro.id(i32, ptr readnone, ptr nocapture readonly, ptr) 84declare i1 @llvm.coro.alloc(token) #3 85declare noalias nonnull ptr @"\01??2@YAPEAX_K@Z"(i64) local_unnamed_addr 86declare i64 @llvm.coro.size.i64() #5 87declare ptr @llvm.coro.begin(token, ptr writeonly) #3 88declare void @"\01?puts@@YAXZZ"(...) 89declare token @llvm.coro.save(ptr) #3 90declare ptr @llvm.coro.frame() #5 91declare i8 @llvm.coro.suspend(token, i1) #3 92declare void @"\01??3@YAXPEAX@Z"(ptr) local_unnamed_addr #10 93declare ptr @llvm.coro.free(token, ptr nocapture readonly) #2 94declare i1 @llvm.coro.end(ptr, i1, token) #3 95declare void @llvm.lifetime.start.p0(i64, ptr nocapture) #4 96declare void @llvm.lifetime.end.p0(i64, ptr nocapture) #4 97