1 | // Make sure it works on x86-64. |
2 | // RUN: %clang_cc1 -triple x86_64-apple-darwin11 -fobjc-runtime=macosx-10.11 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-UNOPTIMIZED |
3 | |
4 | // Make sure it works on x86-32. |
5 | // RUN: %clang_cc1 -triple i386-apple-darwin11 -fobjc-runtime=macosx-fragile-10.11 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-UNOPTIMIZED -check-prefix=CHECK-MARKED |
6 | |
7 | // Make sure it works on ARM. |
8 | // RUN: %clang_cc1 -triple arm64-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-UNOPTIMIZED -check-prefix=CHECK-MARKED |
9 | // RUN: %clang_cc1 -triple arm64-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -O -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-OPTIMIZED |
10 | |
11 | // Make sure it works on ARM64. |
12 | // RUN: %clang_cc1 -triple armv7-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-UNOPTIMIZED -check-prefix=CHECK-MARKED |
13 | // RUN: %clang_cc1 -triple armv7-apple-ios9 -fobjc-runtime=ios-9.0 -fobjc-arc -O -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-OPTIMIZED |
14 | |
15 | // Make sure that it's implicitly disabled if the runtime version isn't high enough. |
16 | // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-10.10 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=DISABLED |
17 | // RUN: %clang_cc1 -triple arm64-apple-ios8 -fobjc-runtime=ios-8 -fobjc-arc -emit-llvm -o - %s | FileCheck %s -check-prefix=DISABLED -check-prefix=DISABLED-MARKED |
18 | |
19 | @class A; |
20 | |
21 | A *makeA(void); |
22 | |
23 | void test_assign() { |
24 | __unsafe_unretained id x; |
25 | x = makeA(); |
26 | } |
27 | // CHECK-LABEL: define void @test_assign() |
28 | // CHECK: [[X:%.*]] = alloca i8* |
29 | // CHECK: [[T0:%.*]] = call [[A:.*]]* @makeA() |
30 | // CHECK-MARKED-NEXT: call void asm sideeffect |
31 | // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8* |
32 | // CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) |
33 | // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]* |
34 | // CHECK-NEXT: [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8* |
35 | // CHECK-NEXT: store i8* [[T4]], i8** [[X]] |
36 | // CHECK-OPTIMIZED-NEXT: bitcast |
37 | // CHECK-OPTIMIZED-NEXT: lifetime.end |
38 | // CHECK-NEXT: ret void |
39 | |
40 | // DISABLED-LABEL: define void @test_assign() |
41 | // DISABLED: [[T0:%.*]] = call [[A:.*]]* @makeA() |
42 | // DISABLED-MARKED-NEXT: call void asm sideeffect |
43 | // DISABLED-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8* |
44 | // DISABLED-NEXT: [[T2:%.*]] = {{.*}}call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* [[T1]]) |
45 | |
46 | void test_assign_assign() { |
47 | __unsafe_unretained id x, y; |
48 | x = y = makeA(); |
49 | } |
50 | // CHECK-LABEL: define void @test_assign_assign() |
51 | // CHECK: [[X:%.*]] = alloca i8* |
52 | // CHECK: [[Y:%.*]] = alloca i8* |
53 | // CHECK: [[T0:%.*]] = call [[A]]* @makeA() |
54 | // CHECK-MARKED-NEXT: call void asm sideeffect |
55 | // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8* |
56 | // CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) |
57 | // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]* |
58 | // CHECK-NEXT: [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8* |
59 | // CHECK-NEXT: store i8* [[T4]], i8** [[Y]] |
60 | // CHECK-NEXT: store i8* [[T4]], i8** [[X]] |
61 | // CHECK-OPTIMIZED-NEXT: bitcast |
62 | // CHECK-OPTIMIZED-NEXT: lifetime.end |
63 | // CHECK-OPTIMIZED-NEXT: bitcast |
64 | // CHECK-OPTIMIZED-NEXT: lifetime.end |
65 | // CHECK-NEXT: ret void |
66 | |
67 | void test_strong_assign_assign() { |
68 | __strong id x; |
69 | __unsafe_unretained id y; |
70 | x = y = makeA(); |
71 | } |
72 | // CHECK-LABEL: define void @test_strong_assign_assign() |
73 | // CHECK: [[X:%.*]] = alloca i8* |
74 | // CHECK: [[Y:%.*]] = alloca i8* |
75 | // CHECK: [[T0:%.*]] = call [[A]]* @makeA() |
76 | // CHECK-MARKED-NEXT: call void asm sideeffect |
77 | // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8* |
78 | // CHECK-NEXT: [[T2:%.*]] = {{.*}}call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* [[T1]]) |
79 | // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]* |
80 | // CHECK-NEXT: [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8* |
81 | // CHECK-NEXT: store i8* [[T4]], i8** [[Y]] |
82 | // CHECK-NEXT: [[OLD:%.*]] = load i8*, i8** [[X]] |
83 | // CHECK-NEXT: store i8* [[T4]], i8** [[X]] |
84 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[OLD]] |
85 | // CHECK-OPTIMIZED-NEXT: bitcast |
86 | // CHECK-OPTIMIZED-NEXT: lifetime.end |
87 | // CHECK-UNOPTIMIZED-NEXT: call void @llvm.objc.storeStrong(i8** [[X]], i8* null) |
88 | // CHECK-OPTIMIZED-NEXT: [[T0:%.*]] = load i8*, i8** [[X]] |
89 | // CHECK-OPTIMIZED-NEXT: call void @llvm.objc.release(i8* [[T0]]) |
90 | // CHECK-OPTIMIZED-NEXT: bitcast |
91 | // CHECK-OPTIMIZED-NEXT: lifetime.end |
92 | // CHECK-NEXT: ret void |
93 | |
94 | void test_assign_strong_assign() { |
95 | __unsafe_unretained id x; |
96 | __strong id y; |
97 | x = y = makeA(); |
98 | } |
99 | // CHECK-LABEL: define void @test_assign_strong_assign() |
100 | // CHECK: [[X:%.*]] = alloca i8* |
101 | // CHECK: [[Y:%.*]] = alloca i8* |
102 | // CHECK: [[T0:%.*]] = call [[A]]* @makeA() |
103 | // CHECK-MARKED-NEXT: call void asm sideeffect |
104 | // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8* |
105 | // CHECK-NEXT: [[T2:%.*]] = {{.*}}call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* [[T1]]) |
106 | // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]* |
107 | // CHECK-NEXT: [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8* |
108 | // CHECK-NEXT: [[OLD:%.*]] = load i8*, i8** [[Y]] |
109 | // CHECK-NEXT: store i8* [[T4]], i8** [[Y]] |
110 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[OLD]] |
111 | // CHECK-NEXT: store i8* [[T4]], i8** [[X]] |
112 | // CHECK-UNOPTIMIZED-NEXT: call void @llvm.objc.storeStrong(i8** [[Y]], i8* null) |
113 | // CHECK-OPTIMIZED-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]] |
114 | // CHECK-OPTIMIZED-NEXT: call void @llvm.objc.release(i8* [[T0]]) |
115 | // CHECK-OPTIMIZED-NEXT: bitcast |
116 | // CHECK-OPTIMIZED-NEXT: lifetime.end |
117 | // CHECK-OPTIMIZED-NEXT: bitcast |
118 | // CHECK-OPTIMIZED-NEXT: lifetime.end |
119 | // CHECK-NEXT: ret void |
120 | |
121 | void test_init() { |
122 | __unsafe_unretained id x = makeA(); |
123 | } |
124 | // CHECK-LABEL: define void @test_init() |
125 | // CHECK: [[X:%.*]] = alloca i8* |
126 | // CHECK: [[T0:%.*]] = call [[A]]* @makeA() |
127 | // CHECK-MARKED-NEXT: call void asm sideeffect |
128 | // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8* |
129 | // CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) |
130 | // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]* |
131 | // CHECK-NEXT: [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8* |
132 | // CHECK-NEXT: store i8* [[T4]], i8** [[X]] |
133 | // CHECK-OPTIMIZED-NEXT: bitcast |
134 | // CHECK-OPTIMIZED-NEXT: lifetime.end |
135 | // CHECK-NEXT: ret void |
136 | |
137 | void test_init_assignment() { |
138 | __unsafe_unretained id x; |
139 | __unsafe_unretained id y = x = makeA(); |
140 | } |
141 | // CHECK-LABEL: define void @test_init_assignment() |
142 | // CHECK: [[X:%.*]] = alloca i8* |
143 | // CHECK: [[Y:%.*]] = alloca i8* |
144 | // CHECK: [[T0:%.*]] = call [[A]]* @makeA() |
145 | // CHECK-MARKED-NEXT: call void asm sideeffect |
146 | // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8* |
147 | // CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) |
148 | // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]* |
149 | // CHECK-NEXT: [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8* |
150 | // CHECK-NEXT: store i8* [[T4]], i8** [[X]] |
151 | // CHECK-NEXT: store i8* [[T4]], i8** [[Y]] |
152 | // CHECK-OPTIMIZED-NEXT: bitcast |
153 | // CHECK-OPTIMIZED-NEXT: lifetime.end |
154 | // CHECK-OPTIMIZED-NEXT: bitcast |
155 | // CHECK-OPTIMIZED-NEXT: lifetime.end |
156 | // CHECK-NEXT: ret void |
157 | |
158 | void test_strong_init_assignment() { |
159 | __unsafe_unretained id x; |
160 | __strong id y = x = makeA(); |
161 | } |
162 | // CHECK-LABEL: define void @test_strong_init_assignment() |
163 | // CHECK: [[X:%.*]] = alloca i8* |
164 | // CHECK: [[Y:%.*]] = alloca i8* |
165 | // CHECK: [[T0:%.*]] = call [[A]]* @makeA() |
166 | // CHECK-MARKED-NEXT: call void asm sideeffect |
167 | // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8* |
168 | // CHECK-NEXT: [[T2:%.*]] = {{.*}}call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* [[T1]]) |
169 | // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]* |
170 | // CHECK-NEXT: [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8* |
171 | // CHECK-NEXT: store i8* [[T4]], i8** [[X]] |
172 | // CHECK-NEXT: store i8* [[T4]], i8** [[Y]] |
173 | // CHECK-UNOPTIMIZED-NEXT: call void @llvm.objc.storeStrong(i8** [[Y]], i8* null) |
174 | // CHECK-OPTIMIZED-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]] |
175 | // CHECK-OPTIMIZED-NEXT: call void @llvm.objc.release(i8* [[T0]]) |
176 | // CHECK-OPTIMIZED-NEXT: bitcast |
177 | // CHECK-OPTIMIZED-NEXT: lifetime.end |
178 | // CHECK-OPTIMIZED-NEXT: bitcast |
179 | // CHECK-OPTIMIZED-NEXT: lifetime.end |
180 | // CHECK-NEXT: ret void |
181 | |
182 | void test_init_strong_assignment() { |
183 | __strong id x; |
184 | __unsafe_unretained id y = x = makeA(); |
185 | } |
186 | // CHECK-LABEL: define void @test_init_strong_assignment() |
187 | // CHECK: [[X:%.*]] = alloca i8* |
188 | // CHECK: [[Y:%.*]] = alloca i8* |
189 | // CHECK: [[T0:%.*]] = call [[A]]* @makeA() |
190 | // CHECK-MARKED-NEXT: call void asm sideeffect |
191 | // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8* |
192 | // CHECK-NEXT: [[T2:%.*]] = {{.*}}call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* [[T1]]) |
193 | // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[A]]* |
194 | // CHECK-NEXT: [[T4:%.*]] = bitcast [[A]]* [[T3]] to i8* |
195 | // CHECK-NEXT: [[OLD:%.*]] = load i8*, i8** [[X]] |
196 | // CHECK-NEXT: store i8* [[T4]], i8** [[X]] |
197 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[OLD]]) |
198 | // CHECK-NEXT: store i8* [[T4]], i8** [[Y]] |
199 | // CHECK-OPTIMIZED-NEXT: bitcast |
200 | // CHECK-OPTIMIZED-NEXT: lifetime.end |
201 | // CHECK-UNOPTIMIZED-NEXT: call void @llvm.objc.storeStrong(i8** [[X]], i8* null) |
202 | // CHECK-OPTIMIZED-NEXT: [[T0:%.*]] = load i8*, i8** [[X]] |
203 | // CHECK-OPTIMIZED-NEXT: call void @llvm.objc.release(i8* [[T0]]) |
204 | // CHECK-OPTIMIZED-NEXT: bitcast |
205 | // CHECK-OPTIMIZED-NEXT: lifetime.end |
206 | // CHECK-NEXT: ret void |
207 | |
208 | void test_ignored() { |
209 | makeA(); |
210 | } |
211 | // CHECK-LABEL: define void @test_ignored() |
212 | // CHECK: [[T0:%.*]] = call [[A]]* @makeA() |
213 | // CHECK-MARKED-NEXT: call void asm sideeffect |
214 | // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8* |
215 | // CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) |
216 | // CHECK-NEXT: bitcast i8* [[T2]] to [[A]]* |
217 | // CHECK-NEXT: ret void |
218 | |
219 | void test_cast_to_void() { |
220 | (void) makeA(); |
221 | } |
222 | // CHECK-LABEL: define void @test_cast_to_void() |
223 | // CHECK: [[T0:%.*]] = call [[A]]* @makeA() |
224 | // CHECK-MARKED-NEXT: call void asm sideeffect |
225 | // CHECK-NEXT: [[T1:%.*]] = bitcast [[A]]* [[T0]] to i8* |
226 | // CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.unsafeClaimAutoreleasedReturnValue(i8* [[T1]]) |
227 | // CHECK-NEXT: bitcast i8* [[T2]] to [[A]]* |
228 | // CHECK-NEXT: ret void |
229 | |
230 | |
231 | |
232 | // This is always at the end of the module. |
233 | |
234 | // CHECK-OPTIMIZED: !clang.arc.retainAutoreleasedReturnValueMarker = !{!0} |
235 | |