Bump version to 19.1.0-rc3
[llvm-project.git] / llvm / test / Transforms / ObjCARC / contract.ll
blob70bd57a0c719adee7d2a933360dee81b50abe064
1 ; RUN: opt -passes=objc-arc-contract -S < %s | FileCheck %s
3 target datalayout = "e-p:64:64:64"
5 declare ptr @llvm.objc.retain(ptr)
6 declare void @llvm.objc.release(ptr)
7 declare ptr @llvm.objc.autorelease(ptr)
8 declare ptr @llvm.objc.autoreleaseReturnValue(ptr)
9 declare ptr @llvm.objc.retainAutoreleasedReturnValue(ptr)
11 declare void @use_pointer(ptr)
12 declare ptr @returner()
13 declare void @callee()
15 ; CHECK-LABEL: define void @test0(
16 ; CHECK: call void @use_pointer(ptr %0)
17 ; CHECK: }
18 define void @test0(ptr %x) nounwind {
19 entry:
20   %0 = call ptr @llvm.objc.retain(ptr %x) nounwind
21   call void @use_pointer(ptr %x)
22   ret void
25 ; CHECK-LABEL: define void @test1(
26 ; CHECK: call void @use_pointer(ptr %0)
27 ; CHECK: }
28 define void @test1(ptr %x) nounwind {
29 entry:
30   %0 = call ptr @llvm.objc.autorelease(ptr %x) nounwind
31   call void @use_pointer(ptr %x)
32   ret void
35 ; Merge objc_retain and objc_autorelease into objc_retainAutorelease.
37 ; CHECK-LABEL: define void @test2(
38 ; CHECK: tail call ptr @llvm.objc.retainAutorelease(ptr %x) [[NUW:#[0-9]+]]
39 ; CHECK: }
40 define void @test2(ptr %x) nounwind {
41 entry:
42   %0 = tail call ptr @llvm.objc.retain(ptr %x) nounwind
43   call ptr @llvm.objc.autorelease(ptr %0) nounwind
44   call void @use_pointer(ptr %x)
45   ret void
48 ; Same as test2 but the value is returned. Do an RV optimization.
50 ; CHECK-LABEL: define ptr @test2b(
51 ; CHECK: tail call ptr @llvm.objc.retainAutoreleaseReturnValue(ptr %x) [[NUW]]
52 ; CHECK: }
53 define ptr @test2b(ptr %x) nounwind {
54 entry:
55   %0 = tail call ptr @llvm.objc.retain(ptr %x) nounwind
56   tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %0) nounwind
57   ret ptr %x
60 ; Merge a retain,autorelease pair around a call.
62 ; CHECK-LABEL: define void @test3(
63 ; CHECK: tail call ptr @llvm.objc.retainAutorelease(ptr %x) [[NUW]]
64 ; CHECK: @use_pointer(ptr %0)
65 ; CHECK: }
66 define void @test3(ptr %x, i64 %n) {
67 entry:
68   tail call ptr @llvm.objc.retain(ptr %x) nounwind
69   call void @use_pointer(ptr %x)
70   call ptr @llvm.objc.autorelease(ptr %x) nounwind
71   ret void
74 ; Trivial retain,autorelease pair with intervening call, but it's post-dominated
75 ; by another release. The retain and autorelease can be merged.
77 ; CHECK-LABEL: define void @test4(
78 ; CHECK-NEXT: entry:
79 ; CHECK-NEXT: @llvm.objc.retainAutorelease(ptr %x) [[NUW]]
80 ; CHECK-NEXT: @use_pointer
81 ; CHECK-NEXT: @llvm.objc.release
82 ; CHECK-NEXT: ret void
83 ; CHECK-NEXT: }
84 define void @test4(ptr %x, i64 %n) {
85 entry:
86   tail call ptr @llvm.objc.retain(ptr %x) nounwind
87   call void @use_pointer(ptr %x)
88   call ptr @llvm.objc.autorelease(ptr %x) nounwind
89   tail call void @llvm.objc.release(ptr %x) nounwind
90   ret void
93 ; Don't merge retain and autorelease if they're not control-equivalent.
95 ; CHECK-LABEL: define void @test5(
96 ; CHECK: tail call ptr @llvm.objc.retain(ptr %p) [[NUW]]
97 ; CHECK: true:
98 ; CHECK: call ptr @llvm.objc.autorelease(ptr %0) [[NUW]]
99 ; CHECK: }
100 define void @test5(ptr %p, i1 %a) {
101 entry:
102   tail call ptr @llvm.objc.retain(ptr %p) nounwind
103   br i1 %a, label %true, label %false
105 true:
106   call ptr @llvm.objc.autorelease(ptr %p) nounwind
107   call void @use_pointer(ptr %p)
108   ret void
110 false:
111   ret void
114 ; Don't eliminate objc_retainAutoreleasedReturnValue by merging it into
115 ; an objc_autorelease.
116 ; TODO? Merge objc_retainAutoreleasedReturnValue and objc_autorelease into
117 ; objc_retainAutoreleasedReturnValueAutorelease and merge
118 ; objc_retainAutoreleasedReturnValue and objc_autoreleaseReturnValue
119 ; into objc_retainAutoreleasedReturnValueAutoreleaseReturnValue?
120 ; Those entrypoints don't exist yet though.
122 ; CHECK-LABEL: define ptr @test6(
123 ; CHECK: call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %p) [[NUW]]
124 ; CHECK: %t = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %1) [[NUW]]
125 ; CHECK: }
126 define ptr @test6() {
127   %p = call ptr @returner()
128   tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %p) nounwind
129   %t = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %p) nounwind
130   call void @use_pointer(ptr %t)
131   ret ptr %t
134 ; Don't spoil the RV optimization.
136 ; CHECK: define ptr @test7(ptr %p)
137 ; CHECK: tail call ptr @llvm.objc.retain(ptr %p)
138 ; CHECK: call void @use_pointer(ptr %1)
139 ; CHECK: tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %1)
140 ; CHECK: ret ptr %2
141 ; CHECK-NEXT: }
142 define ptr @test7(ptr %p) {
143   %1 = tail call ptr @llvm.objc.retain(ptr %p)
144   call void @use_pointer(ptr %p)
145   %2 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %p)
146   ret ptr %p
149 ; Do the return value substitution for PHI nodes too.
151 ; CHECK-LABEL: define ptr @test8(
152 ; CHECK: %retval = phi ptr [ %p, %if.then ], [ null, %entry ]
153 ; CHECK: }
154 define ptr @test8(i1 %x, ptr %c) {
155 entry:
156   br i1 %x, label %return, label %if.then
158 if.then:                                          ; preds = %entry
159   %p = call ptr @llvm.objc.retain(ptr %c) nounwind
160   br label %return
162 return:                                           ; preds = %if.then, %entry
163   %retval = phi ptr [ %c, %if.then ], [ null, %entry ]
164   ret ptr %retval
167 ; Kill calls to @llvm.objc.clang.arc.use(...)
168 ; CHECK-LABEL: define void @test9(
169 ; CHECK-NOT: clang.arc.use
170 ; CHECK: }
171 define void @test9(ptr %a, ptr %b) {
172   call void (...) @llvm.objc.clang.arc.use(ptr %a, ptr %b) nounwind
173   ret void
177 ; Turn objc_retain into objc_retainAutoreleasedReturnValue if its operand
178 ; is a return value.
180 ; CHECK: define void @test10()
181 ; CHECK: tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %p)
182 define void @test10() {
183   %p = call ptr @returner()
184   tail call ptr @llvm.objc.retain(ptr %p) nounwind
185   ret void
188 ; Convert objc_retain to objc_retainAutoreleasedReturnValue if its
189 ; argument is a return value.
191 ; CHECK-LABEL: define void @test11(
192 ; CHECK-NEXT: %y = call ptr @returner()
193 ; CHECK-NEXT: tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %y) [[NUW]]
194 ; CHECK-NEXT: ret void
195 define void @test11() {
196   %y = call ptr @returner()
197   tail call ptr @llvm.objc.retain(ptr %y) nounwind
198   ret void
201 ; Don't convert objc_retain to objc_retainAutoreleasedReturnValue if its
202 ; argument is not a return value.
204 ; CHECK-LABEL: define void @test12(
205 ; CHECK-NEXT: tail call ptr @llvm.objc.retain(ptr %y) [[NUW]]
206 ; CHECK-NEXT: ret void
207 ; CHECK-NEXT: }
208 define void @test12(ptr %y) {
209   tail call ptr @llvm.objc.retain(ptr %y) nounwind
210   ret void
213 ; Don't Convert objc_retain to objc_retainAutoreleasedReturnValue if it
214 ; isn't next to the call providing its return value.
216 ; CHECK-LABEL: define void @test13(
217 ; CHECK-NEXT: %y = call ptr @returner()
218 ; CHECK-NEXT: call void @callee()
219 ; CHECK-NEXT: tail call ptr @llvm.objc.retain(ptr %y) [[NUW]]
220 ; CHECK-NEXT: ret void
221 ; CHECK-NEXT: }
222 define void @test13() {
223   %y = call ptr @returner()
224   call void @callee()
225   tail call ptr @llvm.objc.retain(ptr %y) nounwind
226   ret void
229 ; CHECK-LABEL: define void @test14(
230 ; CHECK-NOT: clang.arc.noop.use
231 ; CHECK: ret void
232 define void @test14(ptr %a, ptr %b) {
233   call void (...) @llvm.objc.clang.arc.noop.use(ptr %a, ptr %b) nounwind
234   ret void
237 declare void @llvm.objc.clang.arc.use(...) nounwind
238 declare void @llvm.objc.clang.arc.noop.use(...) nounwind
240 ; CHECK: attributes [[NUW]] = { nounwind }