Skip to content

Commit 6cdca90

Browse files
committed
[SCEV] Use no-self-wrap flags infered from exit structure to compute trip count
The basic problem being solved is that we largely give up when encountering a trip count involving an IV which is not an addrec. We will fall back to the brute force constant eval, but that doesn't have the information about the fact that we can't cycle back through the same set of values. There's a high level design question of whether this is the right place to handle this, and if not, where that place is. The major alternative here would be to return a conservative upper bound, and then rely on two invocations of indvars to add the facts to the narrow IV, and then reconstruct SCEV. (I have not implemented the alternative and am not 100% sure this would work out.) That's arguably more in line with existing code, but I find this substantially easier to reason about. During review, no one expressed a strong opinion, so we went with this one. Differential Revision: D108651
1 parent 6b53817 commit 6cdca90

File tree

2 files changed

+59
-28
lines changed

2 files changed

+59
-28
lines changed

llvm/lib/Analysis/ScalarEvolution.cpp

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11581,6 +11581,62 @@ ScalarEvolution::howManyLessThans(const SCEV *LHS, const SCEV *RHS,
1158111581
const SCEVAddRecExpr *IV = dyn_cast<SCEVAddRecExpr>(LHS);
1158211582
bool PredicatedIV = false;
1158311583

11584+
auto canAssumeNoSelfWrap = [&](const SCEVAddRecExpr *AR) {
11585+
// Can we prove this loop *must* be UB if overflow of IV occurs?
11586+
// Reasoning goes as follows:
11587+
// * Suppose the IV did self wrap.
11588+
// * If Stride evenly divides the iteration space, then once wrap
11589+
// occurs, the loop must revisit the same values.
11590+
// * We know that RHS is invariant, and that none of those values
11591+
// caused this exit to be taken previously. Thus, this exit is
11592+
// dynamically dead.
11593+
// * If this is the sole exit, then a dead exit implies the loop
11594+
// must be infinite if there are no abnormal exits.
11595+
// * If the loop were infinite, then it must either not be mustprogress
11596+
// or have side effects. Otherwise, it must be UB.
11597+
// * It can't (by assumption), be UB so we have contradicted our
11598+
// premise and can conclude the IV did not in fact self-wrap.
11599+
if (!isLoopInvariant(RHS, L))
11600+
return false;
11601+
11602+
auto *StrideC = dyn_cast<SCEVConstant>(AR->getStepRecurrence(*this));
11603+
if (!StrideC || !StrideC->getAPInt().isPowerOf2())
11604+
return false;
11605+
11606+
if (!ControlsExit || !loopHasNoAbnormalExits(L))
11607+
return false;
11608+
11609+
return loopIsFiniteByAssumption(L);
11610+
};
11611+
11612+
if (!IV) {
11613+
if (auto *ZExt = dyn_cast<SCEVZeroExtendExpr>(LHS)) {
11614+
const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(ZExt->getOperand());
11615+
if (AR && AR->getLoop() == L && AR->isAffine()) {
11616+
auto Flags = AR->getNoWrapFlags();
11617+
if (!hasFlags(Flags, SCEV::FlagNW) && canAssumeNoSelfWrap(AR)) {
11618+
Flags = setFlags(Flags, SCEV::FlagNW);
11619+
11620+
SmallVector<const SCEV*> Operands{AR->operands()};
11621+
Flags = StrengthenNoWrapFlags(this, scAddRecExpr, Operands, Flags);
11622+
11623+
setNoWrapFlags(const_cast<SCEVAddRecExpr *>(AR), Flags);
11624+
}
11625+
if (AR->hasNoUnsignedWrap()) {
11626+
// Emulate what getZeroExtendExpr would have done during construction
11627+
// if we'd been able to infer the fact just above at that time.
11628+
const SCEV *Step = AR->getStepRecurrence(*this);
11629+
Type *Ty = ZExt->getType();
11630+
auto *S = getAddRecExpr(
11631+
getExtendAddRecStart<SCEVZeroExtendExpr>(AR, Ty, this, 0),
11632+
getZeroExtendExpr(Step, Ty, 0), L, AR->getNoWrapFlags());
11633+
IV = dyn_cast<SCEVAddRecExpr>(S);
11634+
}
11635+
}
11636+
}
11637+
}
11638+
11639+
1158411640
if (!IV && AllowPredicates) {
1158511641
// Try to make this an AddRec using runtime tests, in the first X
1158611642
// iterations of this loop, where X is the SCEV expression found by the
@@ -11694,37 +11750,12 @@ ScalarEvolution::howManyLessThans(const SCEV *LHS, const SCEV *RHS,
1169411750
}
1169511751
} else if (!Stride->isOne() && !NoWrap) {
1169611752
auto isUBOnWrap = [&]() {
11697-
// Can we prove this loop *must* be UB if overflow of IV occurs?
11698-
// Reasoning goes as follows:
11699-
// * Suppose the IV did self wrap.
11700-
// * If Stride evenly divides the iteration space, then once wrap
11701-
// occurs, the loop must revisit the same values.
11702-
// * We know that RHS is invariant, and that none of those values
11703-
// caused this exit to be taken previously. Thus, this exit is
11704-
// dynamically dead.
11705-
// * If this is the sole exit, then a dead exit implies the loop
11706-
// must be infinite if there are no abnormal exits.
11707-
// * If the loop were infinite, then it must either not be mustprogress
11708-
// or have side effects. Otherwise, it must be UB.
11709-
// * It can't (by assumption), be UB so we have contradicted our
11710-
// premise and can conclude the IV did not in fact self-wrap.
1171111753
// From no-self-wrap, we need to then prove no-(un)signed-wrap. This
1171211754
// follows trivially from the fact that every (un)signed-wrapped, but
1171311755
// not self-wrapped value must be LT than the last value before
1171411756
// (un)signed wrap. Since we know that last value didn't exit, nor
1171511757
// will any smaller one.
11716-
11717-
if (!isLoopInvariant(RHS, L))
11718-
return false;
11719-
11720-
auto *StrideC = dyn_cast<SCEVConstant>(Stride);
11721-
if (!StrideC || !StrideC->getAPInt().isPowerOf2())
11722-
return false;
11723-
11724-
if (!ControlsExit || !loopHasNoAbnormalExits(L))
11725-
return false;
11726-
11727-
return loopIsFiniteByAssumption(L);
11758+
return canAssumeNoSelfWrap(IV);
1172811759
};
1172911760

1173011761
// Avoid proven overflow cases: this will ensure that the backedge taken

llvm/test/Analysis/ScalarEvolution/trip-count-implied-addrec.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
@G = external global i8
1010

1111
; CHECK-LABEL: Determining loop execution counts for: @nw_implies_nuw
12-
; CHECK: Loop %for.body: Unpredictable backedge-taken count
13-
; CHECK: Loop %for.body: Unpredictable max backedge-taken count
12+
; CHECK: Loop %for.body: backedge-taken count is %n
13+
; CHECK: Loop %for.body: max backedge-taken count is -1
1414
define void @nw_implies_nuw(i16 %n) mustprogress {
1515
entry:
1616
br label %for.body

0 commit comments

Comments
 (0)