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 "llvm/Support/raw_ostream.h"
21 #include <optional>
22 #include <string>
23 
24 namespace mlir {
25 namespace presburger {
26 class IntegerRelation;
27 
28 /// This class represents the result of operations optimizing something subject
29 /// to some constraints. If the constraints were not satisfiable the, kind will
30 /// be Empty. If the optimum is unbounded, the kind is Unbounded, and if the
31 /// optimum is bounded, the kind will be Bounded and `optimum` holds the optimal
32 /// value.
34 template <typename T>
35 class MaybeOptimum {
36 public:
37 private:
39  T optimum;
40 
41 public:
42  MaybeOptimum() = default;
43  MaybeOptimum(OptimumKind kind) : kind(kind) {
44  assert(kind != OptimumKind::Bounded &&
45  "Bounded optima should be constructed by specifying the optimum!");
46  }
47  MaybeOptimum(const T &optimum)
48  : kind(OptimumKind::Bounded), optimum(optimum) {}
49 
50  OptimumKind getKind() const { return kind; }
51  bool isBounded() const { return kind == OptimumKind::Bounded; }
52  bool isUnbounded() const { return kind == OptimumKind::Unbounded; }
53  bool isEmpty() const { return kind == OptimumKind::Empty; }
54 
55  std::optional<T> getOptimumIfBounded() const { return optimum; }
56  const T &getBoundedOptimum() const {
57  assert(kind == OptimumKind::Bounded &&
58  "This should be called only for bounded optima");
59  return optimum;
60  }
62  assert(kind == OptimumKind::Bounded &&
63  "This should be called only for bounded optima");
64  return optimum;
65  }
66  const T &operator*() const { return getBoundedOptimum(); }
67  T &operator*() { return getBoundedOptimum(); }
68  const T *operator->() const { return &getBoundedOptimum(); }
69  T *operator->() { return &getBoundedOptimum(); }
70  bool operator==(const MaybeOptimum<T> &other) const {
71  if (kind != other.kind)
72  return false;
73  if (kind != OptimumKind::Bounded)
74  return true;
75  return optimum == other.optimum;
76  }
77 
78  // Given f that takes a T and returns a U, convert this `MaybeOptimum<T>` to
79  // a `MaybeOptimum<U>` by applying `f` to the bounded optimum if it exists, or
80  // returning a MaybeOptimum of the same kind otherwise.
81  template <class Function>
82  auto map(const Function &f) const & -> MaybeOptimum<decltype(f(optimum))> {
83  if (kind == OptimumKind::Bounded)
84  return f(optimum);
85  return kind;
86  }
87 };
88 
89 /// `ReprKind` enum is used to set the constraint type in `MaybeLocalRepr`.
90 enum class ReprKind { Inequality, Equality, None };
91 
92 /// `MaybeLocalRepr` contains the indices of the constraints that can be
93 /// expressed as a floordiv of an affine function. If it's an `equality`
94 /// constraint, `equalityIdx` is set, in case of `inequality` the
95 /// `lowerBoundIdx` and `upperBoundIdx` is set. By default the kind attribute is
96 /// set to None.
99  explicit operator bool() const { return kind != ReprKind::None; }
100  union {
101  unsigned equalityIdx;
102  struct {
105  } repr;
106 };
107 
108 /// Class storing division representation of local variables of a constraint
109 /// system. The coefficients of the dividends are stored in order:
110 /// [nonLocalVars, localVars, constant]. Each local variable may or may not have
111 /// a representation. If the local does not have a representation, the dividend
112 /// of the division has no meaning and the denominator is zero. If it has a
113 /// representation, the denominator will be positive.
114 ///
115 /// The i^th division here, represents the division representation of the
116 /// variable at position `divOffset + i` in the constraint system.
118 public:
119  DivisionRepr(unsigned numVars, unsigned numDivs)
120  : dividends(numDivs, numVars + 1), denoms(numDivs, DynamicAPInt(0)) {}
121 
122  DivisionRepr(unsigned numVars) : dividends(0, numVars + 1) {}
123 
124  unsigned getNumVars() const { return dividends.getNumColumns() - 1; }
125  unsigned getNumDivs() const { return dividends.getNumRows(); }
126  unsigned getNumNonDivs() const { return getNumVars() - getNumDivs(); }
127  // Get the offset from where division variables start.
128  unsigned getDivOffset() const { return getNumVars() - getNumDivs(); }
129 
130  // Check whether the `i^th` division has a division representation or not.
131  bool hasRepr(unsigned i) const { return denoms[i] != 0; }
132  // Check whether all the divisions have a division representation or not.
133  bool hasAllReprs() const { return !llvm::is_contained(denoms, 0); }
134 
135  // Clear the division representation of the i^th local variable.
136  void clearRepr(unsigned i) { denoms[i] = 0; }
137 
138  // Get the dividend of the `i^th` division.
140  return dividends.getRow(i);
141  }
143  return dividends.getRow(i);
144  }
145 
146  // For a given point containing values for each variable other than the
147  // division variables, try to find the values for each division variable from
148  // their division representation.
150  divValuesAt(ArrayRef<DynamicAPInt> point) const;
151 
152  // Get the `i^th` denominator.
153  DynamicAPInt &getDenom(unsigned i) { return denoms[i]; }
154  DynamicAPInt getDenom(unsigned i) const { return denoms[i]; }
155 
156  ArrayRef<DynamicAPInt> getDenoms() const { return denoms; }
157 
158  void setDiv(unsigned i, ArrayRef<DynamicAPInt> dividend,
159  const DynamicAPInt &divisor) {
160  dividends.setRow(i, dividend);
161  denoms[i] = divisor;
162  }
163 
164  // Find the greatest common divisor (GCD) of the dividends and divisor for
165  // each valid division. Divide the dividends and divisor by the GCD to
166  // simplify the expression.
167  void normalizeDivs();
168 
169  void insertDiv(unsigned pos, ArrayRef<DynamicAPInt> dividend,
170  const DynamicAPInt &divisor);
171  void insertDiv(unsigned pos, unsigned num = 1);
172 
173  /// Removes duplicate divisions. On every possible duplicate division found,
174  /// `merge(i, j)`, where `i`, `j` are current index of the duplicate
175  /// divisions, is called and division at index `j` is merged into division at
176  /// index `i`. If `merge(i, j)` returns `true`, the divisions are merged i.e.
177  /// `j^th` division gets eliminated and it's each instance is replaced by
178  /// `i^th` division. If it returns `false`, the divisions are not merged.
179  /// `merge` can also do side effects, For example it can merge the local
180  /// variables in IntegerRelation.
181  void
182  removeDuplicateDivs(llvm::function_ref<bool(unsigned i, unsigned j)> merge);
183 
184  void print(raw_ostream &os) const;
185  void dump() const;
186 
187 private:
188  /// Each row of the Matrix represents a single division dividend. The
189  /// `i^th` row represents the dividend of the variable at `divOffset + i`
190  /// in the constraint system (and the `i^th` local variable).
191  IntMatrix dividends;
192 
193  /// Denominators of each division. If a denominator of a division is `0`, the
194  /// division variable is considered to not have a division representation.
195  /// Otherwise, the denominator is positive.
197 };
198 
199 /// If `q` is defined to be equal to `expr floordiv d`, this equivalent to
200 /// saying that `q` is an integer and `q` is subject to the inequalities
201 /// `0 <= expr - d*q <= c - 1` (quotient remainder theorem).
202 ///
203 /// Rearranging, we get the bounds on `q`: d*q <= expr <= d*q + d - 1.
204 ///
205 /// `getDivUpperBound` returns `d*q <= expr`, and
206 /// `getDivLowerBound` returns `expr <= d*q + d - 1`.
207 ///
208 /// The parameter `dividend` corresponds to `expr` above, `divisor` to `d`, and
209 /// `localVarIdx` to the position of `q` in the coefficient list.
210 ///
211 /// The coefficient of `q` in `dividend` must be zero, as it is not allowed for
212 /// local variable to be a floor division of an expression involving itself.
213 /// The divisor must be positive.
215  const DynamicAPInt &divisor,
216  unsigned localVarIdx);
218  const DynamicAPInt &divisor,
219  unsigned localVarIdx);
220 
221 llvm::SmallBitVector getSubrangeBitVector(unsigned len, unsigned setOffset,
222  unsigned numSet);
223 
224 /// Check if the pos^th variable can be expressed as a floordiv of an affine
225 /// function of other variables (where the divisor is a positive constant).
226 /// `foundRepr` contains a boolean for each variable indicating if the
227 /// explicit representation for that variable has already been computed.
228 /// Return the given array as an array of DynamicAPInts.
230 /// Return the given array as an array of int64_t.
232 
233 /// Returns the `MaybeLocalRepr` struct which contains the indices of the
234 /// constraints that can be expressed as a floordiv of an affine function. If
235 /// the representation could be computed, `dividend` and `divisor` are set,
236 /// in which case, denominator will be positive. If the representation could
237 /// not be computed, the kind attribute in `MaybeLocalRepr` is set to None.
238 MaybeLocalRepr computeSingleVarRepr(const IntegerRelation &cst,
239  ArrayRef<bool> foundRepr, unsigned pos,
241  DynamicAPInt &divisor);
242 
243 /// The following overload using int64_t is required for a callsite in
244 /// AffineStructures.h.
245 MaybeLocalRepr computeSingleVarRepr(const IntegerRelation &cst,
246  ArrayRef<bool> foundRepr, unsigned pos,
247  SmallVector<int64_t, 8> &dividend,
248  unsigned &divisor);
249 
250 /// Given two relations, A and B, add additional local vars to the sets such
251 /// that both have the union of the local vars in each set, without changing
252 /// the set of points that lie in A and B.
253 ///
254 /// While taking union, if a local var in any set has a division representation
255 /// which is a duplicate of division representation, of another local var in any
256 /// set, it is not added to the final union of local vars and is instead merged.
257 ///
258 /// On every possible merge, `merge(i, j)` is called. `i`, `j` are position
259 /// of local variables in both sets which are being merged. If `merge(i, j)`
260 /// returns true, the divisions are merged, otherwise the divisions are not
261 /// merged.
262 void mergeLocalVars(IntegerRelation &relA, IntegerRelation &relB,
263  llvm::function_ref<bool(unsigned i, unsigned j)> merge);
264 
265 /// Compute the gcd of the range.
266 DynamicAPInt gcdRange(ArrayRef<DynamicAPInt> range);
267 
268 /// Divide the range by its gcd and return the gcd.
270 
271 /// Normalize the given (numerator, denominator) pair by dividing out the
272 /// common factors between them. The numerator here is an affine expression
273 /// with integer coefficients. The denominator must be positive.
274 void normalizeDiv(MutableArrayRef<DynamicAPInt> num, DynamicAPInt &denom);
275 
276 /// Return `coeffs` with all the elements negated.
278 
279 /// Return the complement of the given inequality.
280 ///
281 /// The complement of a_1 x_1 + ... + a_n x_ + c >= 0 is
282 /// a_1 x_1 + ... + a_n x_ + c < 0, i.e., -a_1 x_1 - ... - a_n x_ - c - 1 >= 0,
283 /// since all the variables are constrained to be integers.
285 
286 /// Compute the dot product of two vectors.
287 /// The vectors must have the same sizes.
289 
290 /// Find the product of two polynomials, each given by an array of
291 /// coefficients.
292 std::vector<Fraction> multiplyPolynomials(ArrayRef<Fraction> a,
294 
296 
297 /// Example usage:
298 /// Print .12, 3.4, 56.7
299 /// preAlign = ".", minSpacing = 1,
300 /// .12 .12
301 /// 3.4 3.4
302 /// 56.7 56.7
304  // If unknown, set to 0 and pass the struct into updatePrintMetrics.
305  unsigned maxPreIndent;
306  unsigned maxPostIndent;
307  std::string preAlign;
308 };
309 
310 /// Iterate over each val in the table and update 'm' where
311 /// .maxPreIndent and .maxPostIndent are initialized to 0.
312 /// class T is any type that can be handled by llvm::raw_string_ostream.
313 template <class T>
315  std::string str;
316  llvm::raw_string_ostream(str) << val;
317  if (str.empty())
318  return;
319  unsigned preIndent = str.find(m.preAlign);
320  preIndent = (preIndent != (unsigned)std::string::npos) ? preIndent + 1 : 0;
321  m.maxPreIndent = std::max(m.maxPreIndent, preIndent);
322  m.maxPostIndent =
323  std::max(m.maxPostIndent, (unsigned int)(str.length() - preIndent));
324 }
325 
326 /// Print val in the table with metrics specified in 'm'.
327 template <class T>
328 void printWithPrintMetrics(raw_ostream &os, T val, unsigned minSpacing,
329  const PrintTableMetrics &m) {
330  std::string str;
331  llvm::raw_string_ostream(str) << val;
332  unsigned preIndent;
333  if (!str.empty()) {
334  preIndent = str.find(m.preAlign);
335  preIndent = (preIndent != (unsigned)std::string::npos) ? preIndent + 1 : 0;
336  } else {
337  preIndent = 0;
338  }
339  for (unsigned i = 0; i < (minSpacing + m.maxPreIndent - preIndent); ++i)
340  os << " ";
341  os << str;
342  for (unsigned i = 0; i < m.maxPostIndent - (str.length() - preIndent); ++i)
343  os << " ";
344 }
345 } // namespace presburger
346 } // namespace mlir
347 
348 #endif // MLIR_ANALYSIS_PRESBURGER_UTILS_H
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
Class storing division representation of local variables of a constraint system.
Definition: Utils.h:117
void removeDuplicateDivs(llvm::function_ref< bool(unsigned i, unsigned j)> merge)
Removes duplicate divisions.
Definition: Utils.cpp:441
bool hasAllReprs() const
Definition: Utils.h:133
void clearRepr(unsigned i)
Definition: Utils.h:136
unsigned getNumNonDivs() const
Definition: Utils.h:126
unsigned getNumVars() const
Definition: Utils.h:124
DivisionRepr(unsigned numVars)
Definition: Utils.h:122
ArrayRef< DynamicAPInt > getDenoms() const
Definition: Utils.h:156
unsigned getDivOffset() const
Definition: Utils.h:128
void print(raw_ostream &os) const
Definition: Utils.cpp:512
unsigned getNumDivs() const
Definition: Utils.h:125
DynamicAPInt getDenom(unsigned i) const
Definition: Utils.h:154
SmallVector< std::optional< DynamicAPInt >, 4 > divValuesAt(ArrayRef< DynamicAPInt > point) const
Definition: Utils.cpp:392
ArrayRef< DynamicAPInt > getDividend(unsigned i) const
Definition: Utils.h:142
DynamicAPInt & getDenom(unsigned i)
Definition: Utils.h:153
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:158
bool hasRepr(unsigned i) const
Definition: Utils.h:131
DivisionRepr(unsigned numVars, unsigned numDivs)
Definition: Utils.h:119
MutableArrayRef< DynamicAPInt > getDividend(unsigned i)
Definition: Utils.h:139
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:56
bool operator==(const MaybeOptimum< T > &other) const
Definition: Utils.h:70
bool isBounded() const
Definition: Utils.h:51
MaybeOptimum(const T &optimum)
Definition: Utils.h:47
MaybeOptimum(OptimumKind kind)
Definition: Utils.h:43
OptimumKind getKind() const
Definition: Utils.h:50
bool isUnbounded() const
Definition: Utils.h:52
std::optional< T > getOptimumIfBounded() const
Definition: Utils.h:55
const T * operator->() const
Definition: Utils.h:68
auto map(const Function &f) const &-> MaybeOptimum< decltype(f(optimum))>
Definition: Utils.h:82
const T & operator*() const
Definition: Utils.h:66
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:90
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:33
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
void printWithPrintMetrics(raw_ostream &os, T val, unsigned minSpacing, const PrintTableMetrics &m)
Print val in the table with metrics specified in 'm'.
Definition: Utils.h:328
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
void updatePrintMetrics(T val, PrintTableMetrics &m)
Iterate over each val in the table and update 'm' where .maxPreIndent and .maxPostIndent are initiali...
Definition: Utils.h:314
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:97
union mlir::presburger::MaybeLocalRepr::@0 repr
struct mlir::presburger::MaybeLocalRepr::@0::@1 inequalityPair
Example usage: Print .12, 3.4, 56.7 preAlign = ".", minSpacing = 1, .12 .12 3.4 3....
Definition: Utils.h:303
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.