MLIR  20.0.0git
Utils.h
Go to the documentation of this file.
1 //===- Utils.h - General utilities for Presburger library ------*- 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 // Utility functions required by the Presburger Library.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef MLIR_ANALYSIS_PRESBURGER_UTILS_H
14 #define MLIR_ANALYSIS_PRESBURGER_UTILS_H
15 
17 #include "llvm/ADT/DynamicAPInt.h"
18 #include "llvm/ADT/STLExtras.h"
19 #include "llvm/ADT/SmallBitVector.h"
20 #include <optional>
21 
22 namespace mlir {
23 namespace presburger {
24 class IntegerRelation;
25 
26 /// This class represents the result of operations optimizing something subject
27 /// to some constraints. If the constraints were not satisfiable the, kind will
28 /// be Empty. If the optimum is unbounded, the kind is Unbounded, and if the
29 /// optimum is bounded, the kind will be Bounded and `optimum` holds the optimal
30 /// value.
32 template <typename T>
33 class MaybeOptimum {
34 public:
35 private:
37  T optimum;
38 
39 public:
40  MaybeOptimum() = default;
41  MaybeOptimum(OptimumKind kind) : kind(kind) {
42  assert(kind != OptimumKind::Bounded &&
43  "Bounded optima should be constructed by specifying the optimum!");
44  }
45  MaybeOptimum(const T &optimum)
46  : kind(OptimumKind::Bounded), optimum(optimum) {}
47 
48  OptimumKind getKind() const { return kind; }
49  bool isBounded() const { return kind == OptimumKind::Bounded; }
50  bool isUnbounded() const { return kind == OptimumKind::Unbounded; }
51  bool isEmpty() const { return kind == OptimumKind::Empty; }
52 
53  std::optional<T> getOptimumIfBounded() const { return optimum; }
54  const T &getBoundedOptimum() const {
55  assert(kind == OptimumKind::Bounded &&
56  "This should be called only for bounded optima");
57  return optimum;
58  }
60  assert(kind == OptimumKind::Bounded &&
61  "This should be called only for bounded optima");
62  return optimum;
63  }
64  const T &operator*() const { return getBoundedOptimum(); }
65  T &operator*() { return getBoundedOptimum(); }
66  const T *operator->() const { return &getBoundedOptimum(); }
67  T *operator->() { return &getBoundedOptimum(); }
68  bool operator==(const MaybeOptimum<T> &other) const {
69  if (kind != other.kind)
70  return false;
71  if (kind != OptimumKind::Bounded)
72  return true;
73  return optimum == other.optimum;
74  }
75 
76  // Given f that takes a T and returns a U, convert this `MaybeOptimum<T>` to
77  // a `MaybeOptimum<U>` by applying `f` to the bounded optimum if it exists, or
78  // returning a MaybeOptimum of the same kind otherwise.
79  template <class Function>
80  auto map(const Function &f) const & -> MaybeOptimum<decltype(f(optimum))> {
81  if (kind == OptimumKind::Bounded)
82  return f(optimum);
83  return kind;
84  }
85 };
86 
87 /// `ReprKind` enum is used to set the constraint type in `MaybeLocalRepr`.
88 enum class ReprKind { Inequality, Equality, None };
89 
90 /// `MaybeLocalRepr` contains the indices of the constraints that can be
91 /// expressed as a floordiv of an affine function. If it's an `equality`
92 /// constraint, `equalityIdx` is set, in case of `inequality` the
93 /// `lowerBoundIdx` and `upperBoundIdx` is set. By default the kind attribute is
94 /// set to None.
97  explicit operator bool() const { return kind != ReprKind::None; }
98  union {
99  unsigned equalityIdx;
100  struct {
103  } repr;
104 };
105 
106 /// Class storing division representation of local variables of a constraint
107 /// system. The coefficients of the dividends are stored in order:
108 /// [nonLocalVars, localVars, constant]. Each local variable may or may not have
109 /// a representation. If the local does not have a representation, the dividend
110 /// of the division has no meaning and the denominator is zero. If it has a
111 /// representation, the denominator will be positive.
112 ///
113 /// The i^th division here, represents the division representation of the
114 /// variable at position `divOffset + i` in the constraint system.
116 public:
117  DivisionRepr(unsigned numVars, unsigned numDivs)
118  : dividends(numDivs, numVars + 1), denoms(numDivs, DynamicAPInt(0)) {}
119 
120  DivisionRepr(unsigned numVars) : dividends(0, numVars + 1) {}
121 
122  unsigned getNumVars() const { return dividends.getNumColumns() - 1; }
123  unsigned getNumDivs() const { return dividends.getNumRows(); }
124  unsigned getNumNonDivs() const { return getNumVars() - getNumDivs(); }
125  // Get the offset from where division variables start.
126  unsigned getDivOffset() const { return getNumVars() - getNumDivs(); }
127 
128  // Check whether the `i^th` division has a division representation or not.
129  bool hasRepr(unsigned i) const { return denoms[i] != 0; }
130  // Check whether all the divisions have a division representation or not.
131  bool hasAllReprs() const { return !llvm::is_contained(denoms, 0); }
132 
133  // Clear the division representation of the i^th local variable.
134  void clearRepr(unsigned i) { denoms[i] = 0; }
135 
136  // Get the dividend of the `i^th` division.
138  return dividends.getRow(i);
139  }
141  return dividends.getRow(i);
142  }
143 
144  // For a given point containing values for each variable other than the
145  // division variables, try to find the values for each division variable from
146  // their division representation.
148  divValuesAt(ArrayRef<DynamicAPInt> point) const;
149 
150  // Get the `i^th` denominator.
151  DynamicAPInt &getDenom(unsigned i) { return denoms[i]; }
152  DynamicAPInt getDenom(unsigned i) const { return denoms[i]; }
153 
154  ArrayRef<DynamicAPInt> getDenoms() const { return denoms; }
155 
156  void setDiv(unsigned i, ArrayRef<DynamicAPInt> dividend,
157  const DynamicAPInt &divisor) {
158  dividends.setRow(i, dividend);
159  denoms[i] = divisor;
160  }
161 
162  // Find the greatest common divisor (GCD) of the dividends and divisor for
163  // each valid division. Divide the dividends and divisor by the GCD to
164  // simplify the expression.
165  void normalizeDivs();
166 
167  void insertDiv(unsigned pos, ArrayRef<DynamicAPInt> dividend,
168  const DynamicAPInt &divisor);
169  void insertDiv(unsigned pos, unsigned num = 1);
170 
171  /// Removes duplicate divisions. On every possible duplicate division found,
172  /// `merge(i, j)`, where `i`, `j` are current index of the duplicate
173  /// divisions, is called and division at index `j` is merged into division at
174  /// index `i`. If `merge(i, j)` returns `true`, the divisions are merged i.e.
175  /// `j^th` division gets eliminated and it's each instance is replaced by
176  /// `i^th` division. If it returns `false`, the divisions are not merged.
177  /// `merge` can also do side effects, For example it can merge the local
178  /// variables in IntegerRelation.
179  void
180  removeDuplicateDivs(llvm::function_ref<bool(unsigned i, unsigned j)> merge);
181 
182  void print(raw_ostream &os) const;
183  void dump() const;
184 
185 private:
186  /// Each row of the Matrix represents a single division dividend. The
187  /// `i^th` row represents the dividend of the variable at `divOffset + i`
188  /// in the constraint system (and the `i^th` local variable).
189  IntMatrix dividends;
190 
191  /// Denominators of each division. If a denominator of a division is `0`, the
192  /// division variable is considered to not have a division representation.
193  /// Otherwise, the denominator is positive.
195 };
196 
197 /// If `q` is defined to be equal to `expr floordiv d`, this equivalent to
198 /// saying that `q` is an integer and `q` is subject to the inequalities
199 /// `0 <= expr - d*q <= c - 1` (quotient remainder theorem).
200 ///
201 /// Rearranging, we get the bounds on `q`: d*q <= expr <= d*q + d - 1.
202 ///
203 /// `getDivUpperBound` returns `d*q <= expr`, and
204 /// `getDivLowerBound` returns `expr <= d*q + d - 1`.
205 ///
206 /// The parameter `dividend` corresponds to `expr` above, `divisor` to `d`, and
207 /// `localVarIdx` to the position of `q` in the coefficient list.
208 ///
209 /// The coefficient of `q` in `dividend` must be zero, as it is not allowed for
210 /// local variable to be a floor division of an expression involving itself.
211 /// The divisor must be positive.
213  const DynamicAPInt &divisor,
214  unsigned localVarIdx);
216  const DynamicAPInt &divisor,
217  unsigned localVarIdx);
218 
219 llvm::SmallBitVector getSubrangeBitVector(unsigned len, unsigned setOffset,
220  unsigned numSet);
221 
222 /// Check if the pos^th variable can be expressed as a floordiv of an affine
223 /// function of other variables (where the divisor is a positive constant).
224 /// `foundRepr` contains a boolean for each variable indicating if the
225 /// explicit representation for that variable has already been computed.
226 /// Return the given array as an array of DynamicAPInts.
228 /// Return the given array as an array of int64_t.
230 
231 /// Returns the `MaybeLocalRepr` struct which contains the indices of the
232 /// constraints that can be expressed as a floordiv of an affine function. If
233 /// the representation could be computed, `dividend` and `divisor` are set,
234 /// in which case, denominator will be positive. If the representation could
235 /// not be computed, the kind attribute in `MaybeLocalRepr` is set to None.
236 MaybeLocalRepr computeSingleVarRepr(const IntegerRelation &cst,
237  ArrayRef<bool> foundRepr, unsigned pos,
239  DynamicAPInt &divisor);
240 
241 /// The following overload using int64_t is required for a callsite in
242 /// AffineStructures.h.
243 MaybeLocalRepr computeSingleVarRepr(const IntegerRelation &cst,
244  ArrayRef<bool> foundRepr, unsigned pos,
245  SmallVector<int64_t, 8> &dividend,
246  unsigned &divisor);
247 
248 /// Given two relations, A and B, add additional local vars to the sets such
249 /// that both have the union of the local vars in each set, without changing
250 /// the set of points that lie in A and B.
251 ///
252 /// While taking union, if a local var in any set has a division representation
253 /// which is a duplicate of division representation, of another local var in any
254 /// set, it is not added to the final union of local vars and is instead merged.
255 ///
256 /// On every possible merge, `merge(i, j)` is called. `i`, `j` are position
257 /// of local variables in both sets which are being merged. If `merge(i, j)`
258 /// returns true, the divisions are merged, otherwise the divisions are not
259 /// merged.
260 void mergeLocalVars(IntegerRelation &relA, IntegerRelation &relB,
261  llvm::function_ref<bool(unsigned i, unsigned j)> merge);
262 
263 /// Compute the gcd of the range.
264 DynamicAPInt gcdRange(ArrayRef<DynamicAPInt> range);
265 
266 /// Divide the range by its gcd and return the gcd.
268 
269 /// Normalize the given (numerator, denominator) pair by dividing out the
270 /// common factors between them. The numerator here is an affine expression
271 /// with integer coefficients. The denominator must be positive.
272 void normalizeDiv(MutableArrayRef<DynamicAPInt> num, DynamicAPInt &denom);
273 
274 /// Return `coeffs` with all the elements negated.
276 
277 /// Return the complement of the given inequality.
278 ///
279 /// The complement of a_1 x_1 + ... + a_n x_ + c >= 0 is
280 /// a_1 x_1 + ... + a_n x_ + c < 0, i.e., -a_1 x_1 - ... - a_n x_ - c - 1 >= 0,
281 /// since all the variables are constrained to be integers.
283 
284 /// Compute the dot product of two vectors.
285 /// The vectors must have the same sizes.
287 
288 /// Find the product of two polynomials, each given by an array of
289 /// coefficients.
290 std::vector<Fraction> multiplyPolynomials(ArrayRef<Fraction> a,
292 
294 
295 } // namespace presburger
296 } // namespace mlir
297 
298 #endif // MLIR_ANALYSIS_PRESBURGER_UTILS_H
Class storing division representation of local variables of a constraint system.
Definition: Utils.h:115
void removeDuplicateDivs(llvm::function_ref< bool(unsigned i, unsigned j)> merge)
Removes duplicate divisions.
Definition: Utils.cpp:441
bool hasAllReprs() const
Definition: Utils.h:131
void clearRepr(unsigned i)
Definition: Utils.h:134
unsigned getNumNonDivs() const
Definition: Utils.h:124
unsigned getNumVars() const
Definition: Utils.h:122
DivisionRepr(unsigned numVars)
Definition: Utils.h:120
ArrayRef< DynamicAPInt > getDenoms() const
Definition: Utils.h:154
unsigned getDivOffset() const
Definition: Utils.h:126
void print(raw_ostream &os) const
Definition: Utils.cpp:512
unsigned getNumDivs() const
Definition: Utils.h:123
DynamicAPInt getDenom(unsigned i) const
Definition: Utils.h:152
SmallVector< std::optional< DynamicAPInt >, 4 > divValuesAt(ArrayRef< DynamicAPInt > point) const
Definition: Utils.cpp:392
ArrayRef< DynamicAPInt > getDividend(unsigned i) const
Definition: Utils.h:140
DynamicAPInt & getDenom(unsigned i)
Definition: Utils.h:151
void insertDiv(unsigned pos, ArrayRef< DynamicAPInt > dividend, const DynamicAPInt &divisor)
Definition: Utils.cpp:495
void setDiv(unsigned i, ArrayRef< DynamicAPInt > dividend, const DynamicAPInt &divisor)
Definition: Utils.h:156
bool hasRepr(unsigned i) const
Definition: Utils.h:129
DivisionRepr(unsigned numVars, unsigned numDivs)
Definition: Utils.h:117
MutableArrayRef< DynamicAPInt > getDividend(unsigned i)
Definition: Utils.h:137
unsigned getNumRows() const
Definition: Matrix.h:86
MutableArrayRef< T > getRow(unsigned row)
Get a [Mutable]ArrayRef corresponding to the specified row.
Definition: Matrix.cpp:130
void setRow(unsigned row, ArrayRef< T > elems)
Set the specified row to elems.
Definition: Matrix.cpp:140
unsigned getNumColumns() const
Definition: Matrix.h:88
const T & getBoundedOptimum() const
Definition: Utils.h:54
bool operator==(const MaybeOptimum< T > &other) const
Definition: Utils.h:68
bool isBounded() const
Definition: Utils.h:49
MaybeOptimum(const T &optimum)
Definition: Utils.h:45
MaybeOptimum(OptimumKind kind)
Definition: Utils.h:41
OptimumKind getKind() const
Definition: Utils.h:48
bool isUnbounded() const
Definition: Utils.h:50
std::optional< T > getOptimumIfBounded() const
Definition: Utils.h:53
const T * operator->() const
Definition: Utils.h:66
auto map(const Function &f) const &-> MaybeOptimum< decltype(f(optimum))>
Definition: Utils.h:80
const T & operator*() const
Definition: Utils.h:64
void normalizeDiv(MutableArrayRef< DynamicAPInt > num, DynamicAPInt &denom)
Normalize the given (numerator, denominator) pair by dividing out the common factors between them.
Definition: Utils.cpp:361
ReprKind
ReprKind enum is used to set the constraint type in MaybeLocalRepr.
Definition: Utils.h:88
SmallVector< DynamicAPInt, 8 > getDynamicAPIntVec(ArrayRef< int64_t > range)
Check if the pos^th variable can be expressed as a floordiv of an affine function of other variables ...
Definition: Utils.cpp:524
DynamicAPInt gcdRange(ArrayRef< DynamicAPInt > range)
Compute the gcd of the range.
Definition: Utils.cpp:342
MaybeLocalRepr computeSingleVarRepr(const IntegerRelation &cst, ArrayRef< bool > foundRepr, unsigned pos, MutableArrayRef< DynamicAPInt > dividend, DynamicAPInt &divisor)
Returns the MaybeLocalRepr struct which contains the indices of the constraints that can be expressed...
Definition: Utils.cpp:228
void mergeLocalVars(IntegerRelation &relA, IntegerRelation &relB, llvm::function_ref< bool(unsigned i, unsigned j)> merge)
Given two relations, A and B, add additional local vars to the sets such that both have the union of ...
Definition: Utils.cpp:289
OptimumKind
This class represents the result of operations optimizing something subject to some constraints.
Definition: Utils.h:31
SmallVector< DynamicAPInt, 8 > getNegatedCoeffs(ArrayRef< DynamicAPInt > coeffs)
Return coeffs with all the elements negated.
Definition: Utils.cpp:373
Fraction dotProduct(ArrayRef< Fraction > a, ArrayRef< Fraction > b)
Compute the dot product of two vectors.
Definition: Utils.cpp:538
SmallVector< int64_t, 8 > getInt64Vec(ArrayRef< DynamicAPInt > range)
Return the given array as an array of int64_t.
Definition: Utils.cpp:531
SmallVector< DynamicAPInt, 8 > getDivUpperBound(ArrayRef< DynamicAPInt > dividend, const DynamicAPInt &divisor, unsigned localVarIdx)
If q is defined to be equal to expr floordiv d, this equivalent to saying that q is an integer and q ...
Definition: Utils.cpp:316
bool isRangeZero(ArrayRef< Fraction > arr)
Definition: Utils.cpp:573
std::vector< Fraction > multiplyPolynomials(ArrayRef< Fraction > a, ArrayRef< Fraction > b)
Find the product of two polynomials, each given by an array of coefficients.
Definition: Utils.cpp:549
llvm::SmallBitVector getSubrangeBitVector(unsigned len, unsigned setOffset, unsigned numSet)
Definition: Utils.cpp:281
SmallVector< DynamicAPInt, 8 > getDivLowerBound(ArrayRef< DynamicAPInt > dividend, const DynamicAPInt &divisor, unsigned localVarIdx)
Definition: Utils.cpp:328
DynamicAPInt normalizeRange(MutableArrayRef< DynamicAPInt > range)
Divide the range by its gcd and return the gcd.
Definition: Utils.cpp:352
SmallVector< DynamicAPInt, 8 > getComplementIneq(ArrayRef< DynamicAPInt > ineq)
Return the complement of the given inequality.
Definition: Utils.cpp:382
Include the generated interface declarations.
MaybeLocalRepr contains the indices of the constraints that can be expressed as a floordiv of an affi...
Definition: Utils.h:95
union mlir::presburger::MaybeLocalRepr::@0 repr
struct mlir::presburger::MaybeLocalRepr::@0::@1 inequalityPair
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.