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: define void @test0(
31 ; CHECK-NEXT: %x = call i8* @returner
32 ; CHECK-NEXT: %0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %x) nounwind
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: 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: 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: 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: 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* %t)
128 ; CHECK: 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 ; Turn objc_retain into objc_retainAutoreleasedReturnValue if its operand
142 ; CHECK: define void @test8()
143 ; CHECK: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
144 define void @test8() {
145 %p = call i8* @returner()
146 call i8* @objc_retain(i8* %p)
150 ; Don't apply the RV optimization to autorelease if there's no retain.
152 ; CHECK: define i8* @test9(i8* %p)
153 ; CHECK: tail call i8* @objc_autorelease(i8* %p)
154 define i8* @test9(i8* %p) {
155 call i8* @objc_autorelease(i8* %p)
159 ; Apply the RV optimization.
161 ; CHECK: define i8* @test10(i8* %p)
162 ; CHECK: tail call i8* @objc_retain(i8* %p) nounwind
163 ; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %p) nounwind
164 ; CHECK-NEXT: ret i8* %p
165 define i8* @test10(i8* %p) {
166 %1 = call i8* @objc_retain(i8* %p)
167 %2 = call i8* @objc_autorelease(i8* %p)
171 ; Don't do the autoreleaseRV optimization because @use_pointer
172 ; could undo the retain.
174 ; CHECK: define i8* @test11(i8* %p)
175 ; CHECK: tail call i8* @objc_retain(i8* %p)
176 ; CHECK-NEXT: call void @use_pointer(i8* %p)
177 ; CHECK: tail call i8* @objc_autorelease(i8* %p)
178 ; CHECK-NEXT: ret i8* %p
179 define i8* @test11(i8* %p) {
180 %1 = call i8* @objc_retain(i8* %p)
181 call void @use_pointer(i8* %p)
182 %2 = call i8* @objc_autorelease(i8* %p)
186 ; Don't spoil the RV optimization.
188 ; CHECK: define i8* @test12(i8* %p)
189 ; CHECK: tail call i8* @objc_retain(i8* %p)
190 ; CHECK: call void @use_pointer(i8* %p)
191 ; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %p)
193 define i8* @test12(i8* %p) {
194 %1 = call i8* @objc_retain(i8* %p)
195 call void @use_pointer(i8* %p)
196 %2 = call i8* @objc_autoreleaseReturnValue(i8* %p)
200 ; Don't zap the objc_retainAutoreleasedReturnValue.
202 ; CHECK: define i8* @test13(
203 ; CHECK: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
204 ; CHECK: tail call i8* @objc_autorelease(i8* %p)
206 define i8* @test13() {
207 %p = call i8* @returner()
208 %1 = call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
210 %2 = call i8* @objc_autorelease(i8* %p)
214 ; Convert objc_retainAutoreleasedReturnValue to objc_retain if its
215 ; argument is not a return value.
217 ; CHECK: define void @test14(
218 ; CHECK-NEXT: tail call i8* @objc_retain(i8* %p) nounwind
219 ; CHECK-NEXT: ret void
220 define void @test14(i8* %p) {
221 call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
225 ; Don't convert objc_retainAutoreleasedReturnValue to objc_retain if its
226 ; argument is a return value.
228 ; CHECK: define void @test15(
229 ; CHECK-NEXT: %y = call i8* @returner()
230 ; CHECK-NEXT: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %y) nounwind
231 ; CHECK-NEXT: ret void
232 define void @test15() {
233 %y = call i8* @returner()
234 call i8* @objc_retainAutoreleasedReturnValue(i8* %y)
238 ; Convert objc_retain to objc_retainAutoreleasedReturnValue if its
239 ; argument is a return value.
241 ; CHECK: define void @test16(
242 ; CHECK-NEXT: %y = call i8* @returner()
243 ; CHECK-NEXT: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %y) nounwind
244 ; CHECK-NEXT: ret void
245 define void @test16() {
246 %y = call i8* @returner()
247 call i8* @objc_retain(i8* %y)
251 ; Don't convert objc_retain to objc_retainAutoreleasedReturnValue if its
252 ; argument is not a return value.
254 ; CHECK: define void @test17(
255 ; CHECK-NEXT: tail call i8* @objc_retain(i8* %y) nounwind
256 ; CHECK-NEXT: ret void
257 define void @test17(i8* %y) {
258 call i8* @objc_retain(i8* %y)
262 ; Don't Convert objc_retain to objc_retainAutoreleasedReturnValue if it
263 ; isn't next to the call providing its return value.
265 ; CHECK: define void @test18(
266 ; CHECK-NEXT: %y = call i8* @returner()
267 ; CHECK-NEXT: call void @callee()
268 ; CHECK-NEXT: tail call i8* @objc_retain(i8* %y) nounwind
269 ; CHECK-NEXT: ret void
270 define void @test18() {
271 %y = call i8* @returner()
273 call i8* @objc_retain(i8* %y)
277 ; Delete autoreleaseRV+retainRV pairs.
279 ; CHECK: define i8* @test19(i8* %p) {
280 ; CHECK-NEXT: ret i8* %p
281 define i8* @test19(i8* %p) {
282 call i8* @objc_autoreleaseReturnValue(i8* %p)
283 call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
287 ; Like test19 but with plain autorelease.
289 ; CHECK: define i8* @test20(i8* %p) {
290 ; CHECK-NEXT: call i8* @objc_autorelease(i8* %p)
291 ; CHECK-NEXT: call i8* @objc_retain(i8* %p)
292 ; CHECK-NEXT: ret i8* %p
293 define i8* @test20(i8* %p) {
294 call i8* @objc_autorelease(i8* %p)
295 call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
299 ; Like test19 but with plain retain.
301 ; CHECK: define i8* @test21(i8* %p) {
302 ; CHECK-NEXT: call i8* @objc_autoreleaseReturnValue(i8* %p)
303 ; CHECK-NEXT: call i8* @objc_retain(i8* %p)
304 ; CHECK-NEXT: ret i8* %p
305 define i8* @test21(i8* %p) {
306 call i8* @objc_autoreleaseReturnValue(i8* %p)
307 call i8* @objc_retain(i8* %p)
311 ; Like test19 but with plain retain and autorelease.
313 ; CHECK: define i8* @test22(i8* %p) {
314 ; CHECK-NEXT: call i8* @objc_autorelease(i8* %p)
315 ; CHECK-NEXT: call i8* @objc_retain(i8* %p)
316 ; CHECK-NEXT: ret i8* %p
317 define i8* @test22(i8* %p) {
318 call i8* @objc_autorelease(i8* %p)
319 call i8* @objc_retain(i8* %p)
323 ; Convert autoreleaseRV to autorelease.
325 ; CHECK: define void @test23(
326 ; CHECK: tail call i8* @objc_autorelease(i8* %p) nounwind
327 define void @test23(i8* %p) {
329 call i8* @objc_autoreleaseReturnValue(i8* %p)