; RUN: opt < %s -S -loop-unroll -verify-loop-info | FileCheck %s
;
; Unit tests for LoopInfo::updateUnloop.

declare i1 @check() nounwind

; Ensure that tail->inner is removed and rely on verify-loopinfo to
; check soundness.
;
; CHECK: @skiplevelexit
; CHECK: tail:
; CHECK-NOT: br
; CHECK: ret void
define void @skiplevelexit() nounwind {
entry:
  br label %outer

outer:
  br label %inner

inner:
  %iv = phi i32 [ 0, %outer ], [ %inc, %tail ]
  %inc = add i32 %iv, 1
  %wbucond = call zeroext i1 @check()
  br i1 %wbucond, label %outer.backedge, label %tail

tail:
  br i1 false, label %inner, label %exit

outer.backedge:
  br label %outer

exit:
  ret void
}

; Remove the middle loop of a triply nested loop tree.
; Ensure that only the middle loop is removed and rely on verify-loopinfo to
; check soundness.
;
; CHECK: @unloopNested
; Outer loop control.
; CHECK: while.body:
; CHECK: br i1 %cmp3, label %if.then, label %if.end
; Inner loop control.
; CHECK: while.end14.i:
; CHECK: br i1 %call15.i, label %if.end.i, label %exit
; Middle loop control should no longer reach %while.cond.
; Now it is the outer loop backedge.
; CHECK: exit:
; CHECK: br label %while.cond.outer
define void @unloopNested() {
entry:
  br label %while.cond.outer

while.cond.outer:
  br label %while.cond

while.cond:
  %cmp = call zeroext i1 @check()
  br i1 %cmp, label %while.body, label %while.end

while.body:
  %cmp3 = call zeroext i1 @check()
  br i1 %cmp3, label %if.then, label %if.end

if.then:
  br label %return

if.end:
  %cmp.i48 = call zeroext i1 @check()
  br i1 %cmp.i48, label %if.then.i, label %if.else20.i

if.then.i:
  %cmp8.i = call zeroext i1 @check()
  br i1 %cmp8.i, label %merge, label %if.else.i

if.else.i:
  br label %merge

if.else20.i:
  %cmp25.i = call zeroext i1 @check()
  br i1 %cmp25.i, label %merge, label %if.else28.i

if.else28.i:
  br label %merge

merge:
  br label %while.cond2.i

while.cond2.i:
  %cmp.i = call zeroext i1 @check()
  br i1 %cmp.i, label %while.cond2.backedge.i, label %while.end.i

while.cond2.backedge.i:
  br label %while.cond2.i

while.end.i:
  %cmp1114.i = call zeroext i1 @check()
  br i1 %cmp1114.i, label %while.body12.lr.ph.i, label %while.end14.i

while.body12.lr.ph.i:
  br label %while.end14.i

while.end14.i:
  %call15.i = call zeroext i1 @check()
  br i1 %call15.i, label %if.end.i, label %exit

if.end.i:
  br label %while.cond2.backedge.i

exit:
  br i1 false, label %while.cond, label %if.else

if.else:
  br label %while.cond.outer

while.end:
  br label %return

return:
  ret void
}

