[Mlir-commits] [mlir] [mlir][Linalg] Fix init operand read detection for linalg.map (PR #221330)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Fri Sep 4 12:58:33 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir

Author: Bhavesh M (beamandala)

<details>
<summary>Changes</summary>

Fix `MapOp::payloadUsesValueFromOperand` to also check reads on `linalg::MapOp` init operands instead of assuming they're write only. This caused one-shot bufferization to omit a required copy when the payload reads the initial value. Without the copy the payload instead reads from an uninitialized buffer resulting in undefined behavior.

Fixes #<!-- -->213241

---
Full diff: https://github.com/llvm/llvm-project/pull/221330.diff


2 Files Affected:

- (modified) mlir/include/mlir/Dialect/Linalg/IR/LinalgStructuredOps.td (-1) 
- (modified) mlir/test/Dialect/Linalg/bufferize.mlir (+39) 


``````````diff
diff --git a/mlir/include/mlir/Dialect/Linalg/IR/LinalgStructuredOps.td b/mlir/include/mlir/Dialect/Linalg/IR/LinalgStructuredOps.td
index 51bfcbec5d1a4..589b35e45a815 100644
--- a/mlir/include/mlir/Dialect/Linalg/IR/LinalgStructuredOps.td
+++ b/mlir/include/mlir/Dialect/Linalg/IR/LinalgStructuredOps.td
@@ -290,7 +290,6 @@ def MapOp : LinalgStructuredBase_Op<"map", [
     MutableOperandRange getDpsInitsMutable() { return getInitMutable(); }
 
     bool payloadUsesValueFromOperand(OpOperand * opOperand) {
-      if (isDpsInit(opOperand)) return false;
       return !getMatchingBlockArgument(opOperand).use_empty();
     }
 
diff --git a/mlir/test/Dialect/Linalg/bufferize.mlir b/mlir/test/Dialect/Linalg/bufferize.mlir
index 7b1af139f0f3e..b18448840bd8e 100644
--- a/mlir/test/Dialect/Linalg/bufferize.mlir
+++ b/mlir/test/Dialect/Linalg/bufferize.mlir
@@ -162,6 +162,45 @@ func.func @generic_with_init_tensor(%arg0: tensor<2x3x4xvector<3x4xi4>>,
 
 // -----
 
+// Test that an init operand that is read by the map payload is copied.
+
+// CHECK-LABEL: func @map_with_read_from_init(
+// CHECK-SAME:      %[[INIT:.*]]: tensor<4xf32>, %[[BUFFER:.*]]: memref<f32>)
+// CHECK:         %[[INIT_BUFFER:.*]] = bufferization.to_buffer %[[INIT]] : tensor<4xf32> to memref<4xf32>
+// CHECK:         %[[RESULT_BUFFER:.*]] = memref.alloc() {{.*}} : memref<4xf32>
+// CHECK:         memref.copy %[[INIT_BUFFER]], %[[RESULT_BUFFER]] : memref<4xf32> to memref<4xf32>
+// CHECK:         linalg.map outs(%[[RESULT_BUFFER]] : memref<4xf32>)
+// CHECK-NEXT:      (%[[OUT:.*]]: f32) {
+// CHECK:           memref.store %[[OUT]], %[[BUFFER]][] : memref<f32>
+func.func @map_with_read_from_init(%init: tensor<4xf32>,
+                                   %buffer: memref<f32>) -> tensor<4xf32> {
+  %cst = arith.constant 0.0 : f32
+  %mapped = linalg.map outs(%init : tensor<4xf32>) (%out: f32) {
+    memref.store %out, %buffer[] : memref<f32>
+    linalg.yield %cst : f32
+  }
+  return %mapped : tensor<4xf32>
+}
+
+// -----
+
+// Test that an init operand that isn't read by the map payload isn't copied.
+
+// CHECK-LABEL: func @map_without_read_from_init(
+// CHECK-SAME:      %{{.*}}: tensor<4xf32>)
+// CHECK:         %[[RESULT_BUFFER:.*]] = memref.alloc() {{.*}} : memref<4xf32>
+// CHECK-NOT:     memref.copy
+// CHECK:         linalg.map outs(%[[RESULT_BUFFER]] : memref<4xf32>)
+func.func @map_without_read_from_init(%init: tensor<4xf32>) -> tensor<4xf32> {
+  %cst = arith.constant 0.0 : f32
+  %mapped = linalg.map outs(%init : tensor<4xf32>) (%out: f32) {
+    linalg.yield %cst : f32
+  }
+  return %mapped : tensor<4xf32>
+}
+
+// -----
+
 // CHECK-LABEL: func @bufferize_fill(
 // CHECK-SAME:    %[[IN:.*]]: tensor<?xf32>
 func.func @bufferize_fill(%arg0: tensor<?xf32>) -> tensor<?xf32> {

``````````

</details>


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


More information about the Mlir-commits mailing list