From: William S. Moses Date: Tue, 25 Jan 2022 01:02:53 +0000 (-0500) Subject: [ScalarEvolution] Handle <= and >= in non infinite loops X-Git-Tag: upstream/15.0.7~18638 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=99d2582164c4bc8f10c3e3c20dd3690243ad49ba;p=platform%2Fupstream%2Fllvm.git [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 --- diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h index 1e6dac4..b16aa70 100644 --- a/llvm/include/llvm/Analysis/ScalarEvolution.h +++ b/llvm/include/llvm/Analysis/ScalarEvolution.h @@ -1111,9 +1111,11 @@ public: /// 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 index 56eb7c6..46833a8a 100644 --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -8466,8 +8466,11 @@ ScalarEvolution::computeExitLimitFromICmp(const Loop *L, 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 @@ ScalarEvolution::computeExitLimitFromICmp(const Loop *L, // 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 @@ static bool HasSameValue(const SCEV *A, const SCEV *B) { 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 @@ bool ScalarEvolution::SimplifyICmpOperands(ICmpInst::Predicate &Pred, } // 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 @@ bool ScalarEvolution::SimplifyICmpOperands(ICmpInst::Predicate &Pred, } 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 @@ bool ScalarEvolution::SimplifyICmpOperands(ICmpInst::Predicate &Pred, } 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 @@ bool ScalarEvolution::SimplifyICmpOperands(ICmpInst::Predicate &Pred, } 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 @@ bool ScalarEvolution::SimplifyICmpOperands(ICmpInst::Predicate &Pred, // 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 index 0000000..1c6cf22 --- /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 +}