1 ; RUN: opt -objc-arc-contract -S < %s | FileCheck %s
3 target datalayout = "e-p:64:64:64"
5 declare i8* @llvm.objc.retain(i8*)
6 declare void @llvm.objc.release(i8*)
7 declare i8* @llvm.objc.autorelease(i8*)
8 declare i8* @llvm.objc.autoreleaseReturnValue(i8*)
9 declare i8* @llvm.objc.retainAutoreleasedReturnValue(i8*)
11 declare void @use_pointer(i8*)
12 declare i8* @returner()
13 declare void @callee()
15 ; CHECK-LABEL: define void @test0(
16 ; CHECK: call void @use_pointer(i8* %0)
18 define void @test0(i8* %x) nounwind {
20 %0 = call i8* @llvm.objc.retain(i8* %x) nounwind
21 call void @use_pointer(i8* %x)
25 ; CHECK-LABEL: define void @test1(
26 ; CHECK: call void @use_pointer(i8* %0)
28 define void @test1(i8* %x) nounwind {
30 %0 = call i8* @llvm.objc.autorelease(i8* %x) nounwind
31 call void @use_pointer(i8* %x)
35 ; Merge objc_retain and objc_autorelease into objc_retainAutorelease.
37 ; CHECK-LABEL: define void @test2(
38 ; CHECK: tail call i8* @llvm.objc.retainAutorelease(i8* %x) [[NUW:#[0-9]+]]
40 define void @test2(i8* %x) nounwind {
42 %0 = tail call i8* @llvm.objc.retain(i8* %x) nounwind
43 call i8* @llvm.objc.autorelease(i8* %0) nounwind
44 call void @use_pointer(i8* %x)
48 ; Same as test2 but the value is returned. Do an RV optimization.
50 ; CHECK-LABEL: define i8* @test2b(
51 ; CHECK: tail call i8* @llvm.objc.retainAutoreleaseReturnValue(i8* %x) [[NUW]]
53 define i8* @test2b(i8* %x) nounwind {
55 %0 = tail call i8* @llvm.objc.retain(i8* %x) nounwind
56 tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %0) nounwind
60 ; Merge a retain,autorelease pair around a call.
62 ; CHECK-LABEL: define void @test3(
63 ; CHECK: tail call i8* @llvm.objc.retainAutorelease(i8* %x) [[NUW]]
64 ; CHECK: @use_pointer(i8* %0)
66 define void @test3(i8* %x, i64 %n) {
68 tail call i8* @llvm.objc.retain(i8* %x) nounwind
69 call void @use_pointer(i8* %x)
70 call i8* @llvm.objc.autorelease(i8* %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(i8* %x) [[NUW]]
80 ; CHECK-NEXT: @use_pointer
81 ; CHECK-NEXT: @llvm.objc.release
82 ; CHECK-NEXT: ret void
84 define void @test4(i8* %x, i64 %n) {
86 tail call i8* @llvm.objc.retain(i8* %x) nounwind
87 call void @use_pointer(i8* %x)
88 call i8* @llvm.objc.autorelease(i8* %x) nounwind
89 tail call void @llvm.objc.release(i8* %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 i8* @llvm.objc.retain(i8* %p) [[NUW]]
98 ; CHECK: call i8* @llvm.objc.autorelease(i8* %0) [[NUW]]
100 define void @test5(i8* %p, i1 %a) {
102 tail call i8* @llvm.objc.retain(i8* %p) nounwind
103 br i1 %a, label %true, label %false
106 call i8* @llvm.objc.autorelease(i8* %p) nounwind
107 call void @use_pointer(i8* %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 i8* @test6(
123 ; CHECK: call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %p) [[NUW]]
124 ; CHECK: %t = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %1) [[NUW]]
126 define i8* @test6() {
127 %p = call i8* @returner()
128 tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %p) nounwind
129 %t = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %p) nounwind
130 call void @use_pointer(i8* %t)
134 ; Don't spoil the RV optimization.
136 ; CHECK: define i8* @test7(i8* %p)
137 ; CHECK: tail call i8* @llvm.objc.retain(i8* %p)
138 ; CHECK: call void @use_pointer(i8* %1)
139 ; CHECK: tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %1)
142 define i8* @test7(i8* %p) {
143 %1 = tail call i8* @llvm.objc.retain(i8* %p)
144 call void @use_pointer(i8* %p)
145 %2 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %p)
149 ; Do the return value substitution for PHI nodes too.
151 ; CHECK-LABEL: define i8* @test8(
152 ; CHECK: %retval = phi i8* [ %p, %if.then ], [ null, %entry ]
154 define i8* @test8(i1 %x, i8* %c) {
156 br i1 %x, label %return, label %if.then
158 if.then: ; preds = %entry
159 %p = call i8* @llvm.objc.retain(i8* %c) nounwind
162 return: ; preds = %if.then, %entry
163 %retval = phi i8* [ %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(i8* %a, i8* %b) {
172 call void (...) @llvm.objc.clang.arc.use(i8* %a, i8* %b) nounwind
177 ; Turn objc_retain into objc_retainAutoreleasedReturnValue if its operand
180 ; CHECK: define void @test10()
181 ; CHECK: tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %p)
182 define void @test10() {
183 %p = call i8* @returner()
184 tail call i8* @llvm.objc.retain(i8* %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 i8* @returner()
193 ; CHECK-NEXT: tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %y) [[NUW]]
194 ; CHECK-NEXT: ret void
195 define void @test11() {
196 %y = call i8* @returner()
197 tail call i8* @llvm.objc.retain(i8* %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 i8* @llvm.objc.retain(i8* %y) [[NUW]]
206 ; CHECK-NEXT: ret void
208 define void @test12(i8* %y) {
209 tail call i8* @llvm.objc.retain(i8* %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 i8* @returner()
218 ; CHECK-NEXT: call void @callee()
219 ; CHECK-NEXT: tail call i8* @llvm.objc.retain(i8* %y) [[NUW]]
220 ; CHECK-NEXT: ret void
222 define void @test13() {
223 %y = call i8* @returner()
225 tail call i8* @llvm.objc.retain(i8* %y) nounwind
230 declare void @llvm.objc.clang.arc.use(...) nounwind
232 ; CHECK: attributes [[NUW]] = { nounwind }