1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4 2; RUN: opt < %s -passes='cgscc(coro-split),simplifycfg,early-cse' -S | FileCheck %s 3 4declare ptr @malloc(i64) 5 6%i8.array = type { [100 x i8] } 7declare void @consume.i8.array(ptr) 8 9@testbool = external local_unnamed_addr global i8, align 1 10 11; testval does not contain an explicit lifetime end. We must assume that it may 12; live across suspension. 13define void @HasNoLifetimeEnd() presplitcoroutine { 14; CHECK-LABEL: define void @HasNoLifetimeEnd() { 15; CHECK-NEXT: entry: 16; CHECK-NEXT: [[ID:%.*]] = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr @HasNoLifetimeEnd.resumers) 17; CHECK-NEXT: [[ALLOC:%.*]] = call ptr @malloc(i64 16) 18; CHECK-NEXT: [[VFRAME:%.*]] = call noalias nonnull ptr @llvm.coro.begin(token [[ID]], ptr [[ALLOC]]) 19; CHECK-NEXT: store ptr @HasNoLifetimeEnd.resume, ptr [[VFRAME]], align 8 20; CHECK-NEXT: [[DESTROY_ADDR:%.*]] = getelementptr inbounds nuw [[HASNOLIFETIMEEND_FRAME:%.*]], ptr [[VFRAME]], i32 0, i32 1 21; CHECK-NEXT: store ptr @HasNoLifetimeEnd.destroy, ptr [[DESTROY_ADDR]], align 8 22; CHECK-NEXT: [[INDEX_ADDR1:%.*]] = getelementptr inbounds [[HASNOLIFETIMEEND_FRAME]], ptr [[VFRAME]], i32 0, i32 2 23; CHECK-NEXT: call void @consume.i8.array(ptr [[INDEX_ADDR1]]) 24; CHECK-NEXT: [[INDEX_ADDR2:%.*]] = getelementptr inbounds nuw [[HASNOLIFETIMEEND_FRAME]], ptr [[VFRAME]], i32 0, i32 3 25; CHECK-NEXT: store i1 false, ptr [[INDEX_ADDR2]], align 1 26; CHECK-NEXT: ret void 27; 28entry: 29 %testval = alloca %i8.array 30 %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null) 31 %alloc = call ptr @malloc(i64 16) #3 32 %vFrame = call noalias nonnull ptr @llvm.coro.begin(token %id, ptr %alloc) 33 34 call void @llvm.lifetime.start.p0(i64 100, ptr %testval) 35 call void @consume.i8.array(ptr %testval) 36 37 %save = call token @llvm.coro.save(ptr null) 38 %suspend = call i8 @llvm.coro.suspend(token %save, i1 false) 39 switch i8 %suspend, label %exit [ 40 i8 0, label %await.ready 41 i8 1, label %exit 42 ] 43await.ready: 44 br label %exit 45exit: 46 call i1 @llvm.coro.end(ptr null, i1 false, token none) 47 ret void 48} 49 50define void @LifetimeEndAfterCoroEnd() presplitcoroutine { 51; CHECK-LABEL: define void @LifetimeEndAfterCoroEnd() { 52; CHECK-NEXT: entry: 53; CHECK-NEXT: [[ID:%.*]] = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr @LifetimeEndAfterCoroEnd.resumers) 54; CHECK-NEXT: [[ALLOC:%.*]] = call ptr @malloc(i64 16) 55; CHECK-NEXT: [[VFRAME:%.*]] = call noalias nonnull ptr @llvm.coro.begin(token [[ID]], ptr [[ALLOC]]) 56; CHECK-NEXT: store ptr @LifetimeEndAfterCoroEnd.resume, ptr [[VFRAME]], align 8 57; CHECK-NEXT: [[DESTROY_ADDR:%.*]] = getelementptr inbounds nuw [[LIFETIMEENDAFTERCOROEND_FRAME:%.*]], ptr [[VFRAME]], i32 0, i32 1 58; CHECK-NEXT: store ptr @LifetimeEndAfterCoroEnd.destroy, ptr [[DESTROY_ADDR]], align 8 59; CHECK-NEXT: [[INDEX_ADDR1:%.*]] = getelementptr inbounds [[LIFETIMEENDAFTERCOROEND_FRAME]], ptr [[VFRAME]], i32 0, i32 2 60; CHECK-NEXT: call void @consume.i8.array(ptr [[INDEX_ADDR1]]) 61; CHECK-NEXT: [[INDEX_ADDR2:%.*]] = getelementptr inbounds nuw [[LIFETIMEENDAFTERCOROEND_FRAME]], ptr [[VFRAME]], i32 0, i32 3 62; CHECK-NEXT: store i1 false, ptr [[INDEX_ADDR2]], align 1 63; CHECK-NEXT: ret void 64; 65entry: 66 %testval = alloca %i8.array 67 %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null) 68 %alloc = call ptr @malloc(i64 16) #3 69 %vFrame = call noalias nonnull ptr @llvm.coro.begin(token %id, ptr %alloc) 70 71 call void @llvm.lifetime.start.p0(i64 100, ptr %testval) 72 call void @consume.i8.array(ptr %testval) 73 74 %save = call token @llvm.coro.save(ptr null) 75 %suspend = call i8 @llvm.coro.suspend(token %save, i1 false) 76 switch i8 %suspend, label %exit [ 77 i8 0, label %await.ready 78 i8 1, label %exit 79 ] 80await.ready: 81 br label %exit 82exit: 83 call i1 @llvm.coro.end(ptr null, i1 false, token none) 84 call void @llvm.lifetime.end.p0(i64 100, ptr %testval) 85 ret void 86} 87 88define void @BranchWithoutLifetimeEnd() presplitcoroutine { 89; CHECK-LABEL: define void @BranchWithoutLifetimeEnd() { 90; CHECK-NEXT: entry: 91; CHECK-NEXT: [[ID:%.*]] = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr @BranchWithoutLifetimeEnd.resumers) 92; CHECK-NEXT: [[ALLOC:%.*]] = call ptr @malloc(i64 16) 93; CHECK-NEXT: [[VFRAME:%.*]] = call noalias nonnull ptr @llvm.coro.begin(token [[ID]], ptr [[ALLOC]]) 94; CHECK-NEXT: store ptr @BranchWithoutLifetimeEnd.resume, ptr [[VFRAME]], align 8 95; CHECK-NEXT: [[DESTROY_ADDR:%.*]] = getelementptr inbounds nuw [[BRANCHWITHOUTLIFETIMEEND_FRAME:%.*]], ptr [[VFRAME]], i32 0, i32 1 96; CHECK-NEXT: store ptr @BranchWithoutLifetimeEnd.destroy, ptr [[DESTROY_ADDR]], align 8 97; CHECK-NEXT: [[TESTVAL:%.*]] = getelementptr inbounds [[BRANCHWITHOUTLIFETIMEEND_FRAME]], ptr [[VFRAME]], i32 0, i32 2 98; CHECK-NEXT: call void @consume.i8.array(ptr [[TESTVAL]]) 99; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr @testbool, align 1 100; CHECK-NEXT: [[INDEX_ADDR1:%.*]] = getelementptr inbounds nuw [[BRANCHWITHOUTLIFETIMEEND_FRAME]], ptr [[VFRAME]], i32 0, i32 3 101; CHECK-NEXT: store i1 false, ptr [[INDEX_ADDR1]], align 1 102; CHECK-NEXT: ret void 103; 104entry: 105 %testval = alloca %i8.array 106 %id = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null) 107 %alloc = call ptr @malloc(i64 16) #3 108 %vFrame = call noalias nonnull ptr @llvm.coro.begin(token %id, ptr %alloc) 109 110 call void @llvm.lifetime.start.p0(i64 100, ptr %testval) 111 call void @consume.i8.array(ptr %testval) 112 113 %0 = load i8, ptr @testbool, align 1 114 %tobool = trunc nuw i8 %0 to i1 115 br i1 %tobool, label %if.then, label %if.end 116 117if.then: 118 call void @llvm.lifetime.end.p0(i64 100, ptr %testval) 119 br label %if.end 120 121if.end: 122 %save = call token @llvm.coro.save(ptr null) 123 %suspend = call i8 @llvm.coro.suspend(token %save, i1 false) 124 switch i8 %suspend, label %exit [ 125 i8 0, label %await.ready 126 i8 1, label %exit 127 ] 128await.ready: 129 br label %exit 130exit: 131 call i1 @llvm.coro.end(ptr null, i1 false, token none) 132 ret void 133} 134 135 136declare token @llvm.coro.id(i32, ptr readnone, ptr nocapture readonly, ptr) 137declare ptr @llvm.coro.begin(token, ptr writeonly) #3 138declare ptr @llvm.coro.frame() #5 139declare i8 @llvm.coro.suspend(token, i1) #3 140declare i1 @llvm.coro.end(ptr, i1, token) #3 141declare void @llvm.lifetime.start.p0(i64, ptr nocapture) #4 142declare void @llvm.lifetime.end.p0(i64, ptr nocapture) #4 143