diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h --- a/llvm/include/llvm/Analysis/ScalarEvolution.h +++ b/llvm/include/llvm/Analysis/ScalarEvolution.h @@ -1111,9 +1111,11 @@ /// Simplify LHS and RHS in a comparison with predicate Pred. Return true /// iff any changes were made. If the operands are provably equal or /// unequal, LHS and RHS are set to the same value and Pred is set to either - /// ICMP_EQ or ICMP_NE. + /// ICMP_EQ or ICMP_NE. ControllingFiniteLoop is set if this comparison + /// controls the exit of a loop known to have a finite number of iterations. bool SimplifyICmpOperands(ICmpInst::Predicate &Pred, const SCEV *&LHS, - const SCEV *&RHS, unsigned Depth = 0); + const SCEV *&RHS, unsigned Depth = 0, + bool ControllingFiniteLoop = false); /// Return the "disposition" of the given SCEV with respect to the given /// loop. diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -8466,8 +8466,11 @@ Pred = ICmpInst::getSwappedPredicate(Pred); } + bool ControllingFiniteLoop = + ControlsExit && loopHasNoAbnormalExits(L) && loopIsFiniteByAssumption(L); // Simplify the operands before analyzing them. - (void)SimplifyICmpOperands(Pred, LHS, RHS); + (void)SimplifyICmpOperands(Pred, LHS, RHS, /*Depth=*/0, + ControllingFiniteLoop); // If we have a comparison of a chrec against a constant, try to use value // ranges to answer this query. @@ -8487,9 +8490,7 @@ // the same values on self-wrap of the IV, then we can infer that IV // doesn't self wrap because if it did, we'd have an infinite (undefined) // loop. - if (ControlsExit && isLoopInvariant(RHS, L) && loopHasNoAbnormalExits(L) && - loopIsFiniteByAssumption(L)) { - + if (ControllingFiniteLoop && isLoopInvariant(RHS, L)) { // TODO: We can peel off any functions which are invertible *in L*. Loop // invariant terms are effectively constants for our purposes here. auto *InnerLHS = LHS; @@ -9940,7 +9941,8 @@ bool ScalarEvolution::SimplifyICmpOperands(ICmpInst::Predicate &Pred, const SCEV *&LHS, const SCEV *&RHS, - unsigned Depth) { + unsigned Depth, + bool ControllingFiniteLoop) { bool Changed = false; // Simplifies ICMP to trivial true or false by turning it into '0 == 0' or // '0 != 0'. @@ -10069,10 +10071,15 @@ } // If possible, canonicalize GE/LE comparisons to GT/LT comparisons, by - // adding or subtracting 1 from one of the operands. + // adding or subtracting 1 from one of the operands. This can be done for + // one of two reasons: + // 1) The range of the RHS does not include the (signed/unsigned) boundaries + // 2) The loop is finite, with this comparison controlling the exit. Since the + // loop is finite, the bound cannot include the corresponding boundary + // (otherwise it would loop forever). switch (Pred) { case ICmpInst::ICMP_SLE: - if (!getSignedRangeMax(RHS).isMaxSignedValue()) { + if (ControllingFiniteLoop || !getSignedRangeMax(RHS).isMaxSignedValue()) { RHS = getAddExpr(getConstant(RHS->getType(), 1, true), RHS, SCEV::FlagNSW); Pred = ICmpInst::ICMP_SLT; @@ -10085,7 +10092,7 @@ } break; case ICmpInst::ICMP_SGE: - if (!getSignedRangeMin(RHS).isMinSignedValue()) { + if (ControllingFiniteLoop || !getSignedRangeMin(RHS).isMinSignedValue()) { RHS = getAddExpr(getConstant(RHS->getType(), (uint64_t)-1, true), RHS, SCEV::FlagNSW); Pred = ICmpInst::ICMP_SGT; @@ -10098,7 +10105,7 @@ } break; case ICmpInst::ICMP_ULE: - if (!getUnsignedRangeMax(RHS).isMaxValue()) { + if (ControllingFiniteLoop || !getUnsignedRangeMax(RHS).isMaxValue()) { RHS = getAddExpr(getConstant(RHS->getType(), 1, true), RHS, SCEV::FlagNUW); Pred = ICmpInst::ICMP_ULT; @@ -10110,7 +10117,7 @@ } break; case ICmpInst::ICMP_UGE: - if (!getUnsignedRangeMin(RHS).isMinValue()) { + if (ControllingFiniteLoop || !getUnsignedRangeMin(RHS).isMinValue()) { RHS = getAddExpr(getConstant(RHS->getType(), (uint64_t)-1, true), RHS); Pred = ICmpInst::ICMP_UGT; Changed = true; @@ -10130,7 +10137,8 @@ // Recursively simplify until we either hit a recursion limit or nothing // changes. if (Changed) - return SimplifyICmpOperands(Pred, LHS, RHS, Depth+1); + return SimplifyICmpOperands(Pred, LHS, RHS, Depth + 1, + ControllingFiniteLoop); return Changed; } diff --git a/llvm/test/Analysis/ScalarEvolution/finite-trip-count.ll b/llvm/test/Analysis/ScalarEvolution/finite-trip-count.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Analysis/ScalarEvolution/finite-trip-count.ll @@ -0,0 +1,175 @@ +; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py +; RUN: opt < %s -disable-output "-passes=print" -scalar-evolution-max-iterations=0 -scalar-evolution-classify-expressions=0 2>&1 | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @non_exit_use(i32 %i) #0 + +define void @SLE(i32 %len) willreturn { +; CHECK-LABEL: 'SLE' +; CHECK-NEXT: Determining loop execution counts for: @SLE +; CHECK-NEXT: Loop %for.body: backedge-taken count is (0 smax (1 + %len)) +; CHECK-NEXT: Loop %for.body: max backedge-taken count is 2147483647 +; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (0 smax (1 + %len)) +; CHECK-NEXT: Predicates: +; +entry: + br label %for.body + +for.body: + %iv = phi i32 [ %inc, %for.body ], [ 0, %entry ] + call void @non_exit_use(i32 %iv) nounwind willreturn + %inc = add i32 %iv, 1 + %cmp = icmp sle i32 %iv, %len + br i1 %cmp, label %for.body, label %for.end + +for.end: + ret void +} + +define void @SLE_infinite(i32 %len) { +; CHECK-LABEL: 'SLE_infinite' +; CHECK-NEXT: Determining loop execution counts for: @SLE_infinite +; CHECK-NEXT: Loop %for.body: Unpredictable backedge-taken count. +; CHECK-NEXT: Loop %for.body: Unpredictable max backedge-taken count. +; +entry: + br label %for.body + +for.body: + %iv = phi i32 [ %inc, %for.body ], [ 0, %entry ] + call void @non_exit_use(i32 %iv) nounwind willreturn + %inc = add i32 %iv, 1 + %cmp = icmp sle i32 %iv, %len + br i1 %cmp, label %for.body, label %for.end + +for.end: + ret void +} + +define void @ULE(i32 %len) willreturn { +; CHECK-LABEL: 'ULE' +; CHECK-NEXT: Determining loop execution counts for: @ULE +; CHECK-NEXT: Loop %for.body: backedge-taken count is (1 + %len) +; CHECK-NEXT: Loop %for.body: max backedge-taken count is -1 +; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (1 + %len) +; CHECK-NEXT: Predicates: +; +entry: + br label %for.body + +for.body: + %iv = phi i32 [ %inc, %for.body ], [ 0, %entry ] + call void @non_exit_use(i32 %iv) nounwind willreturn + %inc = add i32 %iv, 1 + %cmp = icmp ule i32 %iv, %len + br i1 %cmp, label %for.body, label %for.end + +for.end: + ret void +} + +define void @ULE_infinite(i32 %len) { +; CHECK-LABEL: 'ULE_infinite' +; CHECK-NEXT: Determining loop execution counts for: @ULE_infinite +; CHECK-NEXT: Loop %for.body: Unpredictable backedge-taken count. +; CHECK-NEXT: Loop %for.body: Unpredictable max backedge-taken count. +; +entry: + br label %for.body + +for.body: + %iv = phi i32 [ %inc, %for.body ], [ 0, %entry ] + call void @non_exit_use(i32 %iv) nounwind willreturn + %inc = add i32 %iv, 1 + %cmp = icmp ule i32 %iv, %len + br i1 %cmp, label %for.body, label %for.end + +for.end: + ret void +} + +define void @SGE(i32 %end) willreturn { +; CHECK-LABEL: 'SGE' +; CHECK-NEXT: Determining loop execution counts for: @SGE +; CHECK-NEXT: Loop %for.body: backedge-taken count is (100 + (-1 * (100 smin (-1 + %end)))) +; CHECK-NEXT: Loop %for.body: max backedge-taken count is -2147483548 +; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (100 + (-1 * (100 smin (-1 + %end)))) +; CHECK-NEXT: Predicates: +; +entry: + br label %for.body + +for.body: + %iv = phi i32 [ %inc, %for.body ], [ 100, %entry ] + call void @non_exit_use(i32 %iv) nounwind willreturn + %inc = add i32 %iv, -1 + %cmp = icmp sge i32 %iv, %end + br i1 %cmp, label %for.body, label %for.end + +for.end: + ret void +} + +define void @SGE_infinite(i32 %end) { +; CHECK-LABEL: 'SGE_infinite' +; CHECK-NEXT: Determining loop execution counts for: @SGE_infinite +; CHECK-NEXT: Loop %for.body: Unpredictable backedge-taken count. +; CHECK-NEXT: Loop %for.body: Unpredictable max backedge-taken count. +; +entry: + br label %for.body + +for.body: + %iv = phi i32 [ %inc, %for.body ], [ 100, %entry ] + call void @non_exit_use(i32 %iv) nounwind willreturn + %inc = add i32 %iv, -1 + %cmp = icmp sge i32 %iv, %end + br i1 %cmp, label %for.body, label %for.end + +for.end: + ret void +} + +define void @UGE(i32 %end) willreturn { +; CHECK-LABEL: 'UGE' +; CHECK-NEXT: Determining loop execution counts for: @UGE +; CHECK-NEXT: Loop %for.body: backedge-taken count is (100 + (-1 * (100 umin (-1 + %end)))) +; CHECK-NEXT: Loop %for.body: max backedge-taken count is 100 +; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (100 + (-1 * (100 umin (-1 + %end)))) +; CHECK-NEXT: Predicates: +; +entry: + br label %for.body + +for.body: + %iv = phi i32 [ %inc, %for.body ], [ 100, %entry ] + call void @non_exit_use(i32 %iv) nounwind willreturn + %inc = add i32 %iv, -1 + %cmp = icmp uge i32 %iv, %end + br i1 %cmp, label %for.body, label %for.end + +for.end: + ret void +} + +define void @UGE_infinite(i32 %end) { +; CHECK-LABEL: 'UGE_infinite' +; CHECK-NEXT: Determining loop execution counts for: @UGE_infinite +; CHECK-NEXT: Loop %for.body: Unpredictable backedge-taken count. +; CHECK-NEXT: Loop %for.body: Unpredictable max backedge-taken count. +; +entry: + br label %for.body + +for.body: + %iv = phi i32 [ %inc, %for.body ], [ 100, %entry ] + call void @non_exit_use(i32 %iv) nounwind willreturn + %inc = add i32 %iv, -1 + %cmp = icmp uge i32 %iv, %end + br i1 %cmp, label %for.body, label %for.end + +for.end: + ret void +}