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.
// 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;
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'.
}
// 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;
}
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;
}
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;
}
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;
// 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;
}
--- /dev/null
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py
+; RUN: opt < %s -disable-output "-passes=print<scalar-evolution>" -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)<nsw>)
+; 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)<nsw>)
+; 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)<nuw>
+; CHECK-NEXT: Loop %for.body: max backedge-taken count is -1
+; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (1 + %len)<nuw>
+; 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)<nsw>)))
+; 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)<nsw>)))
+; 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)))<nsw>)<nsw>
+; 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)))<nsw>)<nsw>
+; 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
+}