; Remove the middle loop of a deeply nested loop tree.
; Ensure that only the middle loop is removed and rely on verify-loopinfo to
; check soundness.
;
; CHECK: @unloopDeepNested
; Inner-inner loop control.
; CHECK: while.cond.us.i:
; CHECK: br i1 %cmp.us.i, label %next_data.exit, label %while.body.us.i
; CHECK: if.then.us.i:
; CHECK: br label %while.cond.us.i
; Inner loop tail.
; CHECK: if.else.i:
; CHECK: br label %while.cond.outer.i
; Middle loop control (removed).
; CHECK: valid_data.exit:
; CHECK-NOT: br
; CHECK: %cmp = call zeroext i1 @check()
; Outer loop control.
; CHECK: copy_data.exit:
; CHECK: br i1 %cmp38, label %if.then39, label %while.cond.outer
; Outer-outer loop tail.
; CHECK: while.cond.outer.outer.backedge:
; CHECK: br label %while.cond.outer.outer
define void @unloopDeepNested() nounwind {
for.cond8.preheader.i:
  %cmp113.i = call zeroext i1 @check()
  br i1 %cmp113.i, label %make_data.exit, label %for.body13.lr.ph.i

for.body13.lr.ph.i:
  br label %make_data.exit

make_data.exit:
  br label %while.cond.outer.outer

while.cond.outer.outer:
  br label %while.cond.outer

while.cond.outer:
  br label %while.cond

while.cond:
  br label %while.cond.outer.i

while.cond.outer.i:
  %tmp192.ph.i = call zeroext i1 @check()
  br i1 %tmp192.ph.i, label %while.cond.outer.split.us.i, label %while.body.loopexit

while.cond.outer.split.us.i:
  br label %while.cond.us.i

while.cond.us.i:
  %cmp.us.i = call zeroext i1 @check()
  br i1 %cmp.us.i, label %next_data.exit, label %while.body.us.i

while.body.us.i:
  %cmp7.us.i = call zeroext i1 @check()
  br i1 %cmp7.us.i, label %if.then.us.i, label %if.else.i

if.then.us.i:
  br label %while.cond.us.i

if.else.i:
  br label %while.cond.outer.i

next_data.exit:
  %tmp192.ph.i.lcssa28 = call zeroext i1 @check()
  br i1 %tmp192.ph.i.lcssa28, label %while.end, label %while.body

while.body.loopexit:
  br label %while.body

while.body:
  br label %while.cond.i

while.cond.i:
  %cmp.i = call zeroext i1 @check()
  br i1 %cmp.i, label %valid_data.exit, label %while.body.i

while.body.i:
  %cmp7.i = call zeroext i1 @check()
  br i1 %cmp7.i, label %valid_data.exit, label %if.end.i

if.end.i:
  br label %while.cond.i

valid_data.exit:
  br i1 true, label %if.then, label %while.cond

if.then:
  %cmp = call zeroext i1 @check()
  br i1 %cmp, label %if.then12, label %if.end

if.then12:
  br label %if.end

if.end:
  %tobool3.i = call zeroext i1 @check()
  br i1 %tobool3.i, label %copy_data.exit, label %while.body.lr.ph.i

while.body.lr.ph.i:
  br label %copy_data.exit

copy_data.exit:
  %cmp38 = call zeroext i1 @check()
  br i1 %cmp38, label %if.then39, label %while.cond.outer

if.then39:
  %cmp5.i = call zeroext i1 @check()
  br i1 %cmp5.i, label %while.cond.outer.outer.backedge, label %for.cond8.preheader.i8.thread

for.cond8.preheader.i8.thread:
  br label %while.cond.outer.outer.backedge

while.cond.outer.outer.backedge:
  br label %while.cond.outer.outer

while.end:
  ret void
}

; Remove a nested loop with irreducible control flow.
; Ensure that only the middle loop is removed and rely on verify-loopinfo to
; check soundness.
;
; CHECK: @unloopIrreducible
; Irreducible loop.
; CHECK: for.inc117:
; CHECK: br label %for.cond103t
; Nested loop (removed).
; CHECK: for.inc159:
; CHECK: br label %for.inc163
define void @unloopIrreducible() nounwind {

entry:
  br label %for.body

for.body:
  %cmp2113 = call zeroext i1 @check()
  br i1 %cmp2113, label %for.body22.lr.ph, label %for.inc163

for.body22.lr.ph:
  br label %for.body22

for.body22:
  br label %for.body33

for.body33:
  br label %for.end

for.end:
  %cmp424 = call zeroext i1 @check()
  br i1 %cmp424, label %for.body43.lr.ph, label %for.end93

for.body43.lr.ph:
  br label %for.end93

for.end93:
  %cmp96 = call zeroext i1 @check()
  br i1 %cmp96, label %if.then97, label %for.cond103

if.then97:
  br label %for.cond103t

for.cond103t:
  br label %for.cond103

for.cond103:
  %cmp105 = call zeroext i1 @check()
  br i1 %cmp105, label %for.body106, label %for.end120

for.body106:
  %cmp108 = call zeroext i1 @check()
  br i1 %cmp108, label %if.then109, label %for.inc117

if.then109:
  br label %for.inc117

for.inc117:
  br label %for.cond103t

for.end120:
  br label %for.inc159

for.inc159:
  br i1 false, label %for.body22, label %for.cond15.for.inc163_crit_edge

for.cond15.for.inc163_crit_edge:
  br label %for.inc163

for.inc163:
  %cmp12 = call zeroext i1 @check()
  br i1 %cmp12, label %for.body, label %for.end166

for.end166:
  ret void

}

