1 ; RUN: opt -objc-arc -S < %s | FileCheck %s
3 target datalayout = "e-p:64:64:64"
5 declare i8* @objc_retain(i8*)
6 declare i8* @objc_retainAutoreleasedReturnValue(i8*)
7 declare void @objc_release(i8*)
8 declare i8* @objc_autorelease(i8*)
9 declare i8* @objc_autoreleaseReturnValue(i8*)
10 declare i8* @objc_retainAutoreleaseReturnValue(i8*)
11 declare void @objc_autoreleasePoolPop(i8*)
12 declare void @objc_autoreleasePoolPush()
13 declare i8* @objc_retainBlock(i8*)
15 declare i8* @objc_retainedObject(i8*)
16 declare i8* @objc_unretainedObject(i8*)
17 declare i8* @objc_unretainedPointer(i8*)
19 declare void @use_pointer(i8*)
20 declare void @callee()
21 declare void @callee_fnptr(void ()*)
22 declare void @invokee()
23 declare i8* @returner()
25 ; Test that retain+release elimination is suppressed when the
26 ; retain is an objc_retainAutoreleasedReturnValue, since it's
27 ; better to do the RV optimization.
29 ; CHECK-LABEL: define void @test0(
31 ; CHECK-NEXT: %x = call i8* @returner
32 ; CHECK-NEXT: %0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %x) [[NUW:#[0-9]+]]
36 ; CHECK-NEXT: call void @objc_release(i8* %x)
37 ; CHECK-NEXT: ret void
39 define void @test0(i1 %p) nounwind {
41 %x = call i8* @returner()
42 %0 = call i8* @objc_retainAutoreleasedReturnValue(i8* %x)
43 br i1 %p, label %t, label %return
46 call void @use_pointer(i8* %x)
51 call void @objc_release(i8* %x) nounwind
57 ; CHECK-LABEL: define void @test2(
60 define void @test2() {
61 call i8* @objc_retainAutoreleasedReturnValue(i8* null)
62 call i8* @objc_autoreleaseReturnValue(i8* null)
63 ; call i8* @objc_retainAutoreleaseReturnValue(i8* null) ; TODO
67 ; Delete a redundant retainRV,autoreleaseRV when forwaring a call result
68 ; directly to a return value.
70 ; CHECK-LABEL: define i8* @test3(
71 ; CHECK: call i8* @returner()
72 ; CHECK-NEXT: ret i8* %call
75 %call = call i8* @returner()
76 %0 = call i8* @objc_retainAutoreleasedReturnValue(i8* %call) nounwind
77 %1 = call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind
81 ; Delete a redundant retain,autoreleaseRV when forwaring a call result
82 ; directly to a return value.
84 ; CHECK-LABEL: define i8* @test4(
85 ; CHECK: call i8* @returner()
86 ; CHECK-NEXT: ret i8* %call
89 %call = call i8* @returner()
90 %0 = call i8* @objc_retain(i8* %call) nounwind
91 %1 = call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind
95 ; Delete a redundant fused retain+autoreleaseRV when forwaring a call result
96 ; directly to a return value.
99 ; HECK: define i8* @test5
100 ; HECK: call i8* @returner()
101 ; HECK-NEXT: ret i8* %call
102 ;define i8* @test5() {
104 ; %call = call i8* @returner()
105 ; %0 = call i8* @objc_retainAutoreleaseReturnValue(i8* %call) nounwind
109 ; Don't eliminate objc_retainAutoreleasedReturnValue by merging it into
110 ; an objc_autorelease.
111 ; TODO? Merge objc_retainAutoreleasedReturnValue and objc_autorelease into
112 ; objc_retainAutoreleasedReturnValueAutorelease and merge
113 ; objc_retainAutoreleasedReturnValue and objc_autoreleaseReturnValue
114 ; into objc_retainAutoreleasedReturnValueAutoreleaseReturnValue?
115 ; Those entrypoints don't exist yet though.
117 ; CHECK-LABEL: define i8* @test7(
118 ; CHECK: call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
119 ; CHECK: %t = tail call i8* @objc_autoreleaseReturnValue(i8* %p)
120 define i8* @test7() {
121 %p = call i8* @returner()
122 call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
123 %t = call i8* @objc_autoreleaseReturnValue(i8* %p)
124 call void @use_pointer(i8* %p)
128 ; CHECK-LABEL: define i8* @test7b(
129 ; CHECK: call i8* @objc_retain(i8* %p)
130 ; CHECK: %t = tail call i8* @objc_autoreleaseReturnValue(i8* %p)
131 define i8* @test7b() {
132 %p = call i8* @returner()
133 call void @use_pointer(i8* %p)
134 call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
135 %t = call i8* @objc_autoreleaseReturnValue(i8* %p)
139 ; Don't apply the RV optimization to autorelease if there's no retain.
141 ; CHECK: define i8* @test9(i8* %p)
142 ; CHECK: call i8* @objc_autorelease(i8* %p)
143 define i8* @test9(i8* %p) {
144 call i8* @objc_autorelease(i8* %p)
148 ; Do not apply the RV optimization.
150 ; CHECK: define i8* @test10(i8* %p)
151 ; CHECK: tail call i8* @objc_retain(i8* %p) [[NUW]]
152 ; CHECK: call i8* @objc_autorelease(i8* %p) [[NUW]]
153 ; CHECK-NEXT: ret i8* %p
154 define i8* @test10(i8* %p) {
155 %1 = call i8* @objc_retain(i8* %p)
156 %2 = call i8* @objc_autorelease(i8* %p)
160 ; Don't do the autoreleaseRV optimization because @use_pointer
161 ; could undo the retain.
163 ; CHECK: define i8* @test11(i8* %p)
164 ; CHECK: tail call i8* @objc_retain(i8* %p)
165 ; CHECK-NEXT: call void @use_pointer(i8* %p)
166 ; CHECK: call i8* @objc_autorelease(i8* %p)
167 ; CHECK-NEXT: ret i8* %p
168 define i8* @test11(i8* %p) {
169 %1 = call i8* @objc_retain(i8* %p)
170 call void @use_pointer(i8* %p)
171 %2 = call i8* @objc_autorelease(i8* %p)
175 ; Don't spoil the RV optimization.
177 ; CHECK: define i8* @test12(i8* %p)
178 ; CHECK: tail call i8* @objc_retain(i8* %p)
179 ; CHECK: call void @use_pointer(i8* %p)
180 ; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %p)
182 define i8* @test12(i8* %p) {
183 %1 = call i8* @objc_retain(i8* %p)
184 call void @use_pointer(i8* %p)
185 %2 = call i8* @objc_autoreleaseReturnValue(i8* %p)
189 ; Don't zap the objc_retainAutoreleasedReturnValue.
191 ; CHECK-LABEL: define i8* @test13(
192 ; CHECK: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
193 ; CHECK: call i8* @objc_autorelease(i8* %p)
195 define i8* @test13() {
196 %p = call i8* @returner()
197 %1 = call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
199 %2 = call i8* @objc_autorelease(i8* %p)
203 ; Convert objc_retainAutoreleasedReturnValue to objc_retain if its
204 ; argument is not a return value.
206 ; CHECK-LABEL: define void @test14(
207 ; CHECK-NEXT: tail call i8* @objc_retain(i8* %p) [[NUW]]
208 ; CHECK-NEXT: ret void
209 define void @test14(i8* %p) {
210 call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
214 ; Don't convert objc_retainAutoreleasedReturnValue to objc_retain if its
215 ; argument is a return value.
217 ; CHECK-LABEL: define void @test15(
218 ; CHECK-NEXT: %y = call i8* @returner()
219 ; CHECK-NEXT: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %y) [[NUW]]
220 ; CHECK-NEXT: ret void
221 define void @test15() {
222 %y = call i8* @returner()
223 call i8* @objc_retainAutoreleasedReturnValue(i8* %y)
227 ; Delete autoreleaseRV+retainRV pairs.
229 ; CHECK: define i8* @test19(i8* %p) {
230 ; CHECK-NEXT: ret i8* %p
231 define i8* @test19(i8* %p) {
232 call i8* @objc_autoreleaseReturnValue(i8* %p)
233 call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
237 ; Like test19 but with plain autorelease.
239 ; CHECK: define i8* @test20(i8* %p) {
240 ; CHECK-NEXT: call i8* @objc_autorelease(i8* %p)
241 ; CHECK-NEXT: call i8* @objc_retain(i8* %p)
242 ; CHECK-NEXT: ret i8* %p
243 define i8* @test20(i8* %p) {
244 call i8* @objc_autorelease(i8* %p)
245 call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
249 ; Like test19 but with plain retain.
251 ; CHECK: define i8* @test21(i8* %p) {
252 ; CHECK-NEXT: call i8* @objc_autoreleaseReturnValue(i8* %p)
253 ; CHECK-NEXT: call i8* @objc_retain(i8* %p)
254 ; CHECK-NEXT: ret i8* %p
255 define i8* @test21(i8* %p) {
256 call i8* @objc_autoreleaseReturnValue(i8* %p)
257 call i8* @objc_retain(i8* %p)
261 ; Like test19 but with plain retain and autorelease.
263 ; CHECK: define i8* @test22(i8* %p) {
264 ; CHECK-NEXT: call i8* @objc_autorelease(i8* %p)
265 ; CHECK-NEXT: call i8* @objc_retain(i8* %p)
266 ; CHECK-NEXT: ret i8* %p
267 define i8* @test22(i8* %p) {
268 call i8* @objc_autorelease(i8* %p)
269 call i8* @objc_retain(i8* %p)
273 ; Convert autoreleaseRV to autorelease.
275 ; CHECK-LABEL: define void @test23(
276 ; CHECK: call i8* @objc_autorelease(i8* %p) [[NUW]]
277 define void @test23(i8* %p) {
279 call i8* @objc_autoreleaseReturnValue(i8* %p)
283 ; Don't convert autoreleaseRV to autorelease if the result is returned,
284 ; even through a bitcast.
286 ; CHECK-LABEL: define {}* @test24(
287 ; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %p)
288 define {}* @test24(i8* %p) {
289 %t = call i8* @objc_autoreleaseReturnValue(i8* %p)
290 %s = bitcast i8* %p to {}*
294 ; CHECK: attributes [[NUW]] = { nounwind }