Index: llvm/lib/Analysis/ScalarEvolution.cpp =================================================================== --- llvm/lib/Analysis/ScalarEvolution.cpp +++ llvm/lib/Analysis/ScalarEvolution.cpp @@ -2345,22 +2345,25 @@ if (!RHSC) return false; APInt C = RHSC->getAPInt(); - // We can prove that add(x, constant) doesn't wrap if isKnownPredicateAt can - // guarantee that x <= max_int - constant at the given context. // TODO: Support mul. if (BinOp == Instruction::Sub) C = -C; else if (BinOp != Instruction::Add) return false; - // TODO: Also lift this limitation. - if (Signed && C.isNegative()) - return false; unsigned NumBits = C.getBitWidth(); - APInt Max = - Signed ? APInt::getSignedMaxValue(NumBits) : APInt::getMaxValue(NumBits); - APInt Limit = Max - C; ICmpInst::Predicate Pred = Signed ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_ULE; - return isKnownPredicateAt(Pred, LHS, getConstant(Limit), CtxI); + if (Signed && C.isNegative()) { + // No overflow if we can prove that (MIN - C <= LHS). + APInt Min = APInt::getSignedMinValue(NumBits); + APInt Limit = Min - C; + return isKnownPredicateAt(Pred, getConstant(Limit), LHS, CtxI); + } else { + // No overflow if we can prove that (LHS <= MAX - C). + APInt Max = + Signed ? APInt::getSignedMaxValue(NumBits) : APInt::getMaxValue(NumBits); + APInt Limit = Max - C; + return isKnownPredicateAt(Pred, LHS, getConstant(Limit), CtxI); + } } std::optional Index: llvm/test/Transforms/IndVarSimplify/predicated_ranges.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/predicated_ranges.ll +++ llvm/test/Transforms/IndVarSimplify/predicated_ranges.ll @@ -19,7 +19,7 @@ ; CHECK-NEXT: [[ZERO_COND:%.*]] = icmp eq i32 [[IV]], 0 ; CHECK-NEXT: br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]] ; CHECK: range_check_block: -; CHECK-NEXT: [[IV_NEXT]] = sub i32 [[IV]], 1 +; CHECK-NEXT: [[IV_NEXT]] = sub nsw i32 [[IV]], 1 ; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[FAIL:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, ptr [[P]], i32 [[IV]] @@ -68,7 +68,7 @@ ; CHECK-NEXT: [[ZERO_COND:%.*]] = icmp eq i32 [[IV]], 0 ; CHECK-NEXT: br i1 [[ZERO_COND]], label [[EXIT:%.*]], label [[RANGE_CHECK_BLOCK:%.*]] ; CHECK: range_check_block: -; CHECK-NEXT: [[IV_NEXT]] = sub i32 [[IV]], 1 +; CHECK-NEXT: [[IV_NEXT]] = sub nsw i32 [[IV]], 1 ; CHECK-NEXT: br i1 true, label [[BACKEDGE]], label [[FAIL:%.*]] ; CHECK: backedge: ; CHECK-NEXT: [[EL_PTR:%.*]] = getelementptr i32, ptr [[P]], i32 [[IV]]