[mlir][tensor] Make tensor::PadOp a ReifyRankedShapedTypeOpInterface (#145867)
Co-authored-by: Fabian Mora <fmora.dev@gmail.com>
This commit is contained in:
committed by
GitHub
parent
af7166a3f1
commit
e5a8c51c9d
@@ -1256,6 +1256,7 @@ def Tensor_CollapseShapeOp : Tensor_ReassociativeReshapeOp<"collapse_shape"> {
|
||||
|
||||
def Tensor_PadOp : Tensor_Op<"pad", [
|
||||
DeclareOpInterfaceMethods<OpAsmOpInterface, ["getAsmResultNames"]>,
|
||||
DeclareOpInterfaceMethods<ReifyRankedShapedTypeOpInterface>,
|
||||
AttrSizedOperandSegments,
|
||||
Pure,
|
||||
SingleBlockImplicitTerminator<"mlir::tensor::YieldOp">]> {
|
||||
|
||||
@@ -366,9 +366,8 @@ def ReifyRankedShapedTypeOpInterface :
|
||||
|
||||
`reifiedReturnShapes` is populated with one vector per op result. Each
|
||||
of those vectors contains an OpFoldResult for each dimension of the
|
||||
shaped type. In case a dimension in the type is static, the
|
||||
corresponding entry is an IntegerAttr. Otherwise, it is a Value. The
|
||||
given builder may be used to insert ops that compute result shapes.
|
||||
shaped type. The given builder may be used to insert ops that compute
|
||||
result shapes.
|
||||
|
||||
If the shape of a particular result cannot be computed it must be empty.
|
||||
}],
|
||||
|
||||
@@ -7,13 +7,12 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h"
|
||||
#include "mlir/Dialect/Arith/Utils/Utils.h"
|
||||
#include "mlir/Dialect/Bufferization/IR/Bufferization.h"
|
||||
#include "mlir/Dialect/Func/IR/FuncOps.h"
|
||||
#include "mlir/Dialect/MemRef/IR/MemRef.h"
|
||||
#include "mlir/Dialect/Tensor/IR/Tensor.h"
|
||||
#include "mlir/IR/AsmState.h"
|
||||
#include "mlir/IR/BuiltinOps.h"
|
||||
#include "mlir/IR/IRMapping.h"
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "mlir/IR/TypeUtilities.h"
|
||||
#include "mlir/IR/Value.h"
|
||||
@@ -195,9 +194,12 @@ FailureOr<Value> bufferization::allocateTensorForShapedValue(
|
||||
reifiedShapes = true;
|
||||
auto &shape =
|
||||
resultDims[llvm::cast<OpResult>(shapedValue).getResultNumber()];
|
||||
for (const auto &dim : enumerate(tensorType.getShape()))
|
||||
if (ShapedType::isDynamic(dim.value()))
|
||||
dynamicSizes.push_back(cast<Value>(shape[dim.index()]));
|
||||
for (const auto &dim : enumerate(tensorType.getShape())) {
|
||||
if (ShapedType::isDynamic(dim.value())) {
|
||||
dynamicSizes.push_back(
|
||||
getValueOrCreateConstantIndexOp(b, loc, shape[dim.index()]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "mlir/Dialect/Affine/IR/AffineOps.h"
|
||||
#include "mlir/Dialect/Affine/Utils.h"
|
||||
#include "mlir/Dialect/Arith/IR/Arith.h"
|
||||
#include "mlir/Dialect/Arith/Utils/Utils.h"
|
||||
#include "mlir/Dialect/Complex/IR/Complex.h"
|
||||
@@ -3793,6 +3794,29 @@ struct FoldConsecutiveConstantPadding : public OpRewritePattern<tensor::PadOp> {
|
||||
|
||||
} // namespace
|
||||
|
||||
LogicalResult
|
||||
PadOp::reifyResultShapes(OpBuilder &b,
|
||||
ReifiedRankedShapedTypeDims &reifiedReturnShapes) {
|
||||
reifiedReturnShapes.resize(1, SmallVector<OpFoldResult>(getType().getRank()));
|
||||
SmallVector<OpFoldResult> lp = getMixedLowPad();
|
||||
SmallVector<OpFoldResult> hp = getMixedHighPad();
|
||||
for (int64_t i = 0; i < getResultType().getRank(); ++i) {
|
||||
if (!getType().isDynamicDim(i)) {
|
||||
reifiedReturnShapes[0][i] = b.getIndexAttr(getType().getDimSize(i));
|
||||
continue;
|
||||
}
|
||||
Location loc = getLoc();
|
||||
Value dim = b.createOrFold<tensor::DimOp>(
|
||||
loc, getSource(), b.create<arith::ConstantIndexOp>(loc, i));
|
||||
|
||||
AffineExpr d0, d1, d2;
|
||||
bindDims(b.getContext(), d0, d1, d2);
|
||||
reifiedReturnShapes[0][i] = affine::makeComposedFoldedAffineApply(
|
||||
b, loc, {d0 + d1 + d2}, {dim, lp[i], hp[i]});
|
||||
}
|
||||
return success();
|
||||
}
|
||||
|
||||
void PadOp::getCanonicalizationPatterns(RewritePatternSet &results,
|
||||
MLIRContext *context) {
|
||||
results.add<FoldStaticZeroPadding, FoldSourceTensorCast, FoldTargetTensorCast,
|
||||
|
||||
@@ -34,9 +34,9 @@ func.func @dynamic_pad_fusion(%arg0 : tensor<?x?xf32>, %arg1 : index, %arg2 : in
|
||||
// CHECK-DAG: %[[C1:.+]] = arith.constant 1 : index
|
||||
// CHECK-DAG: %[[SOURCE:.+]] = linalg.generic
|
||||
// CHECK-DAG: %[[SOURCE_D0:.+]] = tensor.dim %[[SOURCE]], %[[C0]]
|
||||
// CHECK-DAG: %[[TARGET_D0:.+]] = affine.apply #[[MAP]]()[%[[ARG1]], %[[ARG3]], %[[SOURCE_D0]]]
|
||||
// CHECK-DAG: %[[TARGET_D0:.+]] = affine.apply #[[MAP]]()[%[[SOURCE_D0]], %[[ARG1]], %[[ARG3]]]
|
||||
// CHECK-DAG: %[[SOURCE_D1:.+]] = tensor.dim %[[SOURCE]], %[[C1]]
|
||||
// CHECK-DAG: %[[TARGET_D1:.+]] = affine.apply #[[MAP]]()[%[[ARG2]], %[[ARG4]], %[[SOURCE_D1]]]
|
||||
// CHECK-DAG: %[[TARGET_D1:.+]] = affine.apply #[[MAP]]()[%[[SOURCE_D1]], %[[ARG2]], %[[ARG4]]]
|
||||
// CHECK: %[[INIT:.+]] = tensor.empty(%[[TARGET_D0]], %[[TARGET_D1]])
|
||||
// CHECK: %[[FILL:.+]] = linalg.fill ins(%[[ARG5]]{{.*}}outs(%[[INIT]]
|
||||
// CHECK-DAG: %[[SIZE_D0:.+]] = tensor.dim %[[SOURCE]], %[[C0]]
|
||||
@@ -80,7 +80,7 @@ func.func @mixed_pad_fusion(%arg0 : tensor<?x42xf32>, %arg1 : index, %arg2 : ind
|
||||
// CHECK-DAG: %[[C1:.+]] = arith.constant 1 : index
|
||||
// CHECK-DAG: %[[SOURCE:.+]] = linalg.generic
|
||||
// CHECK-DAG: %[[SOURCE_D1:.+]] = tensor.dim %[[SOURCE]], %[[C1]]
|
||||
// CHECK-DAG: %[[TARGET_D1:.+]] = affine.apply #[[MAP]]()[%[[ARG1]], %[[ARG2]], %[[SOURCE_D1]]]
|
||||
// CHECK-DAG: %[[TARGET_D1:.+]] = affine.apply #[[MAP]]()[%[[SOURCE_D1]], %[[ARG1]], %[[ARG2]]]
|
||||
// CHECK: %[[INIT:.+]] = tensor.empty(%[[TARGET_D1]])
|
||||
// CHECK: %[[FILL:.+]] = linalg.fill ins(%[[ARG3]]{{.*}}outs(%[[INIT]]
|
||||
// CHECK-DAG: %[[SIZE_D1:.+]] = tensor.dim %[[SOURCE]], %[[C1]]
|
||||
|
||||
@@ -268,9 +268,9 @@ func.func @dim_of_pad_op(%arg0 : tensor<2x?x?xf32>, %arg1 : index, %arg2 : index
|
||||
// CHECK-DAG: %[[C2:.+]] = arith.constant 2 : index
|
||||
// CHECK-DAG: %[[C12:.+]] = arith.constant 12 : index
|
||||
// CHECK: %[[IN_DIM1:.+]] = tensor.dim %[[ARG0]], %[[C1]]
|
||||
// CHECK: %[[OUT_DIM1:.+]] = affine.apply #[[MAP0]]()[%[[ARG1]], %[[IN_DIM1]]]
|
||||
// CHECK: %[[OUT_DIM1:.+]] = affine.apply #[[MAP0]]()[%[[IN_DIM1]], %[[ARG1]]]
|
||||
// CHECK: %[[IN_DIM2:.+]] = tensor.dim %[[ARG0]], %[[C2]]
|
||||
// CHECK: %[[OUT_DIM2:.+]] = affine.apply #[[MAP1]]()[%[[ARG2]], %[[IN_DIM2]]]
|
||||
// CHECK: %[[OUT_DIM2:.+]] = affine.apply #[[MAP1]]()[%[[IN_DIM2]], %[[ARG2]]]
|
||||
// CHECK: return %[[C12]], %[[OUT_DIM1]], %[[OUT_DIM2]]
|
||||
|
||||
// -----
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
// CHECK-DAG: %[[c0:.*]] = arith.constant 0 : index
|
||||
// CHECK-DAG: %[[c50:.*]] = arith.constant 50 : index
|
||||
// CHECK-DAG: %[[dim0:.*]] = tensor.dim %[[t]], %[[c0]]
|
||||
// CHECK-DAG: %[[size0:.*]] = affine.apply #[[$map]]()[%[[h1]], %[[dim0]]]
|
||||
// CHECK-DAG: %[[size0:.*]] = affine.apply #[[$map]]()[%[[dim0]], %[[h1]]]
|
||||
// CHECK-DAG: %[[size1:.*]] = affine.apply #[[$map1]]()[%[[l2]], %[[h2]]]
|
||||
// CHECK: %[[alloc:.*]] = memref.alloc(%[[size0]], %[[size1]]) : memref<?x?xindex>
|
||||
// CHECK: linalg.fill ins(%[[c50]] : index) outs(%[[alloc]] : memref<?x?xindex>)
|
||||
|
||||
@@ -119,7 +119,7 @@ module attributes {transform.with_named_sequence} {
|
||||
// CHECK-SAME: %[[t1:.*]]: tensor<?x10xindex>, %[[l2:.*]]: index, %[[h1:.*]]: index, %[[h2:.*]]: index
|
||||
// CHECK-DAG: %[[c0:.*]] = arith.constant 0 : index
|
||||
// CHECK-DAG: %[[dim0:.*]] = tensor.dim %[[t1]], %[[c0]]
|
||||
// CHECK-DAG: %[[size0:.*]] = affine.apply #[[$map]]()[%[[h1]], %[[dim0]]]
|
||||
// CHECK-DAG: %[[size0:.*]] = affine.apply #[[$map]]()[%[[dim0]], %[[h1]]]
|
||||
// CHECK-DAG: %[[size1:.*]] = affine.apply #[[$map1]]()[%[[l2]], %[[h2]]]
|
||||
// CHECK: %[[empty:.*]] = tensor.empty(%[[size0]], %[[size1]]) : tensor<?x?xindex>
|
||||
// CHECK: %[[generic:.*]] = linalg.generic
|
||||
@@ -162,7 +162,7 @@ module attributes {transform.with_named_sequence} {
|
||||
// CHECK-DAG: %[[c0:.*]] = arith.constant 0 : index
|
||||
// CHECK-DAG: %[[c50:.*]] = arith.constant 50 : index
|
||||
// CHECK-DAG: %[[dim0:.*]] = tensor.dim %[[t1]], %[[c0]]
|
||||
// CHECK-DAG: %[[size0:.*]] = affine.apply #[[$map]]()[%[[h1]], %[[dim0]]]
|
||||
// CHECK-DAG: %[[size0:.*]] = affine.apply #[[$map]]()[%[[dim0]], %[[h1]]]
|
||||
// CHECK-DAG: %[[size1:.*]] = affine.apply #[[$map1]]()[%[[l2]], %[[h2]]]
|
||||
// CHECK: %[[empty:.*]] = tensor.empty(%[[size0]], %[[size1]]) : tensor<?x?xindex>
|
||||
// CHECK: %[[filled:.*]] = linalg.fill ins(%[[c50]] : index) outs(%[[empty]] : tensor<?x?xindex>)
|
||||
@@ -197,7 +197,7 @@ module attributes {transform.with_named_sequence} {
|
||||
// CHECK-SAME: %[[t1:.*]]: tensor<?x10xindex>, %[[l2:.*]]: index, %[[h1:.*]]: index, %[[h2:.*]]: index, %[[padding:.*]]: index
|
||||
// CHECK-DAG: %[[c0:.*]] = arith.constant 0 : index
|
||||
// CHECK-DAG: %[[dim0:.*]] = tensor.dim %[[t1]], %[[c0]]
|
||||
// CHECK-DAG: %[[size0:.*]] = affine.apply #[[$map]]()[%[[h1]], %[[dim0]]]
|
||||
// CHECK-DAG: %[[size0:.*]] = affine.apply #[[$map]]()[%[[dim0]], %[[h1]]]
|
||||
// CHECK-DAG: %[[size1:.*]] = affine.apply #[[$map1]]()[%[[l2]], %[[h2]]]
|
||||
// CHECK: %[[empty:.*]] = tensor.empty(%[[size0]], %[[size1]]) : tensor<?x?xindex>
|
||||
// CHECK: %[[filled:.*]] = linalg.fill ins(%[[padding]] : index) outs(%[[empty]] : tensor<?x?xindex>)
|
||||
|
||||
@@ -571,7 +571,7 @@ func.func @tensor.pad(%t1: tensor<?x10xindex>, %l2: index, %h1: index,
|
||||
// CHECK-DAG: %[[c1:.*]] = arith.constant 1 : index
|
||||
// CHECK-DAG: %[[dim0:.*]] = memref.dim %[[m1]], %[[c0]]
|
||||
// CHECK-DAG: %[[dim1:.*]] = memref.dim %[[m1]], %[[c1]]
|
||||
// CHECK-DAG: %[[size0:.*]] = affine.apply #[[$sum_map_1]]()[%[[h1]], %[[dim0]]]
|
||||
// CHECK-DAG: %[[size0:.*]] = affine.apply #[[$sum_map_1]]()[%[[dim0]], %[[h1]]]
|
||||
// CHECK-DAG: %[[size1:.*]] = affine.apply #[[$sum_map_2]]()[%[[l2]], %[[h2]]]
|
||||
// CHECK: %[[alloc:.*]] = memref.alloc(%[[size0]], %[[size1]]) {{.*}} : memref<?x?xindex>
|
||||
// CHECK: %[[alloc_t:.*]] = bufferization.to_tensor %[[alloc]]
|
||||
|
||||
@@ -213,3 +213,20 @@ func.func @dynamic_dims_are_maybe_equal_2(%t: tensor<?x?xf32>) {
|
||||
"test.compare"(%dim0, %dim1) : (index, index) -> ()
|
||||
return
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// CHECK-LABEL: func.func @pad_reification
|
||||
func.func @pad_reification(%cst : f32, %idx : index, %t: tensor<64x?x64xf32>) {
|
||||
%pad_amt = affine.apply affine_map<(d0) -> (-d0 + 256)>(%idx)
|
||||
%es = tensor.extract_slice %t[0, 0, 0] [1, %idx, 64] [1, 1, 1] : tensor<64x?x64xf32> to tensor<1x?x64xf32>
|
||||
|
||||
%padded = tensor.pad %es low[0, 0, 0] high[0, %pad_amt, 0] {
|
||||
^bb0(%a: index, %b: index, %c: index):
|
||||
tensor.yield %cst : f32
|
||||
} : tensor<1x?x64xf32> to tensor<1x?x64xf32>
|
||||
|
||||
// CHECK: arith.constant 256 : index
|
||||
%1 = "test.reify_bound"(%padded) {dim = 1, constant} : (tensor<1x?x64xf32>) -> (index)
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user