1; RUN: opt -objc-arc -S < %s | FileCheck %s
2
3target datalayout = "e-p:64:64:64"
4
5declare i8* @llvm.objc.retain(i8*)
6declare i8* @llvm.objc.retainAutoreleasedReturnValue(i8*)
7declare void @llvm.objc.release(i8*)
8declare i8* @llvm.objc.autorelease(i8*)
9declare i8* @llvm.objc.autoreleaseReturnValue(i8*)
10declare i8* @llvm.objc.retainAutoreleaseReturnValue(i8*)
11declare void @llvm.objc.autoreleasePoolPop(i8*)
12declare void @llvm.objc.autoreleasePoolPush()
13declare i8* @llvm.objc.retainBlock(i8*)
14
15declare i8* @objc_retainedObject(i8*)
16declare i8* @objc_unretainedObject(i8*)
17declare i8* @objc_unretainedPointer(i8*)
18
19declare void @use_pointer(i8*)
20declare void @callee()
21declare void @callee_fnptr(void ()*)
22declare void @invokee()
23declare i8* @returner()
24declare i8* @returner1(i8*)
25declare i32 @__gxx_personality_v0(...)
26
27; Test that retain+release elimination is suppressed when the
28; retain is an objc_retainAutoreleasedReturnValue, since it's
29; better to do the RV optimization.
30
31; CHECK-LABEL:      define void @test0(
32; CHECK-NEXT: entry:
33; CHECK-NEXT:   %x = call i8* @returner
34; CHECK-NEXT:   %0 = tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %x) [[NUW:#[0-9]+]]
35; CHECK: t:
36; CHECK-NOT: @llvm.objc.
37; CHECK: return:
38; CHECK-NEXT: call void @llvm.objc.release(i8* %x)
39; CHECK-NEXT: ret void
40; CHECK-NEXT: }
41define void @test0(i1 %p) nounwind {
42entry:
43  %x = call i8* @returner()
44  %0 = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %x)
45  br i1 %p, label %t, label %return
46
47t:
48  call void @use_pointer(i8* %x)
49  store i8 0, i8* %x
50  br label %return
51
52return:
53  call void @llvm.objc.release(i8* %x) nounwind
54  ret void
55}
56
57; Delete no-ops.
58
59; CHECK-LABEL: define void @test2(
60; CHECK-NOT: @llvm.objc.
61; CHECK: }
62define void @test2() {
63  call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* null)
64  call i8* @llvm.objc.autoreleaseReturnValue(i8* null)
65  ; call i8* @llvm.objc.retainAutoreleaseReturnValue(i8* null) ; TODO
66  %bitcast = bitcast i32* null to i8*
67  %rb = call i8* @llvm.objc.retainBlock(i8* %bitcast)
68  call void @use_pointer(i8* %rb)
69  %rb2 = call i8* @llvm.objc.retainBlock(i8* undef)
70  call void @use_pointer(i8* %rb2)
71  ret void
72}
73
74; Delete a redundant retainRV,autoreleaseRV when forwaring a call result
75; directly to a return value.
76
77; CHECK-LABEL: define i8* @test3(
78; CHECK: call i8* @returner()
79; CHECK-NEXT: ret i8* %call
80define i8* @test3() {
81entry:
82  %call = tail call i8* @returner()
83  %0 = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call) nounwind
84  %1 = call i8* @llvm.objc.autoreleaseReturnValue(i8* %0) nounwind
85  ret i8* %1
86}
87
88; Delete a redundant retain,autoreleaseRV when forwaring a call result
89; directly to a return value.
90
91; CHECK-LABEL: define i8* @test4(
92; CHECK: call i8* @returner()
93; CHECK-NEXT: ret i8* %call
94define i8* @test4() {
95entry:
96  %call = call i8* @returner()
97  %0 = call i8* @llvm.objc.retain(i8* %call) nounwind
98  %1 = call i8* @llvm.objc.autoreleaseReturnValue(i8* %0) nounwind
99  ret i8* %1
100}
101
102; Delete a redundant fused retain+autoreleaseRV when forwaring a call result
103; directly to a return value.
104
105; TODO
106; HECK: define i8* @test5
107; HECK: call i8* @returner()
108; HECK-NEXT: ret i8* %call
109;define i8* @test5() {
110;entry:
111;  %call = call i8* @returner()
112;  %0 = call i8* @llvm.objc.retainAutoreleaseReturnValue(i8* %call) nounwind
113;  ret i8* %0
114;}
115
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.
123
124; CHECK-LABEL: define i8* @test7(
125; CHECK: call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %p)
126; CHECK: %t = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %p)
127define i8* @test7() {
128  %p = call i8* @returner()
129  call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %p)
130  %t = call i8* @llvm.objc.autoreleaseReturnValue(i8* %p)
131  call void @use_pointer(i8* %p)
132  ret i8* %t
133}
134
135; CHECK-LABEL: define i8* @test7b(
136; CHECK: call i8* @llvm.objc.retain(i8* %p)
137; CHECK: %t = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %p)
138define i8* @test7b() {
139  %p = call i8* @returner()
140  call void @use_pointer(i8* %p)
141  call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %p)
142  %t = call i8* @llvm.objc.autoreleaseReturnValue(i8* %p)
143  ret i8* %p
144}
145
146; Don't apply the RV optimization to autorelease if there's no retain.
147
148; CHECK: define i8* @test9(i8* %p)
149; CHECK: call i8* @llvm.objc.autorelease(i8* %p)
150define i8* @test9(i8* %p) {
151  call i8* @llvm.objc.autorelease(i8* %p)
152  ret i8* %p
153}
154
155; Do not apply the RV optimization.
156
157; CHECK: define i8* @test10(i8* %p)
158; CHECK: tail call i8* @llvm.objc.retain(i8* %p) [[NUW]]
159; CHECK: call i8* @llvm.objc.autorelease(i8* %p) [[NUW]]
160; CHECK-NEXT: ret i8* %p
161define i8* @test10(i8* %p) {
162  %1 = call i8* @llvm.objc.retain(i8* %p)
163  %2 = call i8* @llvm.objc.autorelease(i8* %p)
164  ret i8* %p
165}
166
167; Don't do the autoreleaseRV optimization because @use_pointer
168; could undo the retain.
169
170; CHECK: define i8* @test11(i8* %p)
171; CHECK: tail call i8* @llvm.objc.retain(i8* %p)
172; CHECK-NEXT: call void @use_pointer(i8* %p)
173; CHECK: call i8* @llvm.objc.autorelease(i8* %p)
174; CHECK-NEXT: ret i8* %p
175define i8* @test11(i8* %p) {
176  %1 = call i8* @llvm.objc.retain(i8* %p)
177  call void @use_pointer(i8* %p)
178  %2 = call i8* @llvm.objc.autorelease(i8* %p)
179  ret i8* %p
180}
181
182; Don't spoil the RV optimization.
183
184; CHECK: define i8* @test12(i8* %p)
185; CHECK: tail call i8* @llvm.objc.retain(i8* %p)
186; CHECK: call void @use_pointer(i8* %p)
187; CHECK: tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %p)
188; CHECK: ret i8* %p
189define i8* @test12(i8* %p) {
190  %1 = call i8* @llvm.objc.retain(i8* %p)
191  call void @use_pointer(i8* %p)
192  %2 = call i8* @llvm.objc.autoreleaseReturnValue(i8* %p)
193  ret i8* %p
194}
195
196; Don't zap the objc_retainAutoreleasedReturnValue.
197
198; CHECK-LABEL: define i8* @test13(
199; CHECK: tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %p)
200; CHECK: call i8* @llvm.objc.autorelease(i8* %p)
201; CHECK: ret i8* %p
202define i8* @test13() {
203  %p = call i8* @returner()
204  %1 = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %p)
205  call void @callee()
206  %2 = call i8* @llvm.objc.autorelease(i8* %p)
207  ret i8* %p
208}
209
210; Convert objc_retainAutoreleasedReturnValue to objc_retain if its
211; argument is not a return value.
212
213; CHECK-LABEL: define void @test14(
214; CHECK-NEXT: tail call i8* @llvm.objc.retain(i8* %p) [[NUW]]
215; CHECK-NEXT: ret void
216define void @test14(i8* %p) {
217  call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %p)
218  ret void
219}
220
221; Don't convert objc_retainAutoreleasedReturnValue to objc_retain if its
222; argument is a return value.
223
224; CHECK-LABEL: define void @test15(
225; CHECK-NEXT: %y = call i8* @returner()
226; CHECK-NEXT: tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %y) [[NUW]]
227; CHECK-NEXT: ret void
228define void @test15() {
229  %y = call i8* @returner()
230  call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %y)
231  ret void
232}
233
234; Delete autoreleaseRV+retainRV pairs.
235
236; CHECK: define i8* @test19(i8* %p) {
237; CHECK-NEXT: ret i8* %p
238define i8* @test19(i8* %p) {
239  call i8* @llvm.objc.autoreleaseReturnValue(i8* %p)
240  call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %p)
241  ret i8* %p
242}
243
244; Delete autoreleaseRV+retainRV pairs when they have equivalent PHIs as inputs
245
246; CHECK: define i8* @test19phi(i8* %p) {
247; CHECK-NEXT: entry:
248; CHECK-NEXT: br label %test19bb
249; CHECK: test19bb:
250; CHECK-NEXT: ret i8* %p
251define i8* @test19phi(i8* %p) {
252entry:
253  br label %test19bb
254test19bb:
255  %phi1 = phi i8* [ %p, %entry ]
256  %phi2 = phi i8* [ %p, %entry ]
257  call i8* @llvm.objc.autoreleaseReturnValue(i8* %phi1)
258  call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %phi2)
259  ret i8* %p
260}
261
262; Like test19 but with plain autorelease.
263
264; CHECK: define i8* @test20(i8* %p) {
265; CHECK-NEXT: call i8* @llvm.objc.autorelease(i8* %p)
266; CHECK-NEXT: call i8* @llvm.objc.retain(i8* %p)
267; CHECK-NEXT: ret i8* %p
268define i8* @test20(i8* %p) {
269  call i8* @llvm.objc.autorelease(i8* %p)
270  call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %p)
271  ret i8* %p
272}
273
274; Like test19 but with plain retain.
275
276; CHECK: define i8* @test21(i8* %p) {
277; CHECK-NEXT: call i8* @llvm.objc.autoreleaseReturnValue(i8* %p)
278; CHECK-NEXT: call i8* @llvm.objc.retain(i8* %p)
279; CHECK-NEXT: ret i8* %p
280define i8* @test21(i8* %p) {
281  call i8* @llvm.objc.autoreleaseReturnValue(i8* %p)
282  call i8* @llvm.objc.retain(i8* %p)
283  ret i8* %p
284}
285
286; Like test19 but with plain retain and autorelease.
287
288; CHECK: define i8* @test22(i8* %p) {
289; CHECK-NEXT: call i8* @llvm.objc.autorelease(i8* %p)
290; CHECK-NEXT: call i8* @llvm.objc.retain(i8* %p)
291; CHECK-NEXT: ret i8* %p
292define i8* @test22(i8* %p) {
293  call i8* @llvm.objc.autorelease(i8* %p)
294  call i8* @llvm.objc.retain(i8* %p)
295  ret i8* %p
296}
297
298; Convert autoreleaseRV to autorelease.
299
300; CHECK-LABEL: define void @test23(
301; CHECK: call i8* @llvm.objc.autorelease(i8* %p) [[NUW]]
302define void @test23(i8* %p) {
303  store i8 0, i8* %p
304  call i8* @llvm.objc.autoreleaseReturnValue(i8* %p)
305  ret void
306}
307
308; Don't convert autoreleaseRV to autorelease if the result is returned,
309; even through a bitcast.
310
311; CHECK-LABEL: define {}* @test24(
312; CHECK: tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %p)
313define {}* @test24(i8* %p) {
314  %t = call i8* @llvm.objc.autoreleaseReturnValue(i8* %p)
315  %s = bitcast i8* %p to {}*
316  ret {}* %s
317}
318
319declare i8* @first_test25();
320declare i8* @second_test25(i8*);
321declare void @somecall_test25();
322
323; ARC optimizer used to move the last release between the call to second_test25
324; and the call to objc_retainAutoreleasedReturnValue, causing %second to be
325; released prematurely when %first and %second were pointing to the same object.
326
327; CHECK-LABEL: define void @test25(
328; CHECK: %[[CALL1:.*]] = call i8* @second_test25(
329; CHECK-NEXT: tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %[[CALL1]])
330
331define void @test25() {
332  %first = call i8* @first_test25()
333  %v0 = call i8* @llvm.objc.retain(i8* %first)
334  call void @somecall_test25()
335  %second = call i8* @second_test25(i8* %first)
336  %call2 = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %second)
337  call void @llvm.objc.release(i8* %second), !clang.imprecise_release !0
338  call void @llvm.objc.release(i8* %first), !clang.imprecise_release !0
339  ret void
340}
341
342; Check that ObjCARCOpt::OptimizeReturns removes the redundant calls even when
343; they are not in the same basic block. This code used to cause an assertion
344; failure.
345
346; CHECK-LABEL: define i8* @test26()
347; CHECK: call i8* @returner()
348; CHECK-NOT:  call
349define i8* @test26() {
350bb0:
351  %v0 = call i8* @returner()
352  %v1 = tail call i8* @llvm.objc.retain(i8* %v0)
353  br label %bb1
354bb1:
355  %v2 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %v1)
356  br label %bb2
357bb2:
358  ret i8* %v2
359}
360
361declare i32* @func27(i32);
362
363; Check that ObjCARCOpt::OptimizeAutoreleaseRVCall doesn't turn a call to
364; @llvm.objc.autoreleaseReturnValue into a call to @llvm.objc.autorelease when a return
365; instruction uses a value equivalent to @llvm.objc.autoreleaseReturnValue's operand.
366; In the code below, %phival and %retval are considered equivalent.
367
368; CHECK-LABEL: define i32* @test27(
369; CHECK: %[[PHIVAL:.*]] = phi i8* [ %{{.*}}, %bb1 ], [ %{{.*}}, %bb2 ]
370; CHECK: %[[RETVAL:.*]] = phi i32* [ %{{.*}}, %bb1 ], [ %{{.*}}, %bb2 ]
371; CHECK: tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %[[PHIVAL]])
372; CHECK: ret i32* %[[RETVAL]]
373
374define i32* @test27(i1 %cond) {
375entry:
376  br i1 %cond, label %bb1, label %bb2
377bb1:
378  %v0 = call i32* @func27(i32 1)
379  %v1 = bitcast i32* %v0 to i8*
380  br label %bb3
381bb2:
382  %v2 = call i32* @func27(i32 2)
383  %v3 = bitcast i32* %v2 to i8*
384  br label %bb3
385bb3:
386  %phival = phi i8* [ %v1, %bb1 ], [ %v3, %bb2 ]
387  %retval = phi i32* [ %v0, %bb1 ], [ %v2, %bb2 ]
388  %v4 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %phival)
389  ret i32* %retval
390}
391
392; Don't eliminate the retainRV/autoreleaseRV pair if the call isn't a tail call.
393
394; CHECK-LABEL: define i8* @test28(
395; CHECK: call i8* @returner()
396; CHECK: call i8* @llvm.objc.retainAutoreleasedReturnValue(
397; CHECK: call i8* @llvm.objc.autoreleaseReturnValue(
398define i8* @test28() {
399entry:
400  %call = call i8* @returner()
401  %0 = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call) nounwind
402  %1 = call i8* @llvm.objc.autoreleaseReturnValue(i8* %0) nounwind
403  ret i8* %1
404}
405
406; CHECK-LABEL: define i8* @test29(
407; CHECK: call i8* @llvm.objc.retainAutoreleasedReturnValue(
408; CHECK: call i8* @llvm.objc.autoreleaseReturnValue(
409
410define i8* @test29(i8* %k) local_unnamed_addr personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
411entry:
412  %0 = tail call i8* @llvm.objc.retain(i8* %k)
413  %call = invoke i8* @returner1(i8* %k)
414          to label %invoke.cont unwind label %lpad
415
416invoke.cont:
417  %1 = bitcast i8* %call to i8*
418  %2 = notail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %1)
419  tail call void @llvm.objc.release(i8* %k), !clang.imprecise_release !0
420  %3 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %1)
421  ret i8* %call
422
423lpad:
424  %4 = landingpad { i8*, i32 }
425          cleanup
426  tail call void @llvm.objc.release(i8* %k) #1, !clang.imprecise_release !0
427  resume { i8*, i32 } %4
428}
429
430; The second retainRV/autoreleaseRV pair can be removed since the call to
431; @returner is a tail call.
432
433; CHECK-LABEL: define i8* @test30(
434; CHECK: %[[V0:.*]] = call i8* @returner()
435; CHECK-NEXT: call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %[[V0]])
436; CHECK-NEXT: call i8* @llvm.objc.autoreleaseReturnValue(i8* %[[V0]])
437; CHECK-NEXT: ret i8* %[[V0]]
438; CHECK: %[[V3:.*]] = tail call i8* @returner()
439; CHECK-NEXT: ret i8* %[[V3]]
440
441define i8* @test30(i1 %cond) {
442  br i1 %cond, label %bb0, label %bb1
443bb0:
444  %v0 = call i8* @returner()
445  %v1 = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %v0)
446  %v2 = call i8* @llvm.objc.autoreleaseReturnValue(i8* %v0)
447  ret i8* %v0
448bb1:
449  %v3 = tail call i8* @returner()
450  %v4 = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %v3)
451  %v5 = call i8* @llvm.objc.autoreleaseReturnValue(i8* %v3)
452  ret i8* %v3
453}
454
455!0 = !{}
456
457; CHECK: attributes [[NUW]] = { nounwind }
458