From 80853a16738f457c1706234048636d9aebf36944 Mon Sep 17 00:00:00 2001 From: Matthias Springer Date: Wed, 14 Jun 2023 09:31:13 +0200 Subject: [PATCH] [mlir][vector][bufferize] Better analysis for vector.transfer_write The destination operand does not bufferize to a memory read if it is completely overwritten. Differential Revision: https://reviews.llvm.org/D152823 --- .../Transforms/BufferizableOpInterfaceImpl.cpp | 31 ++++++++++++++++++++++ mlir/test/Dialect/Vector/one-shot-bufferize.mlir | 20 ++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/mlir/lib/Dialect/Vector/Transforms/BufferizableOpInterfaceImpl.cpp b/mlir/lib/Dialect/Vector/Transforms/BufferizableOpInterfaceImpl.cpp index ad7e367..a8ed4d3 100644 --- a/mlir/lib/Dialect/Vector/Transforms/BufferizableOpInterfaceImpl.cpp +++ b/mlir/lib/Dialect/Vector/Transforms/BufferizableOpInterfaceImpl.cpp @@ -71,6 +71,37 @@ struct TransferReadOpInterface struct TransferWriteOpInterface : public DstBufferizableOpInterfaceExternalModel { + bool bufferizesToMemoryRead(Operation *op, OpOperand &opOperand, + const AnalysisState &state) const { + auto writeOp = cast(op); + + // Does not bufferize to a memory read if the vector completely overwrites + // the buffer. + + // Destination must have static shape. + if (!writeOp.getShapedType().hasStaticShape()) + return true; + + // All offsets must be 0. + for (Value offset : writeOp.getIndices()) { + if (getConstantIntValue(offset) != 0) + return true; + } + + // There is no mask. + if (writeOp.isMasked()) + return true; + + // Must write at least the full dimension size. + for (auto [d0, d1] : llvm::zip(writeOp.getShapedType().getShape(), + writeOp.getVectorType().getShape())) { + if (d0 > d1) + return true; + } + + return false; + } + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, const BufferizationOptions &options) const { auto writeOp = cast(op); diff --git a/mlir/test/Dialect/Vector/one-shot-bufferize.mlir b/mlir/test/Dialect/Vector/one-shot-bufferize.mlir index 738be1a..64238c3 100644 --- a/mlir/test/Dialect/Vector/one-shot-bufferize.mlir +++ b/mlir/test/Dialect/Vector/one-shot-bufferize.mlir @@ -1,4 +1,5 @@ // RUN: mlir-opt %s -one-shot-bufferize="bufferize-function-boundaries" -split-input-file | FileCheck %s +// RUN: mlir-opt %s -one-shot-bufferize="bufferize-function-boundaries test-analysis-only" -split-input-file | FileCheck %s -check-prefix=CHECK-ANALYSIS // CHECK-LABEL: func @mask( // CHECK-SAME: %[[t0:.*]]: memref> @@ -10,3 +11,22 @@ func.func @mask(%t0: tensor, %val: vector<16xf32>, %idx: index, %m0: vect // CHECK: return %[[t0]] return %0 : tensor } + +// ----- + +// CHECK-ANALYSIS-LABEL: func @non_reading_xfer_write( +// CHECK-ANALYSIS-SAME: tensor<5x10xf32> {bufferization.access = "write"} +func.func @non_reading_xfer_write(%t: tensor<5x10xf32>, %v: vector<6x11xf32>) -> tensor<5x10xf32> { + %c0 = arith.constant 0 : index + %1 = vector.transfer_write %v, %t[%c0, %c0] : vector<6x11xf32>, tensor<5x10xf32> + return %1 : tensor<5x10xf32> +} +// ----- + +// CHECK-ANALYSIS-LABEL: func @reading_xfer_write( +// CHECK-ANALYSIS-SAME: tensor<5x10xf32> {bufferization.access = "read-write"} +func.func @reading_xfer_write(%t: tensor<5x10xf32>, %v: vector<4x11xf32>) -> tensor<5x10xf32> { + %c0 = arith.constant 0 : index + %1 = vector.transfer_write %v, %t[%c0, %c0] : vector<4x11xf32>, tensor<5x10xf32> + return %1 : tensor<5x10xf32> +} -- 2.7.4