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