13#include "llvm/ADT/SmallVectorExtras.h"
21struct AffineApplyOpInterface
22 :
public ValueBoundsOpInterface::ExternalModel<AffineApplyOpInterface,
24 void populateBoundsForIndexValue(Operation *op, Value value,
25 ValueBoundsConstraintSet &cstr)
const {
26 auto applyOp = cast<AffineApplyOp>(op);
27 assert(value == applyOp.getResult() &&
"invalid value");
28 assert(applyOp.getAffineMap().getNumResults() == 1 &&
29 "expected single result");
34 AffineMap map = applyOp.getAffineMap();
35 SmallVector<Value> operands = llvm::to_vector(applyOp.getOperands());
40 SmallVector<AffineExpr> dimReplacements, symReplacements;
41 for (int64_t i = 0, e = map.
getNumDims(); i < e; ++i)
42 dimReplacements.push_back(cstr.
getExpr(operands[i]));
46 symReplacements.push_back(cstr.
getExpr(operands[i]));
49 cstr.
bound(value) == bound;
60 llvm::map_to_vector(operands.take_front(map.
getNumDims()),
61 [&](
Value v) { return cstr.getExpr(v); });
63 llvm::map_to_vector(operands.drop_front(map.
getNumDims()),
64 [&](
Value v) { return cstr.getExpr(v); });
68struct AffineForOpInterface
69 :
public ValueBoundsOpInterface::ExternalModel<AffineForOpInterface,
71 void populateBoundsForIndexValue(Operation *op, Value value,
72 ValueBoundsConstraintSet &cstr)
const {
73 auto forOp = cast<AffineForOp>(op);
77 if (value != forOp.getInductionVar())
80 AffineMap lbMap = forOp.getLowerBoundMap();
81 AffineMap ubMap = forOp.getUpperBoundMap();
82 ValueRange lbOperands = forOp.getLowerBoundOperands();
83 ValueRange ubOperands = forOp.getUpperBoundOperands();
89 cstr.
bound(value) >= alignBoundExpr(expr, lbMap, lbOperands, cstr);
91 cstr.
bound(value) < alignBoundExpr(expr, ubMap, ubOperands, cstr);
101 int64_t step = forOp.getStepAsInt();
104 AffineExpr lb = alignBoundExpr(lbMap.
getResult(0), lbMap, lbOperands, cstr);
105 AffineExpr ub = alignBoundExpr(ubMap.
getResult(0), ubMap, ubOperands, cstr);
106 AffineExpr tripCount = (ub - lb).ceilDiv(step);
107 cstr.
bound(value) <= lb + (tripCount - 1) * step;
111struct AffineMinOpInterface
112 :
public ValueBoundsOpInterface::ExternalModel<AffineMinOpInterface,
114 void populateBoundsForIndexValue(Operation *op, Value value,
115 ValueBoundsConstraintSet &cstr)
const {
116 auto minOp = cast<AffineMinOp>(op);
117 assert(value == minOp.getResult() &&
"invalid value");
120 for (AffineExpr expr : minOp.getAffineMap().getResults()) {
121 SmallVector<AffineExpr> dimReplacements = llvm::map_to_vector(
122 minOp.getDimOperands(), [&](Value v) { return cstr.getExpr(v); });
123 SmallVector<AffineExpr> symReplacements = llvm::map_to_vector(
124 minOp.getSymbolOperands(), [&](Value v) { return cstr.getExpr(v); });
127 cstr.
bound(value) <= bound;
132struct AffineMaxOpInterface
133 :
public ValueBoundsOpInterface::ExternalModel<AffineMaxOpInterface,
135 void populateBoundsForIndexValue(Operation *op, Value value,
136 ValueBoundsConstraintSet &cstr)
const {
137 auto maxOp = cast<AffineMaxOp>(op);
138 assert(value == maxOp.getResult() &&
"invalid value");
141 for (AffineExpr expr : maxOp.getAffineMap().getResults()) {
142 SmallVector<AffineExpr> dimReplacements = llvm::map_to_vector(
143 maxOp.getDimOperands(), [&](Value v) { return cstr.getExpr(v); });
144 SmallVector<AffineExpr> symReplacements = llvm::map_to_vector(
145 maxOp.getSymbolOperands(), [&](Value v) { return cstr.getExpr(v); });
148 cstr.
bound(value) >= bound;
153struct AffineDelinearizeIndexOpInterface
154 :
public ValueBoundsOpInterface::ExternalModel<
155 AffineDelinearizeIndexOpInterface, AffineDelinearizeIndexOp> {
156 void populateBoundsForIndexValue(Operation *rawOp, Value value,
157 ValueBoundsConstraintSet &cstr)
const {
158 auto op = cast<AffineDelinearizeIndexOp>(rawOp);
159 auto result = cast<OpResult>(value);
160 assert(
result.getOwner() == rawOp &&
161 "bounded value isn't a result of this delinearize_index");
162 unsigned resIdx =
result.getResultNumber();
164 AffineExpr linearIdx = cstr.
getExpr(op.getLinearIndex());
166 SmallVector<OpFoldResult> basis = op.getPaddedBasis();
167 AffineExpr divisor = cstr.
getExpr(1);
168 for (OpFoldResult basisElem : llvm::drop_begin(basis, resIdx + 1))
169 divisor = divisor * cstr.
getExpr(basisElem);
173 if (!basis.front().isNull())
177 AffineExpr thisBasis = cstr.
getExpr(basis[resIdx]);
178 cstr.
bound(value) == (linearIdx % (thisBasis * divisor)).floorDiv(divisor);
182struct AffineLinearizeIndexOpInterface
183 :
public ValueBoundsOpInterface::ExternalModel<
184 AffineLinearizeIndexOpInterface, AffineLinearizeIndexOp> {
185 void populateBoundsForIndexValue(Operation *rawOp, Value value,
186 ValueBoundsConstraintSet &cstr)
const {
187 auto op = cast<AffineLinearizeIndexOp>(rawOp);
189 "value isn't the result of this linearize");
191 AffineExpr bound = cstr.
getExpr(0);
192 AffineExpr stride = cstr.
getExpr(1);
193 SmallVector<OpFoldResult> basis = op.getPaddedBasis();
194 OperandRange multiIndex = op.getMultiIndex();
195 unsigned numArgs = multiIndex.size();
196 for (
auto [revArgNum, length] : llvm::enumerate(llvm::reverse(basis))) {
197 unsigned argNum = numArgs - (revArgNum + 1);
201 bound = bound + cstr.
getExpr(indexAsFoldRes) * stride;
202 stride = stride * cstr.
getExpr(length);
204 bound = bound + cstr.
getExpr(op.getMultiIndex().front()) * stride;
205 cstr.
bound(value) == bound;
206 if (op.getDisjoint() && !basis.front().isNull()) {
207 cstr.
bound(value) < stride *cstr.
getExpr(basis.front());
217 AffineApplyOp::attachInterface<AffineApplyOpInterface>(*ctx);
218 AffineForOp::attachInterface<AffineForOpInterface>(*ctx);
219 AffineMaxOp::attachInterface<AffineMaxOpInterface>(*ctx);
220 AffineMinOp::attachInterface<AffineMinOpInterface>(*ctx);
221 AffineDelinearizeIndexOp::attachInterface<
222 AffineDelinearizeIndexOpInterface>(*ctx);
223 AffineLinearizeIndexOp::attachInterface<AffineLinearizeIndexOpInterface>(
237 b.getAffineDimExpr(0) -
b.getAffineDimExpr(1));
242 mapOperands.push_back(value1);
243 mapOperands.push_back(value2);
Base type for affine expression.
AffineExpr replaceDimsAndSymbols(ArrayRef< AffineExpr > dimReplacements, ArrayRef< AffineExpr > symReplacements) const
This method substitutes any uses of dimensions and symbols (e.g.
AffineExpr floorDiv(uint64_t v) const
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
unsigned getNumSymbols() const
unsigned getNumDims() const
ArrayRef< AffineExpr > getResults() const
unsigned getNumResults() const
AffineExpr getResult(unsigned idx) const
This class is a general helper class for creating context-global objects like types,...
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.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
A variable that can be added to the constraint set as a "column".
A helper class to be used with ValueBoundsOpInterface.
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.
static FailureOr< int64_t > computeConstantBound(presburger::BoundType type, const Variable &var, const StopConditionFn &stopCondition=nullptr, ValueBoundsOptions options={})
Compute a constant bound for the given variable.
BoundBuilder bound(Value value)
Add a bound for the given index-typed value or shaped value.
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
MLIRContext * getContext() const
Utility to get the associated MLIRContext that this value is defined in.
Type getType() const
Return the type of this value.
void registerValueBoundsOpInterfaceExternalModels(DialectRegistry ®istry)
void fullyComposeAffineMapAndOperands(AffineMap *map, SmallVectorImpl< Value > *operands, bool composeAffineMin=false)
Given an affine map map and its input operands, this method composes into map, maps of AffineApplyOps...
FailureOr< int64_t > fullyComposeAndComputeConstantDelta(Value value1, Value value2)
Compute a constant delta of the given two values.
Include the generated interface declarations.
OpFoldResult getAsOpFoldResult(Value val)
Given a value, try to extract a constant Attribute.