SimplifyCFG: don't remove unreachable default switch destinations
[oota-llvm.git] / test / Transforms / ObjCARC / cfg-hazards.ll
1 ; RUN: opt -S -objc-arc < %s | FileCheck %s
2 ; rdar://9503416
3
4 ; Detect loop boundaries and don't move retains and releases
5 ; across them.
6
7 declare void @use_pointer(i8*)
8 declare i8* @objc_retain(i8*)
9 declare void @objc_release(i8*)
10 declare void @callee()
11 declare void @block_callee(void ()*)
12
13 ; CHECK-LABEL: define void @test0(
14 ; CHECK:   call i8* @objc_retain(
15 ; CHECK: for.body:
16 ; CHECK-NOT: @objc
17 ; CHECK: for.end:
18 ; CHECK:   call void @objc_release(
19 ; CHECK: }
20 define void @test0(i8* %digits) {
21 entry:
22   %tmp1 = call i8* @objc_retain(i8* %digits) nounwind
23   call void @use_pointer(i8* %digits)
24   br label %for.body
25
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
32
33 for.end:                                          ; preds = %for.body
34   call void @objc_release(i8* %digits) nounwind, !clang.imprecise_release !0
35   ret void
36 }
37
38 ; CHECK-LABEL: define void @test1(
39 ; CHECK:   call i8* @objc_retain(
40 ; CHECK: for.body:
41 ; CHECK-NOT: @objc
42 ; CHECK: for.end:
43 ; CHECK:   void @objc_release(
44 ; CHECK: }
45 define void @test1(i8* %digits) {
46 entry:
47   %tmp1 = call i8* @objc_retain(i8* %digits) nounwind
48   br label %for.body
49
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
57
58 for.end:                                          ; preds = %for.body
59   call void @objc_release(i8* %digits) nounwind, !clang.imprecise_release !0
60   ret void
61 }
62
63 ; CHECK-LABEL: define void @test2(
64 ; CHECK:   call i8* @objc_retain(
65 ; CHECK: for.body:
66 ; CHECK-NOT: @objc
67 ; CHECK: for.end:
68 ; CHECK:   void @objc_release(
69 ; CHECK: }
70 define void @test2(i8* %digits) {
71 entry:
72   %tmp1 = call i8* @objc_retain(i8* %digits) nounwind
73   br label %for.body
74
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
81
82 for.end:                                          ; preds = %for.body
83   call void @use_pointer(i8* %digits)
84   call void @objc_release(i8* %digits) nounwind, !clang.imprecise_release !0
85   ret void
86 }
87
88 ; Delete nested retain+release pairs around loops.
89
90 ;      CHECK: define void @test3(i8* %a) #0 {
91 ; CHECK-NEXT: entry:
92 ; CHECK-NEXT:   tail call i8* @objc_retain(i8* %a) [[NUW:#[0-9]+]]
93 ; CHECK-NEXT:   br label %loop
94 ;  CHECK-NOT:   @objc_
95 ;      CHECK: exit:
96 ; CHECK-NEXT:   call void @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* @objc_retain(i8* %a) nounwind
102   %inner = call i8* @objc_retain(i8* %a) nounwind
103   br label %loop
104
105 loop:
106   call void @callee()
107   store i8 0, i8* %a
108   br i1 undef, label %loop, label %exit
109
110 exit:
111   call void @objc_release(i8* %a) nounwind
112   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
113   ret void
114 }
115
116 ;      CHECK: define void @test4(i8* %a) #0 {
117 ; CHECK-NEXT: entry:
118 ; CHECK-NEXT:   tail call i8* @objc_retain(i8* %a) [[NUW]]
119 ; CHECK-NEXT:   br label %loop
120 ;  CHECK-NOT:   @objc_
121 ;      CHECK: exit:
122 ; CHECK-NEXT:   call void @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* @objc_retain(i8* %a) nounwind
128   %inner = call i8* @objc_retain(i8* %a) nounwind
129   br label %loop
130
131 loop:
132   br label %more
133
134 more:
135   call void @callee()
136   call void @callee()
137   store i8 0, i8* %a
138   br i1 undef, label %loop, label %exit
139
140 exit:
141   call void @objc_release(i8* %a) nounwind
142   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
143   ret void
144 }
145
146 ;      CHECK: define void @test5(i8* %a) #0 {
147 ; CHECK-NEXT: entry:
148 ; CHECK-NEXT:   tail call i8* @objc_retain(i8* %a) [[NUW]]
149 ; CHECK-NEXT:   call void @callee()
150 ; CHECK-NEXT:   br label %loop
151 ;  CHECK-NOT:   @objc_
152 ;      CHECK: exit:
153 ; CHECK-NEXT:   call void @use_pointer(i8* %a)
154 ; CHECK-NEXT:   call void @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* @objc_retain(i8* %a) nounwind
160   %inner = tail call i8* @objc_retain(i8* %a) nounwind
161   call void @callee()
162   br label %loop
163
164 loop:
165   br i1 undef, label %true, label %more
166
167 true:
168   br label %more
169
170 more:
171   br i1 undef, label %exit, label %loop
172
173 exit:
174   call void @use_pointer(i8* %a)
175   call void @objc_release(i8* %a) nounwind
176   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
177   ret void
178 }
179
180 ;      CHECK: define void @test6(i8* %a) #0 {
181 ; CHECK-NEXT: entry:
182 ; CHECK-NEXT:   tail call i8* @objc_retain(i8* %a) [[NUW]]
183 ; CHECK-NEXT:   br label %loop
184 ;  CHECK-NOT:   @objc_
185 ;      CHECK: exit:
186 ; CHECK-NEXT:   call void @use_pointer(i8* %a)
187 ; CHECK-NEXT:   call void @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* @objc_retain(i8* %a) nounwind
193   %inner = tail call i8* @objc_retain(i8* %a) nounwind
194   br label %loop
195
196 loop:
197   br i1 undef, label %true, label %more
198
199 true:
200   call void @callee()
201   br label %more
202
203 more:
204   br i1 undef, label %exit, label %loop
205
206 exit:
207   call void @use_pointer(i8* %a)
208   call void @objc_release(i8* %a) nounwind
209   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
210   ret void
211 }
212
213 ;      CHECK: define void @test7(i8* %a) #0 {
214 ; CHECK-NEXT: entry:
215 ; CHECK-NEXT:   tail call i8* @objc_retain(i8* %a) [[NUW]]
216 ; CHECK-NEXT:   call void @callee()
217 ; CHECK-NEXT:   br label %loop
218 ;  CHECK-NOT:   @objc_
219 ;      CHECK: exit:
220 ; CHECK-NEXT:   call void @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* @objc_retain(i8* %a) nounwind
226   %inner = tail call i8* @objc_retain(i8* %a) nounwind
227   call void @callee()
228   br label %loop
229
230 loop:
231   br i1 undef, label %true, label %more
232
233 true:
234   call void @use_pointer(i8* %a)
235   br label %more
236
237 more:
238   br i1 undef, label %exit, label %loop
239
240 exit:
241   call void @objc_release(i8* %a) nounwind
242   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
243   ret void
244 }
245
246 ;      CHECK: define void @test8(i8* %a) #0 {
247 ; CHECK-NEXT: entry:
248 ; CHECK-NEXT:   tail call i8* @objc_retain(i8* %a) [[NUW]]
249 ; CHECK-NEXT:   br label %loop
250 ;  CHECK-NOT:   @objc_
251 ;      CHECK: exit:
252 ; CHECK-NEXT:   call void @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* @objc_retain(i8* %a) nounwind
258   %inner = tail call i8* @objc_retain(i8* %a) nounwind
259   br label %loop
260
261 loop:
262   br i1 undef, label %true, label %more
263
264 true:
265   call void @callee()
266   call void @use_pointer(i8* %a)
267   br label %more
268
269 more:
270   br i1 undef, label %exit, label %loop
271
272 exit:
273   call void @objc_release(i8* %a) nounwind
274   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
275   ret void
276 }
277
278 ;      CHECK: define void @test9(i8* %a) #0 {
279 ; CHECK-NEXT: entry:
280 ; CHECK-NEXT:   br label %loop
281 ;  CHECK-NOT:   @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* @objc_retain(i8* %a) nounwind
288   %inner = tail call i8* @objc_retain(i8* %a) nounwind
289   br label %loop
290
291 loop:
292   br i1 undef, label %true, label %more
293
294 true:
295   call void @use_pointer(i8* %a)
296   br label %more
297
298 more:
299   br i1 undef, label %exit, label %loop
300
301 exit:
302   call void @objc_release(i8* %a) nounwind
303   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
304   ret void
305 }
306
307 ;      CHECK: define void @test10(i8* %a) #0 {
308 ; CHECK-NEXT: entry:
309 ; CHECK-NEXT:   br label %loop
310 ;  CHECK-NOT:   @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* @objc_retain(i8* %a) nounwind
317   %inner = tail call i8* @objc_retain(i8* %a) nounwind
318   br label %loop
319
320 loop:
321   br i1 undef, label %true, label %more
322
323 true:
324   call void @callee()
325   br label %more
326
327 more:
328   br i1 undef, label %exit, label %loop
329
330 exit:
331   call void @objc_release(i8* %a) nounwind
332   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
333   ret void
334 }
335
336 ;      CHECK: define void @test11(i8* %a) #0 {
337 ; CHECK-NEXT: entry:
338 ; CHECK-NEXT:   br label %loop
339 ;  CHECK-NOT:   @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* @objc_retain(i8* %a) nounwind
346   %inner = tail call i8* @objc_retain(i8* %a) nounwind
347   br label %loop
348
349 loop:
350   br i1 undef, label %true, label %more
351
352 true:
353   br label %more
354
355 more:
356   br i1 undef, label %exit, label %loop
357
358 exit:
359   call void @objc_release(i8* %a) nounwind
360   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
361   ret void
362 }
363
364 ; Don't delete anything if they're not balanced.
365
366 ;      CHECK: define void @test12(i8* %a) #0 {
367 ; CHECK-NEXT: entry:
368 ; CHECK-NEXT:   %outer = tail call i8* @objc_retain(i8* %a) [[NUW]]
369 ; CHECK-NEXT:   %inner = tail call i8* @objc_retain(i8* %a) [[NUW]]
370 ; CHECK-NEXT:   br label %loop
371 ;  CHECK-NOT:   @objc_
372 ;      CHECK: exit:
373 ; CHECK-NEXT: call void @objc_release(i8* %a) [[NUW]]
374 ; CHECK-NEXT: call void @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* @objc_retain(i8* %a) nounwind
380   %inner = tail call i8* @objc_retain(i8* %a) nounwind
381   br label %loop
382
383 loop:
384   br i1 undef, label %true, label %more
385
386 true:
387   ret void
388
389 more:
390   br i1 undef, label %exit, label %loop
391
392 exit:
393   call void @objc_release(i8* %a) nounwind
394   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
395   ret void
396 }
397
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
402
403 ; CHECK: define void @test13(i8* %a) [[NUW]] {
404 ; CHECK: entry:
405 ; CHECK:   tail call i8* @objc_retain(i8* %a) [[NUW]]
406 ; CHECK: loop:
407 ; CHECK:   tail call i8* @objc_retain(i8* %a) [[NUW]]
408 ; CHECK:   call void @block_callee
409 ; CHECK:   call void @objc_release(i8* %reloaded_a) [[NUW]]
410 ; CHECK: exit:
411 ; CHECK:   call void @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* @objc_retain(i8* %a) nounwind
417   br label %loop
418
419 loop:
420   %a2 = tail call i8* @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** %block, align 8
425   call void @objc_release(i8* %reloaded_a) nounwind, !clang.imprecise_release !0
426   br i1 undef, label %loop, label %exit
427   
428 exit:
429   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
430   ret void
431 }
432
433 ; CHECK: attributes [[NUW]] = { nounwind }
434
435 !0 = !{}