Skip to content

Commit 1aa86ca

Browse files
authored
[LoopUnroll] Fix division by zero (#166258)
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 3922171 commit 1aa86ca

File tree

2 files changed

+137
-0
lines changed

2 files changed

+137
-0
lines changed

llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,27 @@ static void ConnectProlog(Loop *L, Value *BECount, unsigned Count,
202202
/// probability of executing at least one more iteration?
203203
static BranchProbability
204204
probOfNextInRemainder(BranchProbability OriginalLoopProb, unsigned N) {
205+
// OriginalLoopProb == 1 would produce a division by zero in the calculation
206+
// below. The problem is that case indicates an always infinite loop, but a
207+
// remainder loop cannot be calculated at run time if the original loop is
208+
// infinite as infinity % UnrollCount is undefined. We then choose
209+
// probabilities indicating that all remainder loop iterations will always
210+
// execute.
211+
//
212+
// Currently, the remainder loop here is an epilogue, which cannot be reached
213+
// if the original loop is infinite, so the aforementioned choice is
214+
// arbitrary.
215+
//
216+
// FIXME: Branch weights still need to be fixed in the case of prologues
217+
// (issue #135812). In that case, the aforementioned choice seems reasonable
218+
// for the goal of maintaining the original loop's block frequencies. That
219+
// is, an infinite loop's initial iterations are not skipped, and the prologue
220+
// loop body might have unique blocks that execute a finite number of times
221+
// if, for example, the original loop body contains conditionals like i <
222+
// UnrollCount.
223+
if (OriginalLoopProb == BranchProbability::getOne())
224+
return BranchProbability::getOne();
225+
205226
// Each of these variables holds the original loop's probability that the
206227
// number of iterations it will execute is some m in the specified range.
207228
BranchProbability ProbOne = OriginalLoopProb; // 1 <= m
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
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+
; That case indicates an always infinite loop. A remainder loop cannot be
6+
; calculated at run time when the original loop is infinite as infinity %
7+
; UnrollCount is undefined, so consistent remainder loop probabilities are
8+
; difficult or impossible to reason about. The implementation chooses
9+
; probabilities indicating that all remainder loop iterations will always
10+
; execute.
11+
12+
; DEFINE: %{unroll} = opt < %s -unroll-count=3 -passes=loop-unroll -S
13+
; DEFINE: %{rt} = %{unroll} -unroll-runtime
14+
15+
; RUN: %{unroll} | FileCheck %s -check-prefix UNROLL
16+
; RUN: %{rt} -unroll-runtime-epilog=true | FileCheck %s -check-prefix EPILOG
17+
; RUN: %{rt} -unroll-runtime-epilog=false | FileCheck %s -check-prefix PROLOG
18+
19+
define void @test(i32 %n) {
20+
entry:
21+
br label %loop
22+
23+
loop:
24+
%i = phi i32 [ 0, %entry ], [ %inc, %loop ]
25+
%inc = add i32 %i, 1
26+
%c = icmp slt i32 %inc, %n
27+
br i1 %c, label %loop, label %end, !prof !0
28+
29+
end:
30+
ret void
31+
}
32+
33+
34+
!0 = !{!"branch_weights", i32 1, i32 0}
35+
36+
; UNROLL: define void @test(i32 %n) {
37+
; UNROLL: entry:
38+
; UNROLL: br label %loop
39+
; UNROLL: loop:
40+
; UNROLL: br i1 %c, label %loop.1, label %end, !prof !0
41+
; UNROLL: loop.1:
42+
; UNROLL: br i1 %c.1, label %loop.2, label %end, !prof !0
43+
; UNROLL: loop.2:
44+
; UNROLL: br i1 %c.2, label %loop, label %end, !prof !0, !llvm.loop !1
45+
; UNROLL-NOT: loop.3
46+
; UNROLL: end:
47+
; UNROLL: ret void
48+
; UNROLL: }
49+
;
50+
; Infinite unrolled loop.
51+
; UNROLL: !0 = !{!"branch_weights", i32 1, i32 0}
52+
53+
; EPILOG: define void @test(i32 %n) {
54+
; EPILOG: entry:
55+
; EPILOG: br i1 %{{.*}}, label %loop.epil.preheader, label %entry.new, !prof !0
56+
; EPILOG: entry.new:
57+
; EPILOG: br label %loop
58+
; EPILOG: loop:
59+
; EPILOG: br i1 %{{.*}}, label %loop, label %end.unr-lcssa, !prof !1
60+
; EPILOG: end.unr-lcssa:
61+
; EPILOG: br i1 %{{.*}}, label %loop.epil.preheader, label %end, !prof !1
62+
; EPILOG: loop.epil.preheader:
63+
; EPILOG: br label %loop.epil
64+
; EPILOG: loop.epil:
65+
; EPILOG: br i1 %{{.*}}, label %loop.epil, label %end.epilog-lcssa, !prof !4
66+
; EPILOG: end.epilog-lcssa:
67+
; EPILOG: br label %end
68+
; EPILOG: end:
69+
; EPILOG: ret void
70+
; EPILOG: }
71+
;
72+
; Unrolled loop guard: Unrolled loop is always entered.
73+
; EPILOG: !0 = !{!"branch_weights", i32 0, i32 -2147483648}
74+
;
75+
; Unrolled loop latch: Unrolled loop is infinite.
76+
; Epilogue loop guard: Epilogue loop is always entered if unrolled loop exits.
77+
; EPILOG: !1 = !{!"branch_weights", i32 -2147483648, i32 0}
78+
;
79+
; Epilogue loop latch: Epilogue loop executes both of its 2 iterations.
80+
; EPILOG: !4 = !{!"branch_weights", i32 1073741824, i32 1073741824}
81+
82+
; PROLOG: define void @test(i32 %n) {
83+
; PROLOG: entry:
84+
; PROLOG: br i1 %{{.*}}, label %loop.prol.preheader, label %loop.prol.loopexit, !prof !0
85+
; PROLOG: loop.prol.preheader:
86+
; PROLOG: br label %loop.prol
87+
; PROLOG: loop.prol:
88+
; PROLOG: br i1 %{{.*}}, label %loop.prol, label %loop.prol.loopexit.unr-lcssa, !prof !1
89+
; PROLOG: loop.prol.loopexit.unr-lcssa:
90+
; PROLOG: br label %loop.prol.loopexit
91+
; PROLOG: loop.prol.loopexit:
92+
; PROLOG: br i1 %{{.*}}, label %end, label %entry.new, !prof !0
93+
; PROLOG: entry.new:
94+
; PROLOG: br label %loop
95+
; PROLOG: loop:
96+
; PROLOG: br i1 %{{.*}}, label %loop, label %end.unr-lcssa, !prof !4
97+
; PROLOG: end.unr-lcssa:
98+
; PROLOG: br label %end
99+
; PROLOG: end:
100+
; PROLOG: ret void
101+
; PROLOG: }
102+
;
103+
; FIXME: Branch weights still need to be fixed in the case of prologues (issue
104+
; #135812), so !0 and !1 do not yet match their comments below. When we do
105+
; fix it, this test will hopefully catch any bug like issue #165998, which
106+
; impacted the case of epilogues.
107+
;
108+
; Prologue loop guard: Prologue loop is always entered.
109+
; Unrolled loop guard: Unrolled loop is always entered.
110+
; PROLOG: !0 = !{!"branch_weights", i32 1, i32 127}
111+
;
112+
; Prologue loop latch: Prologue loop executes both of its 2 iterations.
113+
; PROLOG: !1 = !{!"branch_weights", i32 0, i32 1}
114+
;
115+
; Unrolled loop latch: Unrolled loop is infinite.
116+
; PROLOG: !4 = !{!"branch_weights", i32 1, i32 0}

0 commit comments

Comments
 (0)