Modify the LLVM assembly output so that it uses references to represent function...
[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
12 ; CHECK: define void @test0(
13 ; CHECK:   call i8* @objc_retain(
14 ; CHECK: for.body:
15 ; CHECK-NOT: @objc
16 ; CHECK: for.end:
17 ; CHECK:   call void @objc_release(
18 ; CHECK: }
19 define void @test0(i8* %digits) {
20 entry:
21   %tmp1 = call i8* @objc_retain(i8* %digits) nounwind
22   call void @use_pointer(i8* %digits)
23   br label %for.body
24
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
31
32 for.end:                                          ; preds = %for.body
33   call void @objc_release(i8* %digits) nounwind, !clang.imprecise_release !0
34   ret void
35 }
36
37 ; CHECK: define void @test1(
38 ; CHECK:   call i8* @objc_retain(
39 ; CHECK: for.body:
40 ; CHECK-NOT: @objc
41 ; CHECK: for.end:
42 ; CHECK:   void @objc_release(
43 ; CHECK: }
44 define void @test1(i8* %digits) {
45 entry:
46   %tmp1 = call i8* @objc_retain(i8* %digits) nounwind
47   br label %for.body
48
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
56
57 for.end:                                          ; preds = %for.body
58   call void @objc_release(i8* %digits) nounwind, !clang.imprecise_release !0
59   ret void
60 }
61
62 ; CHECK: define void @test2(
63 ; CHECK:   call i8* @objc_retain(
64 ; CHECK: for.body:
65 ; CHECK-NOT: @objc
66 ; CHECK: for.end:
67 ; CHECK:   void @objc_release(
68 ; CHECK: }
69 define void @test2(i8* %digits) {
70 entry:
71   %tmp1 = call i8* @objc_retain(i8* %digits) nounwind
72   br label %for.body
73
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
80
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
84   ret void
85 }
86
87 ; Delete nested retain+release pairs around loops.
88
89 ;      CHECK: define void @test3(i8* %a) #0 {
90 ; CHECK-NEXT: entry:
91 ; CHECK-NEXT:   tail call i8* @objc_retain(i8* %a) nounwind
92 ; CHECK-NEXT:   br label %loop
93 ;  CHECK-NOT:   @objc_
94 ;      CHECK: exit:
95 ; CHECK-NEXT:   call void @objc_release(i8* %a)
96 ; CHECK-NEXT:   ret void
97 ; CHECK-NEXT: }
98 define void @test3(i8* %a) nounwind {
99 entry:
100   %outer = call i8* @objc_retain(i8* %a) nounwind
101   %inner = call i8* @objc_retain(i8* %a) nounwind
102   br label %loop
103
104 loop:
105   call void @callee()
106   store i8 0, i8* %a
107   br i1 undef, label %loop, label %exit
108
109 exit:
110   call void @objc_release(i8* %a) nounwind
111   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
112   ret void
113 }
114
115 ;      CHECK: define void @test4(i8* %a) #0 {
116 ; CHECK-NEXT: entry:
117 ; CHECK-NEXT:   tail call i8* @objc_retain(i8* %a) nounwind
118 ; CHECK-NEXT:   br label %loop
119 ;  CHECK-NOT:   @objc_
120 ;      CHECK: exit:
121 ; CHECK-NEXT:   call void @objc_release(i8* %a)
122 ; CHECK-NEXT:   ret void
123 ; CHECK-NEXT: }
124 define void @test4(i8* %a) nounwind {
125 entry:
126   %outer = call i8* @objc_retain(i8* %a) nounwind
127   %inner = call i8* @objc_retain(i8* %a) nounwind
128   br label %loop
129
130 loop:
131   br label %more
132
133 more:
134   call void @callee()
135   call void @callee()
136   store i8 0, i8* %a
137   br i1 undef, label %loop, label %exit
138
139 exit:
140   call void @objc_release(i8* %a) nounwind
141   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
142   ret void
143 }
144
145 ;      CHECK: define void @test5(i8* %a) #0 {
146 ; CHECK-NEXT: entry:
147 ; CHECK-NEXT:   tail call i8* @objc_retain(i8* %a) nounwind
148 ; CHECK-NEXT:   call void @callee()
149 ; CHECK-NEXT:   br label %loop
150 ;  CHECK-NOT:   @objc_
151 ;      CHECK: exit:
152 ; CHECK-NEXT:   call void @use_pointer(i8* %a)
153 ; CHECK-NEXT:   call void @objc_release(i8* %a)
154 ; CHECK-NEXT:   ret void
155 ; CHECK-NEXT: }
156 define void @test5(i8* %a) nounwind {
157 entry:
158   %outer = tail call i8* @objc_retain(i8* %a) nounwind
159   %inner = tail call i8* @objc_retain(i8* %a) nounwind
160   call void @callee()
161   br label %loop
162
163 loop:
164   br i1 undef, label %true, label %more
165
166 true:
167   br label %more
168
169 more:
170   br i1 undef, label %exit, label %loop
171
172 exit:
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
176   ret void
177 }
178
179 ;      CHECK: define void @test6(i8* %a) #0 {
180 ; CHECK-NEXT: entry:
181 ; CHECK-NEXT:   tail call i8* @objc_retain(i8* %a) nounwind
182 ; CHECK-NEXT:   br label %loop
183 ;  CHECK-NOT:   @objc_
184 ;      CHECK: exit:
185 ; CHECK-NEXT:   call void @use_pointer(i8* %a)
186 ; CHECK-NEXT:   call void @objc_release(i8* %a)
187 ; CHECK-NEXT:   ret void
188 ; CHECK-NEXT: }
189 define void @test6(i8* %a) nounwind {
190 entry:
191   %outer = tail call i8* @objc_retain(i8* %a) nounwind
192   %inner = tail call i8* @objc_retain(i8* %a) nounwind
193   br label %loop
194
195 loop:
196   br i1 undef, label %true, label %more
197
198 true:
199   call void @callee()
200   br label %more
201
202 more:
203   br i1 undef, label %exit, label %loop
204
205 exit:
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
209   ret void
210 }
211
212 ;      CHECK: define void @test7(i8* %a) #0 {
213 ; CHECK-NEXT: entry:
214 ; CHECK-NEXT:   tail call i8* @objc_retain(i8* %a) nounwind
215 ; CHECK-NEXT:   call void @callee()
216 ; CHECK-NEXT:   br label %loop
217 ;  CHECK-NOT:   @objc_
218 ;      CHECK: exit:
219 ; CHECK-NEXT:   call void @objc_release(i8* %a)
220 ; CHECK-NEXT:   ret void
221 ; CHECK-NEXT: }
222 define void @test7(i8* %a) nounwind {
223 entry:
224   %outer = tail call i8* @objc_retain(i8* %a) nounwind
225   %inner = tail call i8* @objc_retain(i8* %a) nounwind
226   call void @callee()
227   br label %loop
228
229 loop:
230   br i1 undef, label %true, label %more
231
232 true:
233   call void @use_pointer(i8* %a)
234   br label %more
235
236 more:
237   br i1 undef, label %exit, label %loop
238
239 exit:
240   call void @objc_release(i8* %a) nounwind
241   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
242   ret void
243 }
244
245 ;      CHECK: define void @test8(i8* %a) #0 {
246 ; CHECK-NEXT: entry:
247 ; CHECK-NEXT:   tail call i8* @objc_retain(i8* %a) nounwind
248 ; CHECK-NEXT:   br label %loop
249 ;  CHECK-NOT:   @objc_
250 ;      CHECK: exit:
251 ; CHECK-NEXT:   call void @objc_release(i8* %a)
252 ; CHECK-NEXT:   ret void
253 ; CHECK-NEXT: }
254 define void @test8(i8* %a) nounwind {
255 entry:
256   %outer = tail call i8* @objc_retain(i8* %a) nounwind
257   %inner = tail call i8* @objc_retain(i8* %a) nounwind
258   br label %loop
259
260 loop:
261   br i1 undef, label %true, label %more
262
263 true:
264   call void @callee()
265   call void @use_pointer(i8* %a)
266   br label %more
267
268 more:
269   br i1 undef, label %exit, label %loop
270
271 exit:
272   call void @objc_release(i8* %a) nounwind
273   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
274   ret void
275 }
276
277 ;      CHECK: define void @test9(i8* %a) #0 {
278 ; CHECK-NEXT: entry:
279 ; CHECK-NEXT:   br label %loop
280 ;  CHECK-NOT:   @objc_
281 ;      CHECK: exit:
282 ; CHECK-NEXT:   ret void
283 ; CHECK-NEXT: }
284 define void @test9(i8* %a) nounwind {
285 entry:
286   %outer = tail call i8* @objc_retain(i8* %a) nounwind
287   %inner = tail call i8* @objc_retain(i8* %a) nounwind
288   br label %loop
289
290 loop:
291   br i1 undef, label %true, label %more
292
293 true:
294   call void @use_pointer(i8* %a)
295   br label %more
296
297 more:
298   br i1 undef, label %exit, label %loop
299
300 exit:
301   call void @objc_release(i8* %a) nounwind
302   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
303   ret void
304 }
305
306 ;      CHECK: define void @test10(i8* %a) #0 {
307 ; CHECK-NEXT: entry:
308 ; CHECK-NEXT:   br label %loop
309 ;  CHECK-NOT:   @objc_
310 ;      CHECK: exit:
311 ; CHECK-NEXT:   ret void
312 ; CHECK-NEXT: }
313 define void @test10(i8* %a) nounwind {
314 entry:
315   %outer = tail call i8* @objc_retain(i8* %a) nounwind
316   %inner = tail call i8* @objc_retain(i8* %a) nounwind
317   br label %loop
318
319 loop:
320   br i1 undef, label %true, label %more
321
322 true:
323   call void @callee()
324   br label %more
325
326 more:
327   br i1 undef, label %exit, label %loop
328
329 exit:
330   call void @objc_release(i8* %a) nounwind
331   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
332   ret void
333 }
334
335 ;      CHECK: define void @test11(i8* %a) #0 {
336 ; CHECK-NEXT: entry:
337 ; CHECK-NEXT:   br label %loop
338 ;  CHECK-NOT:   @objc_
339 ;      CHECK: exit:
340 ; CHECK-NEXT:   ret void
341 ; CHECK-NEXT: }
342 define void @test11(i8* %a) nounwind {
343 entry:
344   %outer = tail call i8* @objc_retain(i8* %a) nounwind
345   %inner = tail call i8* @objc_retain(i8* %a) nounwind
346   br label %loop
347
348 loop:
349   br i1 undef, label %true, label %more
350
351 true:
352   br label %more
353
354 more:
355   br i1 undef, label %exit, label %loop
356
357 exit:
358   call void @objc_release(i8* %a) nounwind
359   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
360   ret void
361 }
362
363 ; Don't delete anything if they're not balanced.
364
365 ;      CHECK: define void @test12(i8* %a) #0 {
366 ; CHECK-NEXT: entry:
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
370 ;  CHECK-NOT:   @objc_
371 ;      CHECK: exit:
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
375 ; CHECK-NEXT: }
376 define void @test12(i8* %a) nounwind {
377 entry:
378   %outer = tail call i8* @objc_retain(i8* %a) nounwind
379   %inner = tail call i8* @objc_retain(i8* %a) nounwind
380   br label %loop
381
382 loop:
383   br i1 undef, label %true, label %more
384
385 true:
386   ret void
387
388 more:
389   br i1 undef, label %exit, label %loop
390
391 exit:
392   call void @objc_release(i8* %a) nounwind
393   call void @objc_release(i8* %a) nounwind, !clang.imprecise_release !0
394   ret void
395 }
396
397 ; CHECK: attributes #0 = { nounwind }
398
399 !0 = metadata !{}