Skip to content

Commit 99d2582

Browse files
committed
[ScalarEvolution] Handle <= and >= in non infinite loops
Extend scalar evolution to handle >= and <= if a loop is known to be finite and the induction variable guards the condition. Specifically, with these assumptions lhs <= rhs is equivalent to lhs < rhs + 1 and lhs >= rhs to lhs > rhs -1. In the case of lhs <= rhs, this is true since the only case these are not equivalent is when rhs == unsigned/signed intmax, which would have resulted in an infinite loop. In the case of lhs >= rhs, this is true since the only case these are not equivalent is when rhs == unsigned/signed intmin, which would again have resulted in an infinite loop. Reviewed By: lebedev.ri Differential Revision: https://reviews.llvm.org/D118090
1 parent 354ec4a commit 99d2582

File tree

3 files changed

+198
-13
lines changed

3 files changed

+198
-13
lines changed

llvm/include/llvm/Analysis/ScalarEvolution.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,9 +1111,11 @@ class ScalarEvolution {
11111111
/// Simplify LHS and RHS in a comparison with predicate Pred. Return true
11121112
/// iff any changes were made. If the operands are provably equal or
11131113
/// unequal, LHS and RHS are set to the same value and Pred is set to either
1114-
/// ICMP_EQ or ICMP_NE.
1114+
/// ICMP_EQ or ICMP_NE. ControllingFiniteLoop is set if this comparison
1115+
/// controls the exit of a loop known to have a finite number of iterations.
11151116
bool SimplifyICmpOperands(ICmpInst::Predicate &Pred, const SCEV *&LHS,
1116-
const SCEV *&RHS, unsigned Depth = 0);
1117+
const SCEV *&RHS, unsigned Depth = 0,
1118+
bool ControllingFiniteLoop = false);
11171119

11181120
/// Return the "disposition" of the given SCEV with respect to the given
11191121
/// loop.

llvm/lib/Analysis/ScalarEvolution.cpp

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8466,8 +8466,11 @@ ScalarEvolution::computeExitLimitFromICmp(const Loop *L,
84668466
Pred = ICmpInst::getSwappedPredicate(Pred);
84678467
}
84688468

8469+
bool ControllingFiniteLoop =
8470+
ControlsExit && loopHasNoAbnormalExits(L) && loopIsFiniteByAssumption(L);
84698471
// Simplify the operands before analyzing them.
8470-
(void)SimplifyICmpOperands(Pred, LHS, RHS);
8472+
(void)SimplifyICmpOperands(Pred, LHS, RHS, /*Depth=*/0,
8473+
ControllingFiniteLoop);
84718474

