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)
19 define void @test0(i8* %x) nounwind {
21 %0 = call i8* @llvm.objc.retain(i8* %x) nounwind
22 call void @use_pointer(i8* %x)
26 ; CHECK-LABEL: define void @test1(
27 ; CHECK: call void @use_pointer(i8* %0)
29 define void @test1(i8* %x) nounwind {
31 %0 = call i8* @llvm.objc.autorelease(i8* %x) nounwind
32 call void @use_pointer(i8* %x)
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]+]]
41 define void @test2(i8* %x) nounwind {
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)
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]]
54 define i8* @test2b(i8* %x) nounwind {
56 %0 = tail call i8* @llvm.objc.retain(i8* %x) nounwind
57 tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %0) nounwind
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)
67 define void @test3(i8* %x, i64 %n) {
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
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(
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
85 define void @test4(i8* %x, i64 %n) {
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
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]]
99 ; CHECK: call i8* @llvm.objc.autorelease(i8* %0) [[NUW]]
101 define void @test5(i8* %p, i1 %a) {
103 tail call i8* @llvm.objc.retain(i8* %p) nounwind
104 br i1 %a, label %true, label %false
107 call i8* @llvm.objc.autorelease(i8* %p) nounwind
108 call void @use_pointer(i8* %p)
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]]
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)
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)
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)
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 ]
155 define i8* @test8(i1 %x, i8* %c) {
157 br i1 %x, label %return, label %if.then
159 if.then: ; preds = %entry
160 %p = call i8* @llvm.objc.retain(i8* %c) nounwind
163 return: ; preds = %if.then, %entry
164 %retval = phi i8* [ %c, %if.then ], [ null, %entry ]
168 ; Kill calls to @llvm.objc.clang.arc.use(...)
169 ; CHECK-LABEL: define void @test9(
170 ; CHECK-NOT: clang.arc.use
172 define void @test9(i8* %a, i8* %b) {
173 call void (...) @llvm.objc.clang.arc.use(i8* %a, i8* %b) nounwind
178 ; Turn objc_retain into objc_retainAutoreleasedReturnValue if its operand
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
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
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
209 define void @test12(i8* %y) {
210 tail call i8* @llvm.objc.retain(i8* %y) nounwind
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
223 define void @test13() {
224 %y = call i8* @returner()
226 tail call i8* @llvm.objc.retain(i8* %y) nounwind
230 ; CHECK-LABEL: define void @test14(
231 ; CHECK-NOT: clang.arc.noop.use
233 define void @test14(i8* %a, i8* %b) {
234 call void (...) @llvm.objc.clang.arc.noop.use(i8* %a, i8* %b) nounwind
238 declare void @llvm.objc.clang.arc.use(...) nounwind
239 declare void @llvm.objc.clang.arc.noop.use(...) nounwind
241 ; CHECK: attributes [[NUW]] = { nounwind }