[llvm] [DA] Check monotonicity for subscripts (PR #154527)
Ryotaro Kasuga via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 8 03:11:46 PDT 2025
================
@@ -3308,6 +3308,242 @@ void DependenceInfo::updateDirection(Dependence::DVEntry &Level,
llvm_unreachable("constraint has unexpected kind");
}
+namespace {
+
+/// The type of signed monotonicity of a SCEV expression. This property is
+/// defined with respect to the outermost loop that DA is analyzing. Invariant
+/// and MultiMonotonic mutually exclusive, and both imply NoSignedWrap.
+///
+/// This is designed to classify the behavior of AddRec expressions, and does
+/// not care about other SCEVs. For example, given the two loop invariants `A`
+/// and `B`, `A + B` is treated as Invariant even if the addition may wrap. On
+/// the other hand, if either `A` or `B` is an AddRec and we cannot prove the
+/// addition doesn't wrap, the result is classified as Unknown.
+enum class MonotonicityType {
+ Unknown, ///< The expression contains some non loop-invariant SCEVUnknown or
+ ///< arithmetic operation that has some AddRec as its subexpression
+ ///< and may cause signed wrap.
+ NoSignedWrap, ///< The expression doesn't contain any AddRecs that may wrap.
+ ///< This is a weaker property than Invariant or MultiMonotonic.
+ ///< Invariant and MultiMonotonic imply NoSignedWrap.
+ Invariant, ///< The expression is a loop-invariant.
+ MultiMonotonic, ///< The expression is monotonically increasing or decreasing
+ ///< with respect to each loop. This is exclusive of
+ ///< Invariant. That is, we say an SCEV is MultiMonotonic only
+ ///< if it contains at least one AddRec where its step
+ ///< reccurence value is non-zero. Monotonicity is checked
+ ///< independently for each loop. It is allowed to contain
+ ///< both increasing and decreasing AddRecs.
+};
+
+/// 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.
+ static MonotonicityType checkMonotonicity(ScalarEvolution *SE,
+ const SCEV *Expr,
+ const Loop *OutermostLoop,
+ const Value *Ptr = nullptr);
+
+ MonotonicityType visitAddRecExpr(const SCEVAddRecExpr *Expr);
+ MonotonicityType visitUnknown(const SCEVUnknown *Expr);
+ MonotonicityType visitZeroExtendExpr(const SCEVZeroExtendExpr *Expr);
+ MonotonicityType visitSignExtendExpr(const SCEVSignExtendExpr *Expr);
+
+ MonotonicityType visitConstant(const SCEVConstant *) {
+ return MonotonicityType::Invariant;
+ }
+ MonotonicityType visitVScale(const SCEVVScale *) {
+ return MonotonicityType::Invariant;
+ }
+
+ // TODO: Handle more cases.
+ MonotonicityType visitAddExpr(const SCEVAddExpr *Expr) {
+ return checkInvarianceOnly(Expr);
+ }
+ MonotonicityType visitMulExpr(const SCEVMulExpr *Expr) {
+ return checkInvarianceOnly(Expr);
+ }
----------------
kasuga-fj wrote:
Removed support for `SCEVAddExpr` and `SCEVMulExpr` in e83fdb8723f45a53ea4400dcff6e0dddee0c3106. The rationale is as follows:
- This logic can conflict with inference based [GEP attributes](https://github.com/llvm/llvm-project/blob/a0987435560700b6dff04f866910b942956286e2/llvm/lib/Analysis/DependenceAnalysis.cpp#L3418-L3441), which is the reused logic from LoopAccessAnalysis. For instance, if the given SCEV is `%m * {0,+,%n}<%loop>`, I think this reasoning is not valid (but if it is `{0,+,(%m * %n)}<%loop>`, it seems valid). Additionally, I found leveraging GEP attributes is beneficial -- removing this logic caused some tests to fail, which seems non-trivial at a glance. At least, as a first step, I feel it's reasonable to remove these handlings for add/mul and leave the reasoning to GEP attributes.
- Even without the GEP based inference, I think handling `SCEVAddExpr` and `SCEVMulExpr` is non-trivial. For example, in the case of `{0,+,1}<%loop> + {0,+,-1}<%loop>` (apparently, [this could happen](https://github.com/llvm/llvm-project/pull/154527#discussion_r2301036761)), it is unclear whether this should be considered Monotonic or Invariant.
Removing the support caused some test regressions, but all failures were of the form like `[* *]` becoming `confused`. I believe the semantic impact of these changes is essentially negligible.
https://github.com/llvm/llvm-project/pull/154527
More information about the llvm-commits
mailing list