1 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O1 -S -emit-llvm -o - %s | FileCheck %s --check-prefix=O1 2 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O0 -S -emit-llvm -o - %s | FileCheck %s --check-prefix=O0 3 // 4 // Ensure that we place appropriate lifetime markers around indirectly returned 5 // temporaries, and that the lifetime.ends appear in a timely manner. 6 // 7 // -O1 is used so lifetime markers actually get emitted. 8 9 struct S { 10 int ns[40]; 11 }; 12 13 struct S foo(void); 14 15 // CHECK-LABEL: define dso_local void @bar 16 struct S bar() { 17 // O0-NOT: @llvm.lifetime.start 18 // O0-NOT: @llvm.lifetime.end 19 20 struct S r; 21 // O1: call void @llvm.lifetime.start.p0i8({{[^,]*}}, i8* nonnull %[[TMP1:[^)]+]]) 22 // O1: call void @foo 23 r = foo(); 24 // O1: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* nonnull %[[TMP1]]) 25 26 // O1: call void @llvm.lifetime.start.p0i8({{[^,]*}}, i8* nonnull %[[TMP2:[^)]+]]) 27 // O1: call void @foo 28 r = foo(); 29 // O1: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* nonnull %[[TMP2]]) 30 31 // O1: call void @llvm.lifetime.start.p0i8({{[^,]*}}, i8* nonnull %[[TMP3:[^)]+]]) 32 // O1: call void @foo 33 r = foo(); 34 // O1: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* nonnull %[[TMP3]]) 35 36 return r; 37 } 38 39 struct S foo_int(int); 40 41 // Be sure that we're placing the lifetime.end so that all paths go through it. 42 // Since this function turns out to be large-ish, optnone to hopefully keep it 43 // stable. 44 // CHECK-LABEL: define dso_local void @baz 45 __attribute__((optnone)) 46 struct S baz(int i, volatile int *j) { 47 // O0-NOT: @llvm.lifetime.start 48 // O0-NOT: @llvm.lifetime.end 49 50 struct S r; 51 // O1: %[[TMP1_ALLOCA:[^ ]+]] = alloca %struct.S 52 // O1: %[[TMP2_ALLOCA:[^ ]+]] = alloca %struct.S 53 // O1: br label %[[DO_BODY:.+]] 54 55 do { 56 // O1: [[DO_BODY]]: 57 // O1: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP1_ALLOCA]] to i8* 58 // O1: call void @llvm.lifetime.start.p0i8({{[^,]*}}, i8* %[[P]]) 59 // O1: br i1 {{[^,]+}}, label %[[IF_THEN:[^,]+]], label %[[IF_END:[^,]+]] 60 // 61 // O1: [[IF_THEN]]: 62 // O1: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP1_ALLOCA]] to i8* 63 // O1: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* %[[P]]) 64 // O1: br label %[[DO_END:.*]] 65 // 66 // O1: [[IF_END]]: 67 // O1: call void @foo_int(%struct.S* sret %[[TMP1_ALLOCA]], 68 // O1: call void @llvm.memcpy 69 // O1: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP1_ALLOCA]] to i8* 70 // O1: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* %[[P]]) 71 // O1: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP2_ALLOCA]] to i8* 72 // O1: call void @llvm.lifetime.start.p0i8({{[^,]*}}, i8* %[[P]]) 73 // O1: call void @foo_int(%struct.S* sret %[[TMP2_ALLOCA]], 74 // O1: call void @llvm.memcpy 75 // O1: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP2_ALLOCA]] to i8* 76 // O1: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* %[[P]]) 77 // O1: br label %[[DO_COND:.*]] 78 // 79 // O1: [[DO_COND]]: 80 // O1: br label %[[DO_BODY]] 81 r = foo_int(({ 82 if (*j) 83 break; 84 i++; 85 })); 86 87 r = foo_int(i++); 88 } while (1); 89 90 // O1: [[DO_END]]: 91 // O1-NEXT: ret void 92 return r; 93 } 94