[llvm] Redesign Straight-Line Strength Reduction (SLSR) (PR #162930)

Drew Kersnar via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 20 13:43:39 PDT 2025


================
@@ -177,22 +203,164 @@ class StraightLineStrengthReduce {
     // Points to the immediate basis of this candidate, or nullptr if we cannot
     // find any basis for this candidate.
     Candidate *Basis = nullptr;
+
+    DKind DeltaKind = InvalidDelta;
+
+    // Store SCEV of Stride to compute delta from different strides
+    const SCEV *StrideSCEV = nullptr;
+
+    // Points to (Y - X) that will be used to rewrite this candidate.
+    Value *Delta = nullptr;
+
+    /// Cost model: Evaluate the computational efficiency of the candidate.
+    ///
+    /// Efficiency levels (higher is better):
+    ///   ZeroInst (5) - [Variable] or [Const]
+    ///   OneInstOneVar (4) - [Variable + Const] or [Variable * Const]
+    ///   OneInstTwoVar (3) - [Variable + Variable] or [Variable * Variable]
+    ///   TwoInstOneVar (2) - [Const + Const * Variable]
+    ///   TwoInstTwoVar (1) - [Variable + Const * Variable]
+    enum EfficiencyLevel : unsigned {
+      Unknown = 0,
+      TwoInstTwoVar = 1,
+      TwoInstOneVar = 2,
+      OneInstTwoVar = 3,
+      OneInstOneVar = 4,
+      ZeroInst = 5
+    };
+
+    static EfficiencyLevel
+    getComputationEfficiency(Kind CandidateKind, const ConstantInt *Index,
+                             const Value *Stride, const SCEV *Base = nullptr) {
+      bool IsConstantBase = false;
+      bool IsZeroBase = false;
+      // When evaluating the efficiency of a rewrite, if the Basis's SCEV is
+      // not available, conservatively assume the base is not constant.
+      if (auto *ConstBase = dyn_cast_or_null<SCEVConstant>(Base)) {
+        IsConstantBase = true;
+        IsZeroBase = ConstBase->getValue()->isZero();
+      }
+
+      bool IsConstantStride = isa<ConstantInt>(Stride);
+      bool IsZeroStride =
+          IsConstantStride && cast<ConstantInt>(Stride)->isZero();
+      // All constants
+      if (IsConstantBase && IsConstantStride)
+        return ZeroInst;
+
+      // [(Base + Index) * Stride]
+      if (CandidateKind == Mul) {
+        if (IsZeroStride)
+          return ZeroInst;
+        if (Index->isZero())
+          return (IsConstantStride || IsConstantBase) ? OneInstOneVar
+                                                      : OneInstTwoVar;
+
+        if (IsConstantBase)
+          return IsZeroBase && (Index->isOne() || Index->isMinusOne())
+                     ? ZeroInst
+                     : OneInstOneVar;
+
+        if (IsConstantStride) {
+          auto *CI = cast<ConstantInt>(Stride);
+          return (CI->isOne() || CI->isMinusOne()) ? OneInstOneVar
+                                                   : TwoInstOneVar;
+        }
+        return TwoInstTwoVar;
+      }
+
+      // Base + Index * Stride
+      assert(CandidateKind == Add || CandidateKind == GEP);
+      if (Index->isZero() || IsZeroStride)
+        return ZeroInst;
+
+      bool IsSimpleIndex = Index->isOne() || Index->isMinusOne();
+
+      if (IsConstantBase)
+        return IsZeroBase ? (IsSimpleIndex ? ZeroInst : OneInstOneVar)
+                          : (IsSimpleIndex ? OneInstOneVar : TwoInstOneVar);
+
+      if (IsConstantStride)
+        return IsZeroStride ? ZeroInst : OneInstOneVar;
+
+      if (IsSimpleIndex)
+        return OneInstTwoVar;
+
+      return TwoInstTwoVar;
+    }
+
+    // Evaluate if the given delta is profitable to rewrite this candidate.
+    bool isProfitableRewrite(const Value *Delta, const DKind DeltaKind) const {
+      // This function cannot accurately evaluate the profit of whole expression
+      // with context. A candidate (B + I * S) cannot express whether this
+      // instruction needs to compute on its own (I * S), which may be shared
+      // with other candidates or may need instructions to compute.
+      // If the rewritten form has the same strength, still rewrite to
+      // (X + Delta) since it may expose more CSE opportunities on Delta, as
+      // unrolled loops usually have identical Delta for each unrolled body.
+      //
+      // Note, this function should only be used on Index Delta rewrite.
+      // Base and Stride delta need context info to evaluate the register
+      // pressure impact from variable delta.
+      return getComputationEfficiency(CandidateKind, Index, Stride, Base) <=
+             getRewriteProfit(Delta, DeltaKind);
+    }
+
+    // Evaluate the rewrite profit of this candidate with its Basis
+    EfficiencyLevel getRewriteProfit() const {
----------------
dakersnar wrote:

nit: Maybe rename these to `getRewriteEfficiency`? "Profit" feels like should represents the _difference_ between the current computation efficiency and the rewrite computation efficiency.

https://github.com/llvm/llvm-project/pull/162930


More information about the llvm-commits mailing list