xref: /llvm-project/llvm/test/Transforms/ObjCARC/inlined-autorelease-return-value.ll (revision 01e4f41b43b57dee751146fde9992c660bd7c714)
1; RUN: opt -passes=objc-arc -S < %s | FileCheck %s
2
3target datalayout = "e-p:64:64:64"
4
5declare ptr @llvm.objc.retain(ptr)
6declare ptr @llvm.objc.autoreleaseReturnValue(ptr)
7declare ptr @llvm.objc.retainAutoreleasedReturnValue(ptr)
8declare ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr)
9declare void @opaque()
10declare void @llvm.lifetime.start(i64, ptr nocapture)
11declare void @llvm.lifetime.end(i64, ptr nocapture)
12
13; CHECK-LABEL: define ptr @elide_with_retainRV(
14; CHECK-NEXT:  entry:
15; CHECK-NEXT:    ret ptr %x
16define ptr @elide_with_retainRV(ptr %x) nounwind {
17entry:
18  %b = call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) nounwind
19  %c = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %b) nounwind
20  ret ptr %c
21}
22
23; CHECK-LABEL: define ptr @elide_with_retainRV_bitcast(
24; CHECK-NEXT:  entry:
25; CHECK-NEXT:    ret ptr %x
26define ptr @elide_with_retainRV_bitcast(ptr %x) nounwind {
27entry:
28  %b = call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) nounwind
29  %d = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %x) nounwind
30  ret ptr %d
31}
32
33; CHECK-LABEL: define ptr @elide_with_retainRV_phi(
34; CHECK-NOT:   define
35; CHECK:       phis:
36; CHECK-NEXT:    phi ptr
37; CHECK-NEXT:    ret ptr
38define ptr @elide_with_retainRV_phi(ptr %x) nounwind {
39entry:
40  br label %phis
41
42phis:
43  %a = phi ptr [ %x, %entry ]
44  %c = phi ptr [ %x, %entry ]
45  %b = call ptr @llvm.objc.autoreleaseReturnValue(ptr %a) nounwind
46  %d = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %c) nounwind
47  ret ptr %d
48}
49
50; CHECK-LABEL: define ptr @elide_with_retainRV_splitByRetain(
51; CHECK-NEXT:  entry:
52; CHECK-NEXT:    %b = call ptr @llvm.objc.autorelease(ptr %x)
53; CHECK-NEXT:    tail call ptr @llvm.objc.retain(ptr %x)
54; CHECK-NEXT:    tail call ptr @llvm.objc.retain(ptr %b)
55define ptr @elide_with_retainRV_splitByRetain(ptr %x) nounwind {
56entry:
57  ; Cleanup is blocked by other ARC intrinsics for ease of implementation; we
58  ; only delay processing AutoreleaseRV until the very next ARC intrinsic.  In
59  ; practice, it would be very strange for this to matter.
60  %b = call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) nounwind
61  %c = call ptr @llvm.objc.retain(ptr %x) nounwind
62  %d = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %b) nounwind
63  ret ptr %d
64}
65
66; CHECK-LABEL: define ptr @elide_with_retainRV_splitByOpaque(
67; CHECK-NEXT:  entry:
68; CHECK-NEXT:    %b = call ptr @llvm.objc.autorelease(ptr %x)
69; CHECK-NEXT:    call void @opaque()
70; CHECK-NEXT:    %d = tail call ptr @llvm.objc.retain(ptr %b)
71; CHECK-NEXT:    ret ptr %d
72define ptr @elide_with_retainRV_splitByOpaque(ptr %x) nounwind {
73entry:
74  ; Cleanup should get blocked by opaque calls.
75  %b = call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) nounwind
76  call void @opaque() nounwind
77  %d = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %b) nounwind
78  ret ptr %d
79}
80
81; CHECK-LABEL: define ptr @elide_with_retainRV_splitByLifetime(
82; CHECK-NEXT:  entry:
83; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 8, ptr %x)
84; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 8, ptr %x)
85; CHECK-NEXT:    ret ptr %x
86define ptr @elide_with_retainRV_splitByLifetime(ptr %x) nounwind {
87entry:
88  ; Cleanup should skip over lifetime intrinsics.
89  call void @llvm.lifetime.start(i64 8, ptr %x)
90  %b = call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) nounwind
91  call void @llvm.lifetime.end(i64 8, ptr %x)
92  %d = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %b) nounwind
93  ret ptr %d
94}
95
96; CHECK-LABEL: define ptr @elide_with_retainRV_wrongArg(
97; CHECK-NEXT:  entry:
98; CHECK-NEXT:    call void @llvm.objc.release(ptr %x)
99; CHECK-NEXT:    tail call ptr @llvm.objc.retain(ptr %y)
100define ptr @elide_with_retainRV_wrongArg(ptr %x, ptr %y) nounwind {
101entry:
102  %b = call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) nounwind
103  %c = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %y) nounwind
104  ret ptr %c
105}
106
107; CHECK-LABEL: define ptr @elide_with_retainRV_wrongBB(
108; CHECK-NEXT:  entry:
109; CHECK-NEXT:    call ptr @llvm.objc.autorelease(ptr %x)
110; CHECK-NEXT:    br label %next
111; CHECK:       next:
112; CHECK-NEXT:    tail call ptr @llvm.objc.retain(
113; CHECK-NEXT:    ret ptr
114define ptr @elide_with_retainRV_wrongBB(ptr %x) nounwind {
115entry:
116  %b = call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) nounwind
117  br label %next
118
119next:
120  %c = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %b) nounwind
121  ret ptr %c
122}
123
124; CHECK-LABEL: define ptr @elide_with_retainRV_beforeAutoreleaseRV(
125; CHECK-NEXT:  entry:
126; CHECK-NEXT:    tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %x)
127; CHECK-NEXT:    ret ptr %x
128define ptr @elide_with_retainRV_beforeAutoreleaseRV(ptr %x) nounwind {
129entry:
130  %b = call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) nounwind
131  %c = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %b) nounwind
132  %d = call ptr @llvm.objc.autoreleaseReturnValue(ptr %c) nounwind
133  ret ptr %c
134}
135
136; CHECK-LABEL: define ptr @elide_with_retainRV_afterRetain(
137; CHECK-NEXT:  entry:
138; CHECK-NEXT:    tail call ptr @llvm.objc.retain(ptr %x)
139; CHECK-NEXT:    ret ptr %a
140define ptr @elide_with_retainRV_afterRetain(ptr %x) nounwind {
141entry:
142  %a = call ptr @llvm.objc.retain(ptr %x) nounwind
143  %b = call ptr @llvm.objc.autoreleaseReturnValue(ptr %a) nounwind
144  %c = call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %b) nounwind
145  ret ptr %c
146}
147
148; CHECK-LABEL: define ptr @elide_with_claimRV(
149; CHECK-NEXT:  entry:
150; CHECK-NEXT:    tail call void @llvm.objc.release(ptr %x)
151; CHECK-NEXT:    ret ptr %x
152define ptr @elide_with_claimRV(ptr %x) nounwind {
153entry:
154  %b = call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) nounwind
155  %c = call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %b) nounwind
156  ret ptr %c
157}
158
159; CHECK-LABEL: define ptr @elide_with_claimRV_bitcast(
160; CHECK-NEXT:  entry:
161; CHECK-NEXT:    tail call void @llvm.objc.release(ptr %x)
162; CHECK-NEXT:    ret ptr %x
163define ptr @elide_with_claimRV_bitcast(ptr %x) nounwind {
164entry:
165  %b = call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) nounwind
166  %d = call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %x) nounwind
167  ret ptr %d
168}
169
170; CHECK-LABEL: define ptr @elide_with_claimRV_phi(
171; CHECK-NOT:   define
172; CHECK:       phis:
173; CHECK-NEXT:    %c = phi ptr
174; CHECK-NEXT:    tail call void @llvm.objc.release(ptr %c)
175; CHECK-NEXT:    ret ptr %c
176define ptr @elide_with_claimRV_phi(ptr %x) nounwind {
177entry:
178  br label %phis
179
180phis:
181  %a = phi ptr [ %x, %entry ]
182  %c = phi ptr [ %x, %entry ]
183  %b = call ptr @llvm.objc.autoreleaseReturnValue(ptr %a) nounwind
184  %d = call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %c) nounwind
185  ret ptr %d
186}
187
188; CHECK-LABEL: define ptr @elide_with_claimRV_splitByRetain(
189; CHECK-NEXT:  entry:
190; CHECK-NEXT:    %b = call ptr @llvm.objc.autorelease(ptr %x)
191; CHECK-NEXT:    tail call ptr @llvm.objc.retain(ptr %x)
192; CHECK-NEXT:    tail call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %b)
193define ptr @elide_with_claimRV_splitByRetain(ptr %x) nounwind {
194entry:
195  ; Cleanup is blocked by other ARC intrinsics for ease of implementation; we
196  ; only delay processing AutoreleaseRV until the very next ARC intrinsic.  In
197  ; practice, it would be very strange for this to matter.
198  %b = call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) nounwind
199  %c = call ptr @llvm.objc.retain(ptr %x) nounwind
200  %d = call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %b) nounwind
201  ret ptr %d
202}
203
204; CHECK-LABEL: define ptr @elide_with_claimRV_splitByOpaque(
205; CHECK-NEXT:  entry:
206; CHECK-NEXT:    %b = call ptr @llvm.objc.autorelease(ptr %x)
207; CHECK-NEXT:    call void @opaque()
208; CHECK-NEXT:    %d = tail call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %b)
209; CHECK-NEXT:    ret ptr %d
210define ptr @elide_with_claimRV_splitByOpaque(ptr %x) nounwind {
211entry:
212  ; Cleanup should get blocked by opaque calls.
213  %b = call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) nounwind
214  call void @opaque() nounwind
215  %d = call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %b) nounwind
216  ret ptr %d
217}
218
219; CHECK-LABEL: define ptr @elide_with_claimRV_splitByLifetime(
220; CHECK-NEXT:  entry:
221; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 8, ptr %x)
222; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 8, ptr %x)
223; CHECK-NEXT:    tail call void @llvm.objc.release(ptr %x)
224; CHECK-NEXT:    ret ptr %x
225define ptr @elide_with_claimRV_splitByLifetime(ptr %x) nounwind {
226entry:
227  ; Cleanup should skip over lifetime intrinsics.
228  call void @llvm.lifetime.start(i64 8, ptr %x)
229  %b = call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) nounwind
230  call void @llvm.lifetime.end(i64 8, ptr %x)
231  %d = call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %b) nounwind
232  ret ptr %d
233}
234
235; CHECK-LABEL: define ptr @elide_with_claimRV_wrongArg(
236; CHECK-NEXT:  entry:
237; CHECK-NEXT:    call void @llvm.objc.release(ptr %x)
238; CHECK-NEXT:    tail call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %y)
239define ptr @elide_with_claimRV_wrongArg(ptr %x, ptr %y) nounwind {
240entry:
241  %b = call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) nounwind
242  %c = call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %y) nounwind
243  ret ptr %c
244}
245
246; CHECK-LABEL: define ptr @elide_with_claimRV_wrongBB(
247; CHECK-NEXT:  entry:
248; CHECK-NEXT:    call ptr @llvm.objc.autorelease(ptr %x)
249; CHECK-NEXT:    br label %next
250; CHECK:       next:
251; CHECK-NEXT:    tail call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(
252; CHECK-NEXT:    ret ptr
253define ptr @elide_with_claimRV_wrongBB(ptr %x) nounwind {
254entry:
255  %b = call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) nounwind
256  br label %next
257
258next:
259  %c = call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %b) nounwind
260  ret ptr %c
261}
262
263
264; CHECK-LABEL: define ptr @elide_with_claimRV_beforeAutoreleaseRV(
265; CHECK-NEXT:  entry:
266; CHECK-NEXT:    tail call void @llvm.objc.release(ptr %x)
267; CHECK-NEXT:    tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %x)
268; CHECK-NEXT:    ret ptr %x
269define ptr @elide_with_claimRV_beforeAutoreleaseRV(ptr %x) nounwind {
270entry:
271  %b = call ptr @llvm.objc.autoreleaseReturnValue(ptr %x) nounwind
272  %c = call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %b) nounwind
273  %d = call ptr @llvm.objc.autoreleaseReturnValue(ptr %c) nounwind
274  ret ptr %c
275}
276
277; CHECK-LABEL: define ptr @elide_with_claimRV_afterRetain(
278; CHECK-NEXT:  entry:
279; CHECK-NEXT:    ret ptr %x
280define ptr @elide_with_claimRV_afterRetain(ptr %x) nounwind {
281entry:
282  %a = call ptr @llvm.objc.retain(ptr %x) nounwind
283  %b = call ptr @llvm.objc.autoreleaseReturnValue(ptr %a) nounwind
284  %c = call ptr @llvm.objc.unsafeClaimAutoreleasedReturnValue(ptr %b) nounwind
285  ret ptr %c
286}
287