[ARM] Better OR's for MVE compares
[llvm-core.git] / test / Transforms / ObjCARC / cfg-hazards.ll
blob9559b3c31146eda9406120d65a4d24aedcdbd18e
1 ; RUN: opt -S -objc-arc < %s | FileCheck %s
2 ; rdar://9503416
4 ; Detect loop boundaries and don't move retains and releases
5 ; across them.
7 declare void @use_pointer(i8*)
8 declare i8* @llvm.objc.retain(i8*)
9 declare void @llvm.objc.release(i8*)
10 declare void @callee()
11 declare void @block_callee(void ()*)
13 ; CHECK-LABEL: define void @test0(
14 ; CHECK:   call i8* @llvm.objc.retain
15 ; CHECK: for.body:
16 ; CHECK-NOT: @objc
17 ; CHECK: for.end:
18 ; CHECK:   call void @llvm.objc.release
19 ; CHECK: }
20 define void @test0(i8* %digits) {
21 entry:
22   %tmp1 = call i8* @llvm.objc.retain(i8* %digits) nounwind
23   call void @use_pointer(i8* %digits)
24   br label %for.body
26 for.body:                                         ; preds = %for.body, %entry
27   %upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ]
28   call void @use_pointer(i8* %digits)
29   %inc = add i64 %upcDigitIndex.01, 1
30   %cmp = icmp ult i64 %inc, 12
31   br i1 %cmp, label %for.body, label %for.end
33 for.end:                                          ; preds = %for.body
34   call void @llvm.objc.release(i8* %digits) nounwind, !clang.imprecise_release !0
35   ret void
38 ; CHECK-LABEL: define void @test1(
39 ; CHECK:   call i8* @llvm.objc.retain
40 ; CHECK: for.body:
41 ; CHECK-NOT: @objc
42 ; CHECK: for.end:
43 ; CHECK:   void @llvm.objc.release
44 ; CHECK: }
45 define void @test1(i8* %digits) {
46 entry:
47   %tmp1 = call i8* @llvm.objc.retain(i8* %digits) nounwind
48   br label %for.body
50 for.body:                                         ; preds = %for.body, %entry
51   %upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ]
52   call void @use_pointer(i8* %digits)
53   call void @use_pointer(i8* %digits)
54   %inc = add i64 %upcDigitIndex.01, 1
55   %cmp = icmp ult i64 %inc, 12
56   br i1 %cmp, label %for.body, label %for.end
58 for.end:                                          ; preds = %for.body
59   call void @llvm.objc.release(i8* %digits) nounwind, !clang.imprecise_release !0
60   ret void
63 ; CHECK-LABEL: define void @test2(
64 ; CHECK:   call i8* @llvm.objc.retain
65 ; CHECK: for.body:
66 ; CHECK-NOT: @objc
67 ; CHECK: for.end:
68 ; CHECK:   void @llvm.objc.release
69 ; CHECK: }
70 define void @test2(i8* %digits) {
71 entry:
72   %tmp1 = call i8* @llvm.objc.retain(i8* %digits) nounwind
73   br label %for.body
75 for.body:                                         ; preds = %for.body, %entry
76   %upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ]
77   call void @use_pointer(i8* %digits)
78   %inc = add i64 %upcDigitIndex.01, 1
79   %cmp = icmp ult i64 %inc, 12
80   br i1 %cmp, label %for.body, label %for.end
82 for.end:                                          ; preds = %for.body
83   call void @use_pointer(i8* %digits)
84   call void @llvm.objc.release(i8* %digits) nounwind, !clang.imprecise_release !0
85   ret void
88 ; Delete nested retain+release pairs around loops.
90 ;      CHECK: define void @test3(i8* %a) #0 {
91 ; CHECK-NEXT: entry:
92 ; CHECK-NEXT:   tail call i8* @llvm.objc.retain(i8* %a) [[NUW:#[0-9]+]]
93 ; CHECK-NEXT:   br label %loop
94 ;  CHECK-NOT:   @llvm.objc.
95 ;      CHECK: exit:
96 ; CHECK-NEXT:   call void @llvm.objc.release(i8* %a)
97 ; CHECK-NEXT:   ret void
98 ; CHECK-NEXT: }
99 define void @test3(i8* %a) nounwind {
100 entry:
101   %outer = call i8* @llvm.objc.retain(i8* %a) nounwind
102   %inner = call i8* @llvm.objc.retain(i8* %a) nounwind
103   br label %loop
105 loop:
106   call void @callee()
107   store i8 0, i8* %a
108   br i1 undef, label %loop, label %exit
110 exit:
111   call void @llvm.objc.release(i8* %a) nounwind
112   call void @llvm.objc.release(i8* %a) nounwind, !clang.imprecise_release !0
113   ret void
116 ;      CHECK: define void @test4(i8* %a) #0 {
117 ; CHECK-NEXT: entry:
118 ; CHECK-NEXT:   tail call i8* @llvm.objc.retain(i8* %a) [[NUW]]
119 ; CHECK-NEXT:   br label %loop
120 ;  CHECK-NOT:   @llvm.objc.
121 ;      CHECK: exit:
122 ; CHECK-NEXT:   call void @llvm.objc.release(i8* %a)
123 ; CHECK-NEXT:   ret void
124 ; CHECK-NEXT: }
125 define void @test4(i8* %a) nounwind {
126 entry:
127   %outer = call i8* @llvm.objc.retain(i8* %a) nounwind
128   %inner = call i8* @llvm.objc.retain(i8* %a) nounwind
129   br label %loop
131 loop:
132   br label %more
134 more:
135   call void @callee()
136   call void @callee()
137   store i8 0, i8* %a
138   br i1 undef, label %loop, label %exit
140 exit:
141   call void @llvm.objc.release(i8* %a) nounwind
142   call void @llvm.objc.release(i8* %a) nounwind, !clang.imprecise_release !0
143   ret void
146 ;      CHECK: define void @test5(i8* %a) #0 {
147 ; CHECK-NEXT: entry:
148 ; CHECK-NEXT:   tail call i8* @llvm.objc.retain(i8* %a) [[NUW]]
149 ; CHECK-NEXT:   call void @callee()
150 ; CHECK-NEXT:   br label %loop
151 ;  CHECK-NOT:   @llvm.objc.
152 ;      CHECK: exit:
153 ; CHECK-NEXT:   call void @use_pointer(i8* %a)
154 ; CHECK-NEXT:   call void @llvm.objc.release(i8* %a)
155 ; CHECK-NEXT:   ret void
156 ; CHECK-NEXT: }
157 define void @test5(i8* %a) nounwind {
158 entry:
159   %outer = tail call i8* @llvm.objc.retain(i8* %a) nounwind
160   %inner = tail call i8* @llvm.objc.retain(i8* %a) nounwind
161   call void @callee()
162   br label %loop
164 loop:
165   br i1 undef, label %true, label %more
167 true:
168   br label %more
170 more:
171   br i1 undef, label %exit, label %loop
173 exit:
174   call void @use_pointer(i8* %a)
175   call void @llvm.objc.release(i8* %a) nounwind
176   call void @llvm.objc.release(i8* %a) nounwind, !clang.imprecise_release !0
177   ret void
180 ;      CHECK: define void @test6(i8* %a) #0 {
181 ; CHECK-NEXT: entry:
182 ; CHECK-NEXT:   tail call i8* @llvm.objc.retain(i8* %a) [[NUW]]
183 ; CHECK-NEXT:   br label %loop
184 ;  CHECK-NOT:   @llvm.objc.
185 ;      CHECK: exit:
186 ; CHECK-NEXT:   call void @use_pointer(i8* %a)
187 ; CHECK-NEXT:   call void @llvm.objc.release(i8* %a)
188 ; CHECK-NEXT:   ret void
189 ; CHECK-NEXT: }
190 define void @test6(i8* %a) nounwind {
191 entry:
192   %outer = tail call i8* @llvm.objc.retain(i8* %a) nounwind
193   %inner = tail call i8* @llvm.objc.retain(i8* %a) nounwind
194   br label %loop
196 loop:
197   br i1 undef, label %true, label %more
199 true:
200   call void @callee()
201   br label %more
203 more:
204   br i1 undef, label %exit, label %loop
206 exit:
207   call void @use_pointer(i8* %a)
208   call void @llvm.objc.release(i8* %a) nounwind
209   call void @llvm.objc.release(i8* %a) nounwind, !clang.imprecise_release !0
210   ret void
213 ;      CHECK: define void @test7(i8* %a) #0 {
214 ; CHECK-NEXT: entry:
215 ; CHECK-NEXT:   tail call i8* @llvm.objc.retain(i8* %a) [[NUW]]
216 ; CHECK-NEXT:   call void @callee()
217 ; CHECK-NEXT:   br label %loop
218 ;  CHECK-NOT:   @llvm.objc.
219 ;      CHECK: exit:
220 ; CHECK-NEXT:   call void @llvm.objc.release(i8* %a)
221 ; CHECK-NEXT:   ret void
222 ; CHECK-NEXT: }
223 define void @test7(i8* %a) nounwind {
224 entry:
225   %outer = tail call i8* @llvm.objc.retain(i8* %a) nounwind
226   %inner = tail call i8* @llvm.objc.retain(i8* %a) nounwind
227   call void @callee()
228   br label %loop
230 loop:
231   br i1 undef, label %true, label %more
233 true:
234   call void @use_pointer(i8* %a)
235   br label %more
237 more:
238   br i1 undef, label %exit, label %loop
240 exit:
241   call void @llvm.objc.release(i8* %a) nounwind
242   call void @llvm.objc.release(i8* %a) nounwind, !clang.imprecise_release !0
243   ret void
246 ;      CHECK: define void @test8(i8* %a) #0 {
247 ; CHECK-NEXT: entry:
248 ; CHECK-NEXT:   tail call i8* @llvm.objc.retain(i8* %a) [[NUW]]
249 ; CHECK-NEXT:   br label %loop
250 ;  CHECK-NOT:   @llvm.objc.
251 ;      CHECK: exit:
252 ; CHECK-NEXT:   call void @llvm.objc.release(i8* %a)
253 ; CHECK-NEXT:   ret void
254 ; CHECK-NEXT: }
255 define void @test8(i8* %a) nounwind {
256 entry:
257   %outer = tail call i8* @llvm.objc.retain(i8* %a) nounwind
258   %inner = tail call i8* @llvm.objc.retain(i8* %a) nounwind
259   br label %loop
261 loop:
262   br i1 undef, label %true, label %more
264 true:
265   call void @callee()
266   call void @use_pointer(i8* %a)
267   br label %more
269 more:
270   br i1 undef, label %exit, label %loop
272 exit:
273   call void @llvm.objc.release(i8* %a) nounwind
274   call void @llvm.objc.release(i8* %a) nounwind, !clang.imprecise_release !0
275   ret void
278 ;      CHECK: define void @test9(i8* %a) #0 {
279 ; CHECK-NEXT: entry:
280 ; CHECK-NEXT:   br label %loop
281 ;  CHECK-NOT:   @llvm.objc.
282 ;      CHECK: exit:
283 ; CHECK-NEXT:   ret void
284 ; CHECK-NEXT: }
285 define void @test9(i8* %a) nounwind {
286 entry:
287   %outer = tail call i8* @llvm.objc.retain(i8* %a) nounwind
288   %inner = tail call i8* @llvm.objc.retain(i8* %a) nounwind
289   br label %loop
291 loop:
292   br i1 undef, label %true, label %more
294 true:
295   call void @use_pointer(i8* %a)
296   br label %more
298 more:
299   br i1 undef, label %exit, label %loop
301 exit:
302   call void @llvm.objc.release(i8* %a) nounwind
303   call void @llvm.objc.release(i8* %a) nounwind, !clang.imprecise_release !0
304   ret void
307 ;      CHECK: define void @test10(i8* %a) #0 {
308 ; CHECK-NEXT: entry:
309 ; CHECK-NEXT:   br label %loop
310 ;  CHECK-NOT:   @llvm.objc.
311 ;      CHECK: exit:
312 ; CHECK-NEXT:   ret void
313 ; CHECK-NEXT: }
314 define void @test10(i8* %a) nounwind {
315 entry:
316   %outer = tail call i8* @llvm.objc.retain(i8* %a) nounwind
317   %inner = tail call i8* @llvm.objc.retain(i8* %a) nounwind
318   br label %loop
320 loop:
321   br i1 undef, label %true, label %more
323 true:
324   call void @callee()
325   br label %more
327 more:
328   br i1 undef, label %exit, label %loop
330 exit:
331   call void @llvm.objc.release(i8* %a) nounwind
332   call void @llvm.objc.release(i8* %a) nounwind, !clang.imprecise_release !0
333   ret void
336 ;      CHECK: define void @test11(i8* %a) #0 {
337 ; CHECK-NEXT: entry:
338 ; CHECK-NEXT:   br label %loop
339 ;  CHECK-NOT:   @llvm.objc.
340 ;      CHECK: exit:
341 ; CHECK-NEXT:   ret void
342 ; CHECK-NEXT: }
343 define void @test11(i8* %a) nounwind {
344 entry:
345   %outer = tail call i8* @llvm.objc.retain(i8* %a) nounwind
346   %inner = tail call i8* @llvm.objc.retain(i8* %a) nounwind
347   br label %loop
349 loop:
350   br i1 undef, label %true, label %more
352 true:
353   br label %more
355 more:
356   br i1 undef, label %exit, label %loop
358 exit:
359   call void @llvm.objc.release(i8* %a) nounwind
360   call void @llvm.objc.release(i8* %a) nounwind, !clang.imprecise_release !0
361   ret void
364 ; Don't delete anything if they're not balanced.
366 ;      CHECK: define void @test12(i8* %a) #0 {
367 ; CHECK-NEXT: entry:
368 ; CHECK-NEXT:   %outer = tail call i8* @llvm.objc.retain(i8* %a) [[NUW]]
369 ; CHECK-NEXT:   %inner = tail call i8* @llvm.objc.retain(i8* %a) [[NUW]]
370 ; CHECK-NEXT:   br label %loop
371 ;  CHECK-NOT:   @llvm.objc.
372 ;      CHECK: exit:
373 ; CHECK-NEXT: call void @llvm.objc.release(i8* %a) [[NUW]]
374 ; CHECK-NEXT: call void @llvm.objc.release(i8* %a) [[NUW]], !clang.imprecise_release !0
375 ; CHECK-NEXT:   ret void
376 ; CHECK-NEXT: }
377 define void @test12(i8* %a) nounwind {
378 entry:
379   %outer = tail call i8* @llvm.objc.retain(i8* %a) nounwind
380   %inner = tail call i8* @llvm.objc.retain(i8* %a) nounwind
381   br label %loop
383 loop:
384   br i1 undef, label %true, label %more
386 true:
387   ret void
389 more:
390   br i1 undef, label %exit, label %loop
392 exit:
393   call void @llvm.objc.release(i8* %a) nounwind
394   call void @llvm.objc.release(i8* %a) nounwind, !clang.imprecise_release !0
395   ret void
398 ; Do not improperly pair retains in a for loop with releases outside of a for
399 ; loop when the proper pairing is disguised by a separate provenance represented
400 ; by an alloca.
401 ; rdar://12969722
403 ; CHECK: define void @test13(i8* %a) [[NUW]] {
404 ; CHECK: entry:
405 ; CHECK:   tail call i8* @llvm.objc.retain(i8* %a) [[NUW]]
406 ; CHECK: loop:
407 ; CHECK:   tail call i8* @llvm.objc.retain(i8* %a) [[NUW]]
408 ; CHECK:   call void @block_callee
409 ; CHECK:   call void @llvm.objc.release(i8* %reloaded_a) [[NUW]]
410 ; CHECK: exit:
411 ; CHECK:   call void @llvm.objc.release(i8* %a) [[NUW]]
412 ; CHECK: }
413 define void @test13(i8* %a) nounwind {
414 entry:
415   %block = alloca i8*
416   %a1 = tail call i8* @llvm.objc.retain(i8* %a) nounwind
417   br label %loop
419 loop:
420   %a2 = tail call i8* @llvm.objc.retain(i8* %a) nounwind
421   store i8* %a, i8** %block, align 8
422   %casted_block = bitcast i8** %block to void ()*
423   call void @block_callee(void ()* %casted_block)
424   %reloaded_a = load i8*, i8** %block, align 8
425   call void @llvm.objc.release(i8* %reloaded_a) nounwind, !clang.imprecise_release !0
426   br i1 undef, label %loop, label %exit
427   
428 exit:
429   call void @llvm.objc.release(i8* %a) nounwind, !clang.imprecise_release !0
430   ret void
433 ; CHECK: attributes [[NUW]] = { nounwind }
435 !0 = !{}