[docs] Add LICENSE.txt to the root of the mono-repo
[llvm-project.git] / llvm / test / Transforms / ObjCARC / contract.ll
blob36f0a842d0e667860bb1483f59800b5217f63065
1 ; RUN: opt -objc-arc-contract -S < %s | FileCheck %s
2 ; RUN: opt -passes=objc-arc-contract -S < %s | FileCheck %s
4 target datalayout = "e-p:64:64:64"
6 declare i8* @llvm.objc.retain(i8*)
7 declare void @llvm.objc.release(i8*)
8 declare i8* @llvm.objc.autorelease(i8*)
9 declare i8* @llvm.objc.autoreleaseReturnValue(i8*)
10 declare i8* @llvm.objc.retainAutoreleasedReturnValue(i8*)
12 declare void @use_pointer(i8*)
13 declare i8* @returner()
14 declare void @callee()
16 ; CHECK-LABEL: define void @test0(
17 ; CHECK: call void @use_pointer(i8* %0)
18 ; CHECK: }
19 define void @test0(i8* %x) nounwind {
20 entry:
21   %0 = call i8* @llvm.objc.retain(i8* %x) nounwind
22   call void @use_pointer(i8* %x)
23   ret void
26 ; CHECK-LABEL: define void @test1(
27 ; CHECK: call void @use_pointer(i8* %0)
28 ; CHECK: }
29 define void @test1(i8* %x) nounwind {
30 entry:
31   %0 = call i8* @llvm.objc.autorelease(i8* %x) nounwind
32   call void @use_pointer(i8* %x)
33   ret void
36 ; Merge objc_retain and objc_autorelease into objc_retainAutorelease.
38 ; CHECK-LABEL: define void @test2(
39 ; CHECK: tail call i8* @llvm.objc.retainAutorelease(i8* %x) [[NUW:#[0-9]+]]
40 ; CHECK: }
41 define void @test2(i8* %x) nounwind {
42 entry:
43   %0 = tail call i8* @llvm.objc.retain(i8* %x) nounwind
44   call i8* @llvm.objc.autorelease(i8* %0) nounwind
45   call void @use_pointer(i8* %x)
46   ret void
49 ; Same as test2 but the value is returned. Do an RV optimization.
51 ; CHECK-LABEL: define i8* @test2b(
52 ; CHECK: tail call i8* @llvm.objc.retainAutoreleaseReturnValue(i8* %x) [[NUW]]
53 ; CHECK: }
54 define i8* @test2b(i8* %x) nounwind {
55 entry:
56   %0 = tail call i8* @llvm.objc.retain(i8* %x) nounwind
57   tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %0) nounwind
58   ret i8* %x
61 ; Merge a retain,autorelease pair around a call.
63 ; CHECK-LABEL: define void @test3(
64 ; CHECK: tail call i8* @llvm.objc.retainAutorelease(i8* %x) [[NUW]]
65 ; CHECK: @use_pointer(i8* %0)
66 ; CHECK: }
67 define void @test3(i8* %x, i64 %n) {
68 entry:
69   tail call i8* @llvm.objc.retain(i8* %x) nounwind
70   call void @use_pointer(i8* %x)
71   call i8* @llvm.objc.autorelease(i8* %x) nounwind
72   ret void
75 ; Trivial retain,autorelease pair with intervening call, but it's post-dominated
76 ; by another release. The retain and autorelease can be merged.
78 ; CHECK-LABEL: define void @test4(
79 ; CHECK-NEXT: entry:
80 ; CHECK-NEXT: @llvm.objc.retainAutorelease(i8* %x) [[NUW]]
81 ; CHECK-NEXT: @use_pointer
82 ; CHECK-NEXT: @llvm.objc.release
83 ; CHECK-NEXT: ret void
84 ; CHECK-NEXT: }
85 define void @test4(i8* %x, i64 %n) {
86 entry:
87   tail call i8* @llvm.objc.retain(i8* %x) nounwind
88   call void @use_pointer(i8* %x)
89   call i8* @llvm.objc.autorelease(i8* %x) nounwind
90   tail call void @llvm.objc.release(i8* %x) nounwind
91   ret void
94 ; Don't merge retain and autorelease if they're not control-equivalent.
96 ; CHECK-LABEL: define void @test5(
97 ; CHECK: tail call i8* @llvm.objc.retain(i8* %p) [[NUW]]
98 ; CHECK: true:
99 ; CHECK: call i8* @llvm.objc.autorelease(i8* %0) [[NUW]]
100 ; CHECK: }
101 define void @test5(i8* %p, i1 %a) {
102 entry:
103   tail call i8* @llvm.objc.retain(i8* %p) nounwind
104   br i1 %a, label %true, label %false
106 true:
107   call i8* @llvm.objc.autorelease(i8* %p) nounwind
108   call void @use_pointer(i8* %p)
109   ret void
111 false:
112   ret void
115 ; Don't eliminate objc_retainAutoreleasedReturnValue by merging it into
116 ; an objc_autorelease.
117 ; TODO? Merge objc_retainAutoreleasedReturnValue and objc_autorelease into
118 ; objc_retainAutoreleasedReturnValueAutorelease and merge
119 ; objc_retainAutoreleasedReturnValue and objc_autoreleaseReturnValue
120 ; into objc_retainAutoreleasedReturnValueAutoreleaseReturnValue?
121 ; Those entrypoints don't exist yet though.
123 ; CHECK-LABEL: define i8* @test6(
124 ; CHECK: call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %p) [[NUW]]
125 ; CHECK: %t = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %1) [[NUW]]
126 ; CHECK: }
127 define i8* @test6() {
128   %p = call i8* @returner()
129   tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %p) nounwind
130   %t = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %p) nounwind
131   call void @use_pointer(i8* %t)
132   ret i8* %t
135 ; Don't spoil the RV optimization.
137 ; CHECK: define i8* @test7(i8* %p)
138 ; CHECK: tail call i8* @llvm.objc.retain(i8* %p)
139 ; CHECK: call void @use_pointer(i8* %1)
140 ; CHECK: tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %1)
141 ; CHECK: ret i8* %2
142 ; CHECK-NEXT: }
143 define i8* @test7(i8* %p) {
144   %1 = tail call i8* @llvm.objc.retain(i8* %p)
145   call void @use_pointer(i8* %p)
146   %2 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %p)
147   ret i8* %p
150 ; Do the return value substitution for PHI nodes too.
152 ; CHECK-LABEL: define i8* @test8(
153 ; CHECK: %retval = phi i8* [ %p, %if.then ], [ null, %entry ]
154 ; CHECK: }
155 define i8* @test8(i1 %x, i8* %c) {
156 entry:
157   br i1 %x, label %return, label %if.then
159 if.then:                                          ; preds = %entry
160   %p = call i8* @llvm.objc.retain(i8* %c) nounwind
161   br label %return
163 return:                                           ; preds = %if.then, %entry
164   %retval = phi i8* [ %c, %if.then ], [ null, %entry ]
165   ret i8* %retval
168 ; Kill calls to @llvm.objc.clang.arc.use(...)
169 ; CHECK-LABEL: define void @test9(
170 ; CHECK-NOT: clang.arc.use
171 ; CHECK: }
172 define void @test9(i8* %a, i8* %b) {
173   call void (...) @llvm.objc.clang.arc.use(i8* %a, i8* %b) nounwind
174   ret void
178 ; Turn objc_retain into objc_retainAutoreleasedReturnValue if its operand
179 ; is a return value.
181 ; CHECK: define void @test10()
182 ; CHECK: tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %p)
183 define void @test10() {
184   %p = call i8* @returner()
185   tail call i8* @llvm.objc.retain(i8* %p) nounwind
186   ret void
189 ; Convert objc_retain to objc_retainAutoreleasedReturnValue if its
190 ; argument is a return value.
192 ; CHECK-LABEL: define void @test11(
193 ; CHECK-NEXT: %y = call i8* @returner()
194 ; CHECK-NEXT: tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %y) [[NUW]]
195 ; CHECK-NEXT: ret void
196 define void @test11() {
197   %y = call i8* @returner()
198   tail call i8* @llvm.objc.retain(i8* %y) nounwind
199   ret void
202 ; Don't convert objc_retain to objc_retainAutoreleasedReturnValue if its
203 ; argument is not a return value.
205 ; CHECK-LABEL: define void @test12(
206 ; CHECK-NEXT: tail call i8* @llvm.objc.retain(i8* %y) [[NUW]]
207 ; CHECK-NEXT: ret void
208 ; CHECK-NEXT: }
209 define void @test12(i8* %y) {
210   tail call i8* @llvm.objc.retain(i8* %y) nounwind
211   ret void
214 ; Don't Convert objc_retain to objc_retainAutoreleasedReturnValue if it
215 ; isn't next to the call providing its return value.
217 ; CHECK-LABEL: define void @test13(
218 ; CHECK-NEXT: %y = call i8* @returner()
219 ; CHECK-NEXT: call void @callee()
220 ; CHECK-NEXT: tail call i8* @llvm.objc.retain(i8* %y) [[NUW]]
221 ; CHECK-NEXT: ret void
222 ; CHECK-NEXT: }
223 define void @test13() {
224   %y = call i8* @returner()
225   call void @callee()
226   tail call i8* @llvm.objc.retain(i8* %y) nounwind
227   ret void
230 ; CHECK-LABEL: define void @test14(
231 ; CHECK-NOT: clang.arc.noop.use
232 ; CHECK: ret void
233 define void @test14(i8* %a, i8* %b) {
234   call void (...) @llvm.objc.clang.arc.noop.use(i8* %a, i8* %b) nounwind
235   ret void
238 declare void @llvm.objc.clang.arc.use(...) nounwind
239 declare void @llvm.objc.clang.arc.noop.use(...) nounwind
241 ; CHECK: attributes [[NUW]] = { nounwind }