Index: lib/Analysis/ScalarEvolution.cpp =================================================================== --- lib/Analysis/ScalarEvolution.cpp +++ lib/Analysis/ScalarEvolution.cpp @@ -7206,17 +7206,27 @@ // 1*N = -Start; -1*N = Start (mod 2^BW), so: // N = Distance (as unsigned) if (StepC->getValue()->equalsInt(1) || StepC->getValue()->isAllOnesValue()) { - ConstantRange CR = getUnsignedRange(Start); - const SCEV *MaxBECount; - if (!CountDown && CR.getUnsignedMin().isMinValue()) - // When counting up, the worst starting value is 1, not 0. - MaxBECount = CR.getUnsignedMax().isMinValue() - ? getConstant(APInt::getMinValue(CR.getBitWidth())) - : getConstant(APInt::getMaxValue(CR.getBitWidth())); - else - MaxBECount = getConstant(CountDown ? CR.getUnsignedMax() - : -CR.getUnsignedMin()); - return ExitLimit(Distance, MaxBECount, false, Predicates); + APInt MaxBECount = getUnsignedRange(Distance).getUnsignedMax(); + + // When a loop like "for (int i = 0; i != n; ++i) { /* body */ }" is rotated, + // we end up with a loop whose backedge-taken count is n - 1. Detect this + // case, and see if we can improve the bound. + // + // Explicitly handling this here is necessary because getUnsignedRange + // isn't context-sensitive; it doesn't know that we only care about the + // range inside the loop. + const SCEV *Zero = getZero(Distance->getType()); + const SCEVConstant *One = cast(getOne(Distance->getType())); + const SCEV *DistancePlusOne = getAddExpr(Distance, getOne(Distance->getType())); + if (isLoopEntryGuardedByCond(L, ICmpInst::ICMP_NE, DistancePlusOne, Zero)) { + // If Distance + 1 doesn't overflow, we can compute the maximum distance + // as "unsigned_max(Distance + 1) - 1". + ConstantRange CR = getUnsignedRange(DistancePlusOne); + APInt NewMaxBECount = CR.getUnsignedMax() - One->getAPInt(); + if (NewMaxBECount.ult(MaxBECount)) + MaxBECount = NewMaxBECount; + } + return ExitLimit(Distance, getConstant(MaxBECount), false, Predicates); } // As a special case, handle the instance where Step is a positive power of Index: test/Analysis/ScalarEvolution/max-trip-count.ll =================================================================== --- test/Analysis/ScalarEvolution/max-trip-count.ll +++ test/Analysis/ScalarEvolution/max-trip-count.ll @@ -207,3 +207,84 @@ bar.exit: ; preds = %for.cond.i, %for.body.i ret i32 0 } + +; CHECK-LABEL: @ne_max_trip_count_1 +; CHECK: Loop %for.body: max backedge-taken count is 7 +define i32 @ne_max_trip_count_1(i32 %n) { +entry: + %masked = and i32 %n, 7 + br label %for.body + +for.body: + %i = phi i32 [ 0, %entry ], [ %add, %for.body ] + %add = add nsw i32 %i, 1 + %cmp = icmp ne i32 %i, %masked + br i1 %cmp, label %for.body, label %bar.exit + +bar.exit: + ret i32 0 +} + +; CHECK-LABEL: @ne_max_trip_count_2 +; CHECK: Loop %for.body: max backedge-taken count is -1 +define i32 @ne_max_trip_count_2(i32 %n) { +entry: + %masked = and i32 %n, 7 + br label %for.body + +for.body: + %i = phi i32 [ 0, %entry ], [ %add, %for.body ] + %add = add nsw i32 %i, 1 + %cmp = icmp ne i32 %add, %masked + br i1 %cmp, label %for.body, label %bar.exit + +bar.exit: + ret i32 0 +} + +; CHECK-LABEL: @ne_max_trip_count_3 +; CHECK: Loop %for.body: max backedge-taken count is 6 +define i32 @ne_max_trip_count_3(i32 %n) { +entry: + %masked = and i32 %n, 7 + %guard = icmp eq i32 %masked, 0 + br i1 %guard, label %exit, label %for.preheader + +for.preheader: + br label %for.body + +for.body: + %i = phi i32 [ 0, %for.preheader ], [ %add, %for.body ] + %add = add nsw i32 %i, 1 + %cmp = icmp ne i32 %add, %masked + br i1 %cmp, label %for.body, label %loop.exit + +loop.exit: + br label %exit + +exit: + ret i32 0 +} + +; CHECK-LABEL: @ne_max_trip_count_4 +; CHECK: Loop %for.body: max backedge-taken count is -2 +define i32 @ne_max_trip_count_4(i32 %n) { +entry: + %guard = icmp eq i32 %n, 0 + br i1 %guard, label %exit, label %for.preheader + +for.preheader: + br label %for.body + +for.body: + %i = phi i32 [ 0, %for.preheader ], [ %add, %for.body ] + %add = add nsw i32 %i, 1 + %cmp = icmp ne i32 %add, %n + br i1 %cmp, label %for.body, label %loop.exit + +loop.exit: + br label %exit + +exit: + ret i32 0 +}