LoopUnroll is a loop pass, so the analysis of OptimizationRemarkEmitter
is added to the common function analysis passes that loop passes
depend on.
The BFI and indirectly BPI used in this pass is computed lazily so no
overhead should be observed unless -pass-remarks-with-hotness is used.
This is how the patch affects the O3 pipeline:
Dominator Tree Construction
Natural Loop Information
Canonicalize natural loops
Loop-Closed SSA Form Pass
Basic Alias Analysis (stateless AA impl)
Function Alias Analysis Results
Scalar Evolution Analysis
+ Lazy Branch Probability Analysis
+ Lazy Block Frequency Analysis
+ Optimization Remark Emitter
Loop Pass Manager
Rotate Loops
Loop Invariant Code Motion
Unswitch loops
Simplify the CFG
Dominator Tree Construction
Basic Alias Analysis (stateless AA impl)
Function Alias Analysis Results
Combine redundant instructions
Natural Loop Information
Canonicalize natural loops
Loop-Closed SSA Form Pass
Scalar Evolution Analysis
+ Lazy Branch Probability Analysis
+ Lazy Block Frequency Analysis
+ Optimization Remark Emitter
Loop Pass Manager
Induction Variable Simplification
Recognize loop idioms
Delete dead loops
Unroll loops
...
llvm-svn: 277203
474 lines
12 KiB
LLVM
474 lines
12 KiB
LLVM
; RUN: opt < %s -S -loop-unroll -verify-loop-info | FileCheck %s
|
|
; RUN: opt < %s -S -passes='function(require<scalar-evolution>,require<targetir>,require<opt-remark-emit>,loop(unroll),verify<loops>)' | FileCheck %s
|
|
;
|
|
; Unit tests for LoopInfo::markAsRemoved.
|
|
|
|
declare i1 @check() nounwind
|
|
|
|
; Ensure that tail->inner is removed and rely on verify-loopinfo to
|
|
; check soundness.
|
|
;
|
|
; CHECK-LABEL: @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
|
|
call zeroext i1 @check()
|
|
br i1 true, 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-LABEL: @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.
|
|
;
|
|
; This test must be disabled until trip count computation can be optimized...
|
|
; rdar:14038809 [SCEV]: Optimize trip count computation for multi-exit loops.
|
|
; CHECKFIXME-LABEL: @unloopDeepNested(
|
|
; Inner-inner loop control.
|
|
; CHECKFIXME: while.cond.us.i:
|
|
; CHECKFIXME: br i1 %cmp.us.i, label %next_data.exit, label %while.body.us.i
|
|
; CHECKFIXME: if.then.us.i:
|
|
; CHECKFIXME: br label %while.cond.us.i
|
|
; Inner loop tail.
|
|
; CHECKFIXME: if.else.i:
|
|
; CHECKFIXME: br label %while.cond.outer.i
|
|
; Middle loop control (removed).
|
|
; CHECKFIXME: valid_data.exit:
|
|
; CHECKFIXME-NOT: br
|
|
; CHECKFIXME: %cmp = call zeroext i1 @check()
|
|
; Outer loop control.
|
|
; CHECKFIXME: copy_data.exit:
|
|
; CHECKFIXME: br i1 %cmp38, label %if.then39, label %while.cond.outer
|
|
; Outer-outer loop tail.
|
|
; CHECKFIXME: while.cond.outer.outer.backedge:
|
|
; CHECKFIXME: 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-LABEL: @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-LABEL: @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-LABEL: @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
|
|
}
|