Skip to content

Commit 9f1b6b6

Browse files
committed
[LoopUnroll] Fix division by zero
PR #159163's probability computation for epilogue loops does not handle the possibility of an original loop probability of one. Runtime loop unrolling does not make sense for such an infinite loop, and a division by zero results. This patch works around that case. Issue #165998.
1 parent 28d3194 commit 9f1b6b6

File tree

2 files changed

+123
-0
lines changed

2 files changed

+123
-0
lines changed

llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,17 @@ static void ConnectProlog(Loop *L, Value *BECount, unsigned Count,
200200
/// from 0 to \p N more iterations can possibly execute. Among such cases in
201201
/// the original loop (with loop probability \p OriginalLoopProb), what is the
202202
/// probability of executing at least one more iteration?
203+
///
204+
/// If \p OriginalLoopProb is 1, then the original loop was somehow determined
205+
/// to be always infinite. Runtime loop unrolling should be impossible for that
206+
/// case. What is infinity % UnrollCount? But we might have bad profile data.
207+
/// In that case, we arbitrarily choose to keep the probability at 1 throughout
208+
/// the remainder loop.
203209
static BranchProbability
204210
probOfNextInRemainder(BranchProbability OriginalLoopProb, unsigned N) {
211+
if (OriginalLoopProb == BranchProbability::getOne())
212+
return BranchProbability::getOne();
213+
205214
// Each of these variables holds the original loop's probability that the
206215
// number of iterations it will execute is some m in the specified range.
207216
BranchProbability ProbOne = OriginalLoopProb; // 1 <= m
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
; Check that a loop probability of one (indicating an always infinite loop) does
2+
; not crash or otherwise break LoopUnroll behavior when it tries to compute new
3+
; probabilities from it.
4+
;
5+
; Runtime loop unrolling should be impossible for that case. What is infinity %
6+
; UnrollCount? But we can have bad profile data. In that case, the
7+
; implementation arbitrarily chooses to keep the probability at 1 throughout the
8+
; remainder loop.
9+
10+
; DEFINE: %{unroll} = opt < %s -unroll-count=3 -passes=loop-unroll -S
11+
; DEFINE: %{rt} = %{unroll} -unroll-runtime
12+
13+
; RUN: %{unroll} | FileCheck %s -check-prefix UNROLL
14+
; RUN: %{rt} -unroll-runtime-epilog=true | FileCheck %s -check-prefix EPILOG
15+
; RUN: %{rt} -unroll-runtime-epilog=false | FileCheck %s -check-prefix PROLOG
16+
17+
define void @test(i32 %n) {
18+
entry:
19+
br label %loop
20+
21+
loop:
22+
%i = phi i32 [ 0, %entry ], [ %inc, %loop ]
23+
%inc = add i32 %i, 1
24+
%c = icmp slt i32 %inc, %n
25+
br i1 %c, label %loop, label %end, !prof !0
26+
27+
end:
28+
ret void
29+
}
30+
31+
32+
!0 = !{!"branch_weights", i32 1, i32 0}
33+
34+
; UNROLL: define void @test(i32 %n) {
35+
; UNROLL: entry:
36+
; UNROLL: br label %loop
37+
; UNROLL: loop:
38+
; UNROLL: br i1 %c, label %loop.1, label %end, !prof !0
39+
; UNROLL: loop.1:
40+
; UNROLL: br i1 %c.1, label %loop.2, label %end, !prof !0
41+
; UNROLL: loop.2:
42+
; UNROLL: br i1 %c.2, label %loop, label %end, !prof !0, !llvm.loop !1
43+
; UNROLL-NOT: loop.3
44+
; UNROLL: end:
45+
; UNROLL: ret void
46+
; UNROLL: }
47+
;
48+
; Infinite unrolled loop.
49+
; UNROLL: !0 = !{!"branch_weights", i32 1, i32 0}
50+
51+
; EPILOG: define void @test(i32 %n) {
52+
; EPILOG: entry:
53+
; EPILOG: br i1 %{{.*}}, label %loop.epil.preheader, label %entry.new, !prof !0
54+
; EPILOG: entry.new:
55+
; EPILOG: br label %loop
56+
; EPILOG: loop:
57+
; EPILOG: br i1 %{{.*}}, label %loop, label %end.unr-lcssa, !prof !1
58+
; EPILOG: end.unr-lcssa:
59+
; EPILOG: br i1 %{{.*}}, label %loop.epil.preheader, label %end, !prof !1
60+
; EPILOG: loop.epil.preheader:
61+
; EPILOG: br label %loop.epil
62+
; EPILOG: loop.epil:
63+
; EPILOG: br i1 %{{.*}}, label %loop.epil, label %end.epilog-lcssa, !prof !4
64+
; EPILOG: end.epilog-lcssa:
65+
; EPILOG: br label %end
66+
; EPILOG: end:
67+
; EPILOG: ret void
68+
; EPILOG: }
69+
;
70+
; Unrolled loop guard: Unrolled loop is always entered.
71+
; EPILOG: !0 = !{!"branch_weights", i32 0, i32 -2147483648}
72+
;
73+
; Unrolled loop latch: Unrolled loop is infinite.
74+
; Epilogue loop guard: Epilogue loop is always entered if unrolled loop exits.
75+
; EPILOG: !1 = !{!"branch_weights", i32 -2147483648, i32 0}
76+
;
77+
; Epilogue loop latch: Epilogue loop executes both of its 2 iterations.
78+
; EPILOG: !4 = !{!"branch_weights", i32 1073741824, i32 1073741824}
79+
80+
; PROLOG: define void @test(i32 %n) {
81+
; PROLOG: entry:
82+
; PROLOG: br i1 %{{.*}}, label %loop.prol.preheader, label %loop.prol.loopexit, !prof !0
83+
; PROLOG: loop.prol.preheader:
84+
; PROLOG: br label %loop.prol
85+
; PROLOG: loop.prol:
86+
; PROLOG: br i1 %{{.*}}, label %loop.prol, label %loop.prol.loopexit.unr-lcssa, !prof !1
87+
; PROLOG: loop.prol.loopexit.unr-lcssa:
88+
; PROLOG: br label %loop.prol.loopexit
89+
; PROLOG: loop.prol.loopexit:
90+
; PROLOG: br i1 %{{.*}}, label %end, label %entry.new, !prof !0
91+
; PROLOG: entry.new:
92+
; PROLOG: br label %loop
93+
; PROLOG: loop:
94+
; PROLOG: br i1 %{{.*}}, label %loop, label %end.unr-lcssa, !prof !4
95+
; PROLOG: end.unr-lcssa:
96+
; PROLOG: br label %end
97+
; PROLOG: end:
98+
; PROLOG: ret void
99+
; PROLOG: }
100+
;
101+
; FIXME: Branch weights still need to be fixed in the case of prologues (issue
102+
; #135812), so !0 and !1 do not yet match their comments below. When we do
103+
; fix it, this test will hopefully catch any bug like issue #165998, which
104+
; impacted the case of epilogues.
105+
;
106+
; Prologue loop guard: Prologue loop is always entered.
107+
; Unrolled loop guard: Unrolled loop is always entered.
108+
; PROLOG: !0 = !{!"branch_weights", i32 1, i32 127}
109+
;
110+
; Prologue loop latch: Prologue loop executes both of its 2 iterations.
111+
; PROLOG: !1 = !{!"branch_weights", i32 0, i32 1}
112+
;
113+
; Unrolled loop latch: Unrolled loop is infinite.
114+
; PROLOG: !4 = !{!"branch_weights", i32 1, i32 0}

0 commit comments

Comments
 (0)