MLIR 23.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
13
14using namespace mlir;
15
16namespace mlir {
17namespace memref {
18namespace {
19
20template <typename OpTy>
21struct AllocOpInterface
22 : public ValueBoundsOpInterface::ExternalModel<AllocOpInterface<OpTy>,
23 OpTy> {
24 void populateBoundsForShapedValueDim(Operation *op, Value value, int64_t dim,
25 ValueBoundsConstraintSet &cstr) const {
26 auto allocOp = cast<OpTy>(op);
27 assert(value == allocOp.getResult() && "invalid value");
28
29 cstr.bound(value)[dim] == allocOp.getMixedSizes()[dim];
30 }
31};
32
33struct AssumeAlignmentOpInterface
34 : public ValueBoundsOpInterface::ExternalModel<AssumeAlignmentOpInterface,
35 memref::AssumeAlignmentOp> {
36 void populateBoundsForShapedValueDim(Operation *op, Value value, int64_t dim,
37 ValueBoundsConstraintSet &cstr) const {
38 auto assumeAlignmentOp = cast<memref::AssumeAlignmentOp>(op);
39 assert(value == assumeAlignmentOp.getResult() && "invalid value");
40
41 cstr.bound(value)[dim] ==
42 cstr.getExpr(assumeAlignmentOp.getViewSource(), dim);
43 }
44};
45
46struct CastOpInterface
47 : public ValueBoundsOpInterface::ExternalModel<CastOpInterface, CastOp> {
48 void populateBoundsForShapedValueDim(Operation *op, Value value, int64_t dim,
49 ValueBoundsConstraintSet &cstr) const {
50 auto castOp = cast<CastOp>(op);
51 assert(value == castOp.getResult() && "invalid value");
52
53 if (llvm::isa<MemRefType>(castOp.getResult().getType()) &&
54 llvm::isa<MemRefType>(castOp.getSource().getType())) {
55 cstr.bound(value)[dim] == cstr.getExpr(castOp.getSource(), dim);
56 }
57 }
58};
59
60struct DimOpInterface
61 : public ValueBoundsOpInterface::ExternalModel<DimOpInterface, DimOp> {
62 void populateBoundsForIndexValue(Operation *op, Value value,
63 ValueBoundsConstraintSet &cstr) const {
64 auto dimOp = cast<DimOp>(op);
65 assert(value == dimOp.getResult() && "invalid value");
66
67 cstr.bound(value) >= 0;
68 auto constIndex = dimOp.getConstantIndex();
69 if (!constIndex.has_value())
70 return;
71 cstr.bound(value) == cstr.getExpr(dimOp.getSource(), *constIndex);
72 }
73};
74
75struct ExpandShapeOpInterface
76 : public ValueBoundsOpInterface::ExternalModel<ExpandShapeOpInterface,
77 memref::ExpandShapeOp> {
78 void populateBoundsForShapedValueDim(Operation *op, Value value, int64_t dim,
79 ValueBoundsConstraintSet &cstr) const {
80 auto expandOp = cast<memref::ExpandShapeOp>(op);
81 assert(value == expandOp.getResult() && "invalid value");
82 cstr.bound(value)[dim] == expandOp.getMixedOutputShape()[dim];
83 }
84};
85
86struct ExtractStridedMetadataOpInterface
87 : public ValueBoundsOpInterface::ExternalModel<
88 ExtractStridedMetadataOpInterface, memref::ExtractStridedMetadataOp> {
89 void populateBoundsForIndexValue(Operation *op, Value value,
90 ValueBoundsConstraintSet &cstr) const {
91 auto metadataOp = cast<memref::ExtractStridedMetadataOp>(op);
92 auto result = llvm::cast<OpResult>(value);
93 assert(result.getOwner() == op && "invalid value");
94 int64_t resultNumber = result.getResultNumber();
95
96 if (resultNumber == 1) {
97 cstr.bound(value) == metadataOp.getConstifiedMixedOffset();
98 return;
99 }
100
101 int64_t sourceRank = metadataOp.getSource().getType().getRank();
102 int64_t sizeStart = 2;
103 int64_t strideStart = sizeStart + sourceRank;
104 if (resultNumber >= sizeStart && resultNumber < strideStart) {
105 int64_t idx = resultNumber - sizeStart;
106 cstr.bound(value) >= 0;
107 cstr.bound(value) == cstr.getExpr(metadataOp.getSource(), idx);
108 return;
109 }
110
111 int64_t strideEnd = strideStart + sourceRank;
112 if (resultNumber >= strideStart && resultNumber < strideEnd) {
113 int64_t idx = resultNumber - strideStart;
114 SmallVector<OpFoldResult> strides =
115 metadataOp.getConstifiedMixedStrides();
116 cstr.bound(value) == strides[idx];
117 return;
118 }
119 llvm_unreachable("unexpected index value from extract_strided_metadata");
120 }
121};
122
123struct GetGlobalOpInterface
124 : public ValueBoundsOpInterface::ExternalModel<GetGlobalOpInterface,
125 GetGlobalOp> {
126 void populateBoundsForShapedValueDim(Operation *op, Value value, int64_t dim,
127 ValueBoundsConstraintSet &cstr) const {
128 auto getGlobalOp = cast<GetGlobalOp>(op);
129 assert(value == getGlobalOp.getResult() && "invalid value");
130
131 auto type = getGlobalOp.getType();
132 assert(!type.isDynamicDim(dim) && "expected static dim");
133 cstr.bound(value)[dim] == type.getDimSize(dim);
134 }
135};
136
137struct RankOpInterface
138 : public ValueBoundsOpInterface::ExternalModel<RankOpInterface, RankOp> {
139 void populateBoundsForIndexValue(Operation *op, Value value,
140 ValueBoundsConstraintSet &cstr) const {
141 auto rankOp = cast<RankOp>(op);
142 assert(value == rankOp.getResult() && "invalid value");
143
144 auto memrefType = llvm::dyn_cast<MemRefType>(rankOp.getMemref().getType());
145 if (!memrefType)
146 return;
147 cstr.bound(value) == memrefType.getRank();
148 }
149};
150
151struct CollapseShapeOpInterface
152 : public ValueBoundsOpInterface::ExternalModel<CollapseShapeOpInterface,
153 memref::CollapseShapeOp> {
154 void populateBoundsForShapedValueDim(Operation *op, Value value, int64_t dim,
155 ValueBoundsConstraintSet &cstr) const {
156 auto collapseOp = cast<memref::CollapseShapeOp>(op);
157 assert(value == collapseOp.getResult() && "invalid value");
158
159 // Multiply the expressions for the dimensions in the reassociation group.
160 const ReassociationIndices reassocIndices =
161 collapseOp.getReassociationIndices()[dim];
162 AffineExpr productExpr =
163 cstr.getExpr(collapseOp.getSrc(), reassocIndices[0]);
164 for (size_t i = 1; i < reassocIndices.size(); ++i) {
165 productExpr =
166 productExpr * cstr.getExpr(collapseOp.getSrc(), reassocIndices[i]);
167 }
168 cstr.bound(value)[dim] == productExpr;
169 }
170};
171
172struct SubViewOpInterface
173 : public ValueBoundsOpInterface::ExternalModel<SubViewOpInterface,
174 SubViewOp> {
175 void populateBoundsForShapedValueDim(Operation *op, Value value, int64_t dim,
176 ValueBoundsConstraintSet &cstr) const {
177 auto subViewOp = cast<SubViewOp>(op);
178 assert(value == subViewOp.getResult() && "invalid value");
179
180 llvm::SmallBitVector dropped = subViewOp.getDroppedDims();
181 int64_t ctr = -1;
182 for (int64_t i = 0, e = subViewOp.getMixedSizes().size(); i < e; ++i) {
183 // Skip over rank-reduced dimensions.
184 if (!dropped.test(i))
185 ++ctr;
186 if (ctr == dim) {
187 cstr.bound(value)[dim] == subViewOp.getMixedSizes()[i];
188 return;
189 }
190 }
191 llvm_unreachable("could not find non-rank-reduced dim");
192 }
193};
194
195} // namespace
196} // namespace memref
197} // namespace mlir
198
200 DialectRegistry &registry) {
201 registry.addExtension(+[](MLIRContext *ctx, memref::MemRefDialect *dialect) {
202 memref::AllocOp::attachInterface<memref::AllocOpInterface<memref::AllocOp>>(
203 *ctx);
204 memref::AllocaOp::attachInterface<
205 memref::AllocOpInterface<memref::AllocaOp>>(*ctx);
206 memref::CastOp::attachInterface<memref::CastOpInterface>(*ctx);
207 memref::DimOp::attachInterface<memref::DimOpInterface>(*ctx);
208 memref::CollapseShapeOp::attachInterface<memref::CollapseShapeOpInterface>(
209 *ctx);
210 memref::ExpandShapeOp::attachInterface<memref::ExpandShapeOpInterface>(
211 *ctx);
212 memref::GetGlobalOp::attachInterface<memref::GetGlobalOpInterface>(*ctx);
213 memref::RankOp::attachInterface<memref::RankOpInterface>(*ctx);
214 memref::SubViewOp::attachInterface<memref::SubViewOpInterface>(*ctx);
215 memref::AssumeAlignmentOp::attachInterface<
216 memref::AssumeAlignmentOpInterface>(*ctx);
217 memref::ExtractStridedMetadataOp::attachInterface<
218 memref::ExtractStridedMetadataOpInterface>(*ctx);
219 });
220}
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< int64_t, 2 > ReassociationIndices
Definition Utils.h:27