• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
7declare void @use_pointer(i8*)
8declare i8* @objc_retain(i8*)
9declare void @objc_release(i8*)
10declare 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: }
19define void @test0(i8* %digits) {
20entry:
21  %tmp1 = call i8* @objc_retain(i8* %digits) nounwind
22  call void @use_pointer(i8* %digits)
23  br label %for.body
24
25for.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
32for.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: }
44define void @test1(i8* %digits) {
45entry:
46  %tmp1 = call i8* @objc_retain(i8* %digits) nounwind
47  br label %for.body
48
49for.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
57for.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: }
69define void @test2(i8* %digits) {
70entry:
71  %tmp1 = call i8* @objc_retain(i8* %digits) nounwind
72  br label %for.body
73
74for.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
81for.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) nounwind {
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: }
98define void @test3(i8* %a) nounwind {
99entry:
100  %outer = call i8* @objc_retain(i8* %a) nounwind
101  %inner = call i8* @objc_retain(i8* %a) nounwind
102  br label %loop
103
104loop:
105  call void @callee()
106  store i8 0, i8* %a
107  br i1 undef, label %loop, label %exit
108
109exit:
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) nounwind {
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: }
124define void @test4(i8* %a) nounwind {
125entry:
126  %outer = call i8* @objc_retain(i8* %a) nounwind
127  %inner = call i8* @objc_retain(i8* %a) nounwind
128  br label %loop
129
130loop:
131  br label %more
132
133more:
134  call void @callee()
135  call void @callee()
136  store i8 0, i8* %a
137  br i1 undef, label %loop, label %exit
138
139exit:
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) nounwind {
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: }
156define void @test5(i8* %a) nounwind {
157entry:
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
163loop:
164  br i1 undef, label %true, label %more
165
166true:
167  br label %more
168
169more:
170  br i1 undef, label %exit, label %loop
171
172exit:
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) nounwind {
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: }
189define void @test6(i8* %a) nounwind {
190entry:
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
195loop:
196  br i1 undef, label %true, label %more
197
198true:
199  call void @callee()
200  br label %more
201
202more:
203  br i1 undef, label %exit, label %loop
204
205exit:
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) nounwind {
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: }
222define void @test7(i8* %a) nounwind {
223entry:
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
229loop:
230  br i1 undef, label %true, label %more
231
232true:
233  call void @use_pointer(i8* %a)
234  br label %more
235
236more:
237  br i1 undef, label %exit, label %loop
238
239exit:
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) nounwind {
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: }
254define void @test8(i8* %a) nounwind {
255entry:
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
260loop:
261  br i1 undef, label %true, label %more
262
263true:
264  call void @callee()
265  call void @use_pointer(i8* %a)
266  br label %more
267
268more:
269  br i1 undef, label %exit, label %loop
270
271exit:
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) nounwind {
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: }
284define void @test9(i8* %a) nounwind {
285entry:
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
290loop:
291  br i1 undef, label %true, label %more
292
293true:
294  call void @use_pointer(i8* %a)
295  br label %more
296
297more:
298  br i1 undef, label %exit, label %loop
299
300exit:
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) nounwind {
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: }
313define void @test10(i8* %a) nounwind {
314entry:
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
319loop:
320  br i1 undef, label %true, label %more
321
322true:
323  call void @callee()
324  br label %more
325
326more:
327  br i1 undef, label %exit, label %loop
328
329exit:
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) nounwind {
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: }
342define void @test11(i8* %a) nounwind {
343entry:
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
348loop:
349  br i1 undef, label %true, label %more
350
351true:
352  br label %more
353
354more:
355  br i1 undef, label %exit, label %loop
356
357exit:
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) nounwind {
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: }
376define void @test12(i8* %a) nounwind {
377entry:
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
382loop:
383  br i1 undef, label %true, label %more
384
385true:
386  ret void
387
388more:
389  br i1 undef, label %exit, label %loop
390
391exit:
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!0 = metadata !{}
398