1 //===- Utils.cpp - General utilities for Presburger library ---------------===//
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 #include "mlir/Analysis/Presburger/Utils.h"
14 #include "mlir/Analysis/Presburger/IntegerRelation.h"
15 #include "mlir/Support/LogicalResult.h"
16 #include "mlir/Support/MathExtras.h"
17 
18 using namespace mlir;
19 using namespace presburger;
20 
21 /// Normalize a division's `dividend` and the `divisor` by their GCD. For
22 /// example: if the dividend and divisor are [2,0,4] and 4 respectively,
23 /// they get normalized to [1,0,2] and 2.
24 static void normalizeDivisionByGCD(SmallVectorImpl<int64_t> &dividend,
25                                    unsigned &divisor) {
26   if (divisor == 0 || dividend.empty())
27     return;
28   // We take the absolute value of dividend's coefficients to make sure that
29   // `gcd` is positive.
30   int64_t gcd =
31       llvm::greatestCommonDivisor(std::abs(dividend.front()), int64_t(divisor));
32 
33   // The reason for ignoring the constant term is as follows.
34   // For a division:
35   //      floor((a + m.f(x))/(m.d))
36   // It can be replaced by:
37   //      floor((floor(a/m) + f(x))/d)
38   // Since `{a/m}/d` in the dividend satisfies 0 <= {a/m}/d < 1/d, it will not
39   // influence the result of the floor division and thus, can be ignored.
40   for (size_t i = 1, m = dividend.size() - 1; i < m; i++) {
41     gcd = llvm::greatestCommonDivisor(std::abs(dividend[i]), gcd);
42     if (gcd == 1)
43       return;
44   }
45 
46   // Normalize the dividend and the denominator.
47   std::transform(dividend.begin(), dividend.end(), dividend.begin(),
48                  [gcd](int64_t &n) { return floorDiv(n, gcd); });
49   divisor /= gcd;
50 }
51 
52 /// Check if the pos^th variable can be represented as a division using upper
53 /// bound inequality at position `ubIneq` and lower bound inequality at position
54 /// `lbIneq`.
55 ///
56 /// Let `var` be the pos^th variable, then `var` is equivalent to
57 /// `expr floordiv divisor` if there are constraints of the form:
58 ///      0 <= expr - divisor * var <= divisor - 1
59 /// Rearranging, we have:
60 ///       divisor * var - expr + (divisor - 1) >= 0  <-- Lower bound for 'var'
61 ///      -divisor * var + expr                 >= 0  <-- Upper bound for 'var'
62 ///
63 /// For example:
64 ///     32*k >= 16*i + j - 31                 <-- Lower bound for 'k'
65 ///     32*k  <= 16*i + j                     <-- Upper bound for 'k'
66 ///     expr = 16*i + j, divisor = 32
67 ///     k = ( 16*i + j ) floordiv 32
68 ///
69 ///     4q >= i + j - 2                       <-- Lower bound for 'q'
70 ///     4q <= i + j + 1                       <-- Upper bound for 'q'
71 ///     expr = i + j + 1, divisor = 4
72 ///     q = (i + j + 1) floordiv 4
73 //
74 /// This function also supports detecting divisions from bounds that are
75 /// strictly tighter than the division bounds described above, since tighter
76 /// bounds imply the division bounds. For example:
77 ///     4q - i - j + 2 >= 0                       <-- Lower bound for 'q'
78 ///    -4q + i + j     >= 0                       <-- Tight upper bound for 'q'
79 ///
80 /// To extract floor divisions with tighter bounds, we assume that that the
81 /// constraints are of the form:
82 ///     c <= expr - divisior * var <= divisor - 1, where 0 <= c <= divisor - 1
83 /// Rearranging, we have:
84 ///     divisor * var - expr + (divisor - 1) >= 0  <-- Lower bound for 'var'
85 ///    -divisor * var + expr - c             >= 0  <-- Upper bound for 'var'
86 ///
87 /// If successful, `expr` is set to dividend of the division and `divisor` is
88 /// set to the denominator of the division. The final division expression is
89 /// normalized by GCD.
90 static LogicalResult getDivRepr(const IntegerRelation &cst, unsigned pos,
91                                 unsigned ubIneq, unsigned lbIneq,
92                                 SmallVector<int64_t, 8> &expr,
93                                 unsigned &divisor) {
94 
95   assert(pos <= cst.getNumVars() && "Invalid variable position");
96   assert(ubIneq <= cst.getNumInequalities() &&
97          "Invalid upper bound inequality position");
98   assert(lbIneq <= cst.getNumInequalities() &&
99          "Invalid upper bound inequality position");
100 
101   // Extract divisor from the lower bound.
102   divisor = cst.atIneq(lbIneq, pos);
103 
104   // First, check if the constraints are opposite of each other except the
105   // constant term.
106   unsigned i = 0, e = 0;
107   for (i = 0, e = cst.getNumVars(); i < e; ++i)
108     if (cst.atIneq(ubIneq, i) != -cst.atIneq(lbIneq, i))
109       break;
110 
111   if (i < e)
112     return failure();
113 
114   // Then, check if the constant term is of the proper form.
115   // Due to the form of the upper/lower bound inequalities, the sum of their
116   // constants is `divisor - 1 - c`. From this, we can extract c:
117   int64_t constantSum = cst.atIneq(lbIneq, cst.getNumCols() - 1) +
118                         cst.atIneq(ubIneq, cst.getNumCols() - 1);
119   int64_t c = divisor - 1 - constantSum;
120 
121   // Check if `c` satisfies the condition `0 <= c <= divisor - 1`. This also
122   // implictly checks that `divisor` is positive.
123   if (!(0 <= c && c <= divisor - 1)) // NOLINT
124     return failure();
125 
126   // The inequality pair can be used to extract the division.
127   // Set `expr` to the dividend of the division except the constant term, which
128   // is set below.
129   expr.resize(cst.getNumCols(), 0);
130   for (i = 0, e = cst.getNumVars(); i < e; ++i)
131     if (i != pos)
132       expr[i] = cst.atIneq(ubIneq, i);
133 
134   // From the upper bound inequality's form, its constant term is equal to the
135   // constant term of `expr`, minus `c`. From this,
136   // constant term of `expr` = constant term of upper bound + `c`.
137   expr.back() = cst.atIneq(ubIneq, cst.getNumCols() - 1) + c;
138   normalizeDivisionByGCD(expr, divisor);
139 
140   return success();
141 }
142 
143 /// Check if the pos^th variable can be represented as a division using
144 /// equality at position `eqInd`.
145 ///
146 /// For example:
147 ///     32*k == 16*i + j - 31                 <-- `eqInd` for 'k'
148 ///     expr = 16*i + j - 31, divisor = 32
149 ///     k = (16*i + j - 31) floordiv 32
150 ///
151 /// If successful, `expr` is set to dividend of the division and `divisor` is
152 /// set to the denominator of the division. The final division expression is
153 /// normalized by GCD.
154 static LogicalResult getDivRepr(const IntegerRelation &cst, unsigned pos,
155                                 unsigned eqInd, SmallVector<int64_t, 8> &expr,
156                                 unsigned &divisor) {
157 
158   assert(pos <= cst.getNumVars() && "Invalid variable position");
159   assert(eqInd <= cst.getNumEqualities() && "Invalid equality position");
160 
161   // Extract divisor, the divisor can be negative and hence its sign information
162   // is stored in `signDiv` to reverse the sign of dividend's coefficients.
163   // Equality must involve the pos-th variable and hence `tempDiv` != 0.
164   int64_t tempDiv = cst.atEq(eqInd, pos);
165   if (tempDiv == 0)
166     return failure();
167   int64_t signDiv = tempDiv < 0 ? -1 : 1;
168 
169   // The divisor is always a positive integer.
170   divisor = tempDiv * signDiv;
171 
172   expr.resize(cst.getNumCols(), 0);
173   for (unsigned i = 0, e = cst.getNumVars(); i < e; ++i)
174     if (i != pos)
175       expr[i] = -signDiv * cst.atEq(eqInd, i);
176 
177   expr.back() = -signDiv * cst.atEq(eqInd, cst.getNumCols() - 1);
178   normalizeDivisionByGCD(expr, divisor);
179 
180   return success();
181 }
182 
183 // Returns `false` if the constraints depends on a variable for which an
184 // explicit representation has not been found yet, otherwise returns `true`.
185 static bool checkExplicitRepresentation(const IntegerRelation &cst,
186                                         ArrayRef<bool> foundRepr,
187                                         ArrayRef<int64_t> dividend,
188                                         unsigned pos) {
189   // Exit to avoid circular dependencies between divisions.
190   for (unsigned c = 0, e = cst.getNumVars(); c < e; ++c) {
191     if (c == pos)
192       continue;
193 
194     if (!foundRepr[c] && dividend[c] != 0) {
195       // Expression can't be constructed as it depends on a yet unknown
196       // variable.
197       //
198       // TODO: Visit/compute the variables in an order so that this doesn't
199       // happen. More complex but much more efficient.
200       return false;
201     }
202   }
203 
204   return true;
205 }
206 
207 /// Check if the pos^th variable can be expressed as a floordiv of an affine
208 /// function of other variables (where the divisor is a positive constant).
209 /// `foundRepr` contains a boolean for each variable indicating if the
210 /// explicit representation for that variable has already been computed.
211 /// Returns the `MaybeLocalRepr` struct which contains the indices of the
212 /// constraints that can be expressed as a floordiv of an affine function. If
213 /// the representation could be computed, `dividend` and `denominator` are set.
214 /// If the representation could not be computed, the kind attribute in
215 /// `MaybeLocalRepr` is set to None.
216 MaybeLocalRepr presburger::computeSingleVarRepr(
217     const IntegerRelation &cst, ArrayRef<bool> foundRepr, unsigned pos,
218     SmallVector<int64_t, 8> &dividend, unsigned &divisor) {
219   assert(pos < cst.getNumVars() && "invalid position");
220   assert(foundRepr.size() == cst.getNumVars() &&
221          "Size of foundRepr does not match total number of variables");
222 
223   SmallVector<unsigned, 4> lbIndices, ubIndices, eqIndices;
224   cst.getLowerAndUpperBoundIndices(pos, &lbIndices, &ubIndices, &eqIndices);
225   MaybeLocalRepr repr{};
226 
227   for (unsigned ubPos : ubIndices) {
228     for (unsigned lbPos : lbIndices) {
229       // Attempt to get divison representation from ubPos, lbPos.
230       if (failed(getDivRepr(cst, pos, ubPos, lbPos, dividend, divisor)))
231         continue;
232 
233       if (!checkExplicitRepresentation(cst, foundRepr, dividend, pos))
234         continue;
235 
236       repr.kind = ReprKind::Inequality;
237       repr.repr.inequalityPair = {ubPos, lbPos};
238       return repr;
239     }
240   }
241   for (unsigned eqPos : eqIndices) {
242     // Attempt to get divison representation from eqPos.
243     if (failed(getDivRepr(cst, pos, eqPos, dividend, divisor)))
244       continue;
245 
246     if (!checkExplicitRepresentation(cst, foundRepr, dividend, pos))
247       continue;
248 
249     repr.kind = ReprKind::Equality;
250     repr.repr.equalityIdx = eqPos;
251     return repr;
252   }
253   return repr;
254 }
255 
256 llvm::SmallBitVector presburger::getSubrangeBitVector(unsigned len,
257                                                       unsigned setOffset,
258                                                       unsigned numSet) {
259   llvm::SmallBitVector vec(len, false);
260   vec.set(setOffset, setOffset + numSet);
261   return vec;
262 }
263 
264 void presburger::removeDuplicateDivs(
265     std::vector<SmallVector<int64_t, 8>> &divs,
266     SmallVectorImpl<unsigned> &denoms, unsigned localOffset,
267     llvm::function_ref<bool(unsigned i, unsigned j)> merge) {
268 
269   // Find and merge duplicate divisions.
270   // TODO: Add division normalization to support divisions that differ by
271   // a constant.
272   // TODO: Add division ordering such that a division representation for local
273   // variable at position `i` only depends on local variables at position <
274   // `i`. This would make sure that all divisions depending on other local
275   // variables that can be merged, are merged.
276   for (unsigned i = 0; i < divs.size(); ++i) {
277     // Check if a division representation exists for the `i^th` local var.
278     if (denoms[i] == 0)
279       continue;
280     // Check if a division exists which is a duplicate of the division at `i`.
281     for (unsigned j = i + 1; j < divs.size(); ++j) {
282       // Check if a division representation exists for the `j^th` local var.
283       if (denoms[j] == 0)
284         continue;
285       // Check if the denominators match.
286       if (denoms[i] != denoms[j])
287         continue;
288       // Check if the representations are equal.
289       if (divs[i] != divs[j])
290         continue;
291 
292       // Merge divisions at position `j` into division at position `i`. If
293       // merge fails, do not merge these divs.
294       bool mergeResult = merge(i, j);
295       if (!mergeResult)
296         continue;
297 
298       // Update division information to reflect merging.
299       for (unsigned k = 0, g = divs.size(); k < g; ++k) {
300         SmallVector<int64_t, 8> &div = divs[k];
301         if (denoms[k] != 0) {
302           div[localOffset + i] += div[localOffset + j];
303           div.erase(div.begin() + localOffset + j);
304         }
305       }
306 
307       divs.erase(divs.begin() + j);
308       denoms.erase(denoms.begin() + j);
309       // Since `j` can never be zero, we do not need to worry about overflows.
310       --j;
311     }
312   }
313 }
314 
315 void presburger::mergeLocalVars(
316     IntegerRelation &relA, IntegerRelation &relB,
317     llvm::function_ref<bool(unsigned i, unsigned j)> merge) {
318   assert(relA.getSpace().isCompatible(relB.getSpace()) &&
319          "Spaces should be compatible.");
320 
321   // Merge local vars of relA and relB without using division information,
322   // i.e. append local vars of `relB` to `relA` and insert local vars of `relA`
323   // to `relB` at start of its local vars.
324   unsigned initLocals = relA.getNumLocalVars();
325   relA.insertVar(VarKind::Local, relA.getNumLocalVars(),
326                  relB.getNumLocalVars());
327   relB.insertVar(VarKind::Local, 0, initLocals);
328 
329   // Get division representations from each rel.
330   std::vector<SmallVector<int64_t, 8>> divsA, divsB;
331   SmallVector<unsigned, 4> denomsA, denomsB;
332   relA.getLocalReprs(divsA, denomsA);
333   relB.getLocalReprs(divsB, denomsB);
334 
335   // Copy division information for relB into `divsA` and `denomsA`, so that
336   // these have the combined division information of both rels. Since newly
337   // added local variables in relA and relB have no constraints, they will not
338   // have any division representation.
339   std::copy(divsB.begin() + initLocals, divsB.end(),
340             divsA.begin() + initLocals);
341   std::copy(denomsB.begin() + initLocals, denomsB.end(),
342             denomsA.begin() + initLocals);
343 
344   // Merge all divisions by removing duplicate divisions.
345   unsigned localOffset = relA.getVarKindOffset(VarKind::Local);
346   presburger::removeDuplicateDivs(divsA, denomsA, localOffset, merge);
347 }
348 
349 SmallVector<int64_t, 8> presburger::getDivUpperBound(ArrayRef<int64_t> dividend,
350                                                      int64_t divisor,
351                                                      unsigned localVarIdx) {
352   assert(dividend[localVarIdx] == 0 &&
353          "Local to be set to division must have zero coeff!");
354   SmallVector<int64_t, 8> ineq(dividend.begin(), dividend.end());
355   ineq[localVarIdx] = -divisor;
356   return ineq;
357 }
358 
359 SmallVector<int64_t, 8> presburger::getDivLowerBound(ArrayRef<int64_t> dividend,
360                                                      int64_t divisor,
361                                                      unsigned localVarIdx) {
362   assert(dividend[localVarIdx] == 0 &&
363          "Local to be set to division must have zero coeff!");
364   SmallVector<int64_t, 8> ineq(dividend.size());
365   std::transform(dividend.begin(), dividend.end(), ineq.begin(),
366                  std::negate<int64_t>());
367   ineq[localVarIdx] = divisor;
368   ineq.back() += divisor - 1;
369   return ineq;
370 }
371 
372 int64_t presburger::gcdRange(ArrayRef<int64_t> range) {
373   int64_t gcd = 0;
374   for (int64_t elem : range) {
375     gcd = llvm::GreatestCommonDivisor64(gcd, std::abs(elem));
376     if (gcd == 1)
377       return gcd;
378   }
379   return gcd;
380 }
381 
382 int64_t presburger::normalizeRange(MutableArrayRef<int64_t> range) {
383   int64_t gcd = gcdRange(range);
384   if (gcd == 0 || gcd == 1)
385     return gcd;
386   for (int64_t &elem : range)
387     elem /= gcd;
388   return gcd;
389 }
390 
391 void presburger::normalizeDiv(MutableArrayRef<int64_t> num, int64_t &denom) {
392   assert(denom > 0 && "denom must be positive!");
393   int64_t gcd = llvm::greatestCommonDivisor(gcdRange(num), denom);
394   for (int64_t &coeff : num)
395     coeff /= gcd;
396   denom /= gcd;
397 }
398 
399 SmallVector<int64_t, 8> presburger::getNegatedCoeffs(ArrayRef<int64_t> coeffs) {
400   SmallVector<int64_t, 8> negatedCoeffs;
401   negatedCoeffs.reserve(coeffs.size());
402   for (int64_t coeff : coeffs)
403     negatedCoeffs.emplace_back(-coeff);
404   return negatedCoeffs;
405 }
406 
407 SmallVector<int64_t, 8> presburger::getComplementIneq(ArrayRef<int64_t> ineq) {
408   SmallVector<int64_t, 8> coeffs;
409   coeffs.reserve(ineq.size());
410   for (int64_t coeff : ineq)
411     coeffs.emplace_back(-coeff);
412   --coeffs.back();
413   return coeffs;
414 }
415