diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h --- a/llvm/include/llvm/Analysis/ScalarEvolution.h +++ b/llvm/include/llvm/Analysis/ScalarEvolution.h @@ -1157,6 +1157,11 @@ /// to be a constant. Optional computeConstantDifference(const SCEV *LHS, const SCEV *RHS); + /// Update no-wrap flags of an AddRec. This may drop the cached info about + /// this AddRec (such as range info) in case if new flags may potentially + /// sharpen it. + void setNoWrapFlags(SCEVAddRecExpr *AddRec, SCEV::NoWrapFlags Flags); + private: /// A CallbackVH to arrange for ScalarEvolution to be notified whenever a /// Value is deleted. diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -1381,7 +1381,7 @@ // If we know `AR` == {`PreStart`+`Step`,+,`Step`} is `WrapType` (FlagNSW // or FlagNUW) and that `PreStart` + `Step` is `WrapType` too, then // `PreAR` == {`PreStart`,+,`Step`} is also `WrapType`. Cache this fact. - const_cast(PreAR)->setNoWrapFlags(WrapType); + SE->setNoWrapFlags(const_cast(PreAR), WrapType); } return PreStart; } @@ -1585,7 +1585,7 @@ if (!AR->hasNoUnsignedWrap()) { auto NewFlags = proveNoWrapViaConstantRanges(AR); - const_cast(AR)->setNoWrapFlags(NewFlags); + setNoWrapFlags(const_cast(AR), NewFlags); } // If we have special knowledge that this addrec won't overflow, @@ -1634,7 +1634,7 @@ SCEV::FlagAnyWrap, Depth + 1); if (ZAdd == OperandExtendedAdd) { // Cache knowledge of AR NUW, which is propagated to this AddRec. - const_cast(AR)->setNoWrapFlags(SCEV::FlagNUW); + setNoWrapFlags(const_cast(AR), SCEV::FlagNUW); // Return the expression with the addrec on the outside. return getAddRecExpr( getExtendAddRecStart(AR, Ty, this, @@ -1653,7 +1653,7 @@ if (ZAdd == OperandExtendedAdd) { // Cache knowledge of AR NW, which is propagated to this AddRec. // Negative step causes unsigned wrap, but it still can't self-wrap. - const_cast(AR)->setNoWrapFlags(SCEV::FlagNW); + setNoWrapFlags(const_cast(AR), SCEV::FlagNW); // Return the expression with the addrec on the outside. return getAddRecExpr( getExtendAddRecStart(AR, Ty, this, @@ -1685,7 +1685,7 @@ isKnownOnEveryIteration(ICmpInst::ICMP_ULT, AR, N)) { // Cache knowledge of AR NUW, which is propagated to this // AddRec. - const_cast(AR)->setNoWrapFlags(SCEV::FlagNUW); + setNoWrapFlags(const_cast(AR), SCEV::FlagNUW); // Return the expression with the addrec on the outside. return getAddRecExpr( getExtendAddRecStart(AR, Ty, this, @@ -1701,7 +1701,7 @@ // Cache knowledge of AR NW, which is propagated to this // AddRec. Negative step causes unsigned wrap, but it // still can't self-wrap. - const_cast(AR)->setNoWrapFlags(SCEV::FlagNW); + setNoWrapFlags(const_cast(AR), SCEV::FlagNW); // Return the expression with the addrec on the outside. return getAddRecExpr( getExtendAddRecStart(AR, Ty, this, @@ -1730,7 +1730,7 @@ } if (proveNoWrapByVaryingStart(Start, Step, L)) { - const_cast(AR)->setNoWrapFlags(SCEV::FlagNUW); + setNoWrapFlags(const_cast(AR), SCEV::FlagNUW); return getAddRecExpr( getExtendAddRecStart(AR, Ty, this, Depth + 1), getZeroExtendExpr(Step, Ty, Depth + 1), L, AR->getNoWrapFlags()); @@ -1929,7 +1929,7 @@ if (!AR->hasNoSignedWrap()) { auto NewFlags = proveNoWrapViaConstantRanges(AR); - const_cast(AR)->setNoWrapFlags(NewFlags); + setNoWrapFlags(const_cast(AR), NewFlags); } // If we have special knowledge that this addrec won't overflow, @@ -1978,7 +1978,7 @@ SCEV::FlagAnyWrap, Depth + 1); if (SAdd == OperandExtendedAdd) { // Cache knowledge of AR NSW, which is propagated to this AddRec. - const_cast(AR)->setNoWrapFlags(SCEV::FlagNSW); + setNoWrapFlags(const_cast(AR), SCEV::FlagNSW); // Return the expression with the addrec on the outside. return getAddRecExpr( getExtendAddRecStart(AR, Ty, this, @@ -2003,7 +2003,7 @@ // Thus (AR is not NW => SAdd != OperandExtendedAdd) <=> // (SAdd == OperandExtendedAdd => AR is NW) - const_cast(AR)->setNoWrapFlags(SCEV::FlagNW); + setNoWrapFlags(const_cast(AR), SCEV::FlagNW); // Return the expression with the addrec on the outside. return getAddRecExpr( @@ -2037,7 +2037,7 @@ (isLoopBackedgeGuardedByCond(L, Pred, AR, OverflowLimit) || isKnownOnEveryIteration(Pred, AR, OverflowLimit))) { // Cache knowledge of AR NSW, then propagate NSW to the wide AddRec. - const_cast(AR)->setNoWrapFlags(SCEV::FlagNSW); + setNoWrapFlags(const_cast(AR), SCEV::FlagNSW); return getAddRecExpr( getExtendAddRecStart(AR, Ty, this, Depth + 1), getSignExtendExpr(Step, Ty, Depth + 1), L, AR->getNoWrapFlags()); @@ -2062,7 +2062,7 @@ } if (proveNoWrapByVaryingStart(Start, Step, L)) { - const_cast(AR)->setNoWrapFlags(SCEV::FlagNSW); + setNoWrapFlags(const_cast(AR), SCEV::FlagNSW); return getAddRecExpr( getExtendAddRecStart(AR, Ty, this, Depth + 1), getSignExtendExpr(Step, Ty, Depth + 1), L, AR->getNoWrapFlags()); @@ -2732,7 +2732,7 @@ UniqueSCEVs.InsertNode(S, IP); addToLoopUseLists(S); } - S->setNoWrapFlags(Flags); + setNoWrapFlags(S, Flags); return S; } @@ -5514,6 +5514,15 @@ return None; } +void ScalarEvolution::setNoWrapFlags(SCEVAddRecExpr *AddRec, + SCEV::NoWrapFlags Flags) { + if (AddRec->getNoWrapFlags(Flags) != Flags) { + AddRec->setNoWrapFlags(Flags); + UnsignedRanges.erase(AddRec); + SignedRanges.erase(AddRec); + } +} + /// Determine the range for a particular SCEV. If SignHint is /// HINT_RANGE_UNSIGNED (resp. HINT_RANGE_SIGNED) then getRange prefers ranges /// with a "cleaner" unsigned (resp. signed) representation. diff --git a/llvm/test/Analysis/ScalarEvolution/srem.ll b/llvm/test/Analysis/ScalarEvolution/srem.ll --- a/llvm/test/Analysis/ScalarEvolution/srem.ll +++ b/llvm/test/Analysis/ScalarEvolution/srem.ll @@ -29,7 +29,7 @@ ; CHECK-NEXT: %add = add nsw i32 %2, %call ; CHECK-NEXT: --> (%2 + %call) U: full-set S: full-set Exits: <> LoopDispositions: { %for.cond: Variant } ; CHECK-NEXT: %inc = add nsw i32 %i.0, 1 -; CHECK-NEXT: --> {1,+,1}<%for.cond> U: full-set S: full-set Exits: (1 + %width) LoopDispositions: { %for.cond: Computable } +; CHECK-NEXT: --> {1,+,1}<%for.cond> U: [1,0) S: [1,0) Exits: (1 + %width) LoopDispositions: { %for.cond: Computable } ; CHECK-NEXT: Determining loop execution counts for: @_Z4loopi ; CHECK-NEXT: Loop %for.cond: backedge-taken count is %width ; CHECK-NEXT: Loop %for.cond: max backedge-taken count is -1 diff --git a/llvm/test/Transforms/IndVarSimplify/floating-point-iv.ll b/llvm/test/Transforms/IndVarSimplify/floating-point-iv.ll --- a/llvm/test/Transforms/IndVarSimplify/floating-point-iv.ll +++ b/llvm/test/Transforms/IndVarSimplify/floating-point-iv.ll @@ -150,7 +150,7 @@ ; CHECK-NEXT: [[INDVAR_CONV:%.*]] = sitofp i32 [[TMP11_INT]] to double ; CHECK-NEXT: [[TMP12]] = fadd double [[TMP10]], [[INDVAR_CONV]] ; CHECK-NEXT: [[TMP13_INT]] = add nuw nsw i32 [[TMP11_INT]], 1 -; CHECK-NEXT: [[TMP14:%.*]] = icmp slt i32 [[TMP13_INT]], 99999 +; CHECK-NEXT: [[TMP14:%.*]] = icmp ult i32 [[TMP13_INT]], 99999 ; CHECK-NEXT: br i1 [[TMP14]], label [[BB22]], label [[BB6:%.*]] ; CHECK: bb22: ; CHECK-NEXT: br i1 true, label [[BB8]], label [[BB6]] @@ -189,7 +189,7 @@ ; CHECK-NEXT: [[INDVAR_CONV:%.*]] = sitofp i32 [[TMP11_INT]] to float ; CHECK-NEXT: [[TMP12]] = fadd float [[TMP10]], [[INDVAR_CONV]] ; CHECK-NEXT: [[TMP13_INT]] = add nuw nsw i32 [[TMP11_INT]], 1 -; CHECK-NEXT: [[TMP14:%.*]] = icmp slt i32 [[TMP13_INT]], 99999 +; CHECK-NEXT: [[TMP14:%.*]] = icmp ult i32 [[TMP13_INT]], 99999 ; CHECK-NEXT: br i1 [[TMP14]], label [[BB22]], label [[BB6:%.*]] ; CHECK: bb22: ; CHECK-NEXT: br i1 true, label [[BB8]], label [[BB6]] @@ -229,7 +229,7 @@ ; CHECK-NEXT: [[INDVAR_CONV:%.*]] = sitofp i32 [[TMP11_INT]] to float ; CHECK-NEXT: [[TMP12]] = fadd float [[TMP10]], [[INDVAR_CONV]] ; CHECK-NEXT: [[TMP13_INT]] = add nuw nsw i32 [[TMP11_INT]], 1 -; CHECK-NEXT: [[TMP14:%.*]] = icmp slt i32 [[TMP13_INT]], 99999 +; CHECK-NEXT: [[TMP14:%.*]] = icmp ult i32 [[TMP13_INT]], 99999 ; CHECK-NEXT: br i1 [[TMP14]], label [[BB22]], label [[BB6:%.*]] ; CHECK: bb22: ; CHECK-NEXT: br i1 true, label [[BB8]], label [[BB6]]