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/IntegerPolyhedron.h"
15 #include "mlir/Support/LogicalResult.h"
16 #include "mlir/Support/MathExtras.h"
17 
18 using namespace mlir;
19 using namespace presburger_utils;
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   int64_t gcd = llvm::greatestCommonDivisor(dividend.front(), int64_t(divisor));
29 
30   // The reason for ignoring the constant term is as follows.
31   // For a division:
32   //      floor((a + m.f(x))/(m.d))
33   // It can be replaced by:
34   //      floor((floor(a/m) + f(x))/d)
35   // Since `{a/m}/d` in the dividend satisfies 0 <= {a/m}/d < 1/d, it will not
36   // influence the result of the floor division and thus, can be ignored.
37   for (size_t i = 1, m = dividend.size() - 1; i < m; i++) {
38     gcd = llvm::greatestCommonDivisor(dividend[i], gcd);
39     if (gcd == 1)
40       return;
41   }
42 
43   // Normalize the dividend and the denominator.
44   std::transform(dividend.begin(), dividend.end(), dividend.begin(),
45                  [gcd](int64_t &n) { return floor(n / gcd); });
46   divisor /= gcd;
47 }
48 
49 /// Check if the pos^th identifier can be represented as a division using upper
50 /// bound inequality at position `ubIneq` and lower bound inequality at position
51 /// `lbIneq`.
52 ///
53 /// Let `id` be the pos^th identifier, then `id` is equivalent to
54 /// `expr floordiv divisor` if there are constraints of the form:
55 ///      0 <= expr - divisor * id <= divisor - 1
56 /// Rearranging, we have:
57 ///       divisor * id - expr + (divisor - 1) >= 0  <-- Lower bound for 'id'
58 ///      -divisor * id + expr                 >= 0  <-- Upper bound for 'id'
59 ///
60 /// For example:
61 ///     32*k >= 16*i + j - 31                 <-- Lower bound for 'k'
62 ///     32*k  <= 16*i + j                     <-- Upper bound for 'k'
63 ///     expr = 16*i + j, divisor = 32
64 ///     k = ( 16*i + j ) floordiv 32
65 ///
66 ///     4q >= i + j - 2                       <-- Lower bound for 'q'
67 ///     4q <= i + j + 1                       <-- Upper bound for 'q'
68 ///     expr = i + j + 1, divisor = 4
69 ///     q = (i + j + 1) floordiv 4
70 //
71 /// This function also supports detecting divisions from bounds that are
72 /// strictly tighter than the division bounds described above, since tighter
73 /// bounds imply the division bounds. For example:
74 ///     4q - i - j + 2 >= 0                       <-- Lower bound for 'q'
75 ///    -4q + i + j     >= 0                       <-- Tight upper bound for 'q'
76 ///
77 /// To extract floor divisions with tighter bounds, we assume that that the
78 /// constraints are of the form:
79 ///     c <= expr - divisior * id <= divisor - 1, where 0 <= c <= divisor - 1
80 /// Rearranging, we have:
81 ///     divisor * id - expr + (divisor - 1) >= 0  <-- Lower bound for 'id'
82 ///    -divisor * id + expr - c             >= 0  <-- Upper bound for 'id'
83 ///
84 /// If successful, `expr` is set to dividend of the division and `divisor` is
85 /// set to the denominator of the division. The final division expression is
86 /// normalized by GCD.
87 static LogicalResult getDivRepr(const IntegerPolyhedron &cst, unsigned pos,
88                                 unsigned ubIneq, unsigned lbIneq,
89                                 SmallVector<int64_t, 8> &expr,
90                                 unsigned &divisor) {
91 
92   assert(pos <= cst.getNumIds() && "Invalid identifier position");
93   assert(ubIneq <= cst.getNumInequalities() &&
94          "Invalid upper bound inequality position");
95   assert(lbIneq <= cst.getNumInequalities() &&
96          "Invalid upper bound inequality position");
97 
98   // Extract divisor from the lower bound.
99   divisor = cst.atIneq(lbIneq, pos);
100 
101   // First, check if the constraints are opposite of each other except the
102   // constant term.
103   unsigned i = 0, e = 0;
104   for (i = 0, e = cst.getNumIds(); i < e; ++i)
105     if (cst.atIneq(ubIneq, i) != -cst.atIneq(lbIneq, i))
106       break;
107 
108   if (i < e)
109     return failure();
110 
111   // Then, check if the constant term is of the proper form.
112   // Due to the form of the upper/lower bound inequalities, the sum of their
113   // constants is `divisor - 1 - c`. From this, we can extract c:
114   int64_t constantSum = cst.atIneq(lbIneq, cst.getNumCols() - 1) +
115                         cst.atIneq(ubIneq, cst.getNumCols() - 1);
116   int64_t c = divisor - 1 - constantSum;
117 
118   // Check if `c` satisfies the condition `0 <= c <= divisor - 1`. This also
119   // implictly checks that `divisor` is positive.
120   if (!(c >= 0 && c <= divisor - 1))
121     return failure();
122 
123   // The inequality pair can be used to extract the division.
124   // Set `expr` to the dividend of the division except the constant term, which
125   // is set below.
126   expr.resize(cst.getNumCols(), 0);
127   for (i = 0, e = cst.getNumIds(); i < e; ++i)
128     if (i != pos)
129       expr[i] = cst.atIneq(ubIneq, i);
130 
131   // From the upper bound inequality's form, its constant term is equal to the
132   // constant term of `expr`, minus `c`. From this,
133   // constant term of `expr` = constant term of upper bound + `c`.
134   expr.back() = cst.atIneq(ubIneq, cst.getNumCols() - 1) + c;
135   normalizeDivisionByGCD(expr, divisor);
136 
137   return success();
138 }
139 
140 /// Check if the pos^th identifier can be expressed as a floordiv of an affine
141 /// function of other identifiers (where the divisor is a positive constant).
142 /// `foundRepr` contains a boolean for each identifier indicating if the
143 /// explicit representation for that identifier has already been computed.
144 /// Returns the upper and lower bound inequalities using which the floordiv can
145 /// be computed. If the representation could be computed, `dividend` and
146 /// `denominator` are set. If the representation could not be computed,
147 /// `llvm::None` is returned.
148 MaybeLocalRepr presburger_utils::computeSingleVarRepr(
149     const IntegerPolyhedron &cst, ArrayRef<bool> foundRepr, unsigned pos,
150     SmallVector<int64_t, 8> &dividend, unsigned &divisor) {
151   assert(pos < cst.getNumIds() && "invalid position");
152   assert(foundRepr.size() == cst.getNumIds() &&
153          "Size of foundRepr does not match total number of variables");
154 
155   SmallVector<unsigned, 4> lbIndices, ubIndices;
156   cst.getLowerAndUpperBoundIndices(pos, &lbIndices, &ubIndices);
157   MaybeLocalRepr repr;
158 
159   for (unsigned ubPos : ubIndices) {
160     for (unsigned lbPos : lbIndices) {
161       // Attempt to get divison representation from ubPos, lbPos.
162       if (failed(getDivRepr(cst, pos, ubPos, lbPos, dividend, divisor)))
163         continue;
164 
165       // Check if the inequalities depend on a variable for which
166       // an explicit representation has not been found yet.
167       // Exit to avoid circular dependencies between divisions.
168       unsigned c, f;
169       for (c = 0, f = cst.getNumIds(); c < f; ++c) {
170         if (c == pos)
171           continue;
172         if (!foundRepr[c] && dividend[c] != 0)
173           break;
174       }
175 
176       // Expression can't be constructed as it depends on a yet unknown
177       // identifier.
178       // TODO: Visit/compute the identifiers in an order so that this doesn't
179       // happen. More complex but much more efficient.
180       if (c < f)
181         continue;
182 
183       repr.kind = ReprKind::Inequality;
184       repr.repr.inEqualityPair = {ubPos, lbPos};
185       return repr;
186     }
187   }
188   return repr;
189 }
190