MLIR 24.0.0git
ValueBoundsOpInterfaceImpl.cpp
Go to the documentation of this file.
1//===- ValueBoundsOpInterfaceImpl.cpp - Impl. of ValueBoundsOpInterface ---===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
14
15using namespace mlir;
16
17namespace mlir {
18namespace tensor {
19namespace {
20
21struct CastOpInterface
22 : public ValueBoundsOpInterface::ExternalModel<CastOpInterface, CastOp> {
23 void populateBoundsForShapedValueDim(Operation *op, Value value, int64_t dim,
24 ValueBoundsConstraintSet &cstr) const {
25 auto castOp = cast<CastOp>(op);
26 assert(value == castOp.getResult() && "invalid value");
27
28 if (llvm::isa<RankedTensorType>(castOp.getResult().getType()) &&
29 llvm::isa<RankedTensorType>(castOp.getSource().getType())) {
30 cstr.bound(value)[dim] == cstr.getExpr(castOp.getSource(), dim);
31 }
32 }
33};
34
35struct CollapseShapeOpInterface
36 : public ValueBoundsOpInterface::ExternalModel<CollapseShapeOpInterface,
37 CollapseShapeOp> {
38 void populateBoundsForShapedValueDim(Operation *op, Value value, int64_t dim,
39 ValueBoundsConstraintSet &cstr) const {
40 auto collapseOp = cast<CollapseShapeOp>(op);
41 assert(value == collapseOp.getResult() && "invalid value");
42
43 // Multiply the expressions for the dimensions in the reassociation group.
44 const ReassociationIndices reassocIndices =
45 collapseOp.getReassociationIndices()[dim];
46 AffineExpr productExpr =
47 cstr.getExpr(collapseOp.getSrc(), reassocIndices[0]);
48 for (size_t i = 1; i < reassocIndices.size(); ++i) {
49 productExpr =
50 productExpr * cstr.getExpr(collapseOp.getSrc(), reassocIndices[i]);
51 }
52 cstr.bound(value)[dim] == productExpr;
53 }
54};
55
56struct ConcatOpInterface
57 : public ValueBoundsOpInterface::ExternalModel<ConcatOpInterface,
58 ConcatOp> {
59 void populateBoundsForShapedValueDim(Operation *op, Value value, int64_t dim,
60 ValueBoundsConstraintSet &cstr) const {
61 auto concatOp = cast<ConcatOp>(op);
62 assert(value == concatOp.getResult() && "invalid value");
63
64 ValueRange inputs = concatOp.getInputs();
65 if (dim != static_cast<int64_t>(concatOp.getDim())) {
66 // All inputs have the same size as the result in a dimension that is not
67 // concatenated. Relate the result to every input: relating it to a single
68 // input loses the bound when that input is the unbounded one.
69 for (Value input : inputs)
70 cstr.bound(value)[dim] == cstr.getExpr(input, dim);
71 return;
72 }
73
74 // The concatenated dimension is the sum of the input sizes.
75 AffineExpr sum = cstr.getExpr(inputs.front(), dim);
76 for (Value input : inputs.drop_front())
77 sum = sum + cstr.getExpr(input, dim);
78 cstr.bound(value)[dim] == sum;
79 }
80};
81
82struct DimOpInterface
83 : public ValueBoundsOpInterface::ExternalModel<DimOpInterface, DimOp> {
84 void populateBoundsForIndexValue(Operation *op, Value value,
85 ValueBoundsConstraintSet &cstr) const {
86 auto dimOp = cast<DimOp>(op);
87 assert(value == dimOp.getResult() && "invalid value");
88
89 cstr.bound(value) >= 0;
90 auto constIndex = dimOp.getConstantIndex();
91 if (!constIndex.has_value())
92 return;
93 cstr.bound(value) == cstr.getExpr(dimOp.getSource(), *constIndex);
94 }
95};
96
97struct EmptyOpInterface
98 : public ValueBoundsOpInterface::ExternalModel<EmptyOpInterface, EmptyOp> {
99 void populateBoundsForShapedValueDim(Operation *op, Value value, int64_t dim,
100 ValueBoundsConstraintSet &cstr) const {
101 auto emptyOp = cast<EmptyOp>(op);
102 assert(value == emptyOp.getResult() && "invalid value");
103
104 cstr.bound(value)[dim] == emptyOp.getMixedSizes()[dim];
105 }
106};
107
108struct ExpandShapeOpInterface
109 : public ValueBoundsOpInterface::ExternalModel<ExpandShapeOpInterface,
110 ExpandShapeOp> {
111 void populateBoundsForShapedValueDim(Operation *op, Value value, int64_t dim,
112 ValueBoundsConstraintSet &cstr) const {
113 auto expandOp = cast<ExpandShapeOp>(op);
114 assert(value == expandOp.getResult() && "invalid value");
115 cstr.bound(value)[dim] == expandOp.getMixedOutputShape()[dim];
116 }
117};
118
119struct ExtractSliceOpInterface
120 : public ValueBoundsOpInterface::ExternalModel<ExtractSliceOpInterface,
121 ExtractSliceOp> {
122 void populateBoundsForShapedValueDim(Operation *op, Value value, int64_t dim,
123 ValueBoundsConstraintSet &cstr) const {
124 auto extractSliceOp = cast<ExtractSliceOp>(op);
125 assert(value == extractSliceOp.getResult() && "invalid value");
126
127 llvm::SmallBitVector dropped = extractSliceOp.getDroppedDims();
128 int64_t ctr = -1;
129 for (int64_t i = 0, e = extractSliceOp.getMixedSizes().size(); i < e; ++i) {
130 // Skip over rank-reduced dimensions.
131 if (!dropped.test(i))
132 ++ctr;
133 if (ctr == dim) {
134 cstr.bound(value)[dim] == extractSliceOp.getMixedSizes()[i];
135 return;
136 }
137 }
138 llvm_unreachable("could not find non-rank-reduced dim");
139 }
140};
141
142struct PadOpInterface
143 : public ValueBoundsOpInterface::ExternalModel<PadOpInterface, PadOp> {
144 void populateBoundsForShapedValueDim(Operation *op, Value value, int64_t dim,
145 ValueBoundsConstraintSet &cstr) const {
146 auto padOp = cast<PadOp>(op);
147 assert(value == padOp.getResult() && "invalid value");
148
149 AffineExpr srcSize = cstr.getExpr(padOp.getSource(), dim);
150 AffineExpr lowPad = cstr.getExpr(padOp.getMixedLowPad()[dim]);
151 AffineExpr highPad = cstr.getExpr(padOp.getMixedHighPad()[dim]);
152 cstr.bound(value)[dim] == srcSize + lowPad + highPad;
153 }
154};
155
156struct RankOpInterface
157 : public ValueBoundsOpInterface::ExternalModel<RankOpInterface, RankOp> {
158 void populateBoundsForIndexValue(Operation *op, Value value,
159 ValueBoundsConstraintSet &cstr) const {
160 auto rankOp = cast<RankOp>(op);
161 assert(value == rankOp.getResult() && "invalid value");
162
163 auto tensorType =
164 llvm::dyn_cast<RankedTensorType>(rankOp.getTensor().getType());
165 if (!tensorType)
166 return;
167 cstr.bound(value) == tensorType.getRank();
168 }
169};
170
171struct SplatOpInterface
172 : public ValueBoundsOpInterface::ExternalModel<SplatOpInterface, SplatOp> {
173 void populateBoundsForShapedValueDim(Operation *op, Value value, int64_t dim,
174 ValueBoundsConstraintSet &cstr) const {
175 auto splatOp = cast<SplatOp>(op);
176 assert(value == splatOp.getAggregate() && "invalid value");
177
178 RankedTensorType type = splatOp.getType();
179 SmallVector<OpFoldResult> sizes = getMixedValues(
180 type.getShape(), splatOp.getDynamicSizes(), type.getContext());
181 cstr.bound(value)[dim] == sizes[dim];
182 }
183};
184
185} // namespace
186} // namespace tensor
187} // namespace mlir
188
190 DialectRegistry &registry) {
191 registry.addExtension(+[](MLIRContext *ctx, tensor::TensorDialect *dialect) {
192 tensor::CastOp::attachInterface<tensor::CastOpInterface>(*ctx);
193 tensor::CollapseShapeOp::attachInterface<tensor::CollapseShapeOpInterface>(
194 *ctx);
195 tensor::ConcatOp::attachInterface<tensor::ConcatOpInterface>(*ctx);
196 tensor::DimOp::attachInterface<tensor::DimOpInterface>(*ctx);
197 tensor::EmptyOp::attachInterface<tensor::EmptyOpInterface>(*ctx);
198 tensor::ExpandShapeOp::attachInterface<tensor::ExpandShapeOpInterface>(
199 *ctx);
200 tensor::ExtractSliceOp::attachInterface<tensor::ExtractSliceOpInterface>(
201 *ctx);
202 tensor::PadOp::attachInterface<tensor::PadOpInterface>(*ctx);
203 tensor::RankOp::attachInterface<tensor::RankOpInterface>(*ctx);
204 tensor::SplatOp::attachInterface<tensor::SplatOpInterface>(*ctx);
205 // Note: ValueBoundsOpInterface implementation is not required for ops that
206 // implement `DestinationStyleOpInterface` (for querying shaped OpResults).
207 });
208}
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
bool addExtension(TypeID extensionID, std::unique_ptr< DialectExtensionBase > extension)
Add the given extension to the registry.
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
AffineExpr getExpr(Value value, std::optional< int64_t > dim=std::nullopt)
Return an expression that represents the given index-typed value or shaped value dimension.
BoundBuilder bound(Value value)
Add a bound for the given index-typed value or shaped value.
void registerValueBoundsOpInterfaceExternalModels(DialectRegistry &registry)
Include the generated interface declarations.
SmallVector< OpFoldResult > getMixedValues(ArrayRef< int64_t > staticValues, ValueRange dynamicValues, MLIRContext *context)
Return a vector of OpFoldResults with the same size a staticValues, but all elements for which Shaped...
SmallVector< int64_t, 2 > ReassociationIndices
Definition Utils.h:27