[llvm] [DA] Check monotonicity for subscripts (PR #154527)
Sushant Gokhale via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 24 23:48:32 PDT 2025
================
@@ -3308,6 +3308,322 @@ void DependenceInfo::updateDirection(Dependence::DVEntry &Level,
llvm_unreachable("constraint has unexpected kind");
}
+namespace {
+
+enum class MonotonicityType {
+ MaySignedWrap, ///< The expression contains arithmetic operations that may
+ ///< cause signed wrap.
+ Constant, ///< The expression is constant. If a SCEV is classified as
+ ///< Constant, it also implies that it doesn't contain any
+ ///< arithmetic operations that may cause signed wrap.
+ Monotonic, ///< The expression is monotonically increasing or decreasing. This
+ ///< is exclusive of Constant. That is, we say an SCEV is Monotonic
+ ///< iff it contains at least one AddRec where its step reccurence
+ ///< value is non-zero.
+};
+
+/// A visitor that checks the signed monotonicity of SCEVs.
+struct SCEVSignedMonotonicityChecker
+ : public SCEVVisitor<SCEVSignedMonotonicityChecker, MonotonicityType> {
+ /// \p Ptr is the pointer that the SCEV is associated with, if any. It may be
+ /// used for the inferrence.
+ SCEVSignedMonotonicityChecker(ScalarEvolution *SE, const Loop *OutermostLoop,
+ const Value *Ptr = nullptr)
+ : SE(SE), OutermostLoop(OutermostLoop), Ptr(Ptr) {}
+
+ MonotonicityType visitAddExpr(const SCEVAddExpr *Expr);
+ MonotonicityType visitAddRecExpr(const SCEVAddRecExpr *Expr);
+ MonotonicityType visitMulExpr(const SCEVMulExpr *Expr);
+ MonotonicityType visitUnknown(const SCEVUnknown *Expr);
+ MonotonicityType visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr);
+ MonotonicityType visitSignExtendExpr(const SCEVSignExtendExpr *Expr);
+
+ MonotonicityType visitConstant(const SCEVConstant *) {
+ return MonotonicityType::Constant;
+ }
+ MonotonicityType visitVScale(const SCEVVScale *) {
+ return MonotonicityType::Constant;
+ }
+
+ // TODO: Handle more cases.
+ MonotonicityType visitPtrToIntExpr(const SCEVPtrToIntExpr *) {
+ return MonotonicityType::MaySignedWrap;
+ }
+ MonotonicityType visitTruncateExpr(const SCEVTruncateExpr *) {
+ return MonotonicityType::MaySignedWrap;
+ }
+ MonotonicityType visitUDivExpr(const SCEVUDivExpr *) {
+ return MonotonicityType::MaySignedWrap;
+ }
+ MonotonicityType visitSMaxExpr(const SCEVSMaxExpr *) {
+ return MonotonicityType::MaySignedWrap;
+ }
+ MonotonicityType visitUMaxExpr(const SCEVUMaxExpr *) {
+ return MonotonicityType::MaySignedWrap;
+ }
+ MonotonicityType visitSMinExpr(const SCEVSMinExpr *) {
+ return MonotonicityType::MaySignedWrap;
+ }
+ MonotonicityType visitUMinExpr(const SCEVUMinExpr *) {
+ return MonotonicityType::MaySignedWrap;
+ }
+ MonotonicityType visitSequentialUMinExpr(const SCEVSequentialUMinExpr *) {
+ return MonotonicityType::MaySignedWrap;
+ }
+ MonotonicityType visitCouldNotCompute(const SCEVCouldNotCompute *) {
+ return MonotonicityType::MaySignedWrap;
+ }
+
+private:
+ ScalarEvolution *SE;
+ const Loop *OutermostLoop;
+ const Value *Ptr = nullptr;
+};
+
+using MinMaxType = std::pair<const SCEV *, const SCEV *>;
+const MinMaxType Bottom = {nullptr, nullptr};
+
+/// A visitor that calculates the possible minimum and maximum values of SCEVs.
+/// This class assumes that the given SCEV is constant or monotonic.
+struct SCEVMinMaxCalculator
+ : public SCEVVisitor<SCEVMinMaxCalculator, MinMaxType> {
+ SCEVMinMaxCalculator(ScalarEvolution *SE, const Loop *OutermostLoop)
+ : SE(SE), OutermostLoop(OutermostLoop) {}
+
+ MinMaxType visitAddExpr(const SCEVAddExpr *Expr);
+ MinMaxType visitAddRecExpr(const SCEVAddRecExpr *Expr);
+ MinMaxType visitMulExpr(const SCEVMulExpr *Expr);
+ MinMaxType visitSignExtendExpr(const SCEVSignExtendExpr *Expr);
+
+ MinMaxType visitUnknown(const SCEVUnknown *Expr) {
+ return constantHelper(Expr);
+ }
+ MinMaxType visitConstant(const SCEVConstant *Expr) {
+ return constantHelper(Expr);
+ }
+ MinMaxType visitVScale(const SCEVVScale *Expr) {
+ return constantHelper(Expr);
+ }
+
+ MinMaxType visitZeroExtendExpr(const SCEVZeroExtendExpr *) { return Bottom; }
+ MinMaxType visitPtrToIntExpr(const SCEVPtrToIntExpr *) { return Bottom; }
+ MinMaxType visitTruncateExpr(const SCEVTruncateExpr *) { return Bottom; }
+ MinMaxType visitUDivExpr(const SCEVUDivExpr *) { return Bottom; }
+ MinMaxType visitSMaxExpr(const SCEVSMaxExpr *) { return Bottom; }
+ MinMaxType visitUMaxExpr(const SCEVUMaxExpr *) { return Bottom; }
+ MinMaxType visitSMinExpr(const SCEVSMinExpr *) { return Bottom; }
+ MinMaxType visitUMinExpr(const SCEVUMinExpr *) { return Bottom; }
+ MinMaxType visitSequentialUMinExpr(const SCEVSequentialUMinExpr *) {
+ return Bottom;
+ }
+ MinMaxType visitCouldNotCompute(const SCEVCouldNotCompute *) {
+ return Bottom;
+ }
+
+ MinMaxType constantHelper(const SCEV *C) { return MinMaxType(C, C); }
+
+private:
+ ScalarEvolution *SE;
+ const Loop *OutermostLoop;
+};
+
+} // anonymous namespace
+
+MonotonicityType
+SCEVSignedMonotonicityChecker::visitAddExpr(const SCEVAddExpr *Expr) {
+ if (!Expr->hasNoSignedWrap())
+ return MonotonicityType::MaySignedWrap;
+
+ MonotonicityType Result = MonotonicityType::Constant;
+ for (const SCEV *Op : Expr->operands()) {
+ switch (visit(Op)) {
+ case MonotonicityType::MaySignedWrap:
+ return MonotonicityType::MaySignedWrap;
+ case MonotonicityType::Constant:
+ break;
+ case MonotonicityType::Monotonic:
+ // Monotonic + Monotonic might be constant, so at the moment return
+ // MaySignedWrap.
+ // TODO: Should we separate Monotonically increasing and decreasing? Or
+ // SCEV is always simplified enough so that we don't have to consider such
+ // cases?
+ if (Result == MonotonicityType::Monotonic)
+ return MonotonicityType::MaySignedWrap;
+ Result = MonotonicityType::Constant;
+ break;
+ }
----------------
sushgokh wrote:
I dont understand one thing here. If the entire SCEV is NSW, why do we need to check if its NSW for individual operands? Do you have specific case in mind?
Also, I am trying to understand what `MonotonicityType::Monotonic` really means. Just going by the mathematical definition of monotonicity,
1. why `Monotonic + Monotonic` should be MaySignedWrap? Shouldnt it be Monotonic?
2. why `Monotonic + Constant` should be Constant? Shouldnt it be Monotonic?
https://github.com/llvm/llvm-project/pull/154527
More information about the llvm-commits
mailing list