xref: /llvm-project/llvm/test/Transforms/ObjCARC/cfg-hazards.ll (revision 9bf6365237f3a8a401afc0a69d2fb6d1b809ce68)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -S -passes=objc-arc < %s | FileCheck %s
3; rdar://9503416
4
5; Detect loop boundaries and don't move retains and releases
6; across them.
7
8declare void @use_pointer(ptr)
9declare ptr @llvm.objc.retain(ptr)
10declare void @llvm.objc.release(ptr)
11declare void @callee()
12declare void @block_callee(ptr)
13
14define void @test0(ptr %digits) {
15; CHECK-LABEL: @test0(
16; CHECK-NEXT:  entry:
17; CHECK-NEXT:    [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[DIGITS:%.*]]) #[[ATTR0:[0-9]+]]
18; CHECK-NEXT:    call void @use_pointer(ptr [[DIGITS]])
19; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
20; CHECK:       for.body:
21; CHECK-NEXT:    [[UPCDIGITINDEX_01:%.*]] = phi i64 [ 2, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
22; CHECK-NEXT:    call void @use_pointer(ptr [[DIGITS]])
23; CHECK-NEXT:    [[INC]] = add i64 [[UPCDIGITINDEX_01]], 1
24; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[INC]], 12
25; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
26; CHECK:       for.end:
27; CHECK-NEXT:    call void @llvm.objc.release(ptr [[DIGITS]]) #[[ATTR0]], !clang.imprecise_release !0
28; CHECK-NEXT:    ret void
29;
30entry:
31  %tmp1 = call ptr @llvm.objc.retain(ptr %digits) nounwind
32  call void @use_pointer(ptr %digits)
33  br label %for.body
34
35for.body:                                         ; preds = %for.body, %entry
36  %upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ]
37  call void @use_pointer(ptr %digits)
38  %inc = add i64 %upcDigitIndex.01, 1
39  %cmp = icmp ult i64 %inc, 12
40  br i1 %cmp, label %for.body, label %for.end
41
42for.end:                                          ; preds = %for.body
43  call void @llvm.objc.release(ptr %digits) nounwind, !clang.imprecise_release !0
44  ret void
45}
46
47define void @test1(ptr %digits) {
48; CHECK-LABEL: @test1(
49; CHECK-NEXT:  entry:
50; CHECK-NEXT:    [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[DIGITS:%.*]]) #[[ATTR0]]
51; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
52; CHECK:       for.body:
53; CHECK-NEXT:    [[UPCDIGITINDEX_01:%.*]] = phi i64 [ 2, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
54; CHECK-NEXT:    call void @use_pointer(ptr [[DIGITS]])
55; CHECK-NEXT:    call void @use_pointer(ptr [[DIGITS]])
56; CHECK-NEXT:    [[INC]] = add i64 [[UPCDIGITINDEX_01]], 1
57; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[INC]], 12
58; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
59; CHECK:       for.end:
60; CHECK-NEXT:    call void @llvm.objc.release(ptr [[DIGITS]]) #[[ATTR0]], !clang.imprecise_release !0
61; CHECK-NEXT:    ret void
62;
63entry:
64  %tmp1 = call ptr @llvm.objc.retain(ptr %digits) nounwind
65  br label %for.body
66
67for.body:                                         ; preds = %for.body, %entry
68  %upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ]
69  call void @use_pointer(ptr %digits)
70  call void @use_pointer(ptr %digits)
71  %inc = add i64 %upcDigitIndex.01, 1
72  %cmp = icmp ult i64 %inc, 12
73  br i1 %cmp, label %for.body, label %for.end
74
75for.end:                                          ; preds = %for.body
76  call void @llvm.objc.release(ptr %digits) nounwind, !clang.imprecise_release !0
77  ret void
78}
79
80define void @test2(ptr %digits) {
81; CHECK-LABEL: @test2(
82; CHECK-NEXT:  entry:
83; CHECK-NEXT:    [[TMP1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[DIGITS:%.*]]) #[[ATTR0]]
84; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
85; CHECK:       for.body:
86; CHECK-NEXT:    [[UPCDIGITINDEX_01:%.*]] = phi i64 [ 2, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[FOR_BODY]] ]
87; CHECK-NEXT:    call void @use_pointer(ptr [[DIGITS]])
88; CHECK-NEXT:    [[INC]] = add i64 [[UPCDIGITINDEX_01]], 1
89; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[INC]], 12
90; CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
91; CHECK:       for.end:
92; CHECK-NEXT:    call void @use_pointer(ptr [[DIGITS]])
93; CHECK-NEXT:    call void @llvm.objc.release(ptr [[DIGITS]]) #[[ATTR0]], !clang.imprecise_release !0
94; CHECK-NEXT:    ret void
95;
96entry:
97  %tmp1 = call ptr @llvm.objc.retain(ptr %digits) nounwind
98  br label %for.body
99
100for.body:                                         ; preds = %for.body, %entry
101  %upcDigitIndex.01 = phi i64 [ 2, %entry ], [ %inc, %for.body ]
102  call void @use_pointer(ptr %digits)
103  %inc = add i64 %upcDigitIndex.01, 1
104  %cmp = icmp ult i64 %inc, 12
105  br i1 %cmp, label %for.body, label %for.end
106
107for.end:                                          ; preds = %for.body
108  call void @use_pointer(ptr %digits)
109  call void @llvm.objc.release(ptr %digits) nounwind, !clang.imprecise_release !0
110  ret void
111}
112
113; Delete nested retain+release pairs around loops.
114define void @test3(ptr %a, i1 %arg) nounwind {
115; CHECK-LABEL: @test3(
116; CHECK-NEXT:  entry:
117; CHECK-NEXT:    [[OUTER:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A:%.*]]) #[[ATTR0]]
118; CHECK-NEXT:    br label [[LOOP:%.*]]
119; CHECK:       loop:
120; CHECK-NEXT:    call void @callee()
121; CHECK-NEXT:    store i8 0, ptr [[A]], align 1
122; CHECK-NEXT:    br i1 %arg, label [[LOOP]], label [[EXIT:%.*]]
123; CHECK:       exit:
124; CHECK-NEXT:    call void @llvm.objc.release(ptr [[A]]) #[[ATTR0]], !clang.imprecise_release !0
125; CHECK-NEXT:    ret void
126;
127entry:
128  %outer = call ptr @llvm.objc.retain(ptr %a) nounwind
129  %inner = call ptr @llvm.objc.retain(ptr %a) nounwind
130  br label %loop
131
132loop:
133  call void @callee()
134  store i8 0, ptr %a
135  br i1 %arg, label %loop, label %exit
136
137exit:
138  call void @llvm.objc.release(ptr %a) nounwind
139  call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0
140  ret void
141}
142
143define void @test4(ptr %a, i1 %arg) nounwind {
144; CHECK-LABEL: @test4(
145; CHECK-NEXT:  entry:
146; CHECK-NEXT:    [[OUTER:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A:%.*]]) #[[ATTR0]]
147; CHECK-NEXT:    br label [[LOOP:%.*]]
148; CHECK:       loop:
149; CHECK-NEXT:    br label [[MORE:%.*]]
150; CHECK:       more:
151; CHECK-NEXT:    call void @callee()
152; CHECK-NEXT:    call void @callee()
153; CHECK-NEXT:    store i8 0, ptr [[A]], align 1
154; CHECK-NEXT:    br i1 %arg, label [[LOOP]], label [[EXIT:%.*]]
155; CHECK:       exit:
156; CHECK-NEXT:    call void @llvm.objc.release(ptr [[A]]) #[[ATTR0]], !clang.imprecise_release !0
157; CHECK-NEXT:    ret void
158;
159entry:
160  %outer = call ptr @llvm.objc.retain(ptr %a) nounwind
161  %inner = call ptr @llvm.objc.retain(ptr %a) nounwind
162  br label %loop
163
164loop:
165  br label %more
166
167more:
168  call void @callee()
169  call void @callee()
170  store i8 0, ptr %a
171  br i1 %arg, label %loop, label %exit
172
173exit:
174  call void @llvm.objc.release(ptr %a) nounwind
175  call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0
176  ret void
177}
178
179define void @test5(ptr %a, i1 %arg) nounwind {
180; CHECK-LABEL: @test5(
181; CHECK-NEXT:  entry:
182; CHECK-NEXT:    [[OUTER:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A:%.*]]) #[[ATTR0]]
183; CHECK-NEXT:    call void @callee()
184; CHECK-NEXT:    br label [[LOOP:%.*]]
185; CHECK:       loop:
186; CHECK-NEXT:    br i1 %arg, label [[TRUE:%.*]], label [[MORE:%.*]]
187; CHECK:       true:
188; CHECK-NEXT:    br label [[MORE]]
189; CHECK:       more:
190; CHECK-NEXT:    br i1 %arg, label [[EXIT:%.*]], label [[LOOP]]
191; CHECK:       exit:
192; CHECK-NEXT:    call void @use_pointer(ptr [[A]])
193; CHECK-NEXT:    call void @llvm.objc.release(ptr [[A]]) #[[ATTR0]], !clang.imprecise_release !0
194; CHECK-NEXT:    ret void
195;
196entry:
197  %outer = tail call ptr @llvm.objc.retain(ptr %a) nounwind
198  %inner = tail call ptr @llvm.objc.retain(ptr %a) nounwind
199  call void @callee()
200  br label %loop
201
202loop:
203  br i1 %arg, label %true, label %more
204
205true:
206  br label %more
207
208more:
209  br i1 %arg, label %exit, label %loop
210
211exit:
212  call void @use_pointer(ptr %a)
213  call void @llvm.objc.release(ptr %a) nounwind
214  call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0
215  ret void
216}
217
218define void @test6(ptr %a, i1 %arg) nounwind {
219; CHECK-LABEL: @test6(
220; CHECK-NEXT:  entry:
221; CHECK-NEXT:    [[OUTER:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A:%.*]]) #[[ATTR0]]
222; CHECK-NEXT:    br label [[LOOP:%.*]]
223; CHECK:       loop:
224; CHECK-NEXT:    br i1 %arg, label [[TRUE:%.*]], label [[MORE:%.*]]
225; CHECK:       true:
226; CHECK-NEXT:    call void @callee()
227; CHECK-NEXT:    br label [[MORE]]
228; CHECK:       more:
229; CHECK-NEXT:    br i1 %arg, label [[EXIT:%.*]], label [[LOOP]]
230; CHECK:       exit:
231; CHECK-NEXT:    call void @use_pointer(ptr [[A]])
232; CHECK-NEXT:    call void @llvm.objc.release(ptr [[A]]) #[[ATTR0]], !clang.imprecise_release !0
233; CHECK-NEXT:    ret void
234;
235entry:
236  %outer = tail call ptr @llvm.objc.retain(ptr %a) nounwind
237  %inner = tail call ptr @llvm.objc.retain(ptr %a) nounwind
238  br label %loop
239
240loop:
241  br i1 %arg, label %true, label %more
242
243true:
244  call void @callee()
245  br label %more
246
247more:
248  br i1 %arg, label %exit, label %loop
249
250exit:
251  call void @use_pointer(ptr %a)
252  call void @llvm.objc.release(ptr %a) nounwind
253  call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0
254  ret void
255}
256
257define void @test7(ptr %a, i1 %arg) nounwind {
258; CHECK-LABEL: @test7(
259; CHECK-NEXT:  entry:
260; CHECK-NEXT:    [[OUTER:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A:%.*]]) #[[ATTR0]]
261; CHECK-NEXT:    call void @callee()
262; CHECK-NEXT:    br label [[LOOP:%.*]]
263; CHECK:       loop:
264; CHECK-NEXT:    br i1 %arg, label [[TRUE:%.*]], label [[MORE:%.*]]
265; CHECK:       true:
266; CHECK-NEXT:    call void @use_pointer(ptr [[A]])
267; CHECK-NEXT:    br label [[MORE]]
268; CHECK:       more:
269; CHECK-NEXT:    br i1 %arg, label [[EXIT:%.*]], label [[LOOP]]
270; CHECK:       exit:
271; CHECK-NEXT:    call void @llvm.objc.release(ptr [[A]]) #[[ATTR0]], !clang.imprecise_release !0
272; CHECK-NEXT:    ret void
273;
274entry:
275  %outer = tail call ptr @llvm.objc.retain(ptr %a) nounwind
276  %inner = tail call ptr @llvm.objc.retain(ptr %a) nounwind
277  call void @callee()
278  br label %loop
279
280loop:
281  br i1 %arg, label %true, label %more
282
283true:
284  call void @use_pointer(ptr %a)
285  br label %more
286
287more:
288  br i1 %arg, label %exit, label %loop
289
290exit:
291  call void @llvm.objc.release(ptr %a) nounwind
292  call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0
293  ret void
294}
295
296define void @test8(ptr %a, i1 %arg) nounwind {
297; CHECK-LABEL: @test8(
298; CHECK-NEXT:  entry:
299; CHECK-NEXT:    [[OUTER:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A:%.*]]) #[[ATTR0]]
300; CHECK-NEXT:    br label [[LOOP:%.*]]
301; CHECK:       loop:
302; CHECK-NEXT:    br i1 %arg, label [[TRUE:%.*]], label [[MORE:%.*]]
303; CHECK:       true:
304; CHECK-NEXT:    call void @callee()
305; CHECK-NEXT:    call void @use_pointer(ptr [[A]])
306; CHECK-NEXT:    br label [[MORE]]
307; CHECK:       more:
308; CHECK-NEXT:    br i1 %arg, label [[EXIT:%.*]], label [[LOOP]]
309; CHECK:       exit:
310; CHECK-NEXT:    call void @llvm.objc.release(ptr [[A]]) #[[ATTR0]], !clang.imprecise_release !0
311; CHECK-NEXT:    ret void
312;
313entry:
314  %outer = tail call ptr @llvm.objc.retain(ptr %a) nounwind
315  %inner = tail call ptr @llvm.objc.retain(ptr %a) nounwind
316  br label %loop
317
318loop:
319  br i1 %arg, label %true, label %more
320
321true:
322  call void @callee()
323  call void @use_pointer(ptr %a)
324  br label %more
325
326more:
327  br i1 %arg, label %exit, label %loop
328
329exit:
330  call void @llvm.objc.release(ptr %a) nounwind
331  call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0
332  ret void
333}
334
335define void @test9(ptr %a, i1 %arg) nounwind {
336; CHECK-LABEL: @test9(
337; CHECK-NEXT:  entry:
338; CHECK-NEXT:    br label [[LOOP:%.*]]
339; CHECK:       loop:
340; CHECK-NEXT:    br i1 %arg, label [[TRUE:%.*]], label [[MORE:%.*]]
341; CHECK:       true:
342; CHECK-NEXT:    call void @use_pointer(ptr [[A:%.*]])
343; CHECK-NEXT:    br label [[MORE]]
344; CHECK:       more:
345; CHECK-NEXT:    br i1 %arg, label [[EXIT:%.*]], label [[LOOP]]
346; CHECK:       exit:
347; CHECK-NEXT:    ret void
348;
349entry:
350  %outer = tail call ptr @llvm.objc.retain(ptr %a) nounwind
351  %inner = tail call ptr @llvm.objc.retain(ptr %a) nounwind
352  br label %loop
353
354loop:
355  br i1 %arg, label %true, label %more
356
357true:
358  call void @use_pointer(ptr %a)
359  br label %more
360
361more:
362  br i1 %arg, label %exit, label %loop
363
364exit:
365  call void @llvm.objc.release(ptr %a) nounwind
366  call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0
367  ret void
368}
369
370define void @test10(ptr %a, i1 %arg) nounwind {
371; CHECK-LABEL: @test10(
372; CHECK-NEXT:  entry:
373; CHECK-NEXT:    br label [[LOOP:%.*]]
374; CHECK:       loop:
375; CHECK-NEXT:    br i1 %arg, label [[TRUE:%.*]], label [[MORE:%.*]]
376; CHECK:       true:
377; CHECK-NEXT:    call void @callee()
378; CHECK-NEXT:    br label [[MORE]]
379; CHECK:       more:
380; CHECK-NEXT:    br i1 %arg, label [[EXIT:%.*]], label [[LOOP]]
381; CHECK:       exit:
382; CHECK-NEXT:    ret void
383;
384entry:
385  %outer = tail call ptr @llvm.objc.retain(ptr %a) nounwind
386  %inner = tail call ptr @llvm.objc.retain(ptr %a) nounwind
387  br label %loop
388
389loop:
390  br i1 %arg, label %true, label %more
391
392true:
393  call void @callee()
394  br label %more
395
396more:
397  br i1 %arg, label %exit, label %loop
398
399exit:
400  call void @llvm.objc.release(ptr %a) nounwind
401  call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0
402  ret void
403}
404
405define void @test11(ptr %a, i1 %arg) nounwind {
406; CHECK-LABEL: @test11(
407; CHECK-NEXT:  entry:
408; CHECK-NEXT:    br label [[LOOP:%.*]]
409; CHECK:       loop:
410; CHECK-NEXT:    br i1 %arg, label [[TRUE:%.*]], label [[MORE:%.*]]
411; CHECK:       true:
412; CHECK-NEXT:    br label [[MORE]]
413; CHECK:       more:
414; CHECK-NEXT:    br i1 %arg, label [[EXIT:%.*]], label [[LOOP]]
415; CHECK:       exit:
416; CHECK-NEXT:    ret void
417;
418entry:
419  %outer = tail call ptr @llvm.objc.retain(ptr %a) nounwind
420  %inner = tail call ptr @llvm.objc.retain(ptr %a) nounwind
421  br label %loop
422
423loop:
424  br i1 %arg, label %true, label %more
425
426true:
427  br label %more
428
429more:
430  br i1 %arg, label %exit, label %loop
431
432exit:
433  call void @llvm.objc.release(ptr %a) nounwind
434  call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0
435  ret void
436}
437
438; Don't delete anything if they're not balanced.
439
440define void @test12(ptr %a, i1 %arg) nounwind {
441; CHECK-LABEL: @test12(
442; CHECK-NEXT:  entry:
443; CHECK-NEXT:    [[OUTER:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A:%.*]]) #[[ATTR0]]
444; CHECK-NEXT:    [[INNER:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A]]) #[[ATTR0]]
445; CHECK-NEXT:    br label [[LOOP:%.*]]
446; CHECK:       loop:
447; CHECK-NEXT:    br i1 %arg, label [[TRUE:%.*]], label [[MORE:%.*]]
448; CHECK:       true:
449; CHECK-NEXT:    ret void
450; CHECK:       more:
451; CHECK-NEXT:    br i1 %arg, label [[EXIT:%.*]], label [[LOOP]]
452; CHECK:       exit:
453; CHECK-NEXT:    call void @llvm.objc.release(ptr [[A]]) #[[ATTR0]]
454; CHECK-NEXT:    call void @llvm.objc.release(ptr [[A]]) #[[ATTR0]], !clang.imprecise_release !0
455; CHECK-NEXT:    ret void
456;
457entry:
458  %outer = tail call ptr @llvm.objc.retain(ptr %a) nounwind
459  %inner = tail call ptr @llvm.objc.retain(ptr %a) nounwind
460  br label %loop
461
462loop:
463  br i1 %arg, label %true, label %more
464
465true:
466  ret void
467
468more:
469  br i1 %arg, label %exit, label %loop
470
471exit:
472  call void @llvm.objc.release(ptr %a) nounwind
473  call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0
474  ret void
475}
476
477; Do not improperly pair retains in a for loop with releases outside of a for
478; loop when the proper pairing is disguised by a separate provenance represented
479; by an alloca.
480; rdar://12969722
481
482define void @test13(ptr %a, i1 %arg) nounwind {
483; CHECK-LABEL: @test13(
484; CHECK-NEXT:  entry:
485; CHECK-NEXT:    [[BLOCK:%.*]] = alloca ptr, align 8
486; CHECK-NEXT:    [[A1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A:%.*]]) #[[ATTR0]]
487; CHECK-NEXT:    br label [[LOOP:%.*]]
488; CHECK:       loop:
489; CHECK-NEXT:    [[A2:%.*]] = tail call ptr @llvm.objc.retain(ptr [[A]]) #[[ATTR0]]
490; CHECK-NEXT:    store ptr [[A]], ptr [[BLOCK]], align 8
491; CHECK-NEXT:    call void @block_callee(ptr [[BLOCK]])
492; CHECK-NEXT:    [[RELOADED_A:%.*]] = load ptr, ptr [[BLOCK]], align 8
493; CHECK-NEXT:    call void @llvm.objc.release(ptr [[RELOADED_A]]) #[[ATTR0]], !clang.imprecise_release !0
494; CHECK-NEXT:    br i1 %arg, label [[LOOP]], label [[EXIT:%.*]]
495; CHECK:       exit:
496; CHECK-NEXT:    call void @llvm.objc.release(ptr [[A]]) #[[ATTR0]], !clang.imprecise_release !0
497; CHECK-NEXT:    ret void
498;
499entry:
500  %block = alloca ptr
501  %a1 = tail call ptr @llvm.objc.retain(ptr %a) nounwind
502  br label %loop
503
504loop:
505  %a2 = tail call ptr @llvm.objc.retain(ptr %a) nounwind
506  store ptr %a, ptr %block, align 8
507  call void @block_callee(ptr %block)
508  %reloaded_a = load ptr, ptr %block, align 8
509  call void @llvm.objc.release(ptr %reloaded_a) nounwind, !clang.imprecise_release !0
510  br i1 %arg, label %loop, label %exit
511
512exit:
513  call void @llvm.objc.release(ptr %a) nounwind, !clang.imprecise_release !0
514  ret void
515}
516
517; The retain call in the entry block shouldn't be moved to the loop body.
518
519define void @test14(ptr %val0, i8 %val1) {
520; CHECK-LABEL: @test14(
521; CHECK-NEXT:  entry:
522; CHECK-NEXT:    [[V1:%.*]] = tail call ptr @llvm.objc.retain(ptr [[VAL0:%.*]]) #[[ATTR0]]
523; CHECK-NEXT:    [[CMP:%.*]] = icmp eq ptr [[VAL0]], null
524; CHECK-NEXT:    br i1 [[CMP]], label [[IF_END27:%.*]], label [[IF_THEN:%.*]]
525; CHECK:       if.then:
526; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i8 [[VAL1:%.*]], 1
527; CHECK-NEXT:    br label [[FOR_BODY:%.*]]
528; CHECK:       for.cond:
529; CHECK-NEXT:    [[CMP6:%.*]] = icmp eq i8 [[VAL1]], 2
530; CHECK-NEXT:    br i1 [[CMP6]], label [[FOR_BODY]], label [[FOR_END_LOOPEXIT:%.*]]
531; CHECK:       for.body:
532; CHECK-NEXT:    call void @callee()
533; CHECK-NEXT:    [[TOBOOL9:%.*]] = icmp eq i8 [[VAL1]], 0
534; CHECK-NEXT:    br i1 [[TOBOOL9]], label [[FOR_COND:%.*]], label [[IF_THEN10:%.*]]
535; CHECK:       if.then10:
536; CHECK-NEXT:    br label [[FOR_END:%.*]]
537; CHECK:       for.end.loopexit:
538; CHECK-NEXT:    br label [[FOR_END]]
539; CHECK:       for.end:
540; CHECK-NEXT:    call void @callee()
541; CHECK-NEXT:    call void @use_pointer(ptr [[V1]])
542; CHECK-NEXT:    br label [[IF_END27]]
543; CHECK:       if.end27:
544; CHECK-NEXT:    call void @llvm.objc.release(ptr [[V1]]) #[[ATTR0]], !clang.imprecise_release !0
545; CHECK-NEXT:    ret void
546;
547entry:
548  %v1 = tail call ptr @llvm.objc.retain(ptr %val0)
549  %cmp = icmp eq ptr %val0, null
550  br i1 %cmp, label %if.end27, label %if.then
551
552if.then:
553  %tobool = icmp eq i8 %val1, 1
554  br label %for.body
555
556for.cond:
557  %cmp6 = icmp eq i8 %val1, 2
558  br i1 %cmp6, label %for.body, label %for.end.loopexit
559
560for.body:
561  call void @callee()
562  %tobool9 = icmp eq i8 %val1, 0
563  br i1 %tobool9, label %for.cond, label %if.then10
564
565if.then10:
566  br label %for.end
567
568for.end.loopexit:
569  br label %for.end
570
571for.end:
572  call void @callee()
573  call void @use_pointer(ptr %v1)
574  br label %if.end27
575
576if.end27:
577  call void @llvm.objc.release(ptr %v1) #0, !clang.imprecise_release !0
578  ret void
579}
580
581
582!0 = !{}
583