[Mlir-commits] [mlir] [MLIR][affine] Prevent illegal loop fusion with different-sized vector types (PR #178726)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Sat Jan 31 01:10:41 PST 2026


https://github.com/rishabhmadan19 updated https://github.com/llvm/llvm-project/pull/178726

>From ac5dc66c74a36425bc2e0f49fe35e5e11bdc5e9e Mon Sep 17 00:00:00 2001
From: rishabhmadan19 <rishabhkec at gmail.com>
Date: Fri, 30 Jan 2026 00:24:49 +0530
Subject: [PATCH 1/2] Fixes #115849 [MLIR][affine] Prevent illegal loop fusion
 with different-sized vector types

---
 .../Affine/loop-fusion-vector-type-check.mlir | 63 +++++++++++++++++++
 1 file changed, 63 insertions(+)
 create mode 100644 mlir/test/Dialect/Affine/loop-fusion-vector-type-check.mlir

diff --git a/mlir/test/Dialect/Affine/loop-fusion-vector-type-check.mlir b/mlir/test/Dialect/Affine/loop-fusion-vector-type-check.mlir
new file mode 100644
index 0000000000000..2f21d6df62fa8
--- /dev/null
+++ b/mlir/test/Dialect/Affine/loop-fusion-vector-type-check.mlir
@@ -0,0 +1,63 @@
+// RUN: mlir-opt --pass-pipeline='builtin.module(affine-loop-fusion)' %s | FileCheck %s
+
+// Test that fusion is prevented when producer and consumer access different-sized vector types
+// This is a regression test for issue #115849
+
+// CHECK-LABEL: func.func @illegal_fusion_different_vector_sizes
+func.func @illegal_fusion_different_vector_sizes(%a: memref<64x512xf32>, %b: memref<64x512xf32>, %c: memref<64x512xf32>, %d: memref<64x4096xf32>, %e: memref<64x4096xf32>) {
+  // The two loops should NOT be fused because they access different vector sizes
+  // First loop writes vector<64x64xf32>, second loop reads vector<64x512xf32>
+  
+  // CHECK: affine.for %[[IV1:.*]] = 0 to 8 {
+  // CHECK:   affine.vector_store %{{.*}}, %{{.*}}[0, %[[IV1]] * 64] : memref<64x512xf32>, vector<64x64xf32>
+  // CHECK: }
+  // CHECK: affine.for %[[IV2:.*]] = 0 to 8 {
+  // CHECK:   affine.vector_load %{{.*}}[0, 0] : memref<{{.*}}>, vector<64x512xf32>
+  // CHECK:   affine.vector_store %{{.*}}, %{{.*}}[0, %[[IV2]] * 512] : memref<64x4096xf32>, vector<64x512xf32>
+  // CHECK: }
+  affine.for %j = 0 to 8 {
+    %lhs = affine.vector_load %a[0, %j * 64] : memref<64x512xf32>, vector<64x64xf32>
+    %rhs = affine.vector_load %b[0, %j * 64] : memref<64x512xf32>, vector<64x64xf32>
+    %res = arith.addf %lhs, %rhs : vector<64x64xf32>
+    affine.vector_store %res, %c[0, %j * 64] : memref<64x512xf32>, vector<64x64xf32>
+  }
+
+  affine.for %j = 0 to 8 {
+    %lhs = affine.vector_load %c[0, 0] : memref<64x512xf32>, vector<64x512xf32>
+    %rhs = affine.vector_load %d[0, %j * 512] : memref<64x4096xf32>, vector<64x512xf32>
+    %res = arith.subf %lhs, %rhs : vector<64x512xf32>
+    affine.vector_store %res, %d[0, %j * 512] : memref<64x4096xf32>, vector<64x512xf32>
+  }
+
+  func.return
+}
+
+// Test that fusion still works when vector sizes match
+// CHECK-LABEL: func.func @legal_fusion_same_vector_sizes
+func.func @legal_fusion_same_vector_sizes(%a: memref<64x512xf32>, %b: memref<64x512xf32>, %c: memref<64x512xf32>) {
+  // These loops should be fused because they use the same vector size
+  
+  // CHECK: affine.for %[[IV:.*]] = 0 to 8 {
+  // CHECK:   arith.addf
+  // CHECK:   affine.vector_store %{{.*}}, %{{.*}}[0, %[[IV]] * 64] : memref<64x512xf32>, vector<64x64xf32>
+  // CHECK:   affine.vector_load %{{.*}}[0, %[[IV]] * 64] : memref<64x512xf32>, vector<64x64xf32>
+  // CHECK:   arith.mulf
+  // CHECK:   affine.vector_store %{{.*}}, %{{.*}}[0, %[[IV]] * 64] : memref<64x512xf32>, vector<64x64xf32>
+  // CHECK: }
+  // CHECK-NOT: affine.for
+  affine.for %j = 0 to 8 {
+    %lhs = affine.vector_load %a[0, %j * 64] : memref<64x512xf32>, vector<64x64xf32>
+    %rhs = affine.vector_load %b[0, %j * 64] : memref<64x512xf32>, vector<64x64xf32>
+    %res = arith.addf %lhs, %rhs : vector<64x64xf32>
+    affine.vector_store %res, %c[0, %j * 64] : memref<64x512xf32>, vector<64x64xf32>
+  }
+
+  affine.for %j = 0 to 8 {
+    %lhs = affine.vector_load %c[0, %j * 64] : memref<64x512xf32>, vector<64x64xf32>
+    %rhs = affine.vector_load %b[0, %j * 64] : memref<64x512xf32>, vector<64x64xf32>
+    %res = arith.mulf %lhs, %rhs : vector<64x64xf32>
+    affine.vector_store %res, %c[0, %j * 64] : memref<64x512xf32>, vector<64x64xf32>
+  }
+
+  func.return
+}
\ No newline at end of file

>From 68a70e3cffdb3c78fea5d162720a5aec66ff24bc Mon Sep 17 00:00:00 2001
From: rishabhmadan19 <rishabhkec at gmail.com>
Date: Fri, 30 Jan 2026 00:30:50 +0530
Subject: [PATCH 2/2] Fixes #115849 Added Utils.cpp

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

diff --git a/mlir/lib/Dialect/Affine/Analysis/Utils.cpp b/mlir/lib/Dialect/Affine/Analysis/Utils.cpp
index 92d8846a4640d..75e98ca11d92f 100644
--- a/mlir/lib/Dialect/Affine/Analysis/Utils.cpp
+++ b/mlir/lib/Dialect/Affine/Analysis/Utils.cpp
@@ -1648,6 +1648,23 @@ mlir::affine::computeSliceUnion(ArrayRef<Operation *> opsA,
       dstAccess = MemRefAccess(b);
       if (srcAccess.memref != dstAccess.memref)
         continue;
+
+      // Bailout if producer and consumer access different-sized element types.
+      // This prevents illegal fusion when vector types have different shapes.
+      Type srcElementType =
+          cast<MemRefType>(srcAccess.memref.getType()).getElementType();
+      Type dstElementType =
+          cast<MemRefType>(dstAccess.memref.getType()).getElementType();
+      if (auto srcVecType = dyn_cast<VectorType>(srcElementType)) {
+        if (auto dstVecType = dyn_cast<VectorType>(dstElementType)) {
+          if (srcVecType.getShape() != dstVecType.getShape()) {
+            LDBG() << "Cannot fuse: different vector element sizes in "
+                      "producer/consumer";
+            return SliceComputationResult::GenericFailure;
+          }
+        }
+      }
+
       // Check if 'loopDepth' exceeds nesting depth of src/dst ops.
       if ((!isBackwardSlice && loopDepth > getNestingDepth(a)) ||
           (isBackwardSlice && loopDepth > getNestingDepth(b))) {



More information about the Mlir-commits mailing list