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)
18 define void @test0(ptr %x) nounwind {
20 %0 = call ptr @llvm.objc.retain(ptr %x) nounwind
21 call void @use_pointer(ptr %x)
25 ; CHECK-LABEL: define void @test1(
26 ; CHECK: call void @use_pointer(ptr %0)
28 define void @test1(ptr %x) nounwind {
30 %0 = call ptr @llvm.objc.autorelease(ptr %x) nounwind
31 call void @use_pointer(ptr %x)
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]+]]
40 define void @test2(ptr %x) nounwind {
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)
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]]
53 define ptr @test2b(ptr %x) nounwind {
55 %0 = tail call ptr @llvm.objc.retain(ptr %x) nounwind
56 tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %0) nounwind
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)
66 define void @test3(ptr %x, i64 %n) {
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
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(
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
84 define void @test4(ptr %x, i64 %n) {
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
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]]
98 ; CHECK: call ptr @llvm.objc.autorelease(ptr %0) [[NUW]]
100 define void @test5(ptr %p, i1 %a) {
102 tail call ptr @llvm.objc.retain(ptr %p) nounwind
103 br i1 %a, label %true, label %false
106 call ptr @llvm.objc.autorelease(ptr %p) nounwind
107 call void @use_pointer(ptr %p)
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]]
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)
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)
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)
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 ]
154 define ptr @test8(i1 %x, ptr %c) {
156 br i1 %x, label %return, label %if.then
158 if.then: ; preds = %entry
159 %p = call ptr @llvm.objc.retain(ptr %c) nounwind
162 return: ; preds = %if.then, %entry
163 %retval = phi ptr [ %c, %if.then ], [ null, %entry ]
167 ; Kill calls to @llvm.objc.clang.arc.use(...)
168 ; CHECK-LABEL: define void @test9(
169 ; CHECK-NOT: clang.arc.use
171 define void @test9(ptr %a, ptr %b) {
172 call void (...) @llvm.objc.clang.arc.use(ptr %a, ptr %b) nounwind
177 ; Turn objc_retain into objc_retainAutoreleasedReturnValue if its operand
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
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
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
208 define void @test12(ptr %y) {
209 tail call ptr @llvm.objc.retain(ptr %y) nounwind
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
222 define void @test13() {
223 %y = call ptr @returner()
225 tail call ptr @llvm.objc.retain(ptr %y) nounwind
229 ; CHECK-LABEL: define void @test14(
230 ; CHECK-NOT: clang.arc.noop.use
232 define void @test14(ptr %a, ptr %b) {
233 call void (...) @llvm.objc.clang.arc.noop.use(ptr %a, ptr %b) nounwind
237 declare void @llvm.objc.clang.arc.use(...) nounwind
238 declare void @llvm.objc.clang.arc.noop.use(...) nounwind
240 ; CHECK: attributes [[NUW]] = { nounwind }