Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / clang / test / CodeGenObjC / arc-precise-lifetime.m
blob473c0b031f9f9dea7a086b2c52dab7348f820fdf
1 // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-passes -o - %s | FileCheck %s
3 #define PRECISE_LIFETIME __attribute__((objc_precise_lifetime))
5 id test0_helper(void) __attribute__((ns_returns_retained));
6 void test0(void) {
7   PRECISE_LIFETIME id x = test0_helper();
8   x = 0;
9   // CHECK:      [[X:%.*]] = alloca ptr
10   // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[X]])
11   // CHECK-NEXT: [[CALL:%.*]] = call ptr @test0_helper()
12   // CHECK-NEXT: store ptr [[CALL]], ptr [[X]]
14   // CHECK-NEXT: [[T1:%.*]] = load ptr, ptr [[X]]
15   // CHECK-NEXT: store ptr null, ptr [[X]]
16   // CHECK-NEXT: call void @llvm.objc.release(ptr [[T1]]) [[NUW:#[0-9]+]]
17   // CHECK-NOT:  clang.imprecise_release
19   // CHECK-NEXT: [[T1:%.*]] = load ptr, ptr [[X]]
20   // CHECK-NEXT: call void @llvm.objc.release(ptr [[T1]]) [[NUW:#[0-9]+]]
21   // CHECK-NOT:  clang.imprecise_release
23   // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[X]])
24   // CHECK-NEXT: ret void
27 // precise lifetime should suppress extension
28 // should work for calls via property syntax, too
29 @interface Test1
30 - (char*) interior __attribute__((objc_returns_inner_pointer));
31 // Should we allow this on properties? Yes!
32 @property (nonatomic, readonly) char * PropertyReturnsInnerPointer __attribute__((objc_returns_inner_pointer));
33 @end
34 extern Test1 *test1_helper(void);
36 // CHECK-LABEL: define{{.*}} void @test1a_message()
37 void test1a_message(void) {
38   // CHECK:      [[PTR:%.*]] = alloca ptr, align 8
39   // CHECK:      [[C:%.*]] = alloca ptr, align 8
40   // CHECK:      call void @llvm.lifetime.start.p0(i64 8, ptr [[PTR]])
41   // CHECK:      [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
42   // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])
43   // CHECK-NEXT: store ptr [[T0]]
44   // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[C]])
45   // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
46   // CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainAutorelease(ptr [[T0]])
47   // CHECK-NEXT: [[T4:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_
48   // CHECK-NEXT: [[T6:%.*]] = call ptr
49   // CHECK-NEXT: store ptr [[T6]], ptr
50   // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[C]])
51   // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
52   // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]], !clang.imprecise_release
53   // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PTR]])
54   // CHECK-NEXT: ret void
55   Test1 *ptr = test1_helper();
56   char *c = [(ptr) interior];
60 // CHECK-LABEL: define{{.*}} void @test1a_property()
61 void test1a_property(void) {
62   // CHECK:      [[PTR:%.*]] = alloca ptr, align 8
63   // CHECK:      [[C:%.*]] = alloca ptr, align 8
64   // CHECK:      call void @llvm.lifetime.start.p0(i64 8, ptr [[PTR]])
65   // CHECK:      [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
66   // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])
67   // CHECK-NEXT: store ptr [[T0]]
68   // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[C]])
69   // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
70   // CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainAutorelease(ptr [[T0]])
71   // CHECK-NEXT: [[T4:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_
72   // CHECK-NEXT: [[T6:%.*]] = call ptr
73   // CHECK-NEXT: store ptr [[T6]], ptr
74   // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[C]])
75   // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
76   // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]], !clang.imprecise_release
77   // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PTR]])
78   // CHECK-NEXT: ret void
79   Test1 *ptr = test1_helper();
80   char *c = ptr.interior;
84 // CHECK-LABEL: define{{.*}} void @test1b_message()
85 void test1b_message(void) {
86   // CHECK:      [[PTR:%.*]] = alloca ptr, align 8
87   // CHECK:      [[C:%.*]] = alloca ptr, align 8
88   // CHECK:      call void @llvm.lifetime.start.p0(i64 8, ptr [[PTR]])
89   // CHECK:      [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
90   // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])
91   // CHECK-NEXT: store ptr [[T0]]
92   // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[C]])
93   // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
94   // CHECK-NEXT: [[T1:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_
95   // CHECK-NEXT: [[T3:%.*]] = call ptr
96   // CHECK-NEXT: store ptr [[T3]], ptr
97   // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[C]])
98   // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
99   // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]]
100   // CHECK-NOT:  clang.imprecise_release
101   // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PTR]])
102   // CHECK-NEXT: ret void
103   PRECISE_LIFETIME Test1 *ptr = test1_helper();
104   char *c = [ptr interior];
107 // CHECK-LABEL: define{{.*}} void @test1b_property()
108 void test1b_property(void) {
109   // CHECK:      [[PTR:%.*]] = alloca ptr, align 8
110   // CHECK:      [[C:%.*]] = alloca ptr, align 8
111   // CHECK:      call void @llvm.lifetime.start.p0(i64 8, ptr [[PTR]])
112   // CHECK:      [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
113   // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])
114   // CHECK-NEXT: store ptr [[T0]]
115   // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[C]])
116   // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
117   // CHECK-NEXT: [[T1:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_
118   // CHECK-NEXT: [[T3:%.*]] = call ptr
119   // CHECK-NEXT: store ptr [[T3]], ptr
120   // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[C]])
121   // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
122   // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]]
123   // CHECK-NOT:  clang.imprecise_release
124   // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PTR]])
125   // CHECK-NEXT: ret void
126   PRECISE_LIFETIME Test1 *ptr = test1_helper();
127   char *c = ptr.interior;
130 // CHECK-LABEL: define{{.*}} void @test1c_message()
131 void test1c_message(void) {
132   // CHECK:      [[PTR:%.*]] = alloca ptr, align 8
133   // CHECK:      [[PC:%.*]] = alloca ptr, align 8
134   // CHECK:      call void @llvm.lifetime.start.p0(i64 8, ptr [[PTR]])
135   // CHECK:      [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
136   // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])
137   // CHECK-NEXT: store ptr [[T0]]
138   // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[PC]])
139   // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
140   // CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainAutorelease(ptr [[T0]])
141   // CHECK-NEXT: [[T4:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_
142   // CHECK-NEXT: [[T6:%.*]] = call ptr
143   // CHECK-NEXT: store ptr [[T6]], ptr
144   // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PC]])
145   // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
146   // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]], !clang.imprecise_release
147   // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PTR]])
148   // CHECK-NEXT: ret void
149   Test1 *ptr = test1_helper();
150   char *pc = [ptr PropertyReturnsInnerPointer];
153 // CHECK-LABEL: define{{.*}} void @test1c_property()
154 void test1c_property(void) {
155   // CHECK:      [[PTR:%.*]] = alloca ptr, align 8
156   // CHECK:      [[PC:%.*]] = alloca ptr, align 8
157   // CHECK:      call void @llvm.lifetime.start.p0(i64 8, ptr [[PTR]])
158   // CHECK:      [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
159   // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])
160   // CHECK-NEXT: store ptr [[T0]]
161   // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[PC]])
162   // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
163   // CHECK-NEXT: [[T2:%.*]] = call ptr @llvm.objc.retainAutorelease(ptr [[T0]])
164   // CHECK-NEXT: [[T4:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_
165   // CHECK-NEXT: [[T6:%.*]] = call ptr
166   // CHECK-NEXT: store ptr [[T6]], ptr
167   // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PC]])
168   // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
169   // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]], !clang.imprecise_release
170   // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PTR]])
171   // CHECK-NEXT: ret void
172   Test1 *ptr = test1_helper();
173   char *pc = ptr.PropertyReturnsInnerPointer;
176 // CHECK-LABEL: define{{.*}} void @test1d_message()
177 void test1d_message(void) {
178   // CHECK:      [[PTR:%.*]] = alloca ptr, align 8
179   // CHECK:      [[PC:%.*]] = alloca ptr, align 8
180   // CHECK:      call void @llvm.lifetime.start.p0(i64 8, ptr [[PTR]])
181   // CHECK:      [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
182   // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])
183   // CHECK-NEXT: store ptr [[T0]]
184   // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[PC]])
185   // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
186   // CHECK-NEXT: [[SEL:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_
187   // CHECK-NEXT: [[CALL1:%.*]] = call ptr @objc_msgSend(ptr noundef [[T0]], ptr noundef [[SEL]])
188   // CHECK-NEXT: store ptr [[CALL1]], ptr
189   // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PC]])
190   // CHECK-NEXT: [[NINE:%.*]] = load ptr, ptr
191   // CHECK-NEXT: call void @llvm.objc.release(ptr [[NINE]])
192   // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PTR]])
193   // CHECK-NEXT: ret void
194   PRECISE_LIFETIME Test1 *ptr = test1_helper();
195   char *pc = [ptr PropertyReturnsInnerPointer];
198 // CHECK-LABEL: define{{.*}} void @test1d_property()
199 void test1d_property(void) {
200   // CHECK:      [[PTR:%.*]] = alloca ptr, align 8
201   // CHECK:      [[PC:%.*]] = alloca ptr, align 8
202   // CHECK:      call void @llvm.lifetime.start.p0(i64 8, ptr [[PTR]])
203   // CHECK:      [[T0:%.*]] = call ptr @test1_helper() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
204   // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.noop.use(ptr [[T0]])
205   // CHECK-NEXT: store ptr [[T0]]
206   // CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr [[PC]])
207   // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr
208   // CHECK-NEXT: [[SEL:%.*]] = load ptr, ptr @OBJC_SELECTOR_REFERENCES_
209   // CHECK-NEXT: [[CALL1:%.*]] = call ptr @objc_msgSend(ptr noundef [[T0]], ptr noundef [[SEL]])
210   // CHECK-NEXT: store ptr [[CALL1]], ptr
211   // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PC]])
212   // CHECK-NEXT: [[NINE:%.*]] = load ptr, ptr
213   // CHECK-NEXT: call void @llvm.objc.release(ptr [[NINE]])
214   // CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr [[PTR]])
215   // CHECK-NEXT: ret void
216   PRECISE_LIFETIME Test1 *ptr = test1_helper();
217   char *pc = ptr.PropertyReturnsInnerPointer;
220 @interface Test2 {
221 @public
222   id ivar;
224 @end
225 // CHECK-LABEL:      define{{.*}} void @test2(
226 void test2(Test2 *x) {
227   x->ivar = 0;
228   // CHECK:      [[X:%.*]] = alloca ptr
229   // CHECK-NEXT: [[T1:%.*]] = call ptr @llvm.objc.retain(ptr {{%.*}}) [[NUW]]
230   // CHECK-NEXT: store ptr [[T1]], ptr [[X]],
232   // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]],
233   // CHECK-NEXT: [[OFFSET:%.*]] = load i64, ptr @"OBJC_IVAR_$_Test2.ivar"
234   // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds i8, ptr [[T0]], i64 [[OFFSET]]
235   // CHECK-NEXT: [[T4:%.*]] = load ptr, ptr [[T2]],
236   // CHECK-NEXT: store ptr null, ptr [[T2]],
237   // CHECK-NEXT: call void @llvm.objc.release(ptr [[T4]]) [[NUW]]
238   // CHECK-NOT:  imprecise
240   // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]]
241   // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]], !clang.imprecise_release
243   // CHECK-NEXT: ret void
246 // CHECK-LABEL:      define{{.*}} void @test3(ptr
247 void test3(PRECISE_LIFETIME id x) {
248   // CHECK:      [[X:%.*]] = alloca ptr,
249   // CHECK-NEXT: [[T0:%.*]] = call ptr @llvm.objc.retain(ptr {{%.*}}) [[NUW]]
250   // CHECK-NEXT: store ptr [[T0]], ptr [[X]],
252   // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[X]]
253   // CHECK-NEXT: call void @llvm.objc.release(ptr [[T0]]) [[NUW]]
254   // CHECK-NOT:  imprecise_release
256   // CHECK-NEXT: ret void  
259 // CHECK: attributes [[NUW]] = { nounwind }