Revert "[InstCombine] Support gep nuw in icmp folds" (#118698)
[llvm-project.git] / llvm / test / Transforms / ObjCARC / rv.ll
blobae35d28e5b01101053117f0e5d3aad4724118ce4
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(
33 ; CHECK-NEXT: entry:
34 ; CHECK-NEXT:   %x = call ptr @returner
35 ; CHECK-NEXT:   %0 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %x) [[NUW:#[0-9]+]]
36 ; CHECK: t:
37 ; CHECK-NOT: @llvm.objc.
38 ; CHECK: return:
39 ; CHECK-NEXT: call void @llvm.objc.release(ptr %x)
40 ; CHECK-NEXT: ret void
41 ; CHECK-NEXT: }
42 define void @test0(i1 %p) nounwind {
43 entry:
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)
50   store i8 0, ptr %x
51   br label %return
53 return:
54   call void @llvm.objc.release(ptr %x) nounwind
55   ret void
58 ; Delete no-ops.
60 ; CHECK-LABEL: define void @test2(
61 ; CHECK-NOT: @llvm.objc.
62 ; CHECK: }
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)
71   ret void
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
80 define ptr @test3() {
81 entry:
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
85   ret ptr %1
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
94 define ptr @test4() {
95 entry:
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
99   ret ptr %1
102 ; Delete a redundant fused retain+autoreleaseRV when forwaring a call result
103 ; directly to a return value.
105 ; TODO
106 ; HECK: define ptr @test5
107 ; HECK: call ptr @returner()
108 ; HECK-NEXT: ret ptr %call
109 ;define ptr @test5() {
110 ;entry:
111 ;  %call = call ptr @returner()
112 ;  %0 = call ptr @llvm.objc.retainAutoreleaseReturnValue(ptr %call) nounwind
113 ;  ret ptr %0
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)
132   ret ptr %t
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)
143   ret 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)
152   ret 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)
164   ret 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)
179   ret 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)
188 ; CHECK: ret 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)
193   ret 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)
201 ; CHECK: ret ptr %p
202 define ptr @test13() {
203   %p = call ptr @returner()
204   %1 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %p)
205   call void @callee()
206   %2 = call ptr @llvm.objc.autorelease(ptr %p)
207   ret 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)
218   ret void
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)
231   ret void
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)
241   ret ptr %p
244 ; Delete autoreleaseRV+retainRV pairs when they have equivalent PHIs as inputs
246 ; CHECK: define ptr @test19phi(ptr %p) {
247 ; CHECK-NEXT: entry:
248 ; CHECK-NEXT: br label %test19bb
249 ; CHECK: test19bb:
250 ; CHECK-NEXT: ret ptr %p
251 define ptr @test19phi(ptr %p) {
252 entry:
253   br label %test19bb
254 test19bb:
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)
259   ret ptr %p
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)
271   ret 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)
283   ret 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)
295   ret 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) {
303   store i8 0, ptr %p
304   call ptr @llvm.objc.autoreleaseReturnValue(ptr %p)
305   ret void
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)
315   ret 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
338   ret void
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
343 ; failure.
345 ; CHECK-LABEL: define ptr @test26()
346 ; CHECK: call ptr @returner()
347 ; CHECK-NOT:  call
348 define ptr @test26() {
349 bb0:
350   %v0 = call ptr @returner()
351   %v1 = tail call ptr @llvm.objc.retain(ptr %v0)
352   br label %bb1
353 bb1:
354   %v2 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %v1)
355   br label %bb2
356 bb2:
357   ret ptr %v2
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) {
374 entry:
375   br i1 %cond, label %bb1, label %bb2
376 bb1:
377   %v0 = call ptr @func27(i32 1)
378   br label %bb3
379 bb2:
380   %v2 = call ptr @func27(i32 2)
381   br label %bb3
382 bb3:
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)
386   ret ptr %retval
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() {
396 entry:
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
400   ret ptr %1
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 {
408 entry:
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
413 invoke.cont:
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)
417   ret ptr %call
419 lpad:
420   %3 = landingpad { ptr, i32 }
421           cleanup
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
439 bb0:
440   %v0 = call ptr @returner()
441   %v1 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %v0)
442   %v2 = call ptr @llvm.objc.autoreleaseReturnValue(ptr %v0)
443   ret ptr %v0
444 bb1:
445   %v3 = tail call ptr @returner()
446   %v4 = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %v3)
447   %v5 = call ptr @llvm.objc.autoreleaseReturnValue(ptr %v3)
448   ret ptr %v3
451 ; Remove operand bundle "clang.arc.attachedcall" and the autoreleaseRV call if the call
452 ; is a tail 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)
462   ret ptr %1
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)
474   ret ptr %1
477 !0 = !{}
479 ; CHECK: attributes [[NUW]] = { nounwind }