1 ; RUN: opt -S -objc-arc < %s | FileCheck %s
4 ; Detect loop boundaries and don't move retains and releases
7 declare void @use_pointer(i8*)
8 declare i8* @objc_retain(i8*)
9 declare void @objc_release(i8*)
10 declare void @callee()
12 ; CHECK: define void @test0(
13 ; CHECK: call i8* @objc_retain(
17 ; CHECK: call void @objc_release(
19 define void @test0(i8* %digits) {
21 %tmp1 = call i8* @objc_retain(i8* %digits) nounwind
22 call void @use_pointer(i8* %digits)
25 for.body: ; preds = %for.body, %entry
26 %upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ]
27 call void @use_pointer(i8* %digits)
28 %inc = add i64 %upcDigitIndex.01, 1
29 %cmp = icmp ult i64 %inc, 12
30 br i1 %cmp, label %for.body, label %for.end
32 for.end: ; preds = %for.body
33 call void @objc_release(i8* %digits) nounwind, !clang.imprecise_release !0
37 ; CHECK: define void @test1(
38 ; CHECK: call i8* @objc_retain(
42 ; CHECK: void @objc_release(
44 define void @test1(i8* %digits) {
46 %tmp1 = call i8* @objc_retain(i8* %digits) nounwind
49 for.body: ; preds = %for.body, %entry
50 %upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ]
51 call void @use_pointer(i8* %digits)
52 call void @use_pointer(i8* %digits)
53 %inc = add i64 %upcDigitIndex.01, 1
54 %cmp = icmp ult i64 %inc, 12
55 br i1 %cmp, label %for.body, label %for.end
57 for.end: ; preds = %for.body
58 call void @objc_release(i8* %digits) nounwind, !clang.imprecise_release !0
62 ; CHECK: define void @test2(
63 ; CHECK: call i8* @objc_retain(
67 ; CHECK: void @objc_release(
69 define void @test2(i8* %digits) {
71 %tmp1 = call i8* @objc_retain(i8* %digits) nounwind
74 for.body: ; preds = %for.body, %entry
75 %upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ]
76 call void @use_pointer(i8* %digits)
77 %inc = add i64 %upcDigitIndex.01, 1
78 %cmp = icmp ult i64 %inc, 12
79 br i1 %cmp, label %for.body, label %for.end
81 for.end: ; preds = %for.body
82 call void @use_pointer(i8* %digits)
83 call void @objc_release(i8* %digits) nounwind, !clang.imprecise_release !0
87 ; Delete nested retain+release pairs around loops.
89 ; CHECK: define void @test3(i8* %a) nounwind {
91 ; CHECK-NEXT: tail call i8* @objc_retain(i8* %a) nounwind
92 ; CHECK-NEXT: br label %loop
95 ; CHECK-NEXT: call void @objc_release(i8* %a)
96 ; CHECK-NEXT: ret void
98 define void @test3(i8* %a) nounwind {
100 %outer = call i8* @objc_retain(i8* %a) nounwind
101 %inner = call i8* @objc_retain(i8* %a) nounwind
107 br i1 undef, label %loop, label %exit
110 call void @objc_release(i8* %a) nounwind
111 call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
115 ; CHECK: define void @test4(i8* %a) nounwind {
117 ; CHECK-NEXT: tail call i8* @objc_retain(i8* %a) nounwind
118 ; CHECK-NEXT: br label %loop
121 ; CHECK-NEXT: call void @objc_release(i8* %a)
122 ; CHECK-NEXT: ret void
124 define void @test4(i8* %a) nounwind {
126 %outer = call i8* @objc_retain(i8* %a) nounwind
127 %inner = call i8* @objc_retain(i8* %a) nounwind
137 br i1 undef, label %loop, label %exit
140 call void @objc_release(i8* %a) nounwind
141 call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
145 ; CHECK: define void @test5(i8* %a) nounwind {
147 ; CHECK-NEXT: tail call i8* @objc_retain(i8* %a) nounwind
148 ; CHECK-NEXT: call void @callee()
149 ; CHECK-NEXT: br label %loop
152 ; CHECK-NEXT: call void @use_pointer(i8* %a)
153 ; CHECK-NEXT: call void @objc_release(i8* %a)
154 ; CHECK-NEXT: ret void
156 define void @test5(i8* %a) nounwind {
158 %outer = tail call i8* @objc_retain(i8* %a) nounwind
159 %inner = tail call i8* @objc_retain(i8* %a) nounwind
164 br i1 undef, label %true, label %more
170 br i1 undef, label %exit, label %loop
173 call void @use_pointer(i8* %a)
174 call void @objc_release(i8* %a) nounwind
175 call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
179 ; CHECK: define void @test6(i8* %a) nounwind {
181 ; CHECK-NEXT: tail call i8* @objc_retain(i8* %a) nounwind
182 ; CHECK-NEXT: br label %loop
185 ; CHECK-NEXT: call void @use_pointer(i8* %a)
186 ; CHECK-NEXT: call void @objc_release(i8* %a)
187 ; CHECK-NEXT: ret void
189 define void @test6(i8* %a) nounwind {
191 %outer = tail call i8* @objc_retain(i8* %a) nounwind
192 %inner = tail call i8* @objc_retain(i8* %a) nounwind
196 br i1 undef, label %true, label %more
203 br i1 undef, label %exit, label %loop
206 call void @use_pointer(i8* %a)
207 call void @objc_release(i8* %a) nounwind
208 call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
212 ; CHECK: define void @test7(i8* %a) nounwind {
214 ; CHECK-NEXT: tail call i8* @objc_retain(i8* %a) nounwind
215 ; CHECK-NEXT: call void @callee()
216 ; CHECK-NEXT: br label %loop
219 ; CHECK-NEXT: call void @objc_release(i8* %a)
220 ; CHECK-NEXT: ret void
222 define void @test7(i8* %a) nounwind {
224 %outer = tail call i8* @objc_retain(i8* %a) nounwind
225 %inner = tail call i8* @objc_retain(i8* %a) nounwind
230 br i1 undef, label %true, label %more
233 call void @use_pointer(i8* %a)
237 br i1 undef, label %exit, label %loop
240 call void @objc_release(i8* %a) nounwind
241 call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
245 ; CHECK: define void @test8(i8* %a) nounwind {
247 ; CHECK-NEXT: tail call i8* @objc_retain(i8* %a) nounwind
248 ; CHECK-NEXT: br label %loop
251 ; CHECK-NEXT: call void @objc_release(i8* %a)
252 ; CHECK-NEXT: ret void
254 define void @test8(i8* %a) nounwind {
256 %outer = tail call i8* @objc_retain(i8* %a) nounwind
257 %inner = tail call i8* @objc_retain(i8* %a) nounwind
261 br i1 undef, label %true, label %more
265 call void @use_pointer(i8* %a)
269 br i1 undef, label %exit, label %loop
272 call void @objc_release(i8* %a) nounwind
273 call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
277 ; CHECK: define void @test9(i8* %a) nounwind {
279 ; CHECK-NEXT: br label %loop
282 ; CHECK-NEXT: ret void
284 define void @test9(i8* %a) nounwind {
286 %outer = tail call i8* @objc_retain(i8* %a) nounwind
287 %inner = tail call i8* @objc_retain(i8* %a) nounwind
291 br i1 undef, label %true, label %more
294 call void @use_pointer(i8* %a)
298 br i1 undef, label %exit, label %loop
301 call void @objc_release(i8* %a) nounwind
302 call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
306 ; CHECK: define void @test10(i8* %a) nounwind {
308 ; CHECK-NEXT: br label %loop
311 ; CHECK-NEXT: ret void
313 define void @test10(i8* %a) nounwind {
315 %outer = tail call i8* @objc_retain(i8* %a) nounwind
316 %inner = tail call i8* @objc_retain(i8* %a) nounwind
320 br i1 undef, label %true, label %more
327 br i1 undef, label %exit, label %loop
330 call void @objc_release(i8* %a) nounwind
331 call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
335 ; CHECK: define void @test11(i8* %a) nounwind {
337 ; CHECK-NEXT: br label %loop
340 ; CHECK-NEXT: ret void
342 define void @test11(i8* %a) nounwind {
344 %outer = tail call i8* @objc_retain(i8* %a) nounwind
345 %inner = tail call i8* @objc_retain(i8* %a) nounwind
349 br i1 undef, label %true, label %more
355 br i1 undef, label %exit, label %loop
358 call void @objc_release(i8* %a) nounwind
359 call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
363 ; Don't delete anything if they're not balanced.
365 ; CHECK: define void @test12(i8* %a) nounwind {
367 ; CHECK-NEXT: %outer = tail call i8* @objc_retain(i8* %a) nounwind
368 ; CHECK-NEXT: %inner = tail call i8* @objc_retain(i8* %a) nounwind
369 ; CHECK-NEXT: br label %loop
372 ; CHECK-NEXT: call void @objc_release(i8* %a) nounwind
373 ; CHECK-NEXT: call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
374 ; CHECK-NEXT: ret void
376 define void @test12(i8* %a) nounwind {
378 %outer = tail call i8* @objc_retain(i8* %a) nounwind
379 %inner = tail call i8* @objc_retain(i8* %a) nounwind
383 br i1 undef, label %true, label %more
389 br i1 undef, label %exit, label %loop
392 call void @objc_release(i8* %a) nounwind
393 call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0