From: Philip Reames Date: Tue, 13 Jul 2021 20:30:44 +0000 (-0700) Subject: [SCEV] Handle zero stride correctly in howManyLessThans X-Git-Tag: llvmorg-14-init~1568 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4df591b5c960affd1612e330d0c9cd3076c18053;p=platform%2Fupstream%2Fllvm.git [SCEV] Handle zero stride correctly in howManyLessThans This is split from D105216, but the code is hoisted much earlier into the path where we can actually get a zero stride flowing through. Some fairly simple proofs handle the cases which show up in practice. The only test changes are the cases where we really do need a non-zero divider to produce the right result. Differential Revision: https://reviews.llvm.org/D105921 --- diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp index c6a1328..b3eaa66 100644 --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -11653,6 +11653,30 @@ ScalarEvolution::howManyLessThans(const SCEV *LHS, const SCEV *RHS, if (PredicatedIV || !NoWrap || isKnownNonPositive(Stride) || !loopIsFiniteByAssumption(L)) return getCouldNotCompute(); + + // We allow a potentially zero stride, but we need to divide by stride + // below. Since the loop can't be infinite and this check must control + // the sole exit, we can infer the exit must be taken on the first + // iteration (e.g. backedge count = 0) if the stride is zero. Given that, + // we know the numerator in the divides below must be zero, so we can + // pick an arbitrary non-zero value for the denominator (e.g. stride) + // and produce the right result. + // FIXME: Handle the case where Stride is poison? + auto wouldZeroStrideBeUB = [&]() { + // Proof by contradiction. Suppose the stride were zero. If we can + // prove that the backedge *is* taken on the first iteration, then since + // we know this condition controls the sole exit, we must have an + // infinite loop. We can't have a (well defined) infinite loop per + // check just above. + // Note: The (Start - Stride) term is used to get the start' term from + // (start' + stride,+,stride). Remember that we only care about the + // result of this expression when stride == 0 at runtime. + auto *StartIfZero = getMinusSCEV(IV->getStart(), Stride); + return isLoopEntryGuardedByCond(L, Cond, StartIfZero, RHS); + }; + if (!isKnownNonZero(Stride) && !wouldZeroStrideBeUB()) { + Stride = getUMaxExpr(Stride, getOne(Stride->getType())); + } } else if (!Stride->isOne() && !NoWrap) { auto isUBOnWrap = [&]() { // Can we prove this loop *must* be UB if overflow of IV occurs? diff --git a/llvm/test/Analysis/ScalarEvolution/trip-count-unknown-stride.ll b/llvm/test/Analysis/ScalarEvolution/trip-count-unknown-stride.ll index 97399d7..1af81a3 100644 --- a/llvm/test/Analysis/ScalarEvolution/trip-count-unknown-stride.ll +++ b/llvm/test/Analysis/ScalarEvolution/trip-count-unknown-stride.ll @@ -34,8 +34,8 @@ for.end: ; preds = %for.body, %entry ; Check that we are able to compute trip count of a loop without an entry guard. -; CHECK-LABEL: Determining loop execution counts for: @foo2 -; CHECK: backedge-taken count is ((-1 + (%n smax %s)) /u %s) +; CHECK: Determining loop execution counts for: @foo2 +; CHECK: backedge-taken count is ((-1 + (-1 * %s) + (1 umax %s) + (%n smax %s)) /u (1 umax %s)) ; We should have a conservative estimate for the max backedge taken count for ; loops with unknown stride. @@ -84,8 +84,8 @@ for.end: ; preds = %for.body, %entry } ; Same as foo2, but with mustprogress on loop, not function -; CHECK-LABEL: Determining loop execution counts for: @foo4 -; CHECK: backedge-taken count is ((-1 + (%n smax %s)) /u %s) +; CHECK: Determining loop execution counts for: @foo4 +; CHECK: backedge-taken count is ((-1 + (-1 * %s) + (1 umax %s) + (%n smax %s)) /u (1 umax %s)) ; CHECK: max backedge-taken count is -1 define void @foo4(i32* nocapture %A, i32 %n, i32 %s) { @@ -108,7 +108,7 @@ for.end: ; preds = %for.body, %entry ; A more complex case with pre-increment compare instead of post-increment. ; CHECK-LABEL: Determining loop execution counts for: @foo5 -; CHECK: Loop %for.body: backedge-taken count is ((-1 + (-1 * %start) + (%n smax %start) + %s) /u %s) +; CHECK: Loop %for.body: backedge-taken count is ((-1 + (-1 * %start) + (1 umax %s) + (%n smax %start)) /u (1 umax %s)) ; We should have a conservative estimate for the max backedge taken count for ; loops with unknown stride.