1 ; RUN: opt -passes=objc-arc -S < %s | FileCheck %s
3 target datalayout = "e-p:64:64:64"
5 declare ptr @llvm.objc.retain(ptr)
6 declare ptr @llvm.objc.retainAutoreleasedReturnValue(ptr)
7 declare void @llvm.objc.release(ptr)
8 declare ptr @llvm.objc.autorelease(ptr)
9 declare ptr @llvm.objc.autoreleaseReturnValue(ptr)
10 declare ptr @llvm.objc.retainAutoreleaseReturnValue(ptr)
11 declare void @llvm.objc.autoreleasePoolPop(ptr)
12 declare void @llvm.objc.autoreleasePoolPush()
13 declare ptr @llvm.objc.retainBlock(ptr)
14 declare void @llvm.objc.clang.arc.noop.use(...)
16 declare ptr @objc_retainedObject(ptr)
17 declare ptr @objc_unretainedObject(ptr)
18 declare ptr @objc_unretainedPointer(ptr)
20 declare void @use_pointer(ptr)
21 declare void @callee()
22 declare void @callee_fnptr(ptr)
23 declare void @invokee()
24 declare ptr @returner()
25 declare ptr @returner1(ptr)
26 declare i32 @__gxx_personality_v0(...)
28 ; Test that retain+release elimination is suppressed when the
29 ; retain is an objc_retainAutoreleasedReturnValue, since it's
30 ; better to do the RV optimization.
32 ; CHECK-LABEL: define void @test0(
34 ; CHECK-NEXT: %x = call ptr @returner
35 ; CHECK-NEXT: %0 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %x) [[NUW:#[0-9]+]]
37 ; CHECK-NOT: @llvm.objc.
39 ; CHECK-NEXT: call void @llvm.objc.release(ptr %x)
40 ; CHECK-NEXT: ret void
42 define void @test0(i1 %p) nounwind {
44 %x = call ptr @returner()
45 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %x)
46 br i1 %p, label %t, label %return
49 call void @use_pointer(ptr %x)
54 call void @llvm.objc.release(ptr %x) nounwind
60 ; CHECK-LABEL: define void @test2(
61 ; CHECK-NOT: @llvm.objc.
63 define void @test2() {
64 call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr null)
65 call ptr @llvm.objc.autoreleaseReturnValue(ptr null)
66 ; call ptr @llvm.objc.retainAutoreleaseReturnValue(ptr null) ; TODO
67 %rb = call ptr @llvm.objc.retainBlock(ptr null)
68 call void @use_pointer(ptr %rb)
69 %rb2 = call ptr @llvm.objc.retainBlock(ptr undef)
70 call void @use_pointer(ptr %rb2)
74 ; Delete a redundant retainRV,autoreleaseRV when forwaring a call result
75 ; directly to a return value.
77 ; CHECK-LABEL: define ptr @test3(
78 ; CHECK: call ptr @returner()
79 ; CHECK-NEXT: ret ptr %call
82 %call = tail call ptr @returner()
83 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind
84 %1 = call ptr @llvm.objc.autoreleaseReturnValue(ptr %0) nounwind
88 ; Delete a redundant retain,autoreleaseRV when forwaring a call result
89 ; directly to a return value.
91 ; CHECK-LABEL: define ptr @test4(
92 ; CHECK: call ptr @returner()
93 ; CHECK-NEXT: ret ptr %call
96 %call = call ptr @returner()
97 %0 = call ptr @llvm.objc.retain(ptr %call) nounwind
98 %1 = call ptr @llvm.objc.autoreleaseReturnValue(ptr %0) nounwind
102 ; Delete a redundant fused retain+autoreleaseRV when forwaring a call result
103 ; directly to a return value.
106 ; HECK: define ptr @test5
107 ; HECK: call ptr @returner()
108 ; HECK-NEXT: ret ptr %call
109 ;define ptr @test5() {
111 ; %call = call ptr @returner()
112 ; %0 = call ptr @llvm.objc.retainAutoreleaseReturnValue(ptr %call) nounwind
116 ; Don't eliminate objc_retainAutoreleasedReturnValue by merging it into
117 ; an objc_autorelease.
118 ; TODO? Merge objc_retainAutoreleasedReturnValue and objc_autorelease into
119 ; objc_retainAutoreleasedReturnValueAutorelease and merge
120 ; objc_retainAutoreleasedReturnValue and objc_autoreleaseReturnValue
121 ; into objc_retainAutoreleasedReturnValueAutoreleaseReturnValue?
122 ; Those entrypoints don't exist yet though.
124 ; CHECK-LABEL: define ptr @test7(
125 ; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %p)
126 ; CHECK: %t = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %p)
127 define ptr @test7() {
128 %p = call ptr @returner()
129 call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %p)
130 %t = call ptr @llvm.objc.autoreleaseReturnValue(ptr %p)
131 call void @use_pointer(ptr %p)
135 ; CHECK-LABEL: define ptr @test7b(
136 ; CHECK: call ptr @llvm.objc.retain(ptr %p)
137 ; CHECK: %t = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %p)
138 define ptr @test7b() {
139 %p = call ptr @returner()
140 call void @use_pointer(ptr %p)
141 call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %p)
142 %t = call ptr @llvm.objc.autoreleaseReturnValue(ptr %p)
146 ; Don't apply the RV optimization to autorelease if there's no retain.
148 ; CHECK: define ptr @test9(ptr %p)
149 ; CHECK: call ptr @llvm.objc.autorelease(ptr %p)
150 define ptr @test9(ptr %p) {
151 call ptr @llvm.objc.autorelease(ptr %p)
155 ; Do not apply the RV optimization.
157 ; CHECK: define ptr @test10(ptr %p)
158 ; CHECK: tail call ptr @llvm.objc.retain(ptr %p) [[NUW]]
159 ; CHECK: call ptr @llvm.objc.autorelease(ptr %p) [[NUW]]
160 ; CHECK-NEXT: ret ptr %p
161 define ptr @test10(ptr %p) {
162 %1 = call ptr @llvm.objc.retain(ptr %p)
163 %2 = call ptr @llvm.objc.autorelease(ptr %p)
167 ; Don't do the autoreleaseRV optimization because @use_pointer
168 ; could undo the retain.
170 ; CHECK: define ptr @test11(ptr %p)
171 ; CHECK: tail call ptr @llvm.objc.retain(ptr %p)
172 ; CHECK-NEXT: call void @use_pointer(ptr %p)
173 ; CHECK: call ptr @llvm.objc.autorelease(ptr %p)
174 ; CHECK-NEXT: ret ptr %p
175 define ptr @test11(ptr %p) {
176 %1 = call ptr @llvm.objc.retain(ptr %p)
177 call void @use_pointer(ptr %p)
178 %2 = call ptr @llvm.objc.autorelease(ptr %p)
182 ; Don't spoil the RV optimization.
184 ; CHECK: define ptr @test12(ptr %p)
185 ; CHECK: tail call ptr @llvm.objc.retain(ptr %p)
186 ; CHECK: call void @use_pointer(ptr %p)
187 ; CHECK: tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %p)
189 define ptr @test12(ptr %p) {
190 %1 = call ptr @llvm.objc.retain(ptr %p)
191 call void @use_pointer(ptr %p)
192 %2 = call ptr @llvm.objc.autoreleaseReturnValue(ptr %p)
196 ; Don't zap the objc_retainAutoreleasedReturnValue.
198 ; CHECK-LABEL: define ptr @test13(
199 ; CHECK: tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %p)
200 ; CHECK: call ptr @llvm.objc.autorelease(ptr %p)
202 define ptr @test13() {
203 %p = call ptr @returner()
204 %1 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %p)
206 %2 = call ptr @llvm.objc.autorelease(ptr %p)
210 ; Convert objc_retainAutoreleasedReturnValue to objc_retain if its
211 ; argument is not a return value.
213 ; CHECK-LABEL: define void @test14(
214 ; CHECK-NEXT: tail call ptr @llvm.objc.retain(ptr %p) [[NUW]]
215 ; CHECK-NEXT: ret void
216 define void @test14(ptr %p) {
217 call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %p)
221 ; Don't convert objc_retainAutoreleasedReturnValue to objc_retain if its
222 ; argument is a return value.
224 ; CHECK-LABEL: define void @test15(
225 ; CHECK-NEXT: %y = call ptr @returner()
226 ; CHECK-NEXT: tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %y) [[NUW]]
227 ; CHECK-NEXT: ret void
228 define void @test15() {
229 %y = call ptr @returner()
230 call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %y)
234 ; Delete autoreleaseRV+retainRV pairs.
236 ; CHECK: define ptr @test19(ptr %p) {
237 ; CHECK-NEXT: ret ptr %p
238 define ptr @test19(ptr %p) {
239 call ptr @llvm.objc.autoreleaseReturnValue(ptr %p)
240 call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %p)
244 ; Delete autoreleaseRV+retainRV pairs when they have equivalent PHIs as inputs
246 ; CHECK: define ptr @test19phi(ptr %p) {
248 ; CHECK-NEXT: br label %test19bb
250 ; CHECK-NEXT: ret ptr %p
251 define ptr @test19phi(ptr %p) {
255 %phi1 = phi ptr [ %p, %entry ]
256 %phi2 = phi ptr [ %p, %entry ]
257 call ptr @llvm.objc.autoreleaseReturnValue(ptr %phi1)
258 call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %phi2)
262 ; Like test19 but with plain autorelease.
264 ; CHECK: define ptr @test20(ptr %p) {
265 ; CHECK-NEXT: call ptr @llvm.objc.autorelease(ptr %p)
266 ; CHECK-NEXT: call ptr @llvm.objc.retain(ptr %p)
267 ; CHECK-NEXT: ret ptr %p
268 define ptr @test20(ptr %p) {
269 call ptr @llvm.objc.autorelease(ptr %p)
270 call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %p)
274 ; Like test19 but with plain retain.
276 ; CHECK: define ptr @test21(ptr %p) {
277 ; CHECK-NEXT: call ptr @llvm.objc.autoreleaseReturnValue(ptr %p)
278 ; CHECK-NEXT: call ptr @llvm.objc.retain(ptr %p)
279 ; CHECK-NEXT: ret ptr %p
280 define ptr @test21(ptr %p) {
281 call ptr @llvm.objc.autoreleaseReturnValue(ptr %p)
282 call ptr @llvm.objc.retain(ptr %p)
286 ; Like test19 but with plain retain and autorelease.
288 ; CHECK: define ptr @test22(ptr %p) {
289 ; CHECK-NEXT: call ptr @llvm.objc.autorelease(ptr %p)
290 ; CHECK-NEXT: call ptr @llvm.objc.retain(ptr %p)
291 ; CHECK-NEXT: ret ptr %p
292 define ptr @test22(ptr %p) {
293 call ptr @llvm.objc.autorelease(ptr %p)
294 call ptr @llvm.objc.retain(ptr %p)
298 ; Convert autoreleaseRV to autorelease.
300 ; CHECK-LABEL: define void @test23(
301 ; CHECK: call ptr @llvm.objc.autorelease(ptr %p) [[NUW]]
302 define void @test23(ptr %p) {
304 call ptr @llvm.objc.autoreleaseReturnValue(ptr %p)
308 ; Don't convert autoreleaseRV to autorelease if the result is returned,
309 ; even through a bitcast.
311 ; CHECK-LABEL: define ptr @test24(
312 ; CHECK: tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %p)
313 define ptr @test24(ptr %p) {
314 %t = call ptr @llvm.objc.autoreleaseReturnValue(ptr %p)
318 declare ptr @first_test25();
319 declare ptr @second_test25(ptr);
320 declare void @somecall_test25();
322 ; ARC optimizer used to move the last release between the call to second_test25
323 ; and the call to objc_retainAutoreleasedReturnValue, causing %second to be
324 ; released prematurely when %first and %second were pointing to the same object.
326 ; CHECK-LABEL: define void @test25(
327 ; CHECK: %[[CALL1:.*]] = call ptr @second_test25(
328 ; CHECK-NEXT: tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %[[CALL1]])
330 define void @test25() {
331 %first = call ptr @first_test25()
332 %v0 = call ptr @llvm.objc.retain(ptr %first)
333 call void @somecall_test25()
334 %second = call ptr @second_test25(ptr %first)
335 %call2 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %second)
336 call void @llvm.objc.release(ptr %second), !clang.imprecise_release !0
337 call void @llvm.objc.release(ptr %first), !clang.imprecise_release !0
341 ; Check that ObjCARCOpt::OptimizeReturns removes the redundant calls even when
342 ; they are not in the same basic block. This code used to cause an assertion
345 ; CHECK-LABEL: define ptr @test26()
346 ; CHECK: call ptr @returner()
348 define ptr @test26() {
350 %v0 = call ptr @returner()
351 %v1 = tail call ptr @llvm.objc.retain(ptr %v0)
354 %v2 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %v1)
360 declare ptr @func27(i32);
362 ; Check that ObjCARCOpt::OptimizeAutoreleaseRVCall doesn't turn a call to
363 ; @llvm.objc.autoreleaseReturnValue into a call to @llvm.objc.autorelease when a return
364 ; instruction uses a value equivalent to @llvm.objc.autoreleaseReturnValue's operand.
365 ; In the code below, %phival and %retval are considered equivalent.
367 ; CHECK-LABEL: define ptr @test27(
368 ; CHECK: %[[PHIVAL:.*]] = phi ptr [ %{{.*}}, %bb1 ], [ %{{.*}}, %bb2 ]
369 ; CHECK: %[[RETVAL:.*]] = phi ptr [ %{{.*}}, %bb1 ], [ %{{.*}}, %bb2 ]
370 ; CHECK: tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %[[PHIVAL]])
371 ; CHECK: ret ptr %[[RETVAL]]
373 define ptr @test27(i1 %cond) {
375 br i1 %cond, label %bb1, label %bb2
377 %v0 = call ptr @func27(i32 1)
380 %v2 = call ptr @func27(i32 2)
383 %phival = phi ptr [ %v0, %bb1 ], [ %v2, %bb2 ]
384 %retval = phi ptr [ %v0, %bb1 ], [ %v2, %bb2 ]
385 %v4 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %phival)
389 ; Don't eliminate the retainRV/autoreleaseRV pair if the call isn't a tail call.
391 ; CHECK-LABEL: define ptr @test28(
392 ; CHECK: call ptr @returner()
393 ; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue(
394 ; CHECK: call ptr @llvm.objc.autoreleaseReturnValue(
395 define ptr @test28() {
397 %call = call ptr @returner()
398 %0 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call) nounwind
399 %1 = call ptr @llvm.objc.autoreleaseReturnValue(ptr %0) nounwind
403 ; CHECK-LABEL: define ptr @test29(
404 ; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue(
405 ; CHECK: call ptr @llvm.objc.autoreleaseReturnValue(
407 define ptr @test29(ptr %k) local_unnamed_addr personality ptr @__gxx_personality_v0 {
409 %0 = tail call ptr @llvm.objc.retain(ptr %k)
410 %call = invoke ptr @returner1(ptr %k)
411 to label %invoke.cont unwind label %lpad
414 %1 = notail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call)
415 tail call void @llvm.objc.release(ptr %k), !clang.imprecise_release !0
416 %2 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %call)
420 %3 = landingpad { ptr, i32 }
422 tail call void @llvm.objc.release(ptr %k) #1, !clang.imprecise_release !0
423 resume { ptr, i32 } %3
426 ; The second retainRV/autoreleaseRV pair can be removed since the call to
427 ; @returner is a tail call.
429 ; CHECK-LABEL: define ptr @test30(
430 ; CHECK: %[[V0:.*]] = call ptr @returner()
431 ; CHECK-NEXT: call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %[[V0]])
432 ; CHECK-NEXT: call ptr @llvm.objc.autoreleaseReturnValue(ptr %[[V0]])
433 ; CHECK-NEXT: ret ptr %[[V0]]
434 ; CHECK: %[[V3:.*]] = tail call ptr @returner()
435 ; CHECK-NEXT: ret ptr %[[V3]]
437 define ptr @test30(i1 %cond) {
438 br i1 %cond, label %bb0, label %bb1
440 %v0 = call ptr @returner()
441 %v1 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %v0)
442 %v2 = call ptr @llvm.objc.autoreleaseReturnValue(ptr %v0)
445 %v3 = tail call ptr @returner()
446 %v4 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %v3)
447 %v5 = call ptr @llvm.objc.autoreleaseReturnValue(ptr %v3)
451 ; Remove operand bundle "clang.arc.attachedcall" and the autoreleaseRV call if the call
454 ; CHECK-LABEL: define ptr @test31(
455 ; CHECK-NEXT: %[[CALL:.*]] = tail call ptr @returner()
456 ; CHECK-NEXT: ret ptr %[[CALL]]
458 define ptr @test31() {
459 %call = tail call ptr @returner() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
460 call void (...) @llvm.objc.clang.arc.noop.use(ptr %call)
461 %1 = call ptr @llvm.objc.autoreleaseReturnValue(ptr %call)
465 ; CHECK-LABEL: define ptr @test32(
466 ; CHECK: %[[CALL:.*]] = call ptr @returner() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
467 ; CHECK: call void (...) @llvm.objc.clang.arc.noop.use(ptr %[[CALL]])
468 ; CHECK: call ptr @llvm.objc.autoreleaseReturnValue(ptr %[[CALL]])
470 define ptr @test32() {
471 %call = call ptr @returner() [ "clang.arc.attachedcall"(ptr @llvm.objc.retainAutoreleasedReturnValue) ]
472 call void (...) @llvm.objc.clang.arc.noop.use(ptr %call)
473 %1 = call ptr @llvm.objc.autoreleaseReturnValue(ptr %call)
479 ; CHECK: attributes [[NUW]] = { nounwind }