• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; RUN: opt -objc-arc -S < %s | FileCheck %s
2
3target datalayout = "e-p:64:64:64"
4
5declare i8* @objc_retain(i8*)
6declare i8* @objc_retainAutoreleasedReturnValue(i8*)
7declare void @objc_release(i8*)
8declare i8* @objc_autorelease(i8*)
9declare i8* @objc_autoreleaseReturnValue(i8*)
10declare i8* @objc_retainAutoreleaseReturnValue(i8*)
11declare void @objc_autoreleasePoolPop(i8*)
12declare void @objc_autoreleasePoolPush()
13declare i8* @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()
24
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.
28
29; CHECK:      define void @test0(
30; CHECK-NEXT: entry:
31; CHECK-NEXT:   %x = call i8* @returner
32; CHECK-NEXT:   %0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %x) nounwind
33; CHECK: t:
34; CHECK-NOT: @objc_
35; CHECK: return:
36; CHECK-NEXT: call void @objc_release(i8* %x)
37; CHECK-NEXT: ret void
38; CHECK-NEXT: }
39define void @test0(i1 %p) nounwind {
40entry:
41  %x = call i8* @returner()
42  %0 = call i8* @objc_retainAutoreleasedReturnValue(i8* %x)
43  br i1 %p, label %t, label %return
44
45t:
46  call void @use_pointer(i8* %x)
47  store i8 0, i8* %x
48  br label %return
49
50return:
51  call void @objc_release(i8* %x) nounwind
52  ret void
53}
54
55; Delete no-ops.
56
57; CHECK: define void @test2
58; CHECK-NOT: @objc_
59; CHECK: }
60define void @test2() {
61  call i8* @objc_retainAutoreleasedReturnValue(i8* null)
62  call i8* @objc_autoreleaseReturnValue(i8* null)
63  ; call i8* @objc_retainAutoreleaseReturnValue(i8* null) ; TODO
64  ret void
65}
66
67; Delete a redundant retainRV,autoreleaseRV when forwaring a call result
68; directly to a return value.
69
70; CHECK: define i8* @test3
71; CHECK: call i8* @returner()
72; CHECK-NEXT: ret i8* %call
73define i8* @test3() {
74entry:
75  %call = call i8* @returner()
76  %0 = call i8* @objc_retainAutoreleasedReturnValue(i8* %call) nounwind
77  %1 = call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind
78  ret i8* %1
79}
80
81; Delete a redundant retain,autoreleaseRV when forwaring a call result
82; directly to a return value.
83
84; CHECK: define i8* @test4
85; CHECK: call i8* @returner()
86; CHECK-NEXT: ret i8* %call
87define i8* @test4() {
88entry:
89  %call = call i8* @returner()
90  %0 = call i8* @objc_retain(i8* %call) nounwind
91  %1 = call i8* @objc_autoreleaseReturnValue(i8* %0) nounwind
92  ret i8* %1
93}
94
95; Delete a redundant fused retain+autoreleaseRV when forwaring a call result
96; directly to a return value.
97
98; TODO
99; HECK: define i8* @test5
100; HECK: call i8* @returner()
101; HECK-NEXT: ret i8* %call
102;define i8* @test5() {
103;entry:
104;  %call = call i8* @returner()
105;  %0 = call i8* @objc_retainAutoreleaseReturnValue(i8* %call) nounwind
106;  ret i8* %0
107;}
108
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.
116
117; CHECK: define i8* @test7(
118; CHECK: call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
119; CHECK: %t = tail call i8* @objc_autoreleaseReturnValue(i8* %p)
120define 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)
125  ret i8* %t
126}
127
128; CHECK: define i8* @test7b(
129; CHECK: call i8* @objc_retain(i8* %p)
130; CHECK: %t = tail call i8* @objc_autoreleaseReturnValue(i8* %p)
131define 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)
136  ret i8* %t
137}
138
139; Turn objc_retain into objc_retainAutoreleasedReturnValue if its operand
140; is a return value.
141
142; CHECK: define void @test8()
143; CHECK: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
144define void @test8() {
145  %p = call i8* @returner()
146  call i8* @objc_retain(i8* %p)
147  ret void
148}
149
150; Don't apply the RV optimization to autorelease if there's no retain.
151
152; CHECK: define i8* @test9(i8* %p)
153; CHECK: tail call i8* @objc_autorelease(i8* %p)
154define i8* @test9(i8* %p) {
155  call i8* @objc_autorelease(i8* %p)
156  ret i8* %p
157}
158
159; Apply the RV optimization.
160
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
165define i8* @test10(i8* %p) {
166  %1 = call i8* @objc_retain(i8* %p)
167  %2 = call i8* @objc_autorelease(i8* %p)
168  ret i8* %p
169}
170
171; Don't do the autoreleaseRV optimization because @use_pointer
172; could undo the retain.
173
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
179define 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)
183  ret i8* %p
184}
185
186; Don't spoil the RV optimization.
187
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)
192; CHECK: ret i8* %p
193define 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)
197  ret i8* %p
198}
199
200; Don't zap the objc_retainAutoreleasedReturnValue.
201
202; CHECK: define i8* @test13(
203; CHECK: tail call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
204; CHECK: tail call i8* @objc_autorelease(i8* %p)
205; CHECK: ret i8* %p
206define i8* @test13() {
207  %p = call i8* @returner()
208  %1 = call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
209  call void @callee()
210  %2 = call i8* @objc_autorelease(i8* %p)
211  ret i8* %p
212}
213
214; Convert objc_retainAutoreleasedReturnValue to objc_retain if its
215; argument is not a return value.
216
217; CHECK: define void @test14(
218; CHECK-NEXT: tail call i8* @objc_retain(i8* %p) nounwind
219; CHECK-NEXT: ret void
220define void @test14(i8* %p) {
221  call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
222  ret void
223}
224
225; Don't convert objc_retainAutoreleasedReturnValue to objc_retain if its
226; argument is a return value.
227
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
232define void @test15() {
233  %y = call i8* @returner()
234  call i8* @objc_retainAutoreleasedReturnValue(i8* %y)
235  ret void
236}
237
238; Convert objc_retain to objc_retainAutoreleasedReturnValue if its
239; argument is a return value.
240
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
245define void @test16() {
246  %y = call i8* @returner()
247  call i8* @objc_retain(i8* %y)
248  ret void
249}
250
251; Don't convert objc_retain to objc_retainAutoreleasedReturnValue if its
252; argument is not a return value.
253
254; CHECK: define void @test17(
255; CHECK-NEXT: tail call i8* @objc_retain(i8* %y) nounwind
256; CHECK-NEXT: ret void
257define void @test17(i8* %y) {
258  call i8* @objc_retain(i8* %y)
259  ret void
260}
261
262; Don't Convert objc_retain to objc_retainAutoreleasedReturnValue if it
263; isn't next to the call providing its return value.
264
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
270define void @test18() {
271  %y = call i8* @returner()
272  call void @callee()
273  call i8* @objc_retain(i8* %y)
274  ret void
275}
276
277; Delete autoreleaseRV+retainRV pairs.
278
279; CHECK: define i8* @test19(i8* %p) {
280; CHECK-NEXT: ret i8* %p
281define i8* @test19(i8* %p) {
282  call i8* @objc_autoreleaseReturnValue(i8* %p)
283  call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
284  ret i8* %p
285}
286
287; Like test19 but with plain autorelease.
288
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
293define i8* @test20(i8* %p) {
294  call i8* @objc_autorelease(i8* %p)
295  call i8* @objc_retainAutoreleasedReturnValue(i8* %p)
296  ret i8* %p
297}
298
299; Like test19 but with plain retain.
300
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
305define i8* @test21(i8* %p) {
306  call i8* @objc_autoreleaseReturnValue(i8* %p)
307  call i8* @objc_retain(i8* %p)
308  ret i8* %p
309}
310
311; Like test19 but with plain retain and autorelease.
312
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
317define i8* @test22(i8* %p) {
318  call i8* @objc_autorelease(i8* %p)
319  call i8* @objc_retain(i8* %p)
320  ret i8* %p
321}
322
323; Convert autoreleaseRV to autorelease.
324
325; CHECK: define void @test23(
326; CHECK: tail call i8* @objc_autorelease(i8* %p) nounwind
327define void @test23(i8* %p) {
328  store i8 0, i8* %p
329  call i8* @objc_autoreleaseReturnValue(i8* %p)
330  ret void
331}
332
333; Don't convert autoreleaseRV to autorelease if the result is returned,
334; even through a bitcast.
335
336; CHECK: define {}* @test24(
337; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %p)
338define {}* @test24(i8* %p) {
339  %t = call i8* @objc_autoreleaseReturnValue(i8* %p)
340  %s = bitcast i8* %p to {}*
341  ret {}* %s
342}
343