1// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-optzns -o - %s | FileCheck %s
2
3#define PRECISE_LIFETIME __attribute__((objc_precise_lifetime))
4
5id test0_helper(void) __attribute__((ns_returns_retained));
6void test0() {
7  PRECISE_LIFETIME id x = test0_helper();
8  x = 0;
9  // CHECK:      [[X:%.*]] = alloca i8*
10  // CHECK-NEXT: [[XPTR1:%.*]] = bitcast i8** [[X]] to i8*
11  // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[XPTR1]])
12  // CHECK-NEXT: [[CALL:%.*]] = call i8* @test0_helper()
13  // CHECK-NEXT: store i8* [[CALL]], i8** [[X]]
14
15  // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[X]]
16  // CHECK-NEXT: store i8* null, i8** [[X]]
17  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW:#[0-9]+]]
18  // CHECK-NOT:  clang.imprecise_release
19
20  // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[X]]
21  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW:#[0-9]+]]
22  // CHECK-NOT:  clang.imprecise_release
23
24  // CHECK-NEXT: [[XPTR2:%.*]] = bitcast i8** [[X]] to i8*
25  // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[XPTR2]])
26  // CHECK-NEXT: ret void
27}
28
29// rdar://problem/9821110
30@interface Test1
31- (char*) interior __attribute__((objc_returns_inner_pointer));
32// Should we allow this on properties? Yes! see // rdar://14990439
33@property (nonatomic, readonly) char * PropertyReturnsInnerPointer __attribute__((objc_returns_inner_pointer));
34@end
35extern Test1 *test1_helper(void);
36
37// CHECK-LABEL: define void @test1a()
38void test1a(void) {
39  // CHECK:      [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
40  // CHECK:      [[C:%.*]] = alloca i8*, align 8
41  // CHECK:      [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
42  // CHECK:      call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]])
43  // CHECK:      [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
44  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
45  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
46  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
47  // CHECK-NEXT: store [[TEST1]]* [[T3]]
48  // CHECK-NEXT: [[CPTR1:%.*]] = bitcast i8** [[C]] to i8*
49  // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[CPTR1]])
50  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
51  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
52  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
53  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
54  // CHECK-NEXT: [[T4:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
55  // CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST1]]* [[T3]] to i8*
56  // CHECK-NEXT: [[T6:%.*]] = call i8* bitcast
57  // CHECK-NEXT: store i8* [[T6]], i8**
58  // CHECK-NEXT: [[CPTR2:%.*]] = bitcast i8** [[C]] to i8*
59  // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[CPTR2]])
60  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
61  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
62  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
63  // CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
64  // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
65  // CHECK-NEXT: ret void
66  Test1 *ptr = test1_helper();
67  char *c = [(ptr) interior];
68}
69
70// CHECK-LABEL: define void @test1b()
71void test1b(void) {
72  // CHECK:      [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
73  // CHECK:      [[C:%.*]] = alloca i8*, align 8
74  // CHECK:      [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
75  // CHECK:      call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]])
76  // CHECK:      [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
77  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
78  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
79  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
80  // CHECK-NEXT: store [[TEST1]]* [[T3]]
81  // CHECK-NEXT: [[CPTR1:%.*]] = bitcast i8** [[C]] to i8*
82  // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[CPTR1]])
83  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
84  // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
85  // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
86  // CHECK-NEXT: [[T3:%.*]] = call i8* bitcast
87  // CHECK-NEXT: store i8* [[T3]], i8**
88  // CHECK-NEXT: [[CPTR2:%.*]] = bitcast i8** [[C]] to i8*
89  // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[CPTR2]])
90  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
91  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
92  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]]
93  // CHECK-NOT:  clang.imprecise_release
94  // CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
95  // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
96  // CHECK-NEXT: ret void
97  __attribute__((objc_precise_lifetime)) Test1 *ptr = test1_helper();
98  char *c = [ptr interior];
99}
100
101void test1c(void) {
102  // CHECK:      [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
103  // CHECK:      [[PC:%.*]] = alloca i8*, align 8
104  // CHECK:      [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
105  // CHECK:      call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]])
106  // CHECK:      [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
107  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
108  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
109  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
110  // CHECK-NEXT: store [[TEST1]]* [[T3]]
111  // CHECK-NEXT: [[PCPTR1:%.*]] = bitcast i8** [[PC]] to i8*
112  // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[PCPTR1]])
113  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
114  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
115  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutorelease(i8* [[T1]])
116  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
117  // CHECK-NEXT: [[T4:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
118  // CHECK-NEXT: [[T5:%.*]] = bitcast [[TEST1]]* [[T3]] to i8*
119  // CHECK-NEXT: [[T6:%.*]] = call i8* bitcast
120  // CHECK-NEXT: store i8* [[T6]], i8**
121  // CHECK-NEXT: [[PCPTR2:%.*]] = bitcast i8** [[PC]] to i8*
122  // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PCPTR2]])
123  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
124  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
125  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
126  // CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
127  // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
128  // CHECK-NEXT: ret void
129  Test1 *ptr = test1_helper();
130  char *pc = ptr.PropertyReturnsInnerPointer;
131}
132
133void test1d(void) {
134  // CHECK:      [[PTR:%.*]] = alloca [[PTR_T:%.*]]*, align 8
135  // CHECK:      [[PC:%.*]] = alloca i8*, align 8
136  // CHECK:      [[PTRPTR1:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
137  // CHECK:      call void @llvm.lifetime.start(i64 8, i8* [[PTRPTR1]])
138  // CHECK:      [[T0:%.*]] = call [[TEST1:%.*]]* @test1_helper()
139  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
140  // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T1]])
141  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[TEST1]]*
142  // CHECK-NEXT: store [[TEST1]]* [[T3]]
143  // CHECK-NEXT: [[PCPTR1:%.*]] = bitcast i8** [[PC]] to i8*
144  // CHECK-NEXT: call void @llvm.lifetime.start(i64 8, i8* [[PCPTR1]])
145  // CHECK-NEXT: [[T0:%.*]] = load [[TEST1]]*, [[TEST1]]**
146  // CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST1]]* [[T0]] to i8*
147  // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retainAutorelease
148  // CHECK-NEXT: [[SIX:%.*]] = bitcast i8* [[T3]] to [[TEST1]]*
149  // CHECK-NEXT: [[SEVEN:%.*]] = load i8*, i8** @OBJC_SELECTOR_REFERENCES_
150  // CHECK-NEXT: [[EIGHT:%.*]] = bitcast [[TEST1]]* [[SIX]] to i8*
151  // CHECK-NEXT: [[CALL1:%.*]] = call i8* bitcast (i8* (i8*, i8*, ...)* @objc_msgSend to i8* (i8*, i8*)*)(i8* [[EIGHT]], i8* [[SEVEN]])
152  // CHECK-NEXT: store i8* [[CALL1]], i8**
153  // CHECK-NEXT: [[PCPTR2:%.*]] = bitcast i8** [[PC]] to i8*
154  // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PCPTR2]])
155  // CHECK-NEXT: [[NINE:%.*]] = load [[TEST1]]*, [[TEST1]]**
156  // CHECK-NEXT: [[TEN:%.*]] = bitcast [[TEST1]]* [[NINE]] to i8*
157  // CHECK-NEXT: call void @objc_release(i8* [[TEN]])
158  // CHECK-NEXT: [[PTRPTR2:%.*]] = bitcast [[PTR_T]]** [[PTR]] to i8*
159  // CHECK-NEXT: call void @llvm.lifetime.end(i64 8, i8* [[PTRPTR2]])
160  // CHECK-NEXT: ret void
161  __attribute__((objc_precise_lifetime)) Test1 *ptr = test1_helper();
162  char *pc = ptr.PropertyReturnsInnerPointer;
163}
164
165@interface Test2 {
166@public
167  id ivar;
168}
169@end
170// CHECK-LABEL:      define void @test2(
171void test2(Test2 *x) {
172  x->ivar = 0;
173  // CHECK:      [[X:%.*]] = alloca [[TEST2:%.*]]*
174  // CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST2]]* {{%.*}} to i8*
175  // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) [[NUW]]
176  // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[TEST2]]*
177  // CHECK-NEXT: store [[TEST2]]* [[T2]], [[TEST2]]** [[X]],
178
179  // CHECK-NEXT: [[T0:%.*]] = load [[TEST2]]*, [[TEST2]]** [[X]],
180  // CHECK-NEXT: [[OFFSET:%.*]] = load i64, i64* @"OBJC_IVAR_$_Test2.ivar"
181  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST2]]* [[T0]] to i8*
182  // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds i8, i8* [[T1]], i64 [[OFFSET]]
183  // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i8**
184  // CHECK-NEXT: [[T4:%.*]] = load i8*, i8** [[T3]],
185  // CHECK-NEXT: store i8* null, i8** [[T3]],
186  // CHECK-NEXT: call void @objc_release(i8* [[T4]]) [[NUW]]
187  // CHECK-NOT:  imprecise
188
189  // CHECK-NEXT: [[T0:%.*]] = load [[TEST2]]*, [[TEST2]]** [[X]]
190  // CHECK-NEXT: [[T1:%.*]] = bitcast [[TEST2]]* [[T0]] to i8*
191  // CHECK-NEXT: call void @objc_release(i8* [[T1]]) [[NUW]], !clang.imprecise_release
192
193  // CHECK-NEXT: ret void
194}
195
196// CHECK-LABEL:      define void @test3(i8*
197void test3(PRECISE_LIFETIME id x) {
198  // CHECK:      [[X:%.*]] = alloca i8*,
199  // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* {{%.*}}) [[NUW]]
200  // CHECK-NEXT: store i8* [[T0]], i8** [[X]],
201
202  // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[X]]
203  // CHECK-NEXT: call void @objc_release(i8* [[T0]]) [[NUW]]
204  // CHECK-NOT:  imprecise_release
205
206  // CHECK-NEXT: ret void
207}
208
209// CHECK: attributes [[NUW]] = { nounwind }
210