84728475
// If we have a comparison of a chrec against a constant, try to use value
84738476
// ranges to answer this query.
@@ -8487,9 +8490,7 @@ ScalarEvolution::computeExitLimitFromICmp(const Loop *L,
84878490
// the same values on self-wrap of the IV, then we can infer that IV
84888491
// doesn't self wrap because if it did, we'd have an infinite (undefined)
84898492
// loop.
8490-
if (ControlsExit && isLoopInvariant(RHS, L) && loopHasNoAbnormalExits(L) &&
8491-
loopIsFiniteByAssumption(L)) {
8492-
8493+
if (ControllingFiniteLoop && isLoopInvariant(RHS, L)) {
84938494
// TODO: We can peel off any functions which are invertible *in L*. Loop
84948495
// invariant terms are effectively constants for our purposes here.
84958496
auto *InnerLHS = LHS;
@@ -9940,7 +9941,8 @@ static bool HasSameValue(const SCEV *A, const SCEV *B) {
99409941

99419942
bool ScalarEvolution::SimplifyICmpOperands(ICmpInst::Predicate &Pred,
99429943
const SCEV *&LHS, const SCEV *&RHS,
9943-
unsigned Depth) {
9944+
unsigned Depth,
9945+
bool ControllingFiniteLoop) {
99449946
bool Changed = false;
99459947
// Simplifies ICMP to trivial true or false by turning it into '0 == 0' or
99469948
// '0 != 0'.
@@ -10069,10 +10071,15 @@ bool ScalarEvolution::SimplifyICmpOperands(ICmpInst::Predicate &Pred,
1006910071
}
1007010072

1007110073
// If possible, canonicalize GE/LE comparisons to GT/LT comparisons, by
10072-
// adding or subtracting 1 from one of the operands.
10074+
// adding or subtracting 1 from one of the operands. This can be done for
10075+
// one of two reasons:
10076+
// 1) The range of the RHS does not include the (signed/unsigned) boundaries
10077+
// 2) The loop is finite, with this comparison controlling the exit. Since the
10078+
// loop is finite, the bound cannot include the corresponding boundary
10079+
// (otherwise it would loop forever).
1007310080
switch (Pred) {
1007410081
case ICmpInst::ICMP_SLE:
10075-
if (!getSignedRangeMax(RHS).isMaxSignedValue()) {
10082+
if (ControllingFiniteLoop || !getSignedRangeMax(RHS).isMaxSignedValue()) {
1007610083
RHS = getAddExpr(getConstant(RHS->getType(), 1, true), RHS,
1007710084
SCEV::FlagNSW);
1007810085
Pred = ICmpInst::ICMP_SLT;
@@ -10085,7 +10092,7 @@ bool ScalarEvolution::SimplifyICmpOperands(ICmpInst::Predicate &Pred,
1008510092
}
1008610093
break;
1008710094
case ICmpInst::ICMP_SGE:
10088-
if (!getSignedRangeMin(RHS).isMinSignedValue()) {
10095+
if (ControllingFiniteLoop || !getSignedRangeMin(RHS).isMinSignedValue()) {
1008910096
RHS = getAddExpr(getConstant(RHS->getType(), (uint64_t)-1, true), RHS,
1009010097
SCEV::FlagNSW);
1009110098
Pred = ICmpInst::ICMP_SGT;
@@ -10098,7 +10105,7 @@ bool ScalarEvolution::SimplifyICmpOperands(ICmpInst::Predicate &Pred,
1009810105
}
1009910106
break;
1010010107
case ICmpInst::ICMP_ULE:
10101-
if (!getUnsignedRangeMax(RHS).isMaxValue()) {
10108+
if (ControllingFiniteLoop || !getUnsignedRangeMax(RHS).isMaxValue()) {
1010210109
RHS = getAddExpr(getConstant(RHS->getType(), 1, true), RHS,
1010310110
SCEV::FlagNUW);
1010410111
Pred = ICmpInst::ICMP_ULT;
@@ -10110,7 +10117,7 @@ bool ScalarEvolution::SimplifyICmpOperands(ICmpInst::Predicate &Pred,
1011010117
}
1011110118
break;
1011210119
case ICmpInst::ICMP_UGE:
10113-
if (!getUnsignedRangeMin(RHS).isMinValue()) {
10120+
if (ControllingFiniteLoop || !getUnsignedRangeMin(RHS).isMinValue()) {
1011410121
RHS = getAddExpr(getConstant(RHS->getType(), (uint64_t)-1, true), RHS);
1011510122
Pred = ICmpInst::ICMP_UGT;
1011610123
Changed = true;
@@ -10130,7 +10137,8 @@ bool ScalarEvolution::SimplifyICmpOperands(ICmpInst::Predicate &Pred,
1013010137
// Recursively simplify until we either hit a recursion limit or nothing
1013110138
// changes.
1013210139
if (Changed)
10133-
return SimplifyICmpOperands(Pred, LHS, RHS, Depth+1);
10140+
return SimplifyICmpOperands(Pred, LHS, RHS, Depth + 1,
10141+
ControllingFiniteLoop);
1013410142

1013510143
return Changed;
1013610144
}
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py
2+
; RUN: opt < %s -disable-output "-passes=print<scalar-evolution>" -scalar-evolution-max-iterations=0 -scalar-evolution-classify-expressions=0 2>&1 | FileCheck %s
3+
4+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
5+
target triple = "x86_64-unknown-linux-gnu"
6+
7+
declare void @non_exit_use(i32 %i) #0
8+
9+
define void @SLE(i32 %len) willreturn {
10+
; CHECK-LABEL: 'SLE'
11+
; CHECK-NEXT: Determining loop execution counts for: @SLE
12+
; CHECK-NEXT: Loop %for.body: backedge-taken count is (0 smax (1 + %len)<nsw>)
13+
; CHECK-NEXT: Loop %for.body: max backedge-taken count is 2147483647
14+
; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (0 smax (1 + %len)<nsw>)
15+
; CHECK-NEXT: Predicates:
16+
;
17+
entry:
18+
br label %for.body
19+
20+
for.body:
21+
%iv = phi i32 [ %inc, %for.body ], [ 0, %entry ]
22+
call void @non_exit_use(i32 %iv) nounwind willreturn
23+
%inc = add i32 %iv, 1
24+
%cmp = icmp sle i32 %iv, %len
25+
br i1 %cmp, label %for.body, label %for.end
26+
27+
for.end:
28+
ret void
29+
}
30+
31+
define void @SLE_infinite(i32 %len) {
32+
; CHECK-LABEL: 'SLE_infinite'
33+
; CHECK-NEXT: Determining loop execution counts for: @SLE_infinite
34+
; CHECK-NEXT: Loop %for.body: Unpredictable backedge-taken count.
35+
; CHECK-NEXT: Loop %for.body: Unpredictable max backedge-taken count.
36+
;
37+
entry:
38+
br label %for.body
39+
40+
for.body:
41+
%iv = phi i32 [ %inc, %for.body ], [ 0, %entry ]
42+
call void @non_exit_use(i32 %iv) nounwind willreturn
43+
%inc = add i32 %iv, 1
44+
%cmp = icmp sle i32 %iv, %len
45+
br i1 %cmp, label %for.body, label %for.end
46+
47+
for.end:
48+
ret void
49+
}
50+
51+
define void @ULE(i32 %len) willreturn {
52+
; CHECK-LABEL: 'ULE'
53+
; CHECK-NEXT: Determining loop execution counts for: @ULE
54+
; CHECK-NEXT: Loop %for.body: backedge-taken count is (1 + %len)<nuw>
55+
; CHECK-NEXT: Loop %for.body: max backedge-taken count is -1
56+
; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (1 + %len)<nuw>
57+
; CHECK-NEXT: Predicates:
58+
;
59+
entry:
60+
br label %for.body
61+
62+
for.body:
63+
%iv = phi i32 [ %inc, %for.body ], [ 0, %entry ]
64+
call void @non_exit_use(i32 %iv) nounwind willreturn
65+
%inc = add i32 %iv, 1
66+
%cmp = icmp ule i32 %iv, %len
67+
br i1 %cmp, label %for.body, label %for.end
68+
69+
for.end:
70+
ret void
71+
}
72+
73+
define void @ULE_infinite(i32 %len) {
74+
; CHECK-LABEL: 'ULE_infinite'
75+
; CHECK-NEXT: Determining loop execution counts for: @ULE_infinite
76+
; CHECK-NEXT: Loop %for.body: Unpredictable backedge-taken count.
77+
; CHECK-NEXT: Loop %for.body: Unpredictable max backedge-taken count.
78+
;
79+
entry:
80+
br label %for.body
81+
82+
for.body:
83+
%iv = phi i32 [ %inc, %for.body ], [ 0, %entry ]
84+
call void @non_exit_use(i32 %iv) nounwind willreturn
85+
%inc = add i32 %iv, 1
86+
%cmp = icmp ule i32 %iv, %len
87+
br i1 %cmp, label %for.body, label %for.end
88+
89+
for.end:
90+
ret void
91+
}
92+
93+
define void @SGE(i32 %end) willreturn {
94+
; CHECK-LABEL: 'SGE'
95+
; CHECK-NEXT: Determining loop execution counts for: @SGE
96+
; CHECK-NEXT: Loop %for.body: backedge-taken count is (100 + (-1 * (100 smin (-1 + %end)<nsw>)))
97+
; CHECK-NEXT: Loop %for.body: max backedge-taken count is -2147483548
98+
; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (100 + (-1 * (100 smin (-1 + %end)<nsw>)))
99+
; CHECK-NEXT: Predicates:
100+
;
101+
entry:
102+
br label %for.body
103+
104+
for.body:
105+
%iv = phi i32 [ %inc, %for.body ], [ 100, %entry ]
106+
call void @non_exit_use(i32 %iv) nounwind willreturn
107+
%inc = add i32 %iv, -1
108+
%cmp = icmp sge i32 %iv, %end
109+
br i1 %cmp, label %for.body, label %for.end
110+
111+
for.end:
112+
ret void
113+
}
114+
115+
define void @SGE_infinite(i32 %end) {
116+
; CHECK-LABEL: 'SGE_infinite'
117+
; CHECK-NEXT: Determining loop execution counts for: @SGE_infinite
118+
; CHECK-NEXT: Loop %for.body: Unpredictable backedge-taken count.
119+
; CHECK-NEXT: Loop %for.body: Unpredictable max backedge-taken count.
120+
;
121+
entry:
122+
br label %for.body
123+
124+
for.body:
125+
%iv = phi i32 [ %inc, %for.body ], [ 100, %entry ]
126+
call void @non_exit_use(i32 %iv) nounwind willreturn
127+
%inc = add i32 %iv, -1
128+
%cmp = icmp sge i32 %iv, %end
129+
br i1 %cmp, label %for.body, label %for.end
130+
131+
for.end:
132+
ret void
133+
}
134+
135+
define void @UGE(i32 %end) willreturn {
136+
; CHECK-LABEL: 'UGE'
137+
; CHECK-NEXT: Determining loop execution counts for: @UGE
138+
; CHECK-NEXT: Loop %for.body: backedge-taken count is (100 + (-1 * (100 umin (-1 + %end)))<nsw>)<nsw>
139+
; CHECK-NEXT: Loop %for.body: max backedge-taken count is 100
140+
; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (100 + (-1 * (100 umin (-1 + %end)))<nsw>)<nsw>
141+
; CHECK-NEXT: Predicates:
142+
;
143+
entry:
144+
br label %for.body
145+
146+
for.body:
147+
%iv = phi i32 [ %inc, %for.body ], [ 100, %entry ]
148+
call void @non_exit_use(i32 %iv) nounwind willreturn
149+
%inc = add i32 %iv, -1
150+
%cmp = icmp uge i32 %iv, %end
151+
br i1 %cmp, label %for.body, label %for.end
152+
153+
for.end:
154+
ret void
155+
}
156+
157+
define void @UGE_infinite(i32 %end) {
158+
; CHECK-LABEL: 'UGE_infinite'
159+
; CHECK-NEXT: Determining loop execution counts for: @UGE_infinite
160+
; CHECK-NEXT: Loop %for.body: Unpredictable backedge-taken count.
161+
; CHECK-NEXT: Loop %for.body: Unpredictable max backedge-taken count.
162+
;
163+
entry:
164+
br label %for.body
165+
166+
for.body:
167+
%iv = phi i32 [ %inc, %for.body ], [ 100, %entry ]
168+
call void @non_exit_use(i32 %iv) nounwind willreturn
169+
%inc = add i32 %iv, -1
170+
%cmp = icmp uge i32 %iv, %end
171+
br i1 %cmp, label %for.body, label %for.end
172+
173+
for.end:
174+
ret void
175+
}

0 commit comments

Comments
 (0)