Skip to content

Commit 5154a05

Browse files
authored
[mlir][tensor] Add ValueBoundsOpInterface for ExpandShapeOp and CollapseShapeOp (#173356)
Mirroring #164438 and #164955 --------- Signed-off-by: Yu-Zhewen <zhewenyu@amd.com>
1 parent fcd9235 commit 5154a05

2 files changed

Lines changed: 68 additions & 0 deletions

File tree

mlir/lib/Dialect/Tensor/IR/ValueBoundsOpInterfaceImpl.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,27 @@ struct CastOpInterface
3131
}
3232
};
3333

34+
struct CollapseShapeOpInterface
35+
: public ValueBoundsOpInterface::ExternalModel<CollapseShapeOpInterface,
36+
CollapseShapeOp> {
37+
void populateBoundsForShapedValueDim(Operation *op, Value value, int64_t dim,
38+
ValueBoundsConstraintSet &cstr) const {
39+
auto collapseOp = cast<CollapseShapeOp>(op);
40+
assert(value == collapseOp.getResult() && "invalid value");
41+
42+
// Multiply the expressions for the dimensions in the reassociation group.
43+
const ReassociationIndices &reassocIndices =
44+
collapseOp.getReassociationIndices()[dim];
45+
AffineExpr productExpr =
46+
cstr.getExpr(collapseOp.getSrc(), reassocIndices[0]);
47+
for (size_t i = 1; i < reassocIndices.size(); ++i) {
48+
productExpr =
49+
productExpr * cstr.getExpr(collapseOp.getSrc(), reassocIndices[i]);
50+
}
51+
cstr.bound(value)[dim] == productExpr;
52+
}
53+
};
54+
3455
struct DimOpInterface
3556
: public ValueBoundsOpInterface::ExternalModel<DimOpInterface, DimOp> {
3657
void populateBoundsForIndexValue(Operation *op, Value value,
@@ -57,6 +78,17 @@ struct EmptyOpInterface
5778
}
5879
};
5980

81+
struct ExpandShapeOpInterface
82+
: public ValueBoundsOpInterface::ExternalModel<ExpandShapeOpInterface,
83+
ExpandShapeOp> {
84+
void populateBoundsForShapedValueDim(Operation *op, Value value, int64_t dim,
85+
ValueBoundsConstraintSet &cstr) const {
86+
auto expandOp = cast<ExpandShapeOp>(op);
87+
assert(value == expandOp.getResult() && "invalid value");
88+
cstr.bound(value)[dim] == expandOp.getMixedOutputShape()[dim];
89+
}
90+
};
91+
6092
struct ExtractSliceOpInterface
6193
: public ValueBoundsOpInterface::ExternalModel<ExtractSliceOpInterface,
6294
ExtractSliceOp> {
@@ -117,8 +149,12 @@ void mlir::tensor::registerValueBoundsOpInterfaceExternalModels(
117149
DialectRegistry &registry) {
118150
registry.addExtension(+[](MLIRContext *ctx, tensor::TensorDialect *dialect) {
119151
tensor::CastOp::attachInterface<tensor::CastOpInterface>(*ctx);
152+
tensor::CollapseShapeOp::attachInterface<tensor::CollapseShapeOpInterface>(
153+
*ctx);
120154
tensor::DimOp::attachInterface<tensor::DimOpInterface>(*ctx);
121155
tensor::EmptyOp::attachInterface<tensor::EmptyOpInterface>(*ctx);
156+
tensor::ExpandShapeOp::attachInterface<tensor::ExpandShapeOpInterface>(
157+
*ctx);
122158
tensor::ExtractSliceOp::attachInterface<tensor::ExtractSliceOpInterface>(
123159
*ctx);
124160
tensor::PadOp::attachInterface<tensor::PadOpInterface>(*ctx);

mlir/test/Dialect/Tensor/value-bounds-op-interface-impl.mlir

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,35 @@ func.func @pad_reification(%cst : f32, %idx : index, %t: tensor<64x?x64xf32>) {
230230
%1 = "test.reify_bound"(%padded) {dim = 1, constant} : (tensor<1x?x64xf32>) -> (index)
231231
return
232232
}
233+
234+
// -----
235+
236+
// CHECK: #[[$MAP:.+]] = affine_map<()[s0] -> (s0 * 2)>
237+
// CHECK-LABEL: func @tensor_collapse(
238+
// CHECK-SAME: %[[sz0:.*]]: index
239+
// CHECK-DAG: %[[c2:.*]] = arith.constant 2 : index
240+
// CHECK-DAG: %[[c12:.*]] = arith.constant 12 : index
241+
// CHECK: %[[dim:.*]] = tensor.dim %{{.*}}, %[[c2]] : tensor<3x4x?x2xf32>
242+
// CHECK: %[[mul:.*]] = affine.apply #[[$MAP]]()[%[[dim]]]
243+
// CHECK: return %[[c12]], %[[mul]]
244+
func.func @tensor_collapse(%sz0: index) -> (index, index) {
245+
%0 = tensor.empty(%sz0) : tensor<3x4x?x2xf32>
246+
%1 = tensor.collapse_shape %0 [[0, 1], [2, 3]] : tensor<3x4x?x2xf32> into tensor<12x?xf32>
247+
%2 = "test.reify_bound"(%1) {dim = 0} : (tensor<12x?xf32>) -> (index)
248+
%3 = "test.reify_bound"(%1) {dim = 1} : (tensor<12x?xf32>) -> (index)
249+
return %2, %3 : index, index
250+
}
251+
252+
// -----
253+
254+
// CHECK-LABEL: func @tensor_expand(
255+
// CHECK-SAME: %[[t:[a-zA-Z0-9]+]]: tensor<?xf32>
256+
// CHECK-SAME: %[[sz:[a-zA-Z0-9]+]]: index
257+
// CHECK: %[[c4:.*]] = arith.constant 4 : index
258+
// CHECK: return %[[c4]], %[[sz]]
259+
func.func @tensor_expand(%t: tensor<?xf32>, %sz: index) -> (index, index) {
260+
%0 = tensor.expand_shape %t [[0, 1]] output_shape [4, %sz] : tensor<?xf32> into tensor<4x?xf32>
261+
%1 = "test.reify_bound"(%0) {dim = 0} : (tensor<4x?xf32>) -> (index)
262+
%2 = "test.reify_bound"(%0) {dim = 1} : (tensor<4x?xf32>) -> (index)
263+
return %1, %2 : index, index
264+
}

0 commit comments

Comments
 (0)