[Mlir-commits] [mlir] [mlir][tensor][bufferization] Preserve memory space for tensor.concat (PR #213528)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Sun Aug 2 04:09:41 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir
Author: HyunJun (Bammuri)
<details>
<summary>Changes</summary>
## Summary
- query the buffer type of the destination `alloc_tensor` when bufferizing `tensor.concat`
- pass the complete type to `ToBufferOp` instead of reconstructing a default-memory-space `MemRefType`
- add an encoding-based regression test for a non-default destination memory space
## Background
`ConcatOpInterface` allocates its destination through `allocateTensorForShapedValue`. The resulting `alloc_tensor` may bufferize to a memref in a non-default memory space. The implementation then manually reconstructed the destination `MemRefType` without a memory-space attribute.
This could make `ToBufferOp` observe a non-default-space source buffer and a default-space requested result type. Since those types cannot be reconciled with `memref.cast`, bufferization could introduce an additional default-space allocation and a full-result copy. The input-to-subview copies that implement the concat itself are still required.
The existing `defaultMemorySpaceFn` guard is not sufficient because the actual buffer type may be selected through another type-conversion hook. Querying `getBufferType(*tensorAlloc, options, state)` uses the authoritative type of the allocation and also preserves other type information such as layout.
## Testing
- `ninja -j3 tools/mlir/lib/Dialect/Tensor/Transforms/CMakeFiles/obj.MLIRTensorTransforms.dir/BufferizableOpInterfaceImpl.cpp.o`
- `llvm-lit -v mlir/test/Dialect/Tensor/one-shot-bufferize-encodings.mlir mlir/test/Dialect/Tensor/bufferize.mlir`
Both lit tests pass.
---
Full diff: https://github.com/llvm/llvm-project/pull/213528.diff
2 Files Affected:
- (modified) mlir/lib/Dialect/Tensor/Transforms/BufferizableOpInterfaceImpl.cpp (+6-12)
- (modified) mlir/test/Dialect/Tensor/one-shot-bufferize-encodings.mlir (+21)
``````````diff
diff --git a/mlir/lib/Dialect/Tensor/Transforms/BufferizableOpInterfaceImpl.cpp b/mlir/lib/Dialect/Tensor/Transforms/BufferizableOpInterfaceImpl.cpp
index 525d57341cee5..930f0663e2ab8 100644
--- a/mlir/lib/Dialect/Tensor/Transforms/BufferizableOpInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/Tensor/Transforms/BufferizableOpInterfaceImpl.cpp
@@ -1119,18 +1119,12 @@ struct ConcatOpInterface
if (failed(tensorAlloc))
return failure();
auto tensorType = cast<RankedTensorType>(tensorAlloc->getType());
-
- // TODO: Implement memory space for this op.
- if (options.defaultMemorySpaceFn(cast<TensorLikeType>(tensorType)) !=
- Attribute())
- return op->emitError("memory space not implemented yet");
-
- MemRefLayoutAttrInterface layout;
- MemRefType memrefType =
- MemRefType::get(concatOp.getResultType().getShape(),
- concatOp.getResultType().getElementType(), layout);
+ FailureOr<BufferLikeType> memrefType =
+ bufferization::getBufferType(*tensorAlloc, options, state);
+ if (failed(memrefType))
+ return failure();
Value dstBuffer = bufferization::ToBufferOp::create(
- rewriter, op->getLoc(), memrefType, *tensorAlloc);
+ rewriter, op->getLoc(), *memrefType, *tensorAlloc);
// Extract the dimension for the concat op
uint64_t concatDim = concatOp.getDim();
@@ -1166,7 +1160,7 @@ struct ConcatOpInterface
sizes[concatDim] = concatDimSize;
// Create a subview of the destination buffer.
- auto dstMemrefType = cast<MemRefType>(memrefType);
+ auto dstMemrefType = cast<MemRefType>(*memrefType);
MemRefType subviewMemRefType =
memref::SubViewOp::inferRankReducedResultType(
operandTensorType.getShape(), dstMemrefType, offsets, sizes,
diff --git a/mlir/test/Dialect/Tensor/one-shot-bufferize-encodings.mlir b/mlir/test/Dialect/Tensor/one-shot-bufferize-encodings.mlir
index 7398fdf614e1a..5dc301d7f2310 100644
--- a/mlir/test/Dialect/Tensor/one-shot-bufferize-encodings.mlir
+++ b/mlir/test/Dialect/Tensor/one-shot-bufferize-encodings.mlir
@@ -18,3 +18,24 @@ func.func @from_elements(%fill: f32, %f: f32, %idx: index) -> tensor<3xf32, 1> {
// CHECK: memref.store %[[arg1]], %[[alloc]][%[[arg2]]] : memref<3xf32, 1>
// CHECK: %[[v0:.+]] = bufferization.to_tensor %[[alloc]] : memref<3xf32, 1> to tensor<3xf32, 1 : i64>
// CHECK: return %[[v0]] : tensor<3xf32, 1 : i64>
+
+// -----
+
+func.func @concat_memory_space(%arg0: tensor<8xf32, 1>,
+ %arg1: tensor<8xf32, 1>) -> tensor<16xf32, 1> {
+ %0 = tensor.concat dim(0) %arg0, %arg1
+ : (tensor<8xf32, 1>, tensor<8xf32, 1>) -> tensor<16xf32, 1>
+ return %0 : tensor<16xf32, 1>
+}
+
+// CHECK-LABEL: @concat_memory_space
+// CHECK-SAME: (%[[ARG0:.+]]: tensor<8xf32, 1 : i64>, %[[ARG1:.+]]: tensor<8xf32, 1 : i64>)
+// CHECK-DAG: %[[BUFFER0:.+]] = bufferization.to_buffer %[[ARG0]]
+// CHECK-DAG: %[[BUFFER1:.+]] = bufferization.to_buffer %[[ARG1]]
+// CHECK: %[[ALLOC:.+]] = memref.alloc() {{.*}} : memref<16xf32, 1>
+// CHECK: %[[SUBVIEW0:.+]] = memref.subview %[[ALLOC]][0] [8] [1]
+// CHECK: memref.copy %[[BUFFER0]], %[[SUBVIEW0]]
+// CHECK: %[[SUBVIEW1:.+]] = memref.subview %[[ALLOC]][8] [8] [1]
+// CHECK: memref.copy %[[BUFFER1]], %[[SUBVIEW1]]
+// CHECK: %[[RESULT:.+]] = bufferization.to_tensor %[[ALLOC]]
+// CHECK: return %[[RESULT]] : tensor<16xf32, 1 : i64>
``````````
</details>
https://github.com/llvm/llvm-project/pull/213528
More information about the Mlir-commits
mailing list