; Remove a loop whose exit branches into a sibling loop.
; Ensure that only the loop is removed and rely on verify-loopinfo to
; check soundness.
;
; CHECK: @unloopCriticalEdge
; CHECK: while.cond.outer.i.loopexit.split:
; CHECK: br label %while.body
; CHECK: while.body:
; CHECK: br label %for.end78
define void @unloopCriticalEdge() nounwind {
entry:
  br label %for.cond31

for.cond31:
  br i1 undef, label %for.body35, label %for.end94

for.body35:
  br label %while.cond.i.preheader

while.cond.i.preheader:
  br i1 undef, label %while.cond.i.preheader.split, label %while.cond.outer.i.loopexit.split

while.cond.i.preheader.split:
  br label %while.cond.i

while.cond.i:
  br i1 true, label %while.cond.i, label %while.cond.outer.i.loopexit

while.cond.outer.i.loopexit:
  br label %while.cond.outer.i.loopexit.split

while.cond.outer.i.loopexit.split:
  br i1 false, label %while.cond.i.preheader, label %Func2.exit

Func2.exit:
  br label %while.body

while.body:
  br i1 false, label %while.body, label %while.end

while.end:
  br label %for.end78

for.end78:
  br i1 undef, label %Proc2.exit, label %for.cond.i.preheader

for.cond.i.preheader:
  br label %for.cond.i

for.cond.i:
  br label %for.cond.i

Proc2.exit:
  br label %for.cond31

for.end94:
  ret void
}

; Test UnloopUpdater::removeBlocksFromAncestors.
;
; Check that the loop backedge is removed from the middle loop 1699,
; but not the inner loop 1676.
; CHECK: while.body1694:
; CHECK:   br label %while.cond1676
; CHECK: while.end1699:
; CHECK:   br label %sw.default1711
define void @removeSubloopBlocks() nounwind {
entry:
  br label %tryagain.outer

tryagain.outer:                                   ; preds = %sw.bb304, %entry
  br label %tryagain

tryagain:                                         ; preds = %while.end1699, %tryagain.outer
  br i1 undef, label %sw.bb1669, label %sw.bb304

sw.bb304:                                         ; preds = %tryagain
  br i1 undef, label %return, label %tryagain.outer

sw.bb1669:                                        ; preds = %tryagain
  br i1 undef, label %sw.default1711, label %while.cond1676

while.cond1676:                                   ; preds = %while.body1694, %sw.bb1669
  br i1 undef, label %while.end1699, label %while.body1694

while.body1694:                                   ; preds = %while.cond1676
  br label %while.cond1676

while.end1699:                                    ; preds = %while.cond1676
  br i1 false, label %tryagain, label %sw.default1711

sw.default1711:                                   ; preds = %while.end1699, %sw.bb1669, %tryagain
  br label %defchar

defchar:                                          ; preds = %sw.default1711, %sw.bb376
  br i1 undef, label %if.end2413, label %if.then2368

if.then2368:                                      ; preds = %defchar
  unreachable

if.end2413:                                       ; preds = %defchar
  unreachable

return:                                           ; preds = %sw.bb304
  ret void
}

; PR11335: the most deeply nested block should be removed from the outer loop.
; CHECK: @removeSubloopBlocks2
; CHECK: for.cond3:
; CHECK-NOT: br
; CHECK: ret void
define void @removeSubloopBlocks2() nounwind {
entry:
  %tobool.i = icmp ne i32 undef, 0
  br label %lbl_616

lbl_616.loopexit:                                 ; preds = %for.cond
  br label %lbl_616

lbl_616:                                          ; preds = %lbl_616.loopexit, %entry
  br label %for.cond

for.cond:                                         ; preds = %for.cond3, %lbl_616
  br i1 false, label %for.cond1.preheader, label %lbl_616.loopexit

for.cond1.preheader:                              ; preds = %for.cond
  br label %for.cond1

for.cond1.loopexit:                               ; preds = %for.cond.i
  br label %for.cond1

for.cond1:                                        ; preds = %for.cond1.loopexit, %for.cond1.preheader
  br i1 false, label %for.body2, label %for.cond3

for.body2:                                        ; preds = %for.cond1
  br label %for.cond.i

for.cond.i:                                       ; preds = %for.cond.i, %for.body2
  br i1 %tobool.i, label %for.cond.i, label %for.cond1.loopexit

for.cond3:                                        ; preds = %for.cond1
  br i1 false, label %for.cond, label %if.end

if.end:                                           ; preds = %for.cond3
  ret void
}
