[Mlir-commits] [mlir] [MLIR][Affine] Avoid crash on non-affine memory effects (PR #205865)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Thu Jun 25 21:10:54 PDT 2026


https://github.com/mygitljf updated https://github.com/llvm/llvm-project/pull/205865

>From da3c4ce0e725f5da156340d9802d2b918c7acca8 Mon Sep 17 00:00:00 2001
From: mygitljf <2410316423 at qq.com>
Date: Fri, 26 Jun 2026 00:57:17 +0000
Subject: [PATCH 1/2] [MLIR][Affine] Handle memory effects

---
 mlir/lib/Dialect/Affine/Analysis/Utils.cpp | 28 +++++++++++-----------
 mlir/test/Dialect/Affine/loop-fusion.mlir  | 25 ++++++++++++++++++-
 2 files changed, 38 insertions(+), 15 deletions(-)

diff --git a/mlir/lib/Dialect/Affine/Analysis/Utils.cpp b/mlir/lib/Dialect/Affine/Analysis/Utils.cpp
index cac305df8ba75..4aa419e5e81bc 100644
--- a/mlir/lib/Dialect/Affine/Analysis/Utils.cpp
+++ b/mlir/lib/Dialect/Affine/Analysis/Utils.cpp
@@ -243,17 +243,18 @@ addNodeToMDG(Operation *nodeOp, MemRefDependenceGraph &mdg,
   return &node;
 }
 
-/// Returns the memref being read/written by a memref/affine load/store op.
-static Value getMemRef(Operation *memOp) {
-  if (auto memrefLoad = dyn_cast<memref::LoadOp>(memOp))
-    return memrefLoad.getMemRef();
-  if (auto affineLoad = dyn_cast<AffineReadOpInterface>(memOp))
-    return affineLoad.getMemRef();
-  if (auto memrefStore = dyn_cast<memref::StoreOp>(memOp))
-    return memrefStore.getMemRef();
-  if (auto affineStore = dyn_cast<AffineWriteOpInterface>(memOp))
-    return affineStore.getMemRef();
-  llvm_unreachable("unexpected op");
+static bool mayAccessMemRef(Operation *op, Value memref) {
+  if (auto affineRead = dyn_cast<AffineReadOpInterface>(op))
+    return affineRead.getMemRef() == memref;
+  if (auto affineWrite = dyn_cast<AffineWriteOpInterface>(op))
+    return affineWrite.getMemRef() == memref;
+  if (hasEffect<MemoryEffects::Read>(op, memref) ||
+      hasEffect<MemoryEffects::Write>(op, memref))
+    return true;
+  if (isa<MemoryEffectOpInterface>(op) ||
+      op->hasTrait<OpTrait::HasRecursiveMemoryEffects>())
+    return false;
+  return llvm::is_contained(op->getOperands(), memref);
 }
 
 /// Returns true if there may be a dependence on `memref` from srcNode's
@@ -276,11 +277,10 @@ static bool mayDependence(const Node &srcNode, const Node &dstNode,
   auto hasNonAffineDep = [&](ArrayRef<Operation *> srcMemOps,
                              ArrayRef<Operation *> dstMemOps) {
     return llvm::any_of(srcMemOps, [&](Operation *srcOp) {
-      Value srcMemref = getMemRef(srcOp);
-      if (srcMemref != memref)
+      if (!mayAccessMemRef(srcOp, memref))
         return false;
       return llvm::find_if(dstMemOps, [&](Operation *dstOp) {
-               return srcMemref == getMemRef(dstOp);
+               return mayAccessMemRef(dstOp, memref);
              }) != dstMemOps.end();
     });
   };
diff --git a/mlir/test/Dialect/Affine/loop-fusion.mlir b/mlir/test/Dialect/Affine/loop-fusion.mlir
index 1ea42517988c3..3eb3e09bb61fb 100644
--- a/mlir/test/Dialect/Affine/loop-fusion.mlir
+++ b/mlir/test/Dialect/Affine/loop-fusion.mlir
@@ -13,6 +13,30 @@
 
 // -----
 
+// CHECK-LABEL: func @non_affine_memory_effect_in_loop_does_not_crash(
+func.func @non_affine_memory_effect_in_loop_does_not_crash(%arg0: memref<8xf32>) {
+  %0 = builtin.unrealized_conversion_cast %arg0 : memref<8xf32> to !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
+  %c0 = arith.constant 0 : index
+  affine.for %i = 0 to 8 {
+    %1 = builtin.unrealized_conversion_cast %i : index to i64
+    %2 = llvm.extractvalue %0[1] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
+    %3 = llvm.getelementptr %2[%1] : (!llvm.ptr, i64) -> !llvm.ptr, f32
+    %4 = llvm.load %3 : !llvm.ptr -> f32
+    affine.store %4, %arg0[%c0] : memref<8xf32>
+  }
+  affine.for %i = 0 to 8 {
+    %1 = builtin.unrealized_conversion_cast %i : index to i64
+    %2 = llvm.extractvalue %0[1] : !llvm.struct<(ptr, ptr, i64, array<1 x i64>, array<1 x i64>)>
+    %3 = llvm.getelementptr %2[%1] : (!llvm.ptr, i64) -> !llvm.ptr, f32
+    %4 = llvm.load %3 : !llvm.ptr -> f32
+    affine.store %4, %arg0[%c0] : memref<8xf32>
+  }
+  // CHECK: return
+  return
+}
+
+// -----
+
 // CHECK-LABEL: func @should_fuse_raw_dep_for_locality() {
 func.func @should_fuse_raw_dep_for_locality() {
   %m = memref.alloc() : memref<10xf32>
@@ -1575,4 +1599,3 @@ func.func @producer_consumer_with_outmost_user(%arg0 : f16) {
 }
 
 // Add further tests in mlir/test/Transforms/loop-fusion-4.mlir
-

>From a1636e345275746ac2838334df47421863dba84a Mon Sep 17 00:00:00 2001
From: mygitljf <2410316423 at qq.com>
Date: Fri, 26 Jun 2026 12:13:17 +0000
Subject: [PATCH 2/2] [MLIR][Affine] Document memref access check

---
 mlir/lib/Dialect/Affine/Analysis/Utils.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/mlir/lib/Dialect/Affine/Analysis/Utils.cpp b/mlir/lib/Dialect/Affine/Analysis/Utils.cpp
index 4aa419e5e81bc..9620c9d4693cc 100644
--- a/mlir/lib/Dialect/Affine/Analysis/Utils.cpp
+++ b/mlir/lib/Dialect/Affine/Analysis/Utils.cpp
@@ -243,6 +243,10 @@ addNodeToMDG(Operation *nodeOp, MemRefDependenceGraph &mdg,
   return &node;
 }
 
+/// Returns whether `op` may read from or write to `memref`.
+/// Memory effects are used when available; recursively-effectful ops are
+/// handled through their nested operations. Otherwise, conservatively treat a
+/// memref operand as a possible access, which may add dependence edges.
 static bool mayAccessMemRef(Operation *op, Value memref) {
   if (auto affineRead = dyn_cast<AffineReadOpInterface>(op))
     return affineRead.getMemRef() == memref;



More information about the Mlir-commits mailing list