[llvm] [LAA] Add stencil group merging to reduce runtime pointer checks (PR #187252)

Kiran Chandramohan via llvm-commits llvm-commits at lists.llvm.org
Tue May 12 03:26:52 PDT 2026


================
@@ -737,6 +752,367 @@ void RuntimePointerChecking::groupChecks(
   }
 }
 
+/// Result of decomposing a SCEV expression into stencil offset form:
+///   Offset = Constant + sum(Coefficients[stride] * stride)
+/// where each stride is a loop-invariant SCEV expression.
+struct StencilDecomposition {
+  int64_t Constant = 0;
+  /// Map from loop-invariant stride SCEV to its integer coefficient.
+  SmallMapVector<const SCEV *, int64_t, 4> Coefficients;
+};
+
+/// Try to decompose \p Expr into a stencil offset function of loop-invariant
+/// strides: C + a1*s1 + a2*s2 + ...
+/// Relies on SCEV's canonical form: AddExpr operands are flattened,
+/// MulExpr has the constant operand first.
+/// Returns std::nullopt if the expression contains non-stencil terms.
+static std::optional<StencilDecomposition>
+decomposeStencilOffset(const SCEV *Expr, ScalarEvolution &SE, const Loop &L) {
+  StencilDecomposition D;
+
+  // Collect top-level additive terms.
+  SmallVector<const SCEV *, 4> Terms;
+  if (auto *Add = dyn_cast<SCEVAddExpr>(Expr))
+    Terms.append(Add->operands().begin(), Add->operands().end());
+  else
+    Terms.push_back(Expr);
+
+  for (const SCEV *Term : Terms) {
+    if (auto *C = dyn_cast<SCEVConstant>(Term)) {
+      D.Constant += C->getAPInt().getSExtValue();
+    } else if (auto *Mul = dyn_cast<SCEVMulExpr>(Term)) {
+      // SCEV canonical form: constant is operand 0 in a MulExpr.
+      if (Mul->getNumOperands() != 2)
+        return std::nullopt;
+      auto *C = dyn_cast<SCEVConstant>(Mul->getOperand(0));
+      if (!C || !SE.isLoopInvariant(Mul->getOperand(1), &L))
+        return std::nullopt;
+      D.Coefficients[Mul->getOperand(1)] += C->getAPInt().getSExtValue();
+    } else if (SE.isLoopInvariant(Term, &L)) {
+      D.Coefficients[Term] += 1;
+    } else {
+      return std::nullopt;
+    }
+  }
+  return D;
+}
+
+void RuntimePointerChecking::mergeStencilGroups(PredicatedScalarEvolution &PSE,
+                                                Loop &L) {
+  LLVM_DEBUG(dbgs() << "LAA: Attempting stencil group merging on "
+                    << CheckingGroups.size() << " groups\n");
+
+  if (CheckingGroups.size() < 2)
+    return;
+
+  // Count the total checks from current grouping.
+  unsigned TotalChecks = 0;
+  for (unsigned I = 0; I < CheckingGroups.size(); ++I)
+    for (unsigned J = I + 1; J < CheckingGroups.size(); ++J)
+      if (needsChecking(CheckingGroups[I], CheckingGroups[J]))
+        ++TotalChecks;
+
+  if (!EnableStencilMerge && TotalChecks <= StencilMergeCheckThreshold) {
----------------
kiranchandramohan wrote:

Do you intend to enable the pass when (TotalChecks > StencilMergeCheckThreshold) even when the Flag (EnableStencilMerge) is OFF?

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


More information about the llvm-commits mailing list