[Mlir-commits] [mlir] [mlir][affine] Add arith.subi support to memref to affine raise (PR #222880)

Mattéo Rizza Murgier llvmlistbot at llvm.org
Fri Sep 11 01:16:58 PDT 2026


https://github.com/matteo-rm created https://github.com/llvm/llvm-project/pull/222880

This PR adds support for `arith.subi` to `toAffineExpr` to e.g. allow matching expressions like `i-1` which appear with one-indexed arrays.

>From 0e0b98bdcd3db131778d867c9e1e8079d14f6def Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Matt=C3=A9o=20Rizza=20Murgier?=
 <matteo.rizza-murgier at sipearl.com>
Date: Wed, 9 Sep 2026 20:10:41 +0200
Subject: [PATCH] [mlir][affine] Add arith.subi support to memref to affine
 raise

---
 .../Affine/Transforms/RaiseMemrefDialect.cpp  | 15 +++--
 mlir/test/Dialect/Affine/raise-memref.mlir    | 60 ++++++++++++++++++-
 2 files changed, 68 insertions(+), 7 deletions(-)

diff --git a/mlir/lib/Dialect/Affine/Transforms/RaiseMemrefDialect.cpp b/mlir/lib/Dialect/Affine/Transforms/RaiseMemrefDialect.cpp
index 29cc256cb90f9..9c651e9a86910 100644
--- a/mlir/lib/Dialect/Affine/Transforms/RaiseMemrefDialect.cpp
+++ b/mlir/lib/Dialect/Affine/Transforms/RaiseMemrefDialect.cpp
@@ -75,14 +75,14 @@ static AffineExpr toAffineExpr(Value value,
   }
 
   Operation *definingOp = value.getDefiningOp();
-  if (llvm::isa_and_nonnull<arith::AddIOp>(definingOp) ||
-      llvm::isa_and_nonnull<arith::MulIOp>(definingOp)) {
+  if (llvm::isa_and_nonnull<arith::AddIOp, arith::SubIOp, arith::MulIOp>(
+          definingOp)) {
     // TODO: replace recursion with explicit stack.
     // For the moment this can be tolerated as we only recurse on
-    // arith.addi and arith.muli, so there cannot be any infinite
-    // recursion. The depth of these expressions should be in most
-    // cases very manageable, as affine expressions should be as
-    // simple as `a + b * c`.
+    // arith.addi, arith.subi and arith.muli, so there cannot be
+    // any infinite recursion. The depth of these expressions
+    // should be in most cases very manageable, as affine
+    // expressions should be as simple as `a + b * c`.
     AffineExpr lhsE =
         toAffineExpr(definingOp->getOperand(0), affineDims, affineSymbols);
     AffineExpr rhsE =
@@ -92,6 +92,9 @@ static AffineExpr toAffineExpr(Value value,
       AffineExprKind kind;
       if (isa<arith::AddIOp>(definingOp)) {
         kind = mlir::AffineExprKind::Add;
+      } else if (isa<arith::SubIOp>(definingOp)) {
+        kind = mlir::AffineExprKind::Add;
+        rhsE = -rhsE;
       } else {
         kind = mlir::AffineExprKind::Mul;
 
diff --git a/mlir/test/Dialect/Affine/raise-memref.mlir b/mlir/test/Dialect/Affine/raise-memref.mlir
index 8dc24d99db3e2..4f3497999a52f 100644
--- a/mlir/test/Dialect/Affine/raise-memref.mlir
+++ b/mlir/test/Dialect/Affine/raise-memref.mlir
@@ -117,7 +117,6 @@ func.func @symbols(%N : index) {
 // CHECK:                  memref.store %[[lhs5]], %{{.*}}[%[[a1]], %[[lhs7]]] :
 // CHECK:                  affine.yield %[[lhs6]]
 
-
 // CHECK-LABEL:    func @non_affine(
 func.func @non_affine(%N : index) {
   %2 = memref.alloc() : memref<1024x1024xf32>
@@ -136,3 +135,62 @@ func.func @non_affine(%N : index) {
 // CHECK:                  %[[ij:.*]] = arith.muli %[[i]], %[[j]]
 // CHECK:                  %[[v:.*]] = memref.load %{{.*}}[%[[i]], %[[ij]]]
 // CHECK:                  memref.store %[[v]], %{{.*}}[%[[ij]], %[[ij]]]
+
+// CHECK-LABEL:    func @subtract_dims(
+func.func @subtract_dims(%N : index) {
+  %0 = memref.alloc() : memref<1024xf32>
+  affine.for %i = 0 to %N {
+    affine.for %j = 0 to %N {
+      %idx = arith.subi %i, %j : index
+      %v = memref.load %0[%idx] : memref<1024xf32>
+      memref.store %v, %0[%idx] : memref<1024xf32>
+    }
+  }
+  return
+}
+
+// CHECK:          affine.for %[[i:.*]] =
+// CHECK:            affine.for %[[j:.*]] =
+// CHECK:              %[[v:.*]] = affine.load %{{.*}}[%[[i]] - %[[j]]]
+// CHECK:              affine.store %[[v]], %{{.*}}[%[[i]] - %[[j]]]
+// CHECK-NOT:          memref.load
+// CHECK-NOT:          memref.store
+
+// CHECK-LABEL:    func @subtract_constant(
+func.func @subtract_constant(%N : index) {
+  %c1 = arith.constant 1 : index
+  %0 = memref.alloc() : memref<1024xf32>
+  affine.for %i = 1 to %N {
+    %idx = arith.subi %i, %c1 : index
+    %v = memref.load %0[%idx] : memref<1024xf32>
+    memref.store %v, %0[%idx] : memref<1024xf32>
+  }
+  return
+}
+
+// CHECK:          affine.for %[[i:.*]] =
+// CHECK:            %[[v:.*]] = affine.load %{{.*}}[%[[i]] - 1]
+// CHECK:            affine.store %[[v]], %{{.*}}[%[[i]] - 1]
+// CHECK-NOT:        memref.load
+
+// CHECK-LABEL:    func @subtract_from_non_affine(
+func.func @subtract_from_non_affine(%N : index) {
+  %c1 = arith.constant 1 : index
+  %0 = memref.alloc() : memref<1024xf32>
+  affine.for %i = 0 to %N {
+    affine.for %j = 0 to %N {
+      %ij = arith.muli %i, %j : index
+      %idx = arith.subi %ij, %c1 : index
+      %v = memref.load %0[%idx] : memref<1024xf32>
+      memref.store %v, %0[%idx] : memref<1024xf32>
+    }
+  }
+  return
+}
+
+// CHECK:          affine.for %[[i:.*]] =
+// CHECK:            affine.for %[[j:.*]] =
+// CHECK:              %[[ij:.*]] = arith.muli %[[i]], %[[j]]
+// CHECK:              %[[idx:.*]] = arith.subi %[[ij]]
+// CHECK:              %[[v:.*]] = memref.load %{{.*}}[%[[idx]]]
+// CHECK:              memref.store %[[v]], %{{.*}}[%[[idx]]]



More information about the Mlir-commits mailing list