MLIR 22.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
24namespace mlir {
25namespace presburger {
26class 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.
34template <typename T>
36public:
37private:
39 T optimum;
40
41public:
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`.
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 {
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.
118public:
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.
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
187private:
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
221llvm::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.
238MaybeLocalRepr 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.
245MaybeLocalRepr 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.
262void mergeLocalVars(IntegerRelation &relA, IntegerRelation &relB,
263 llvm::function_ref<bool(unsigned i, unsigned j)> merge);
264
265/// Compute the gcd of the range.
266DynamicAPInt 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.
274void 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.
292std::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;
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.
313template <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'.
327template <class T>
328void 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
b
Return true if permutation is a valid permutation of the outer_dims_perm (case OuterOrInnerPerm::Oute...
void removeDuplicateDivs(llvm::function_ref< bool(unsigned i, unsigned j)> merge)
Removes duplicate divisions.
Definition Utils.cpp:440
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:511
unsigned getNumDivs() const
Definition Utils.h:125
ArrayRef< DynamicAPInt > getDividend(unsigned i) const
Definition Utils.h:142
DynamicAPInt getDenom(unsigned i) const
Definition Utils.h:154
SmallVector< std::optional< DynamicAPInt >, 4 > divValuesAt(ArrayRef< DynamicAPInt > point) const
Definition Utils.cpp:391
DynamicAPInt & getDenom(unsigned i)
Definition Utils.h:153
void insertDiv(unsigned pos, ArrayRef< DynamicAPInt > dividend, const DynamicAPInt &divisor)
Definition Utils.cpp:494
void setDiv(unsigned i, ArrayRef< DynamicAPInt > dividend, const DynamicAPInt &divisor)
Definition Utils.h:158
MutableArrayRef< DynamicAPInt > getDividend(unsigned i)
Definition Utils.h:139
bool hasRepr(unsigned i) const
Definition Utils.h:131
DivisionRepr(unsigned numVars, unsigned numDivs)
Definition Utils.h:119
An IntegerRelation represents the set of points from a PresburgerSpace that satisfy a list of affine ...
const T * operator->() const
Definition Utils.h:68
bool operator==(const MaybeOptimum< T > &other) const
Definition Utils.h:70
std::optional< T > getOptimumIfBounded() const
Definition Utils.h:55
MaybeOptimum(const T &optimum)
Definition Utils.h:47
MaybeOptimum(OptimumKind kind)
Definition Utils.h:43
const T & getBoundedOptimum() const
Definition Utils.h:56
const T & operator*() const
Definition Utils.h:66
OptimumKind getKind() const
Definition Utils.h:50
auto map(const Function &f) const &-> MaybeOptimum< decltype(f(optimum))>
Definition Utils.h:82
void normalizeDiv(MutableArrayRef< DynamicAPInt > num, DynamicAPInt &denom)
Normalize the given (numerator, denominator) pair by dividing out the common factors between them.
Definition Utils.cpp:360
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:523
DynamicAPInt gcdRange(ArrayRef< DynamicAPInt > range)
Compute the gcd of the range.
Definition Utils.cpp:341
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:227
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:288
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:372
Fraction dotProduct(ArrayRef< Fraction > a, ArrayRef< Fraction > b)
Compute the dot product of two vectors.
Definition Utils.cpp:537
SmallVector< int64_t, 8 > getInt64Vec(ArrayRef< DynamicAPInt > range)
Return the given array as an array of int64_t.
Definition Utils.cpp:530
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:315
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:572
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:548
llvm::SmallBitVector getSubrangeBitVector(unsigned len, unsigned setOffset, unsigned numSet)
Definition Utils.cpp:280
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:327
DynamicAPInt normalizeRange(MutableArrayRef< DynamicAPInt > range)
Divide the range by its gcd and return the gcd.
Definition Utils.cpp:351
SmallVector< DynamicAPInt, 8 > getComplementIneq(ArrayRef< DynamicAPInt > ineq)
Return the complement of the given inequality.
Definition Utils.cpp:381
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
struct mlir::presburger::MaybeLocalRepr::@377221123230274054275363221004054023045275014036::@331175230026152333045220100217334046353170055246 inequalityPair
union mlir::presburger::MaybeLocalRepr::@377221123230274054275363221004054023045275014036 repr
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.