[InstCombine] Signed saturation tests. NFC
[llvm-complete.git] / test / Transforms / ObjCARC / contract.ll
blob7cf3f5ea886fbc100e995ac47087b6d4ef346438
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)
17 ; CHECK: }
18 define void @test0(i8* %x) nounwind {
19 entry:
20   %0 = call i8* @llvm.objc.retain(i8* %x) nounwind
21   call void @use_pointer(i8* %x)
22   ret void
25 ; CHECK-LABEL: define void @test1(
26 ; CHECK: call void @use_pointer(i8* %0)
27 ; CHECK: }
28 define void @test1(i8* %x) nounwind {
29 entry:
30   %0 = call i8* @llvm.objc.autorelease(i8* %x) nounwind
31   call void @use_pointer(i8* %x)
32   ret void
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]+]]
39 ; CHECK: }
40 define void @test2(i8* %x) nounwind {
41 entry:
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)
45   ret void
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]]
52 ; CHECK: }
53 define i8* @test2b(i8* %x) nounwind {
54 entry:
55   %0 = tail call i8* @llvm.objc.retain(i8* %x) nounwind
56   tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %0) nounwind
57   ret i8* %x
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)
65 ; CHECK: }
66 define void @test3(i8* %x, i64 %n) {
67 entry:
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
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(i8* %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(i8* %x, i64 %n) {
85 entry:
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
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 i8* @llvm.objc.retain(i8* %p) [[NUW]]
97 ; CHECK: true:
98 ; CHECK: call i8* @llvm.objc.autorelease(i8* %0) [[NUW]]
99 ; CHECK: }
100 define void @test5(i8* %p, i1 %a) {
101 entry:
102   tail call i8* @llvm.objc.retain(i8* %p) nounwind
103   br i1 %a, label %true, label %false
105 true:
106   call i8* @llvm.objc.autorelease(i8* %p) nounwind
107   call void @use_pointer(i8* %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 i8* @test6(
123 ; CHECK: call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %p) [[NUW]]
124 ; CHECK: %t = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %1) [[NUW]]
125 ; CHECK: }
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)
131   ret 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)
140 ; CHECK: ret i8* %2
141 ; CHECK-NEXT: }
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)
146   ret 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 ]
153 ; CHECK: }
154 define i8* @test8(i1 %x, i8* %c) {
155 entry:
156   br i1 %x, label %return, label %if.then
158 if.then:                                          ; preds = %entry
159   %p = call i8* @llvm.objc.retain(i8* %c) nounwind
160   br label %return
162 return:                                           ; preds = %if.then, %entry
163   %retval = phi i8* [ %c, %if.then ], [ null, %entry ]
164   ret i8* %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(i8* %a, i8* %b) {
172   call void (...) @llvm.objc.clang.arc.use(i8* %a, i8* %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 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
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 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
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 i8* @llvm.objc.retain(i8* %y) [[NUW]]
206 ; CHECK-NEXT: ret void
207 ; CHECK-NEXT: }
208 define void @test12(i8* %y) {
209   tail call i8* @llvm.objc.retain(i8* %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 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
221 ; CHECK-NEXT: }
222 define void @test13() {
223   %y = call i8* @returner()
224   call void @callee()
225   tail call i8* @llvm.objc.retain(i8* %y) nounwind
226   ret void
230 declare void @llvm.objc.clang.arc.use(...) nounwind
232 ; CHECK: attributes [[NUW]] = { nounwind }