blob: 3539223f2147a09c3ee5a7991e2e185ca49a1377 [file] [log] [blame]
George Burgess IV4deb75d2018-03-10 23:06:31 +00001// 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
9struct S {
10 int ns[40];
11};
12
13struct S foo(void);
14
15// CHECK-LABEL: define dso_local void @bar
16struct 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 %[[R_TMP:[^)]+]])
22
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 // O1: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* nonnull %[[R_TMP]])
39 return r;
40}
41
42struct S foo_int(int);
43
44// Be sure that we're placing the lifetime.end so that all paths go through it.
45// Since this function turns out to be large-ish, optnone to hopefully keep it
46// stable.
47// CHECK-LABEL: define dso_local void @baz
48__attribute__((optnone))
49struct S baz(int i, volatile int *j) {
50 // O0-NOT: @llvm.lifetime.start
51 // O0-NOT: @llvm.lifetime.end
52
53 struct S r;
54 // O1: %[[RESULT_ALLOCA:[^ ]+]] = alloca %struct.S
55 // O1: %[[TMP1_ALLOCA:[^ ]+]] = alloca %struct.S
56 // O1: %[[TMP2_ALLOCA:[^ ]+]] = alloca %struct.S
57 // O1: %[[P:[^ ]+]] = bitcast %struct.S* %[[RESULT_ALLOCA]] to i8*
58 // O1: call void @llvm.lifetime.start.p0i8({{[^,]*}}, i8* %[[P]])
59 // O1: br label %[[DO_BODY:.+]]
60
61 do {
62 // O1: [[DO_BODY]]:
63 // O1: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP1_ALLOCA]] to i8*
64 // O1: call void @llvm.lifetime.start.p0i8({{[^,]*}}, i8* %[[P]])
65 // O1: br i1 {{[^,]+}}, label %[[IF_THEN:[^,]+]], label %[[IF_END:[^,]+]]
66 //
67 // O1: [[IF_THEN]]:
68 // O1: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP1_ALLOCA]] to i8*
69 // O1: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* %[[P]])
70 // O1: br label %[[DO_END:.*]]
71 //
72 // O1: [[IF_END]]:
73 // O1: call void @foo_int(%struct.S* sret %[[TMP1_ALLOCA]],
74 // O1: call void @llvm.memcpy
75 // O1: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP1_ALLOCA]] to i8*
76 // O1: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* %[[P]])
77 // O1: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP2_ALLOCA]] to i8*
78 // O1: call void @llvm.lifetime.start.p0i8({{[^,]*}}, i8* %[[P]])
79 // O1: call void @foo_int(%struct.S* sret %[[TMP2_ALLOCA]],
80 // O1: call void @llvm.memcpy
81 // O1: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP2_ALLOCA]] to i8*
82 // O1: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* %[[P]])
83 // O1: br label %[[DO_COND:.*]]
84 //
85 // O1: [[DO_COND]]:
86 // O1: br label %[[DO_BODY]]
87 r = foo_int(({
88 if (*j)
89 break;
90 i++;
91 }));
92
93 r = foo_int(i++);
94 } while (1);
95
96 // O1: [[DO_END]]:
97 // O1: call void @llvm.memcpy
98 // O1: %[[P:[^ ]+]] = bitcast %struct.S* %[[RESULT_ALLOCA]] to i8*
99 // O1: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* %[[P]])
100 return r;
101}