Index: llvm/lib/Analysis/ScalarEvolution.cpp =================================================================== --- llvm/lib/Analysis/ScalarEvolution.cpp +++ llvm/lib/Analysis/ScalarEvolution.cpp @@ -9143,6 +9143,7 @@ } } + bool IsSigned = ICmpInst::isSigned(Pred); switch (Pred) { case ICmpInst::ICMP_NE: { // while (X != Y) // Convert to: while (X-Y != 0) @@ -9179,17 +9180,26 @@ break; } case ICmpInst::ICMP_SLE: - case ICmpInst::ICMP_ULE: + case ICmpInst::ICMP_ULE: { // Since the loop is finite, an invariant RHS cannot include the boundary // value, otherwise it would loop forever. if (!EnableFiniteLoopControl || !ControllingFiniteLoop || !isLoopInvariant(RHS, L)) break; - RHS = getAddExpr(getOne(RHS->getType()), RHS); + + // This particular add will not overflow, but this does not necessarily + // hold globally. However, if this is an addrec in this loop, then the + // addition can never overflow in its validity scope (otherwise behavior + // would be undefined). + SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap; + if (const auto *AddRec = dyn_cast(LHS)) + if (AddRec->getLoop() == L) + Flags = IsSigned ? SCEV::FlagNSW : SCEV::FlagNUW; + RHS = getAddExpr(getOne(RHS->getType()), RHS, Flags); [[fallthrough]]; + } case ICmpInst::ICMP_SLT: case ICmpInst::ICMP_ULT: { // while (X < Y) - bool IsSigned = ICmpInst::isSigned(Pred); ExitLimit EL = howManyLessThans(LHS, RHS, L, IsSigned, ControlsOnlyExit, AllowPredicates); if (EL.hasAnyInfo()) @@ -9197,17 +9207,24 @@ break; } case ICmpInst::ICMP_SGE: - case ICmpInst::ICMP_UGE: + case ICmpInst::ICMP_UGE: { // Since the loop is finite, an invariant RHS cannot include the boundary // value, otherwise it would loop forever. if (!EnableFiniteLoopControl || !ControllingFiniteLoop || !isLoopInvariant(RHS, L)) break; - RHS = getAddExpr(getMinusOne(RHS->getType()), RHS); + + // See comment on the sle/ule case. We can only handle the signed case + // here, because we're performing an add -1, not sub 1. + SCEV::NoWrapFlags Flags = SCEV::FlagAnyWrap; + if (const auto *AddRec = dyn_cast(LHS)) + if (AddRec->getLoop() == L && IsSigned) + Flags = SCEV::FlagNSW; + RHS = getAddExpr(getMinusOne(RHS->getType()), RHS, Flags); [[fallthrough]]; + } case ICmpInst::ICMP_SGT: case ICmpInst::ICMP_UGT: { // while (X > Y) - bool IsSigned = ICmpInst::isSigned(Pred); ExitLimit EL = howManyGreaterThans(LHS, RHS, L, IsSigned, ControlsOnlyExit, AllowPredicates); if (EL.hasAnyInfo()) Index: llvm/test/Analysis/ScalarEvolution/finite-trip-count.ll =================================================================== --- llvm/test/Analysis/ScalarEvolution/finite-trip-count.ll +++ llvm/test/Analysis/ScalarEvolution/finite-trip-count.ll @@ -9,10 +9,10 @@ define void @sle_pre_inc(i32 %len) willreturn { ; CHECK-LABEL: 'sle_pre_inc' ; CHECK-NEXT: Determining loop execution counts for: @sle_pre_inc -; CHECK-NEXT: Loop %for.body: backedge-taken count is (0 smax (1 + %len)) +; CHECK-NEXT: Loop %for.body: backedge-taken count is (0 smax (1 + %len)) ; CHECK-NEXT: Loop %for.body: constant max backedge-taken count is 2147483647 -; CHECK-NEXT: Loop %for.body: symbolic max backedge-taken count is (0 smax (1 + %len)) -; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (0 smax (1 + %len)) +; CHECK-NEXT: Loop %for.body: symbolic max backedge-taken count is (0 smax (1 + %len)) +; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (0 smax (1 + %len)) ; CHECK-NEXT: Predicates: ; CHECK: Loop %for.body: Trip multiple is 1 ; @@ -33,10 +33,10 @@ define void @sle_post_inc(i32 %len) willreturn { ; CHECK-LABEL: 'sle_post_inc' ; CHECK-NEXT: Determining loop execution counts for: @sle_post_inc -; CHECK-NEXT: Loop %for.body: backedge-taken count is (-1 + (1 smax (1 + %len))) +; CHECK-NEXT: Loop %for.body: backedge-taken count is (-1 + (1 smax (1 + %len))) ; CHECK-NEXT: Loop %for.body: constant max backedge-taken count is 2147483646 -; CHECK-NEXT: Loop %for.body: symbolic max backedge-taken count is (-1 + (1 smax (1 + %len))) -; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (-1 + (1 smax (1 + %len))) +; CHECK-NEXT: Loop %for.body: symbolic max backedge-taken count is (-1 + (1 smax (1 + %len))) +; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (-1 + (1 smax (1 + %len))) ; CHECK-NEXT: Predicates: ; CHECK: Loop %for.body: Trip multiple is 1 ; @@ -79,10 +79,10 @@ define void @ule_pre_inc(i32 %len) willreturn { ; CHECK-LABEL: 'ule_pre_inc' ; CHECK-NEXT: Determining loop execution counts for: @ule_pre_inc -; CHECK-NEXT: Loop %for.body: backedge-taken count is (1 + %len) +; CHECK-NEXT: Loop %for.body: backedge-taken count is (1 + %len) ; CHECK-NEXT: Loop %for.body: constant max backedge-taken count is -1 -; CHECK-NEXT: Loop %for.body: symbolic max backedge-taken count is (1 + %len) -; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (1 + %len) +; CHECK-NEXT: Loop %for.body: symbolic max backedge-taken count is (1 + %len) +; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (1 + %len) ; CHECK-NEXT: Predicates: ; CHECK: Loop %for.body: Trip multiple is 1 ; @@ -103,10 +103,10 @@ define void @ule_post_inc(i32 %len) willreturn { ; CHECK-LABEL: 'ule_post_inc' ; CHECK-NEXT: Determining loop execution counts for: @ule_post_inc -; CHECK-NEXT: Loop %for.body: backedge-taken count is (-1 + (1 umax (1 + %len))) +; CHECK-NEXT: Loop %for.body: backedge-taken count is %len ; CHECK-NEXT: Loop %for.body: constant max backedge-taken count is -2 -; CHECK-NEXT: Loop %for.body: symbolic max backedge-taken count is (-1 + (1 umax (1 + %len))) -; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (-1 + (1 umax (1 + %len))) +; CHECK-NEXT: Loop %for.body: symbolic max backedge-taken count is %len +; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is %len ; CHECK-NEXT: Predicates: ; CHECK: Loop %for.body: Trip multiple is 1 ; @@ -149,10 +149,10 @@ define void @sge_pre_inc(i32 %end) willreturn { ; CHECK-LABEL: 'sge_pre_inc' ; CHECK-NEXT: Determining loop execution counts for: @sge_pre_inc -; CHECK-NEXT: Loop %for.body: backedge-taken count is (100 + (-1 * (100 smin (-1 + %end)))) +; CHECK-NEXT: Loop %for.body: backedge-taken count is (100 + (-1 * (100 smin (-1 + %end)))) ; CHECK-NEXT: Loop %for.body: constant max backedge-taken count is -2147483548 -; CHECK-NEXT: Loop %for.body: symbolic max backedge-taken count is (100 + (-1 * (100 smin (-1 + %end)))) -; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (100 + (-1 * (100 smin (-1 + %end)))) +; CHECK-NEXT: Loop %for.body: symbolic max backedge-taken count is (100 + (-1 * (100 smin (-1 + %end)))) +; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (100 + (-1 * (100 smin (-1 + %end)))) ; CHECK-NEXT: Predicates: ; CHECK: Loop %for.body: Trip multiple is 1 ; @@ -173,10 +173,10 @@ define void @sge_post_inc(i32 %end) willreturn { ; CHECK-LABEL: 'sge_post_inc' ; CHECK-NEXT: Determining loop execution counts for: @sge_post_inc -; CHECK-NEXT: Loop %for.body: backedge-taken count is (100 + (-1 * (100 smin (-1 + %end)))) +; CHECK-NEXT: Loop %for.body: backedge-taken count is (100 + (-1 * (100 smin (-1 + %end)))) ; CHECK-NEXT: Loop %for.body: constant max backedge-taken count is -2147483548 -; CHECK-NEXT: Loop %for.body: symbolic max backedge-taken count is (100 + (-1 * (100 smin (-1 + %end)))) -; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (100 + (-1 * (100 smin (-1 + %end)))) +; CHECK-NEXT: Loop %for.body: symbolic max backedge-taken count is (100 + (-1 * (100 smin (-1 + %end)))) +; CHECK-NEXT: Loop %for.body: Predicated backedge-taken count is (100 + (-1 * (100 smin (-1 + %end)))) ; CHECK-NEXT: Predicates: ; CHECK: Loop %for.body: Trip multiple is 1 ; Index: llvm/test/Transforms/IndVarSimplify/rewrite-loop-exit-value.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/rewrite-loop-exit-value.ll +++ llvm/test/Transforms/IndVarSimplify/rewrite-loop-exit-value.ll @@ -169,9 +169,9 @@ ; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp sgt i16 [[MUL]], [[END:%.*]] ; CHECK-NEXT: br i1 [[CMP_NOT]], label [[CRIT_EDGE:%.*]], label [[FOR_BODY]] ; CHECK: crit_edge: -; CHECK-NEXT: [[TMP0:%.*]] = add i16 [[END]], 1 -; CHECK-NEXT: [[SMAX:%.*]] = call i16 @llvm.smax.i16(i16 [[TMP0]], i16 0) -; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i16 [[END]], 32767 +; CHECK-NEXT: [[TMP0:%.*]] = call i16 @llvm.smax.i16(i16 [[END]], i16 -1) +; CHECK-NEXT: [[SMAX:%.*]] = add nsw i16 [[TMP0]], 1 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i16 [[SMAX]], 0 ; CHECK-NEXT: [[UMIN:%.*]] = zext i1 [[TMP1]] to i16 ; CHECK-NEXT: [[TMP2:%.*]] = sub nsw i16 [[SMAX]], [[UMIN]] ; CHECK-NEXT: [[UMAX:%.*]] = call i16 @llvm.umax.i16(i16 [[M]], i16 1)