Skip to content

Commit

Permalink
[IndVars] Use knowledge about execution on last iteration when removi…
Browse files Browse the repository at this point in the history
…ng checks

If we know that some check will not be executed on the last iteration, we can use this
fact to eliminate its check.

Differential Revision: https://reviews.llvm.org/D88210
Reviwed By: ebrevnov
  • Loading branch information
xortator committed Nov 3, 2020
1 parent b969dfe commit f847094
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 6 deletions.
38 changes: 35 additions & 3 deletions llvm/lib/Transforms/Scalar/IndVarSimplify.cpp
Expand Up @@ -2418,25 +2418,57 @@ bool IndVarSimplify::optimizeLoopExits(Loop *L, SCEVExpander &Rewriter) {
};

bool Changed = false;
bool SkipLastIter = false;
SmallSet<const SCEV*, 8> DominatingExitCounts;
for (BasicBlock *ExitingBB : ExitingBlocks) {
const SCEV *ExitCount = SE->getExitCount(L, ExitingBB);
if (isa<SCEVCouldNotCompute>(ExitCount)) {
// Okay, we do not know the exit count here. Can we at least prove that it
// will remain the same within iteration space?
auto *BI = cast<BranchInst>(ExitingBB->getTerminator());
auto OptimizeCond = [&](bool Inverted) {
if (isTrivialCond(L, BI, SE, Inverted, MaxExitCount)) {
auto OptimizeCond = [this, L, BI, ExitingBB, MaxExitCount, &FoldExit](
bool Inverted, bool SkipLastIter) {
const SCEV *MaxIter = MaxExitCount;
if (SkipLastIter) {
const SCEV *One = SE->getOne(MaxIter->getType());
MaxIter = SE->getMinusSCEV(MaxIter, One);
}
if (isTrivialCond(L, BI, SE, Inverted, MaxIter)) {
FoldExit(ExitingBB, Inverted);
return true;
}
return false;
};
if (OptimizeCond(false) || OptimizeCond(true))

// TODO: We might have proved that we can skip the last iteration for
// this check. In this case, we only want to check the condition on the
// pre-last iteration (MaxExitCount - 1). However, there is a nasty
// corner case:
//
// for (i = len; i != 0; i--) { ... check (i ult X) ... }
//
// If we could not prove that len != 0, then we also could not prove that
// (len - 1) is not a UINT_MAX. If we simply query (len - 1), then
// OptimizeCond will likely not prove anything for it, even if it could
// prove the same fact for len.
//
// As a temporary solution, we query both last and pre-last iterations in
// hope that we will be able to prove triviality for at least one of
// them. We can stop querying MaxExitCount for this case once SCEV
// understands that (MaxExitCount - 1) will not overflow here.
if (OptimizeCond(false, false) || OptimizeCond(true, false))
Changed = true;
else if (SkipLastIter)
if (OptimizeCond(false, true) || OptimizeCond(true, true))
Changed = true;
continue;
}

if (MaxExitCount == ExitCount)
// If the loop has more than 1 iteration, all further checks will be
// executed 1 iteration less.
SkipLastIter = true;

// If we know we'd exit on the first iteration, rewrite the exit to
// reflect this. This does not imply the loop must exit through this
// exit; there may be an earlier one taken on the first iteration.
Expand Down
5 changes: 2 additions & 3 deletions llvm/test/Transforms/IndVarSimplify/predicated_ranges.ll
Expand Up @@ -2,7 +2,7 @@
; RUN: opt -indvars -S < %s | FileCheck %s
; RUN: opt -passes=indvars -S < %s | FileCheck %s

; TODO: should be able to remove the range check basing on the following facts:
; Check that we are able to remove the range check basing on the following facts:
; 0 <= len <= MAX_INT [1];
; iv starts from len and goes down stopping at zero and [1], therefore
; 0 <= iv <= len [2];
Expand All @@ -21,8 +21,7 @@ define void @test_predicated_simple_unsigned(i32* %p, i32* %arr) {
; CHECK-NEXT: br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]]
; CHECK: range_check_block:
; CHECK-NEXT: [[IV_NEXT]] = sub i32 [[IV]], 1
; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp ult i32 [[IV_NEXT]], [[LEN]]
; CHECK-NEXT: br i1 [[RANGE_CHECK]], label [[BACKEDGE]], label [[FAIL:%.*]]
; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[FAIL:%.*]]
; CHECK: backedge:
; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, i32* [[P]], i32 [[IV]]
; CHECK-NEXT: [[EL:%.*]] = load i32, i32* [[EL_PTR]], align 4
Expand Down

0 comments on commit f847094

Please sign in to comment.