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> ÷nd, 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> ÷nd, 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