MLIR 22.0.0git
ValueBoundsOpInterface.h
Go to the documentation of this file.
1//===- ValueBoundsOpInterface.h - Value Bounds ------------------*- C++ -*-===//
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
9#ifndef MLIR_INTERFACES_VALUEBOUNDSOPINTERFACE_H_
10#define MLIR_INTERFACES_VALUEBOUNDSOPINTERFACE_H_
11
13#include "mlir/IR/Builders.h"
15#include "mlir/IR/Value.h"
17#include "llvm/ADT/SetVector.h"
18#include "llvm/ADT/SmallVector.h"
19#include "llvm/Support/ExtensibleRTTI.h"
20
21#include <queue>
22
23namespace mlir {
24class OffsetSizeAndStrideOpInterface;
25
26/// A hyperrectangular slice, represented as a list of offsets, sizes and
27/// strides.
29public:
33
34 /// Create a hyperrectangular slice with unit strides.
37
38 /// Infer a hyperrectangular slice from `OffsetSizeAndStrideOpInterface`.
39 HyperrectangularSlice(OffsetSizeAndStrideOpInterface op);
40
41 ArrayRef<OpFoldResult> getMixedOffsets() const { return mixedOffsets; }
42 ArrayRef<OpFoldResult> getMixedSizes() const { return mixedSizes; }
43 ArrayRef<OpFoldResult> getMixedStrides() const { return mixedStrides; }
44
45private:
46 SmallVector<OpFoldResult> mixedOffsets;
48 SmallVector<OpFoldResult> mixedStrides;
49};
50
52
53/// A helper class to be used with `ValueBoundsOpInterface`. This class stores a
54/// constraint system and mapping of constrained variables to index-typed
55/// values or dimension sizes of shaped values.
56///
57/// Interface implementations of `ValueBoundsOpInterface` use `addBounds` to
58/// insert constraints about their results and/or region block arguments into
59/// the constraint set in the form of an AffineExpr. When a bound should be
60/// expressed in terms of another value/dimension, `getExpr` can be used to
61/// retrieve an AffineExpr that represents the specified value/dimension.
62///
63/// When a value/dimension is retrieved for the first time through `getExpr`,
64/// it is added to an internal worklist. See `computeBound` for more details.
65///
66/// Note: Any modification of existing IR invalides the data stored in this
67/// class. Adding new operations is allowed.
69 : public llvm::RTTIExtends<ValueBoundsConstraintSet, llvm::RTTIRoot> {
70protected:
71 /// Helper class that builds a bound for a shaped value dimension or
72 /// index-typed value.
74 public:
75 /// Specify a dimension, assuming that the underlying value is a shaped
76 /// value.
78
79 // These overloaded operators add lower/upper/equality bounds.
80 void operator<(AffineExpr expr);
81 void operator<=(AffineExpr expr);
82 void operator>(AffineExpr expr);
83 void operator>=(AffineExpr expr);
84 void operator==(AffineExpr expr);
85 void operator<(OpFoldResult ofr);
86 void operator<=(OpFoldResult ofr);
87 void operator>(OpFoldResult ofr);
88 void operator>=(OpFoldResult ofr);
89 void operator==(OpFoldResult ofr);
90 void operator<(int64_t i);
91 void operator<=(int64_t i);
92 void operator>(int64_t i);
93 void operator>=(int64_t i);
94 void operator==(int64_t i);
95
96 protected:
99 : cstr(cstr), value(value) {}
100
101 private:
102 BoundBuilder(const BoundBuilder &) = delete;
103 BoundBuilder &operator=(const BoundBuilder &) = delete;
104 bool operator==(const BoundBuilder &) = delete;
105 bool operator!=(const BoundBuilder &) = delete;
106
108 Value value;
109 std::optional<int64_t> dim;
110 };
111
112public:
113 static char ID;
114
115 /// A variable that can be added to the constraint set as a "column". The
116 /// value bounds infrastructure can compute bounds for variables and compare
117 /// two variables.
118 ///
119 /// Internally, a variable is represented as an affine map and operands.
120 class Variable {
121 public:
122 /// Construct a variable for an index-typed attribute or SSA value.
124
125 /// Construct a variable for an index-typed SSA value.
126 Variable(Value indexValue);
127
128 /// Construct a variable for a dimension of a shaped value.
129 Variable(Value shapedValue, int64_t dim);
130
131 /// Construct a variable for an index-typed attribute/SSA value or for a
132 /// dimension of a shaped value. A non-null dimension must be provided if
133 /// and only if `ofr` is a shaped value.
134 Variable(OpFoldResult ofr, std::optional<int64_t> dim);
135
136 /// Construct a variable for a map and its operands.
137 Variable(AffineMap map, ArrayRef<Variable> mapOperands);
138 Variable(AffineMap map, ValueRange mapOperands);
139
140 MLIRContext *getContext() const { return map.getContext(); }
141
142 /// Returns the affine map.
143 AffineMap getMap() const { return map; }
144
145 /// Returns the map operands.
146 ValueDimList &getOperands() { return mapOperands; }
147 const ValueDimList &getOperands() const { return mapOperands; }
148
149 private:
151 AffineMap map;
152 ValueDimList mapOperands;
153 };
154
155 /// The stop condition when traversing the backward slice of a shaped value/
156 /// index-type value. The traversal continues until the stop condition
157 /// evaluates to "true" for a value.
158 ///
159 /// The first parameter of the function is the shaped value/index-typed
160 /// value. The second parameter is the dimension in case of a shaped value.
161 /// The third parameter is this constraint set.
162 using StopConditionFn = std::function<bool(
163 Value, std::optional<int64_t> /*dim*/, ValueBoundsConstraintSet &cstr)>;
164
165 /// Compute a bound for the given variable. The computed bound is stored in
166 /// `resultMap`. The operands of the bound are stored in `mapOperands`. An
167 /// operand is either an index-type SSA value or a shaped value and a
168 /// dimension.
169 ///
170 /// The bound is computed in terms of values/dimensions for which
171 /// `stopCondition` evaluates to "true". To that end, the backward slice
172 /// (reverse use-def chain) of the given value is visited in a worklist-driven
173 /// manner and the constraint set is populated according to
174 /// `ValueBoundsOpInterface` for each visited value.
175 ///
176 /// By default, lower/equal bounds are closed and upper bounds are open. If
177 /// `closedUB` is set to "true", upper bounds are also closed.
178 static LogicalResult
179 computeBound(AffineMap &resultMap, ValueDimList &mapOperands,
180 presburger::BoundType type, const Variable &var,
181 StopConditionFn stopCondition, bool closedUB = false);
182
183 /// Compute a bound in terms of the values/dimensions in `dependencies`. The
184 /// computed bound consists of only constant terms and dependent values (or
185 /// dimension sizes thereof).
186 static LogicalResult
187 computeDependentBound(AffineMap &resultMap, ValueDimList &mapOperands,
188 presburger::BoundType type, const Variable &var,
189 ValueDimList dependencies, bool closedUB = false);
190
191 /// Compute a bound in that is independent of all values in `independencies`.
192 ///
193 /// Independencies are the opposite of dependencies. The computed bound does
194 /// not contain any SSA values that are part of `independencies`. E.g., this
195 /// function can be used to make ops hoistable from loops. To that end, ops
196 /// must be made independent of loop induction variables (in the case of "for"
197 /// loops). Loop induction variables are the independencies; they may not
198 /// appear in the computed bound.
199 static LogicalResult
200 computeIndependentBound(AffineMap &resultMap, ValueDimList &mapOperands,
201 presburger::BoundType type, const Variable &var,
202 ValueRange independencies, bool closedUB = false);
203
204 /// Compute a constant bound for the given variable.
205 ///
206 /// This function traverses the backward slice of the given operands in a
207 /// worklist-driven manner until `stopCondition` evaluates to "true". The
208 /// constraint set is populated according to `ValueBoundsOpInterface` for each
209 /// visited value. (No constraints are added for values for which the stop
210 /// condition evaluates to "true".)
211 ///
212 /// The stop condition is optional: If none is specified, the backward slice
213 /// is traversed in a breadth-first manner until a constant bound could be
214 /// computed.
215 ///
216 /// By default, lower/equal bounds are closed and upper bounds are open. If
217 /// `closedUB` is set to "true", upper bounds are also closed.
218 static FailureOr<int64_t>
220 const StopConditionFn &stopCondition = nullptr,
221 bool closedUB = false);
222
223 /// Compute a constant delta between the given two values. Return "failure"
224 /// if a constant delta could not be determined.
225 ///
226 /// `dim1`/`dim2` must be `nullopt` if and only if `value1`/`value2` are
227 /// index-typed.
228 static FailureOr<int64_t>
229 computeConstantDelta(Value value1, Value value2,
230 std::optional<int64_t> dim1 = std::nullopt,
231 std::optional<int64_t> dim2 = std::nullopt);
232
233 /// Traverse the IR starting from the given value/dim and populate constraints
234 /// as long as the stop condition holds. Also process all values/dims that are
235 /// already on the worklist.
236 void populateConstraints(Value value, std::optional<int64_t> dim);
237
238 /// Comparison operator for `ValueBoundsConstraintSet::compare`.
240
241 /// Populate constraints for lhs/rhs (until the stop condition is met). Then,
242 /// try to prove that, based on the current state of this constraint set
243 /// (i.e., without analyzing additional IR or adding new constraints), the
244 /// "lhs" value/dim is LE/LT/EQ/GT/GE than the "rhs" value/dim.
245 ///
246 /// Return "true" if the specified relation between the two values/dims was
247 /// proven to hold. Return "false" if the specified relation could not be
248 /// proven. This could be because the specified relation does in fact not hold
249 /// or because there is not enough information in the constraint set. In other
250 /// words, if we do not know for sure, this function returns "false".
251 bool populateAndCompare(const Variable &lhs, ComparisonOperator cmp,
252 const Variable &rhs);
253
254 /// Return "true" if "lhs cmp rhs" was proven to hold. Return "false" if the
255 /// specified relation could not be proven. This could be because the
256 /// specified relation does in fact not hold or because there is not enough
257 /// information in the constraint set. In other words, if we do not know for
258 /// sure, this function returns "false".
259 ///
260 /// This function keeps traversing the backward slice of lhs/rhs until could
261 /// prove the relation or until it ran out of IR.
262 static bool compare(const Variable &lhs, ComparisonOperator cmp,
263 const Variable &rhs);
264 /// This function is similar to `ValueBoundsConstraintSet::compare`, except
265 /// that it returns false if `!(lhs cmp rhs)`, and `failure` if neither the
266 /// relation nor its inverse relation could be proven.
267 static llvm::FailureOr<bool> strongCompare(const Variable &lhs,
269 const Variable &rhs);
270
271 /// Compute whether the given variables are equal. Return "failure" if
272 /// equality could not be determined.
273 static FailureOr<bool> areEqual(const Variable &var1, const Variable &var2);
274
275 /// Return "true" if the given slices are guaranteed to be overlapping.
276 /// Return "false" if the given slices are guaranteed to be non-overlapping.
277 /// Return "failure" if unknown.
278 ///
279 /// Slices are overlapping if for all dimensions:
280 /// * offset1 + size1 * stride1 <= offset2
281 /// * and offset2 + size2 * stride2 <= offset1
282 ///
283 /// Slice are non-overlapping if the above constraint is not satisfied for
284 /// at least one dimension.
285 static FailureOr<bool>
287 const HyperrectangularSlice &slice2);
288
289 /// Return "true" if the given slices are guaranteed to be equivalent.
290 /// Return "false" if the given slices are guaranteed to be non-equivalent.
291 /// Return "failure" if unknown.
292 ///
293 /// Slices are equivalent if their offsets, sizes and strices are equal.
294 static FailureOr<bool>
296 const HyperrectangularSlice &slice2);
297
298 /// Add a bound for the given index-typed value or shaped value. This function
299 /// returns a builder that adds the bound.
300 BoundBuilder bound(Value value) { return BoundBuilder(*this, value); }
301
302 /// Return an expression that represents the given index-typed value or shaped
303 /// value dimension. If this value/dimension was not used so far, it is added
304 /// to the worklist.
305 ///
306 /// `dim` must be `nullopt` if and only if the given value is of index type.
307 AffineExpr getExpr(Value value, std::optional<int64_t> dim = std::nullopt);
308
309 /// Return an expression that represents a constant or index-typed SSA value.
310 /// In case of a value, if this value was not used so far, it is added to the
311 /// worklist.
313
314 /// Return an expression that represents a constant.
315 AffineExpr getExpr(int64_t constant);
316
317 /// Debugging only: Dump the constraint set and the column-to-value/dim
318 /// mapping to llvm::errs.
319 void dump() const;
320
321protected:
322 /// Dimension identifier to indicate a value is index-typed. This is used for
323 /// internal data structures/API only.
324 static constexpr int64_t kIndexValue = -1;
325
326 /// An index-typed value or the dimension of a shaped-type value.
327 using ValueDim = std::pair<Value, int64_t>;
328
332
333 /// Return "true" if, based on the current state of the constraint system,
334 /// "lhs cmp rhs" was proven to hold. Return "false" if the specified relation
335 /// could not be proven. This could be because the specified relation does in
336 /// fact not hold or because there is not enough information in the constraint
337 /// set. In other words, if we do not know for sure, this function returns
338 /// "false".
339 ///
340 /// This function does not analyze any IR and does not populate any additional
341 /// constraints.
342 bool comparePos(int64_t lhsPos, ComparisonOperator cmp, int64_t rhsPos);
343
344 /// Return "true" if, based on the current state of the constraint system,
345 /// "lhs cmp rhs" was proven to hold. It returns "false" if "!(lhs cmp rhs)"
346 /// can be proven. Otherwise, it returns `failure` if neither the relation nor
347 /// its inverse relation could be proven.
348 ///
349 /// This function does not analyze any IR and does not populate any additional
350 /// constraints.
351 llvm::FailureOr<bool> strongComparePos(int64_t lhsPos, ComparisonOperator cmp,
352 int64_t rhsPos);
353
354 /// Given an affine map with a single result (and map operands), add a new
355 /// column to the constraint set that represents the result of the map.
356 /// Traverse additional IR starting from the map operands as needed (as long
357 /// as the stop condition is not satisfied). Also process all values/dims that
358 /// are already on the worklist. Return the position of the newly added
359 /// column.
361
362 /// Iteratively process all elements on the worklist until an index-typed
363 /// value or shaped value meets `stopCondition`. Such values are not processed
364 /// any further.
365 void processWorklist();
366
367 /// Bound the given column in the underlying constraint set by the given
368 /// expression.
369 void addBound(presburger::BoundType type, int64_t pos, AffineExpr expr);
370
371 /// Return the column position of the given value/dimension. Asserts that the
372 /// value/dimension exists in the constraint set.
373 int64_t getPos(Value value, std::optional<int64_t> dim = std::nullopt) const;
374
375 /// Return an affine expression that represents column `pos` in the constraint
376 /// set.
378
379 /// Return "true" if the given value/dim is mapped (i.e., has a corresponding
380 /// column in the constraint system).
381 bool isMapped(Value value, std::optional<int64_t> dim = std::nullopt) const;
382
383 /// Insert a value/dimension into the constraint set. If `isSymbol` is set to
384 /// "false", a dimension is added. The value/dimension is added to the
385 /// worklist if `addToWorklist` is set.
386 ///
387 /// Note: There are certain affine restrictions wrt. dimensions. E.g., they
388 /// cannot be multiplied. Furthermore, bounds can only be queried for
389 /// dimensions but not for symbols.
390 int64_t insert(Value value, std::optional<int64_t> dim, bool isSymbol = true,
391 bool addToWorklist = true);
392
393 /// Insert an anonymous column into the constraint set. The column is not
394 /// bound to any value/dimension. If `isSymbol` is set to "false", a dimension
395 /// is added.
396 ///
397 /// Note: There are certain affine restrictions wrt. dimensions. E.g., they
398 /// cannot be multiplied. Furthermore, bounds can only be queried for
399 /// dimensions but not for symbols.
400 int64_t insert(bool isSymbol = true);
401
402 /// Insert the given affine map and its bound operands as a new column in the
403 /// constraint system. Return the position of the new column. Any operands
404 /// that were not analyzed yet are put on the worklist.
405 int64_t insert(AffineMap map, const ValueDimList &operands,
406 bool isSymbol = true);
407 int64_t insert(const Variable &var, bool isSymbol = true);
408
409 /// Project out the given column in the constraint set.
410 void projectOut(int64_t pos);
411
412 /// Project out all columns for which the condition holds.
413 void projectOut(function_ref<bool(ValueDim)> condition);
414
415 void projectOutAnonymous(std::optional<int64_t> except = std::nullopt);
416
417 /// Mapping of columns to values/shape dimensions.
419 /// Reverse mapping of values/shape dimensions to columns.
421
422 /// Worklist of values/shape dimensions that have not been processed yet.
423 std::queue<int64_t> worklist;
424
425 /// Constraint system of equalities and inequalities.
427
428 /// Builder for constructing affine expressions.
430
431 /// The current stop condition function.
433
434 /// Should conservative bounds be added for semi-affine expressions.
436};
437
438} // namespace mlir
439
440#include "mlir/Interfaces/ValueBoundsOpInterface.h.inc"
441
442#endif // MLIR_INTERFACES_VALUEBOUNDSOPINTERFACE_H_
lhs
Base type for affine expression.
Definition AffineExpr.h:68
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition AffineMap.h:46
This class is a general helper class for creating context-global objects like types,...
Definition Builders.h:51
FlatLinearConstraints is an extension of IntegerPolyhedron.
A hyperrectangular slice, represented as a list of offsets, sizes and strides.
HyperrectangularSlice(ArrayRef< OpFoldResult > offsets, ArrayRef< OpFoldResult > sizes, ArrayRef< OpFoldResult > strides)
ArrayRef< OpFoldResult > getMixedStrides() const
ArrayRef< OpFoldResult > getMixedSizes() const
ArrayRef< OpFoldResult > getMixedOffsets() const
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
This class represents a single result from folding an operation.
Helper class that builds a bound for a shaped value dimension or index-typed value.
BoundBuilder(ValueBoundsConstraintSet &cstr, Value value)
BoundBuilder & operator[](int64_t dim)
Specify a dimension, assuming that the underlying value is a shaped value.
A variable that can be added to the constraint set as a "column".
ValueDimList & getOperands()
Returns the map operands.
Variable(OpFoldResult ofr)
Construct a variable for an index-typed attribute or SSA value.
AffineMap getMap() const
Returns the affine map.
static bool compare(const Variable &lhs, ComparisonOperator cmp, const Variable &rhs)
Return "true" if "lhs cmp rhs" was proven to hold.
static FailureOr< bool > areEqual(const Variable &var1, const Variable &var2)
Compute whether the given variables are equal.
DenseMap< ValueDim, int64_t > valueDimToPosition
Reverse mapping of values/shape dimensions to columns.
void processWorklist()
Iteratively process all elements on the worklist until an index-typed value or shaped value meets sto...
bool addConservativeSemiAffineBounds
Should conservative bounds be added for semi-affine expressions.
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.
SmallVector< std::optional< ValueDim > > positionToValueDim
Mapping of columns to values/shape dimensions.
static LogicalResult computeIndependentBound(AffineMap &resultMap, ValueDimList &mapOperands, presburger::BoundType type, const Variable &var, ValueRange independencies, bool closedUB=false)
Compute a bound in that is independent of all values in independencies.
static FailureOr< bool > areEquivalentSlices(MLIRContext *ctx, const HyperrectangularSlice &slice1, const HyperrectangularSlice &slice2)
Return "true" if the given slices are guaranteed to be equivalent.
void projectOut(int64_t pos)
Project out the given column in the constraint set.
std::function< bool( Value, std::optional< int64_t >, ValueBoundsConstraintSet &cstr)> StopConditionFn
The stop condition when traversing the backward slice of a shaped value/ index-type value.
ValueBoundsConstraintSet(MLIRContext *ctx, const StopConditionFn &stopCondition, bool addConservativeSemiAffineBounds=false)
static FailureOr< int64_t > computeConstantDelta(Value value1, Value value2, std::optional< int64_t > dim1=std::nullopt, std::optional< int64_t > dim2=std::nullopt)
Compute a constant delta between the given two values.
static llvm::FailureOr< bool > strongCompare(const Variable &lhs, ComparisonOperator cmp, const Variable &rhs)
This function is similar to ValueBoundsConstraintSet::compare, except that it returns false if !...
void addBound(presburger::BoundType type, int64_t pos, AffineExpr expr)
Bound the given column in the underlying constraint set by the given expression.
StopConditionFn stopCondition
The current stop condition function.
ComparisonOperator
Comparison operator for ValueBoundsConstraintSet::compare.
BoundBuilder bound(Value value)
Add a bound for the given index-typed value or shaped value.
static LogicalResult computeBound(AffineMap &resultMap, ValueDimList &mapOperands, presburger::BoundType type, const Variable &var, StopConditionFn stopCondition, bool closedUB=false)
Compute a bound for the given variable.
int64_t getPos(Value value, std::optional< int64_t > dim=std::nullopt) const
Return the column position of the given value/dimension.
int64_t insert(Value value, std::optional< int64_t > dim, bool isSymbol=true, bool addToWorklist=true)
Insert a value/dimension into the constraint set.
bool comparePos(int64_t lhsPos, ComparisonOperator cmp, int64_t rhsPos)
Return "true" if, based on the current state of the constraint system, "lhs cmp rhs" was proven to ho...
void dump() const
Debugging only: Dump the constraint set and the column-to-value/dim mapping to llvm::errs.
std::queue< int64_t > worklist
Worklist of values/shape dimensions that have not been processed yet.
FlatLinearConstraints cstr
Constraint system of equalities and inequalities.
bool isMapped(Value value, std::optional< int64_t > dim=std::nullopt) const
Return "true" if the given value/dim is mapped (i.e., has a corresponding column in the constraint sy...
llvm::FailureOr< bool > strongComparePos(int64_t lhsPos, ComparisonOperator cmp, int64_t rhsPos)
Return "true" if, based on the current state of the constraint system, "lhs cmp rhs" was proven to ho...
AffineExpr getPosExpr(int64_t pos)
Return an affine expression that represents column pos in the constraint set.
void projectOutAnonymous(std::optional< int64_t > except=std::nullopt)
static FailureOr< bool > areOverlappingSlices(MLIRContext *ctx, const HyperrectangularSlice &slice1, const HyperrectangularSlice &slice2)
Return "true" if the given slices are guaranteed to be overlapping.
std::pair< Value, int64_t > ValueDim
An index-typed value or the dimension of a shaped-type value.
void populateConstraints(Value value, std::optional< int64_t > dim)
Traverse the IR starting from the given value/dim and populate constraints as long as the stop condit...
Builder builder
Builder for constructing affine expressions.
bool populateAndCompare(const Variable &lhs, ComparisonOperator cmp, const Variable &rhs)
Populate constraints for lhs/rhs (until the stop condition is met).
static FailureOr< int64_t > computeConstantBound(presburger::BoundType type, const Variable &var, const StopConditionFn &stopCondition=nullptr, bool closedUB=false)
Compute a constant bound for the given variable.
static constexpr int64_t kIndexValue
Dimension identifier to indicate a value is index-typed.
static LogicalResult computeDependentBound(AffineMap &resultMap, ValueDimList &mapOperands, presburger::BoundType type, const Variable &var, ValueDimList dependencies, bool closedUB=false)
Compute a bound in terms of the values/dimensions in dependencies.
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:387
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
BoundType
The type of bound: equal, lower bound or upper bound.
Include the generated interface declarations.
bool operator!=(RegionBranchPoint lhs, RegionBranchPoint rhs)
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
Definition LLVM.h:126
SmallVector< std::pair< Value, std::optional< int64_t > > > ValueDimList
llvm::function_ref< Fn > function_ref
Definition LLVM.h:152