1 //===- IntegerRelation.cpp - MLIR IntegerRelation Class ---------------===// 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 // A class to represent an relation over integer tuples. A relation is 10 // represented as a constraint system over a space of tuples of integer valued 11 // varaiables supporting symbolic identifiers and existential quantification. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "mlir/Analysis/Presburger/IntegerRelation.h" 16 #include "mlir/Analysis/Presburger/LinearTransform.h" 17 #include "mlir/Analysis/Presburger/PresburgerRelation.h" 18 #include "mlir/Analysis/Presburger/Simplex.h" 19 #include "mlir/Analysis/Presburger/Utils.h" 20 #include "llvm/ADT/DenseMap.h" 21 #include "llvm/ADT/DenseSet.h" 22 #include "llvm/Support/Debug.h" 23 24 #define DEBUG_TYPE "presburger" 25 26 using namespace mlir; 27 using namespace presburger; 28 29 using llvm::SmallDenseMap; 30 using llvm::SmallDenseSet; 31 32 std::unique_ptr<IntegerRelation> IntegerRelation::clone() const { 33 return std::make_unique<IntegerRelation>(*this); 34 } 35 36 std::unique_ptr<IntegerPolyhedron> IntegerPolyhedron::clone() const { 37 return std::make_unique<IntegerPolyhedron>(*this); 38 } 39 40 void IntegerRelation::append(const IntegerRelation &other) { 41 assert(PresburgerLocalSpace::isEqual(other) && "Spaces must be equal."); 42 43 inequalities.reserveRows(inequalities.getNumRows() + 44 other.getNumInequalities()); 45 equalities.reserveRows(equalities.getNumRows() + other.getNumEqualities()); 46 47 for (unsigned r = 0, e = other.getNumInequalities(); r < e; r++) { 48 addInequality(other.getInequality(r)); 49 } 50 for (unsigned r = 0, e = other.getNumEqualities(); r < e; r++) { 51 addEquality(other.getEquality(r)); 52 } 53 } 54 55 bool IntegerRelation::isEqual(const IntegerRelation &other) const { 56 assert(PresburgerLocalSpace::isEqual(other) && "Spaces must be equal."); 57 return PresburgerRelation(*this).isEqual(PresburgerRelation(other)); 58 } 59 60 bool IntegerRelation::isSubsetOf(const IntegerRelation &other) const { 61 assert(PresburgerLocalSpace::isEqual(other) && "Spaces must be equal."); 62 return PresburgerRelation(*this).isSubsetOf(PresburgerRelation(other)); 63 } 64 65 MaybeOptimum<SmallVector<Fraction, 8>> 66 IntegerRelation::findRationalLexMin() const { 67 assert(getNumSymbolIds() == 0 && "Symbols are not supported!"); 68 MaybeOptimum<SmallVector<Fraction, 8>> maybeLexMin = 69 LexSimplex(*this).findRationalLexMin(); 70 71 if (!maybeLexMin.isBounded()) 72 return maybeLexMin; 73 74 // The Simplex returns the lexmin over all the variables including locals. But 75 // locals are not actually part of the space and should not be returned in the 76 // result. Since the locals are placed last in the list of identifiers, they 77 // will be minimized last in the lexmin. So simply truncating out the locals 78 // from the end of the answer gives the desired lexmin over the dimensions. 79 assert(maybeLexMin->size() == getNumIds() && 80 "Incorrect number of vars in lexMin!"); 81 maybeLexMin->resize(getNumDimAndSymbolIds()); 82 return maybeLexMin; 83 } 84 85 MaybeOptimum<SmallVector<int64_t, 8>> 86 IntegerRelation::findIntegerLexMin() const { 87 assert(getNumSymbolIds() == 0 && "Symbols are not supported!"); 88 MaybeOptimum<SmallVector<int64_t, 8>> maybeLexMin = 89 LexSimplex(*this).findIntegerLexMin(); 90 91 if (!maybeLexMin.isBounded()) 92 return maybeLexMin.getKind(); 93 94 // The Simplex returns the lexmin over all the variables including locals. But 95 // locals are not actually part of the space and should not be returned in the 96 // result. Since the locals are placed last in the list of identifiers, they 97 // will be minimized last in the lexmin. So simply truncating out the locals 98 // from the end of the answer gives the desired lexmin over the dimensions. 99 assert(maybeLexMin->size() == getNumIds() && 100 "Incorrect number of vars in lexMin!"); 101 maybeLexMin->resize(getNumDimAndSymbolIds()); 102 return maybeLexMin; 103 } 104 105 static bool rangeIsZero(ArrayRef<int64_t> range) { 106 return llvm::all_of(range, [](int64_t x) { return x == 0; }); 107 } 108 109 void removeConstraintsInvolvingIdRange(IntegerRelation &poly, unsigned begin, 110 unsigned count) { 111 // We loop until i > 0 and index into i - 1 to avoid sign issues. 112 // 113 // We iterate backwards so that whether we remove constraint i - 1 or not, the 114 // next constraint to be tested is always i - 2. 115 for (unsigned i = poly.getNumEqualities(); i > 0; i--) 116 if (!rangeIsZero(poly.getEquality(i - 1).slice(begin, count))) 117 poly.removeEquality(i - 1); 118 for (unsigned i = poly.getNumInequalities(); i > 0; i--) 119 if (!rangeIsZero(poly.getInequality(i - 1).slice(begin, count))) 120 poly.removeInequality(i - 1); 121 } 122 unsigned IntegerRelation::insertId(IdKind kind, unsigned pos, unsigned num) { 123 assert(pos <= getNumIdKind(kind)); 124 125 unsigned insertPos = PresburgerLocalSpace::insertId(kind, pos, num); 126 inequalities.insertColumns(insertPos, num); 127 equalities.insertColumns(insertPos, num); 128 return insertPos; 129 } 130 131 unsigned IntegerRelation::appendId(IdKind kind, unsigned num) { 132 unsigned pos = getNumIdKind(kind); 133 return insertId(kind, pos, num); 134 } 135 136 void IntegerRelation::addEquality(ArrayRef<int64_t> eq) { 137 assert(eq.size() == getNumCols()); 138 unsigned row = equalities.appendExtraRow(); 139 for (unsigned i = 0, e = eq.size(); i < e; ++i) 140 equalities(row, i) = eq[i]; 141 } 142 143 void IntegerRelation::addInequality(ArrayRef<int64_t> inEq) { 144 assert(inEq.size() == getNumCols()); 145 unsigned row = inequalities.appendExtraRow(); 146 for (unsigned i = 0, e = inEq.size(); i < e; ++i) 147 inequalities(row, i) = inEq[i]; 148 } 149 150 void IntegerRelation::removeId(IdKind kind, unsigned pos) { 151 removeIdRange(kind, pos, pos + 1); 152 } 153 154 void IntegerRelation::removeId(unsigned pos) { removeIdRange(pos, pos + 1); } 155 156 void IntegerRelation::removeIdRange(IdKind kind, unsigned idStart, 157 unsigned idLimit) { 158 assert(idLimit <= getNumIdKind(kind)); 159 160 if (idStart >= idLimit) 161 return; 162 163 // Remove eliminated identifiers from the constraints. 164 unsigned offset = getIdKindOffset(kind); 165 equalities.removeColumns(offset + idStart, idLimit - idStart); 166 inequalities.removeColumns(offset + idStart, idLimit - idStart); 167 168 // Remove eliminated identifiers from the space. 169 PresburgerLocalSpace::removeIdRange(kind, idStart, idLimit); 170 } 171 172 void IntegerRelation::removeIdRange(unsigned idStart, unsigned idLimit) { 173 assert(idLimit <= getNumIds()); 174 175 if (idStart >= idLimit) 176 return; 177 178 // Helper function to remove ids of the specified kind in the given range 179 // [start, limit), The range is absolute (i.e. it is not relative to the kind 180 // of identifier). Also updates `limit` to reflect the deleted identifiers. 181 auto removeIdKindInRange = [this](IdKind kind, unsigned &start, 182 unsigned &limit) { 183 if (start >= limit) 184 return; 185 186 unsigned offset = getIdKindOffset(kind); 187 unsigned num = getNumIdKind(kind); 188 189 // Get `start`, `limit` relative to the specified kind. 190 unsigned relativeStart = 191 start <= offset ? 0 : std::min(num, start - offset); 192 unsigned relativeLimit = 193 limit <= offset ? 0 : std::min(num, limit - offset); 194 195 // Remove ids of the specified kind in the relative range. 196 removeIdRange(kind, relativeStart, relativeLimit); 197 198 // Update `limit` to reflect deleted identifiers. 199 // `start` does not need to be updated because any identifiers that are 200 // deleted are after position `start`. 201 limit -= relativeLimit - relativeStart; 202 }; 203 204 removeIdKindInRange(IdKind::Domain, idStart, idLimit); 205 removeIdKindInRange(IdKind::Range, idStart, idLimit); 206 removeIdKindInRange(IdKind::Symbol, idStart, idLimit); 207 removeIdKindInRange(IdKind::Local, idStart, idLimit); 208 } 209 210 void IntegerRelation::removeEquality(unsigned pos) { 211 equalities.removeRow(pos); 212 } 213 214 void IntegerRelation::removeInequality(unsigned pos) { 215 inequalities.removeRow(pos); 216 } 217 218 void IntegerRelation::removeEqualityRange(unsigned start, unsigned end) { 219 if (start >= end) 220 return; 221 equalities.removeRows(start, end - start); 222 } 223 224 void IntegerRelation::removeInequalityRange(unsigned start, unsigned end) { 225 if (start >= end) 226 return; 227 inequalities.removeRows(start, end - start); 228 } 229 230 void IntegerRelation::swapId(unsigned posA, unsigned posB) { 231 assert(posA < getNumIds() && "invalid position A"); 232 assert(posB < getNumIds() && "invalid position B"); 233 234 if (posA == posB) 235 return; 236 237 inequalities.swapColumns(posA, posB); 238 equalities.swapColumns(posA, posB); 239 } 240 241 void IntegerRelation::clearConstraints() { 242 equalities.resizeVertically(0); 243 inequalities.resizeVertically(0); 244 } 245 246 /// Gather all lower and upper bounds of the identifier at `pos`, and 247 /// optionally any equalities on it. In addition, the bounds are to be 248 /// independent of identifiers in position range [`offset`, `offset` + `num`). 249 void IntegerRelation::getLowerAndUpperBoundIndices( 250 unsigned pos, SmallVectorImpl<unsigned> *lbIndices, 251 SmallVectorImpl<unsigned> *ubIndices, SmallVectorImpl<unsigned> *eqIndices, 252 unsigned offset, unsigned num) const { 253 assert(pos < getNumIds() && "invalid position"); 254 assert(offset + num < getNumCols() && "invalid range"); 255 256 // Checks for a constraint that has a non-zero coeff for the identifiers in 257 // the position range [offset, offset + num) while ignoring `pos`. 258 auto containsConstraintDependentOnRange = [&](unsigned r, bool isEq) { 259 unsigned c, f; 260 auto cst = isEq ? getEquality(r) : getInequality(r); 261 for (c = offset, f = offset + num; c < f; ++c) { 262 if (c == pos) 263 continue; 264 if (cst[c] != 0) 265 break; 266 } 267 return c < f; 268 }; 269 270 // Gather all lower bounds and upper bounds of the variable. Since the 271 // canonical form c_1*x_1 + c_2*x_2 + ... + c_0 >= 0, a constraint is a lower 272 // bound for x_i if c_i >= 1, and an upper bound if c_i <= -1. 273 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) { 274 // The bounds are to be independent of [offset, offset + num) columns. 275 if (containsConstraintDependentOnRange(r, /*isEq=*/false)) 276 continue; 277 if (atIneq(r, pos) >= 1) { 278 // Lower bound. 279 lbIndices->push_back(r); 280 } else if (atIneq(r, pos) <= -1) { 281 // Upper bound. 282 ubIndices->push_back(r); 283 } 284 } 285 286 // An equality is both a lower and upper bound. Record any equalities 287 // involving the pos^th identifier. 288 if (!eqIndices) 289 return; 290 291 for (unsigned r = 0, e = getNumEqualities(); r < e; r++) { 292 if (atEq(r, pos) == 0) 293 continue; 294 if (containsConstraintDependentOnRange(r, /*isEq=*/true)) 295 continue; 296 eqIndices->push_back(r); 297 } 298 } 299 300 bool IntegerRelation::hasConsistentState() const { 301 if (!inequalities.hasConsistentState()) 302 return false; 303 if (!equalities.hasConsistentState()) 304 return false; 305 return true; 306 } 307 308 void IntegerRelation::setAndEliminate(unsigned pos, ArrayRef<int64_t> values) { 309 if (values.empty()) 310 return; 311 assert(pos + values.size() <= getNumIds() && 312 "invalid position or too many values"); 313 // Setting x_j = p in sum_i a_i x_i + c is equivalent to adding p*a_j to the 314 // constant term and removing the id x_j. We do this for all the ids 315 // pos, pos + 1, ... pos + values.size() - 1. 316 unsigned constantColPos = getNumCols() - 1; 317 for (unsigned i = 0, numVals = values.size(); i < numVals; ++i) 318 inequalities.addToColumn(i + pos, constantColPos, values[i]); 319 for (unsigned i = 0, numVals = values.size(); i < numVals; ++i) 320 equalities.addToColumn(i + pos, constantColPos, values[i]); 321 removeIdRange(pos, pos + values.size()); 322 } 323 324 void IntegerRelation::clearAndCopyFrom(const IntegerRelation &other) { 325 *this = other; 326 } 327 328 // Searches for a constraint with a non-zero coefficient at `colIdx` in 329 // equality (isEq=true) or inequality (isEq=false) constraints. 330 // Returns true and sets row found in search in `rowIdx`, false otherwise. 331 bool IntegerRelation::findConstraintWithNonZeroAt(unsigned colIdx, bool isEq, 332 unsigned *rowIdx) const { 333 assert(colIdx < getNumCols() && "position out of bounds"); 334 auto at = [&](unsigned rowIdx) -> int64_t { 335 return isEq ? atEq(rowIdx, colIdx) : atIneq(rowIdx, colIdx); 336 }; 337 unsigned e = isEq ? getNumEqualities() : getNumInequalities(); 338 for (*rowIdx = 0; *rowIdx < e; ++(*rowIdx)) { 339 if (at(*rowIdx) != 0) { 340 return true; 341 } 342 } 343 return false; 344 } 345 346 void IntegerRelation::normalizeConstraintsByGCD() { 347 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) 348 equalities.normalizeRow(i); 349 for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) 350 inequalities.normalizeRow(i); 351 } 352 353 bool IntegerRelation::hasInvalidConstraint() const { 354 assert(hasConsistentState()); 355 auto check = [&](bool isEq) -> bool { 356 unsigned numCols = getNumCols(); 357 unsigned numRows = isEq ? getNumEqualities() : getNumInequalities(); 358 for (unsigned i = 0, e = numRows; i < e; ++i) { 359 unsigned j; 360 for (j = 0; j < numCols - 1; ++j) { 361 int64_t v = isEq ? atEq(i, j) : atIneq(i, j); 362 // Skip rows with non-zero variable coefficients. 363 if (v != 0) 364 break; 365 } 366 if (j < numCols - 1) { 367 continue; 368 } 369 // Check validity of constant term at 'numCols - 1' w.r.t 'isEq'. 370 // Example invalid constraints include: '1 == 0' or '-1 >= 0' 371 int64_t v = isEq ? atEq(i, numCols - 1) : atIneq(i, numCols - 1); 372 if ((isEq && v != 0) || (!isEq && v < 0)) { 373 return true; 374 } 375 } 376 return false; 377 }; 378 if (check(/*isEq=*/true)) 379 return true; 380 return check(/*isEq=*/false); 381 } 382 383 /// Eliminate identifier from constraint at `rowIdx` based on coefficient at 384 /// pivotRow, pivotCol. Columns in range [elimColStart, pivotCol) will not be 385 /// updated as they have already been eliminated. 386 static void eliminateFromConstraint(IntegerRelation *constraints, 387 unsigned rowIdx, unsigned pivotRow, 388 unsigned pivotCol, unsigned elimColStart, 389 bool isEq) { 390 // Skip if equality 'rowIdx' if same as 'pivotRow'. 391 if (isEq && rowIdx == pivotRow) 392 return; 393 auto at = [&](unsigned i, unsigned j) -> int64_t { 394 return isEq ? constraints->atEq(i, j) : constraints->atIneq(i, j); 395 }; 396 int64_t leadCoeff = at(rowIdx, pivotCol); 397 // Skip if leading coefficient at 'rowIdx' is already zero. 398 if (leadCoeff == 0) 399 return; 400 int64_t pivotCoeff = constraints->atEq(pivotRow, pivotCol); 401 int64_t sign = (leadCoeff * pivotCoeff > 0) ? -1 : 1; 402 int64_t lcm = mlir::lcm(pivotCoeff, leadCoeff); 403 int64_t pivotMultiplier = sign * (lcm / std::abs(pivotCoeff)); 404 int64_t rowMultiplier = lcm / std::abs(leadCoeff); 405 406 unsigned numCols = constraints->getNumCols(); 407 for (unsigned j = 0; j < numCols; ++j) { 408 // Skip updating column 'j' if it was just eliminated. 409 if (j >= elimColStart && j < pivotCol) 410 continue; 411 int64_t v = pivotMultiplier * constraints->atEq(pivotRow, j) + 412 rowMultiplier * at(rowIdx, j); 413 isEq ? constraints->atEq(rowIdx, j) = v 414 : constraints->atIneq(rowIdx, j) = v; 415 } 416 } 417 418 /// Returns the position of the identifier that has the minimum <number of lower 419 /// bounds> times <number of upper bounds> from the specified range of 420 /// identifiers [start, end). It is often best to eliminate in the increasing 421 /// order of these counts when doing Fourier-Motzkin elimination since FM adds 422 /// that many new constraints. 423 static unsigned getBestIdToEliminate(const IntegerRelation &cst, unsigned start, 424 unsigned end) { 425 assert(start < cst.getNumIds() && end < cst.getNumIds() + 1); 426 427 auto getProductOfNumLowerUpperBounds = [&](unsigned pos) { 428 unsigned numLb = 0; 429 unsigned numUb = 0; 430 for (unsigned r = 0, e = cst.getNumInequalities(); r < e; r++) { 431 if (cst.atIneq(r, pos) > 0) { 432 ++numLb; 433 } else if (cst.atIneq(r, pos) < 0) { 434 ++numUb; 435 } 436 } 437 return numLb * numUb; 438 }; 439 440 unsigned minLoc = start; 441 unsigned min = getProductOfNumLowerUpperBounds(start); 442 for (unsigned c = start + 1; c < end; c++) { 443 unsigned numLbUbProduct = getProductOfNumLowerUpperBounds(c); 444 if (numLbUbProduct < min) { 445 min = numLbUbProduct; 446 minLoc = c; 447 } 448 } 449 return minLoc; 450 } 451 452 // Checks for emptiness of the set by eliminating identifiers successively and 453 // using the GCD test (on all equality constraints) and checking for trivially 454 // invalid constraints. Returns 'true' if the constraint system is found to be 455 // empty; false otherwise. 456 bool IntegerRelation::isEmpty() const { 457 if (isEmptyByGCDTest() || hasInvalidConstraint()) 458 return true; 459 460 IntegerRelation tmpCst(*this); 461 462 // First, eliminate as many local variables as possible using equalities. 463 tmpCst.removeRedundantLocalVars(); 464 if (tmpCst.isEmptyByGCDTest() || tmpCst.hasInvalidConstraint()) 465 return true; 466 467 // Eliminate as many identifiers as possible using Gaussian elimination. 468 unsigned currentPos = 0; 469 while (currentPos < tmpCst.getNumIds()) { 470 tmpCst.gaussianEliminateIds(currentPos, tmpCst.getNumIds()); 471 ++currentPos; 472 // We check emptiness through trivial checks after eliminating each ID to 473 // detect emptiness early. Since the checks isEmptyByGCDTest() and 474 // hasInvalidConstraint() are linear time and single sweep on the constraint 475 // buffer, this appears reasonable - but can optimize in the future. 476 if (tmpCst.hasInvalidConstraint() || tmpCst.isEmptyByGCDTest()) 477 return true; 478 } 479 480 // Eliminate the remaining using FM. 481 for (unsigned i = 0, e = tmpCst.getNumIds(); i < e; i++) { 482 tmpCst.fourierMotzkinEliminate( 483 getBestIdToEliminate(tmpCst, 0, tmpCst.getNumIds())); 484 // Check for a constraint explosion. This rarely happens in practice, but 485 // this check exists as a safeguard against improperly constructed 486 // constraint systems or artificially created arbitrarily complex systems 487 // that aren't the intended use case for IntegerRelation. This is 488 // needed since FM has a worst case exponential complexity in theory. 489 if (tmpCst.getNumConstraints() >= kExplosionFactor * getNumIds()) { 490 LLVM_DEBUG(llvm::dbgs() << "FM constraint explosion detected\n"); 491 return false; 492 } 493 494 // FM wouldn't have modified the equalities in any way. So no need to again 495 // run GCD test. Check for trivial invalid constraints. 496 if (tmpCst.hasInvalidConstraint()) 497 return true; 498 } 499 return false; 500 } 501 502 // Runs the GCD test on all equality constraints. Returns 'true' if this test 503 // fails on any equality. Returns 'false' otherwise. 504 // This test can be used to disprove the existence of a solution. If it returns 505 // true, no integer solution to the equality constraints can exist. 506 // 507 // GCD test definition: 508 // 509 // The equality constraint: 510 // 511 // c_1*x_1 + c_2*x_2 + ... + c_n*x_n = c_0 512 // 513 // has an integer solution iff: 514 // 515 // GCD of c_1, c_2, ..., c_n divides c_0. 516 // 517 bool IntegerRelation::isEmptyByGCDTest() const { 518 assert(hasConsistentState()); 519 unsigned numCols = getNumCols(); 520 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) { 521 uint64_t gcd = std::abs(atEq(i, 0)); 522 for (unsigned j = 1; j < numCols - 1; ++j) { 523 gcd = llvm::GreatestCommonDivisor64(gcd, std::abs(atEq(i, j))); 524 } 525 int64_t v = std::abs(atEq(i, numCols - 1)); 526 if (gcd > 0 && (v % gcd != 0)) { 527 return true; 528 } 529 } 530 return false; 531 } 532 533 // Returns a matrix where each row is a vector along which the polytope is 534 // bounded. The span of the returned vectors is guaranteed to contain all 535 // such vectors. The returned vectors are NOT guaranteed to be linearly 536 // independent. This function should not be called on empty sets. 537 // 538 // It is sufficient to check the perpendiculars of the constraints, as the set 539 // of perpendiculars which are bounded must span all bounded directions. 540 Matrix IntegerRelation::getBoundedDirections() const { 541 // Note that it is necessary to add the equalities too (which the constructor 542 // does) even though we don't need to check if they are bounded; whether an 543 // inequality is bounded or not depends on what other constraints, including 544 // equalities, are present. 545 Simplex simplex(*this); 546 547 assert(!simplex.isEmpty() && "It is not meaningful to ask whether a " 548 "direction is bounded in an empty set."); 549 550 SmallVector<unsigned, 8> boundedIneqs; 551 // The constructor adds the inequalities to the simplex first, so this 552 // processes all the inequalities. 553 for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) { 554 if (simplex.isBoundedAlongConstraint(i)) 555 boundedIneqs.push_back(i); 556 } 557 558 // The direction vector is given by the coefficients and does not include the 559 // constant term, so the matrix has one fewer column. 560 unsigned dirsNumCols = getNumCols() - 1; 561 Matrix dirs(boundedIneqs.size() + getNumEqualities(), dirsNumCols); 562 563 // Copy the bounded inequalities. 564 unsigned row = 0; 565 for (unsigned i : boundedIneqs) { 566 for (unsigned col = 0; col < dirsNumCols; ++col) 567 dirs(row, col) = atIneq(i, col); 568 ++row; 569 } 570 571 // Copy the equalities. All the equalities' perpendiculars are bounded. 572 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) { 573 for (unsigned col = 0; col < dirsNumCols; ++col) 574 dirs(row, col) = atEq(i, col); 575 ++row; 576 } 577 578 return dirs; 579 } 580 581 bool IntegerRelation::isIntegerEmpty() const { 582 return !findIntegerSample().hasValue(); 583 } 584 585 /// Let this set be S. If S is bounded then we directly call into the GBR 586 /// sampling algorithm. Otherwise, there are some unbounded directions, i.e., 587 /// vectors v such that S extends to infinity along v or -v. In this case we 588 /// use an algorithm described in the integer set library (isl) manual and used 589 /// by the isl_set_sample function in that library. The algorithm is: 590 /// 591 /// 1) Apply a unimodular transform T to S to obtain S*T, such that all 592 /// dimensions in which S*T is bounded lie in the linear span of a prefix of the 593 /// dimensions. 594 /// 595 /// 2) Construct a set B by removing all constraints that involve 596 /// the unbounded dimensions and then deleting the unbounded dimensions. Note 597 /// that B is a Bounded set. 598 /// 599 /// 3) Try to obtain a sample from B using the GBR sampling 600 /// algorithm. If no sample is found, return that S is empty. 601 /// 602 /// 4) Otherwise, substitute the obtained sample into S*T to obtain a set 603 /// C. C is a full-dimensional Cone and always contains a sample. 604 /// 605 /// 5) Obtain an integer sample from C. 606 /// 607 /// 6) Return T*v, where v is the concatenation of the samples from B and C. 608 /// 609 /// The following is a sketch of a proof that 610 /// a) If the algorithm returns empty, then S is empty. 611 /// b) If the algorithm returns a sample, it is a valid sample in S. 612 /// 613 /// The algorithm returns empty only if B is empty, in which case S*T is 614 /// certainly empty since B was obtained by removing constraints and then 615 /// deleting unconstrained dimensions from S*T. Since T is unimodular, a vector 616 /// v is in S*T iff T*v is in S. So in this case, since 617 /// S*T is empty, S is empty too. 618 /// 619 /// Otherwise, the algorithm substitutes the sample from B into S*T. All the 620 /// constraints of S*T that did not involve unbounded dimensions are satisfied 621 /// by this substitution. All dimensions in the linear span of the dimensions 622 /// outside the prefix are unbounded in S*T (step 1). Substituting values for 623 /// the bounded dimensions cannot make these dimensions bounded, and these are 624 /// the only remaining dimensions in C, so C is unbounded along every vector (in 625 /// the positive or negative direction, or both). C is hence a full-dimensional 626 /// cone and therefore always contains an integer point. 627 /// 628 /// Concatenating the samples from B and C gives a sample v in S*T, so the 629 /// returned sample T*v is a sample in S. 630 Optional<SmallVector<int64_t, 8>> IntegerRelation::findIntegerSample() const { 631 // First, try the GCD test heuristic. 632 if (isEmptyByGCDTest()) 633 return {}; 634 635 Simplex simplex(*this); 636 if (simplex.isEmpty()) 637 return {}; 638 639 // For a bounded set, we directly call into the GBR sampling algorithm. 640 if (!simplex.isUnbounded()) 641 return simplex.findIntegerSample(); 642 643 // The set is unbounded. We cannot directly use the GBR algorithm. 644 // 645 // m is a matrix containing, in each row, a vector in which S is 646 // bounded, such that the linear span of all these dimensions contains all 647 // bounded dimensions in S. 648 Matrix m = getBoundedDirections(); 649 // In column echelon form, each row of m occupies only the first rank(m) 650 // columns and has zeros on the other columns. The transform T that brings S 651 // to column echelon form is unimodular as well, so this is a suitable 652 // transform to use in step 1 of the algorithm. 653 std::pair<unsigned, LinearTransform> result = 654 LinearTransform::makeTransformToColumnEchelon(std::move(m)); 655 const LinearTransform &transform = result.second; 656 // 1) Apply T to S to obtain S*T. 657 IntegerRelation transformedSet = transform.applyTo(*this); 658 659 // 2) Remove the unbounded dimensions and constraints involving them to 660 // obtain a bounded set. 661 IntegerRelation boundedSet(transformedSet); 662 unsigned numBoundedDims = result.first; 663 unsigned numUnboundedDims = getNumIds() - numBoundedDims; 664 removeConstraintsInvolvingIdRange(boundedSet, numBoundedDims, 665 numUnboundedDims); 666 boundedSet.removeIdRange(numBoundedDims, boundedSet.getNumIds()); 667 668 // 3) Try to obtain a sample from the bounded set. 669 Optional<SmallVector<int64_t, 8>> boundedSample = 670 Simplex(boundedSet).findIntegerSample(); 671 if (!boundedSample) 672 return {}; 673 assert(boundedSet.containsPoint(*boundedSample) && 674 "Simplex returned an invalid sample!"); 675 676 // 4) Substitute the values of the bounded dimensions into S*T to obtain a 677 // full-dimensional cone, which necessarily contains an integer sample. 678 transformedSet.setAndEliminate(0, *boundedSample); 679 IntegerRelation &cone = transformedSet; 680 681 // 5) Obtain an integer sample from the cone. 682 // 683 // We shrink the cone such that for any rational point in the shrunken cone, 684 // rounding up each of the point's coordinates produces a point that still 685 // lies in the original cone. 686 // 687 // Rounding up a point x adds a number e_i in [0, 1) to each coordinate x_i. 688 // For each inequality sum_i a_i x_i + c >= 0 in the original cone, the 689 // shrunken cone will have the inequality tightened by some amount s, such 690 // that if x satisfies the shrunken cone's tightened inequality, then x + e 691 // satisfies the original inequality, i.e., 692 // 693 // sum_i a_i x_i + c + s >= 0 implies sum_i a_i (x_i + e_i) + c >= 0 694 // 695 // for any e_i values in [0, 1). In fact, we will handle the slightly more 696 // general case where e_i can be in [0, 1]. For example, consider the 697 // inequality 2x_1 - 3x_2 - 7x_3 - 6 >= 0, and let x = (3, 0, 0). How low 698 // could the LHS go if we added a number in [0, 1] to each coordinate? The LHS 699 // is minimized when we add 1 to the x_i with negative coefficient a_i and 700 // keep the other x_i the same. In the example, we would get x = (3, 1, 1), 701 // changing the value of the LHS by -3 + -7 = -10. 702 // 703 // In general, the value of the LHS can change by at most the sum of the 704 // negative a_i, so we accomodate this by shifting the inequality by this 705 // amount for the shrunken cone. 706 for (unsigned i = 0, e = cone.getNumInequalities(); i < e; ++i) { 707 for (unsigned j = 0; j < cone.getNumIds(); ++j) { 708 int64_t coeff = cone.atIneq(i, j); 709 if (coeff < 0) 710 cone.atIneq(i, cone.getNumIds()) += coeff; 711 } 712 } 713 714 // Obtain an integer sample in the cone by rounding up a rational point from 715 // the shrunken cone. Shrinking the cone amounts to shifting its apex 716 // "inwards" without changing its "shape"; the shrunken cone is still a 717 // full-dimensional cone and is hence non-empty. 718 Simplex shrunkenConeSimplex(cone); 719 assert(!shrunkenConeSimplex.isEmpty() && "Shrunken cone cannot be empty!"); 720 721 // The sample will always exist since the shrunken cone is non-empty. 722 SmallVector<Fraction, 8> shrunkenConeSample = 723 *shrunkenConeSimplex.getRationalSample(); 724 725 SmallVector<int64_t, 8> coneSample(llvm::map_range(shrunkenConeSample, ceil)); 726 727 // 6) Return transform * concat(boundedSample, coneSample). 728 SmallVector<int64_t, 8> &sample = boundedSample.getValue(); 729 sample.append(coneSample.begin(), coneSample.end()); 730 return transform.postMultiplyWithColumn(sample); 731 } 732 733 /// Helper to evaluate an affine expression at a point. 734 /// The expression is a list of coefficients for the dimensions followed by the 735 /// constant term. 736 static int64_t valueAt(ArrayRef<int64_t> expr, ArrayRef<int64_t> point) { 737 assert(expr.size() == 1 + point.size() && 738 "Dimensionalities of point and expression don't match!"); 739 int64_t value = expr.back(); 740 for (unsigned i = 0; i < point.size(); ++i) 741 value += expr[i] * point[i]; 742 return value; 743 } 744 745 /// A point satisfies an equality iff the value of the equality at the 746 /// expression is zero, and it satisfies an inequality iff the value of the 747 /// inequality at that point is non-negative. 748 bool IntegerRelation::containsPoint(ArrayRef<int64_t> point) const { 749 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) { 750 if (valueAt(getEquality(i), point) != 0) 751 return false; 752 } 753 for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) { 754 if (valueAt(getInequality(i), point) < 0) 755 return false; 756 } 757 return true; 758 } 759 760 void IntegerRelation::getLocalReprs(std::vector<MaybeLocalRepr> &repr) const { 761 std::vector<SmallVector<int64_t, 8>> dividends(getNumLocalIds()); 762 SmallVector<unsigned, 4> denominators(getNumLocalIds()); 763 getLocalReprs(dividends, denominators, repr); 764 } 765 766 void IntegerRelation::getLocalReprs( 767 std::vector<SmallVector<int64_t, 8>> ÷nds, 768 SmallVector<unsigned, 4> &denominators) const { 769 std::vector<MaybeLocalRepr> repr(getNumLocalIds()); 770 getLocalReprs(dividends, denominators, repr); 771 } 772 773 void IntegerRelation::getLocalReprs( 774 std::vector<SmallVector<int64_t, 8>> ÷nds, 775 SmallVector<unsigned, 4> &denominators, 776 std::vector<MaybeLocalRepr> &repr) const { 777 778 repr.resize(getNumLocalIds()); 779 dividends.resize(getNumLocalIds()); 780 denominators.resize(getNumLocalIds()); 781 782 SmallVector<bool, 8> foundRepr(getNumIds(), false); 783 for (unsigned i = 0, e = getNumDimAndSymbolIds(); i < e; ++i) 784 foundRepr[i] = true; 785 786 unsigned divOffset = getNumDimAndSymbolIds(); 787 bool changed; 788 do { 789 // Each time changed is true, at end of this iteration, one or more local 790 // vars have been detected as floor divs. 791 changed = false; 792 for (unsigned i = 0, e = getNumLocalIds(); i < e; ++i) { 793 if (!foundRepr[i + divOffset]) { 794 MaybeLocalRepr res = computeSingleVarRepr( 795 *this, foundRepr, divOffset + i, dividends[i], denominators[i]); 796 if (!res) 797 continue; 798 foundRepr[i + divOffset] = true; 799 repr[i] = res; 800 changed = true; 801 } 802 } 803 } while (changed); 804 805 // Set 0 denominator for identifiers for which no division representation 806 // could be found. 807 for (unsigned i = 0, e = repr.size(); i < e; ++i) 808 if (!repr[i]) 809 denominators[i] = 0; 810 } 811 812 /// Tightens inequalities given that we are dealing with integer spaces. This is 813 /// analogous to the GCD test but applied to inequalities. The constant term can 814 /// be reduced to the preceding multiple of the GCD of the coefficients, i.e., 815 /// 64*i - 100 >= 0 => 64*i - 128 >= 0 (since 'i' is an integer). This is a 816 /// fast method - linear in the number of coefficients. 817 // Example on how this affects practical cases: consider the scenario: 818 // 64*i >= 100, j = 64*i; without a tightening, elimination of i would yield 819 // j >= 100 instead of the tighter (exact) j >= 128. 820 void IntegerRelation::gcdTightenInequalities() { 821 unsigned numCols = getNumCols(); 822 for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) { 823 // Normalize the constraint and tighten the constant term by the GCD. 824 uint64_t gcd = inequalities.normalizeRow(i, getNumCols() - 1); 825 if (gcd > 1) 826 atIneq(i, numCols - 1) = mlir::floorDiv(atIneq(i, numCols - 1), gcd); 827 } 828 } 829 830 // Eliminates all identifier variables in column range [posStart, posLimit). 831 // Returns the number of variables eliminated. 832 unsigned IntegerRelation::gaussianEliminateIds(unsigned posStart, 833 unsigned posLimit) { 834 // Return if identifier positions to eliminate are out of range. 835 assert(posLimit <= getNumIds()); 836 assert(hasConsistentState()); 837 838 if (posStart >= posLimit) 839 return 0; 840 841 gcdTightenInequalities(); 842 843 unsigned pivotCol = 0; 844 for (pivotCol = posStart; pivotCol < posLimit; ++pivotCol) { 845 // Find a row which has a non-zero coefficient in column 'j'. 846 unsigned pivotRow; 847 if (!findConstraintWithNonZeroAt(pivotCol, /*isEq=*/true, &pivotRow)) { 848 // No pivot row in equalities with non-zero at 'pivotCol'. 849 if (!findConstraintWithNonZeroAt(pivotCol, /*isEq=*/false, &pivotRow)) { 850 // If inequalities are also non-zero in 'pivotCol', it can be 851 // eliminated. 852 continue; 853 } 854 break; 855 } 856 857 // Eliminate identifier at 'pivotCol' from each equality row. 858 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) { 859 eliminateFromConstraint(this, i, pivotRow, pivotCol, posStart, 860 /*isEq=*/true); 861 equalities.normalizeRow(i); 862 } 863 864 // Eliminate identifier at 'pivotCol' from each inequality row. 865 for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) { 866 eliminateFromConstraint(this, i, pivotRow, pivotCol, posStart, 867 /*isEq=*/false); 868 inequalities.normalizeRow(i); 869 } 870 removeEquality(pivotRow); 871 gcdTightenInequalities(); 872 } 873 // Update position limit based on number eliminated. 874 posLimit = pivotCol; 875 // Remove eliminated columns from all constraints. 876 removeIdRange(posStart, posLimit); 877 return posLimit - posStart; 878 } 879 880 // A more complex check to eliminate redundant inequalities. Uses FourierMotzkin 881 // to check if a constraint is redundant. 882 void IntegerRelation::removeRedundantInequalities() { 883 SmallVector<bool, 32> redun(getNumInequalities(), false); 884 // To check if an inequality is redundant, we replace the inequality by its 885 // complement (for eg., i - 1 >= 0 by i <= 0), and check if the resulting 886 // system is empty. If it is, the inequality is redundant. 887 IntegerRelation tmpCst(*this); 888 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) { 889 // Change the inequality to its complement. 890 tmpCst.inequalities.negateRow(r); 891 tmpCst.atIneq(r, tmpCst.getNumCols() - 1)--; 892 if (tmpCst.isEmpty()) { 893 redun[r] = true; 894 // Zero fill the redundant inequality. 895 inequalities.fillRow(r, /*value=*/0); 896 tmpCst.inequalities.fillRow(r, /*value=*/0); 897 } else { 898 // Reverse the change (to avoid recreating tmpCst each time). 899 tmpCst.atIneq(r, tmpCst.getNumCols() - 1)++; 900 tmpCst.inequalities.negateRow(r); 901 } 902 } 903 904 unsigned pos = 0; 905 for (unsigned r = 0, e = getNumInequalities(); r < e; ++r) { 906 if (!redun[r]) 907 inequalities.copyRow(r, pos++); 908 } 909 inequalities.resizeVertically(pos); 910 } 911 912 // A more complex check to eliminate redundant inequalities and equalities. Uses 913 // Simplex to check if a constraint is redundant. 914 void IntegerRelation::removeRedundantConstraints() { 915 // First, we run gcdTightenInequalities. This allows us to catch some 916 // constraints which are not redundant when considering rational solutions 917 // but are redundant in terms of integer solutions. 918 gcdTightenInequalities(); 919 Simplex simplex(*this); 920 simplex.detectRedundant(); 921 922 unsigned pos = 0; 923 unsigned numIneqs = getNumInequalities(); 924 // Scan to get rid of all inequalities marked redundant, in-place. In Simplex, 925 // the first constraints added are the inequalities. 926 for (unsigned r = 0; r < numIneqs; r++) { 927 if (!simplex.isMarkedRedundant(r)) 928 inequalities.copyRow(r, pos++); 929 } 930 inequalities.resizeVertically(pos); 931 932 // Scan to get rid of all equalities marked redundant, in-place. In Simplex, 933 // after the inequalities, a pair of constraints for each equality is added. 934 // An equality is redundant if both the inequalities in its pair are 935 // redundant. 936 pos = 0; 937 for (unsigned r = 0, e = getNumEqualities(); r < e; r++) { 938 if (!(simplex.isMarkedRedundant(numIneqs + 2 * r) && 939 simplex.isMarkedRedundant(numIneqs + 2 * r + 1))) 940 equalities.copyRow(r, pos++); 941 } 942 equalities.resizeVertically(pos); 943 } 944 945 Optional<uint64_t> IntegerRelation::computeVolume() const { 946 assert(getNumSymbolIds() == 0 && "Symbols are not yet supported!"); 947 948 Simplex simplex(*this); 949 // If the polytope is rationally empty, there are certainly no integer 950 // points. 951 if (simplex.isEmpty()) 952 return 0; 953 954 // Just find the maximum and minimum integer value of each non-local id 955 // separately, thus finding the number of integer values each such id can 956 // take. Multiplying these together gives a valid overapproximation of the 957 // number of integer points in the relation. The result this gives is 958 // equivalent to projecting (rationally) the relation onto its non-local ids 959 // and returning the number of integer points in a minimal axis-parallel 960 // hyperrectangular overapproximation of that. 961 // 962 // We also handle the special case where one dimension is unbounded and 963 // another dimension can take no integer values. In this case, the volume is 964 // zero. 965 // 966 // If there is no such empty dimension, if any dimension is unbounded we 967 // just return the result as unbounded. 968 uint64_t count = 1; 969 SmallVector<int64_t, 8> dim(getNumIds() + 1); 970 bool hasUnboundedId = false; 971 for (unsigned i = 0, e = getNumDimAndSymbolIds(); i < e; ++i) { 972 dim[i] = 1; 973 MaybeOptimum<int64_t> min, max; 974 std::tie(min, max) = simplex.computeIntegerBounds(dim); 975 dim[i] = 0; 976 977 assert((!min.isEmpty() && !max.isEmpty()) && 978 "Polytope should be rationally non-empty!"); 979 980 // One of the dimensions is unbounded. Note this fact. We will return 981 // unbounded if none of the other dimensions makes the volume zero. 982 if (min.isUnbounded() || max.isUnbounded()) { 983 hasUnboundedId = true; 984 continue; 985 } 986 987 // In this case there are no valid integer points and the volume is 988 // definitely zero. 989 if (min.getBoundedOptimum() > max.getBoundedOptimum()) 990 return 0; 991 992 count *= (*max - *min + 1); 993 } 994 995 if (count == 0) 996 return 0; 997 if (hasUnboundedId) 998 return {}; 999 return count; 1000 } 1001 1002 void IntegerRelation::eliminateRedundantLocalId(unsigned posA, unsigned posB) { 1003 assert(posA < getNumLocalIds() && "Invalid local id position"); 1004 assert(posB < getNumLocalIds() && "Invalid local id position"); 1005 1006 unsigned localOffset = getIdKindOffset(IdKind::Local); 1007 posA += localOffset; 1008 posB += localOffset; 1009 inequalities.addToColumn(posB, posA, 1); 1010 equalities.addToColumn(posB, posA, 1); 1011 removeId(posB); 1012 } 1013 1014 /// Adds additional local ids to the sets such that they both have the union 1015 /// of the local ids in each set, without changing the set of points that 1016 /// lie in `this` and `other`. 1017 /// 1018 /// To detect local ids that always take the same in both sets, each local id is 1019 /// represented as a floordiv with constant denominator in terms of other ids. 1020 /// After extracting these divisions, local ids with the same division 1021 /// representation are considered duplicate and are merged. It is possible that 1022 /// division representation for some local id cannot be obtained, and thus these 1023 /// local ids are not considered for detecting duplicates. 1024 void IntegerRelation::mergeLocalIds(IntegerRelation &other) { 1025 assert(PresburgerSpace::isEqual(other) && "Spaces should match."); 1026 1027 IntegerRelation &relA = *this; 1028 IntegerRelation &relB = other; 1029 1030 // Merge local ids of relA and relB without using division information, 1031 // i.e. append local ids of `relB` to `relA` and insert local ids of `relA` 1032 // to `relB` at start of its local ids. 1033 unsigned initLocals = relA.getNumLocalIds(); 1034 insertId(IdKind::Local, relA.getNumLocalIds(), relB.getNumLocalIds()); 1035 relB.insertId(IdKind::Local, 0, initLocals); 1036 1037 // Get division representations from each rel. 1038 std::vector<SmallVector<int64_t, 8>> divsA, divsB; 1039 SmallVector<unsigned, 4> denomsA, denomsB; 1040 relA.getLocalReprs(divsA, denomsA); 1041 relB.getLocalReprs(divsB, denomsB); 1042 1043 // Copy division information for relB into `divsA` and `denomsA`, so that 1044 // these have the combined division information of both rels. Since newly 1045 // added local variables in relA and relB have no constraints, they will not 1046 // have any division representation. 1047 std::copy(divsB.begin() + initLocals, divsB.end(), 1048 divsA.begin() + initLocals); 1049 std::copy(denomsB.begin() + initLocals, denomsB.end(), 1050 denomsA.begin() + initLocals); 1051 1052 // Merge function that merges the local variables in both sets by treating 1053 // them as the same identifier. 1054 auto merge = [&relA, &relB](unsigned i, unsigned j) -> bool { 1055 relA.eliminateRedundantLocalId(i, j); 1056 relB.eliminateRedundantLocalId(i, j); 1057 return true; 1058 }; 1059 1060 // Merge all divisions by removing duplicate divisions. 1061 unsigned localOffset = getIdKindOffset(IdKind::Local); 1062 removeDuplicateDivs(divsA, denomsA, localOffset, merge); 1063 } 1064 1065 /// Removes local variables using equalities. Each equality is checked if it 1066 /// can be reduced to the form: `e = affine-expr`, where `e` is a local 1067 /// variable and `affine-expr` is an affine expression not containing `e`. 1068 /// If an equality satisfies this form, the local variable is replaced in 1069 /// each constraint and then removed. The equality used to replace this local 1070 /// variable is also removed. 1071 void IntegerRelation::removeRedundantLocalVars() { 1072 // Normalize the equality constraints to reduce coefficients of local 1073 // variables to 1 wherever possible. 1074 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) 1075 equalities.normalizeRow(i); 1076 1077 while (true) { 1078 unsigned i, e, j, f; 1079 for (i = 0, e = getNumEqualities(); i < e; ++i) { 1080 // Find a local variable to eliminate using ith equality. 1081 for (j = getNumDimAndSymbolIds(), f = getNumIds(); j < f; ++j) 1082 if (std::abs(atEq(i, j)) == 1) 1083 break; 1084 1085 // Local variable can be eliminated using ith equality. 1086 if (j < f) 1087 break; 1088 } 1089 1090 // No equality can be used to eliminate a local variable. 1091 if (i == e) 1092 break; 1093 1094 // Use the ith equality to simplify other equalities. If any changes 1095 // are made to an equality constraint, it is normalized by GCD. 1096 for (unsigned k = 0, t = getNumEqualities(); k < t; ++k) { 1097 if (atEq(k, j) != 0) { 1098 eliminateFromConstraint(this, k, i, j, j, /*isEq=*/true); 1099 equalities.normalizeRow(k); 1100 } 1101 } 1102 1103 // Use the ith equality to simplify inequalities. 1104 for (unsigned k = 0, t = getNumInequalities(); k < t; ++k) 1105 eliminateFromConstraint(this, k, i, j, j, /*isEq=*/false); 1106 1107 // Remove the ith equality and the found local variable. 1108 removeId(j); 1109 removeEquality(i); 1110 } 1111 } 1112 1113 void IntegerRelation::convertDimToLocal(unsigned dimStart, unsigned dimLimit) { 1114 assert(dimLimit <= getNumDimIds() && "Invalid dim pos range"); 1115 1116 if (dimStart >= dimLimit) 1117 return; 1118 1119 // Append new local variables corresponding to the dimensions to be converted. 1120 unsigned convertCount = dimLimit - dimStart; 1121 unsigned newLocalIdStart = getNumIds(); 1122 appendId(IdKind::Local, convertCount); 1123 1124 // Swap the new local variables with dimensions. 1125 for (unsigned i = 0; i < convertCount; ++i) 1126 swapId(i + dimStart, i + newLocalIdStart); 1127 1128 // Remove dimensions converted to local variables. 1129 removeIdRange(IdKind::SetDim, dimStart, dimLimit); 1130 } 1131 1132 void IntegerRelation::addBound(BoundType type, unsigned pos, int64_t value) { 1133 assert(pos < getNumCols()); 1134 if (type == BoundType::EQ) { 1135 unsigned row = equalities.appendExtraRow(); 1136 equalities(row, pos) = 1; 1137 equalities(row, getNumCols() - 1) = -value; 1138 } else { 1139 unsigned row = inequalities.appendExtraRow(); 1140 inequalities(row, pos) = type == BoundType::LB ? 1 : -1; 1141 inequalities(row, getNumCols() - 1) = 1142 type == BoundType::LB ? -value : value; 1143 } 1144 } 1145 1146 void IntegerRelation::addBound(BoundType type, ArrayRef<int64_t> expr, 1147 int64_t value) { 1148 assert(type != BoundType::EQ && "EQ not implemented"); 1149 assert(expr.size() == getNumCols()); 1150 unsigned row = inequalities.appendExtraRow(); 1151 for (unsigned i = 0, e = expr.size(); i < e; ++i) 1152 inequalities(row, i) = type == BoundType::LB ? expr[i] : -expr[i]; 1153 inequalities(inequalities.getNumRows() - 1, getNumCols() - 1) += 1154 type == BoundType::LB ? -value : value; 1155 } 1156 1157 /// Adds a new local identifier as the floordiv of an affine function of other 1158 /// identifiers, the coefficients of which are provided in 'dividend' and with 1159 /// respect to a positive constant 'divisor'. Two constraints are added to the 1160 /// system to capture equivalence with the floordiv. 1161 /// q = expr floordiv c <=> c*q <= expr <= c*q + c - 1. 1162 void IntegerRelation::addLocalFloorDiv(ArrayRef<int64_t> dividend, 1163 int64_t divisor) { 1164 assert(dividend.size() == getNumCols() && "incorrect dividend size"); 1165 assert(divisor > 0 && "positive divisor expected"); 1166 1167 appendId(IdKind::Local); 1168 1169 // Add two constraints for this new identifier 'q'. 1170 SmallVector<int64_t, 8> bound(dividend.size() + 1); 1171 1172 // dividend - q * divisor >= 0 1173 std::copy(dividend.begin(), dividend.begin() + dividend.size() - 1, 1174 bound.begin()); 1175 bound.back() = dividend.back(); 1176 bound[getNumIds() - 1] = -divisor; 1177 addInequality(bound); 1178 1179 // -dividend +qdivisor * q + divisor - 1 >= 0 1180 std::transform(bound.begin(), bound.end(), bound.begin(), 1181 std::negate<int64_t>()); 1182 bound[bound.size() - 1] += divisor - 1; 1183 addInequality(bound); 1184 } 1185 1186 /// Finds an equality that equates the specified identifier to a constant. 1187 /// Returns the position of the equality row. If 'symbolic' is set to true, 1188 /// symbols are also treated like a constant, i.e., an affine function of the 1189 /// symbols is also treated like a constant. Returns -1 if such an equality 1190 /// could not be found. 1191 static int findEqualityToConstant(const IntegerRelation &cst, unsigned pos, 1192 bool symbolic = false) { 1193 assert(pos < cst.getNumIds() && "invalid position"); 1194 for (unsigned r = 0, e = cst.getNumEqualities(); r < e; r++) { 1195 int64_t v = cst.atEq(r, pos); 1196 if (v * v != 1) 1197 continue; 1198 unsigned c; 1199 unsigned f = symbolic ? cst.getNumDimIds() : cst.getNumIds(); 1200 // This checks for zeros in all positions other than 'pos' in [0, f) 1201 for (c = 0; c < f; c++) { 1202 if (c == pos) 1203 continue; 1204 if (cst.atEq(r, c) != 0) { 1205 // Dependent on another identifier. 1206 break; 1207 } 1208 } 1209 if (c == f) 1210 // Equality is free of other identifiers. 1211 return r; 1212 } 1213 return -1; 1214 } 1215 1216 LogicalResult IntegerRelation::constantFoldId(unsigned pos) { 1217 assert(pos < getNumIds() && "invalid position"); 1218 int rowIdx; 1219 if ((rowIdx = findEqualityToConstant(*this, pos)) == -1) 1220 return failure(); 1221 1222 // atEq(rowIdx, pos) is either -1 or 1. 1223 assert(atEq(rowIdx, pos) * atEq(rowIdx, pos) == 1); 1224 int64_t constVal = -atEq(rowIdx, getNumCols() - 1) / atEq(rowIdx, pos); 1225 setAndEliminate(pos, constVal); 1226 return success(); 1227 } 1228 1229 void IntegerRelation::constantFoldIdRange(unsigned pos, unsigned num) { 1230 for (unsigned s = pos, t = pos, e = pos + num; s < e; s++) { 1231 if (failed(constantFoldId(t))) 1232 t++; 1233 } 1234 } 1235 1236 /// Returns a non-negative constant bound on the extent (upper bound - lower 1237 /// bound) of the specified identifier if it is found to be a constant; returns 1238 /// None if it's not a constant. This methods treats symbolic identifiers 1239 /// specially, i.e., it looks for constant differences between affine 1240 /// expressions involving only the symbolic identifiers. See comments at 1241 /// function definition for example. 'lb', if provided, is set to the lower 1242 /// bound associated with the constant difference. Note that 'lb' is purely 1243 /// symbolic and thus will contain the coefficients of the symbolic identifiers 1244 /// and the constant coefficient. 1245 // Egs: 0 <= i <= 15, return 16. 1246 // s0 + 2 <= i <= s0 + 17, returns 16. (s0 has to be a symbol) 1247 // s0 + s1 + 16 <= d0 <= s0 + s1 + 31, returns 16. 1248 // s0 - 7 <= 8*j <= s0 returns 1 with lb = s0, lbDivisor = 8 (since lb = 1249 // ceil(s0 - 7 / 8) = floor(s0 / 8)). 1250 Optional<int64_t> IntegerRelation::getConstantBoundOnDimSize( 1251 unsigned pos, SmallVectorImpl<int64_t> *lb, int64_t *boundFloorDivisor, 1252 SmallVectorImpl<int64_t> *ub, unsigned *minLbPos, 1253 unsigned *minUbPos) const { 1254 assert(pos < getNumDimIds() && "Invalid identifier position"); 1255 1256 // Find an equality for 'pos'^th identifier that equates it to some function 1257 // of the symbolic identifiers (+ constant). 1258 int eqPos = findEqualityToConstant(*this, pos, /*symbolic=*/true); 1259 if (eqPos != -1) { 1260 auto eq = getEquality(eqPos); 1261 // If the equality involves a local var, punt for now. 1262 // TODO: this can be handled in the future by using the explicit 1263 // representation of the local vars. 1264 if (!std::all_of(eq.begin() + getNumDimAndSymbolIds(), eq.end() - 1, 1265 [](int64_t coeff) { return coeff == 0; })) 1266 return None; 1267 1268 // This identifier can only take a single value. 1269 if (lb) { 1270 // Set lb to that symbolic value. 1271 lb->resize(getNumSymbolIds() + 1); 1272 if (ub) 1273 ub->resize(getNumSymbolIds() + 1); 1274 for (unsigned c = 0, f = getNumSymbolIds() + 1; c < f; c++) { 1275 int64_t v = atEq(eqPos, pos); 1276 // atEq(eqRow, pos) is either -1 or 1. 1277 assert(v * v == 1); 1278 (*lb)[c] = v < 0 ? atEq(eqPos, getNumDimIds() + c) / -v 1279 : -atEq(eqPos, getNumDimIds() + c) / v; 1280 // Since this is an equality, ub = lb. 1281 if (ub) 1282 (*ub)[c] = (*lb)[c]; 1283 } 1284 assert(boundFloorDivisor && 1285 "both lb and divisor or none should be provided"); 1286 *boundFloorDivisor = 1; 1287 } 1288 if (minLbPos) 1289 *minLbPos = eqPos; 1290 if (minUbPos) 1291 *minUbPos = eqPos; 1292 return 1; 1293 } 1294 1295 // Check if the identifier appears at all in any of the inequalities. 1296 unsigned r, e; 1297 for (r = 0, e = getNumInequalities(); r < e; r++) { 1298 if (atIneq(r, pos) != 0) 1299 break; 1300 } 1301 if (r == e) 1302 // If it doesn't, there isn't a bound on it. 1303 return None; 1304 1305 // Positions of constraints that are lower/upper bounds on the variable. 1306 SmallVector<unsigned, 4> lbIndices, ubIndices; 1307 1308 // Gather all symbolic lower bounds and upper bounds of the variable, i.e., 1309 // the bounds can only involve symbolic (and local) identifiers. Since the 1310 // canonical form c_1*x_1 + c_2*x_2 + ... + c_0 >= 0, a constraint is a lower 1311 // bound for x_i if c_i >= 1, and an upper bound if c_i <= -1. 1312 getLowerAndUpperBoundIndices(pos, &lbIndices, &ubIndices, 1313 /*eqIndices=*/nullptr, /*offset=*/0, 1314 /*num=*/getNumDimIds()); 1315 1316 Optional<int64_t> minDiff = None; 1317 unsigned minLbPosition = 0, minUbPosition = 0; 1318 for (auto ubPos : ubIndices) { 1319 for (auto lbPos : lbIndices) { 1320 // Look for a lower bound and an upper bound that only differ by a 1321 // constant, i.e., pairs of the form 0 <= c_pos - f(c_i's) <= diffConst. 1322 // For example, if ii is the pos^th variable, we are looking for 1323 // constraints like ii >= i, ii <= ii + 50, 50 being the difference. The 1324 // minimum among all such constant differences is kept since that's the 1325 // constant bounding the extent of the pos^th variable. 1326 unsigned j, e; 1327 for (j = 0, e = getNumCols() - 1; j < e; j++) 1328 if (atIneq(ubPos, j) != -atIneq(lbPos, j)) { 1329 break; 1330 } 1331 if (j < getNumCols() - 1) 1332 continue; 1333 int64_t diff = ceilDiv(atIneq(ubPos, getNumCols() - 1) + 1334 atIneq(lbPos, getNumCols() - 1) + 1, 1335 atIneq(lbPos, pos)); 1336 // This bound is non-negative by definition. 1337 diff = std::max<int64_t>(diff, 0); 1338 if (minDiff == None || diff < minDiff) { 1339 minDiff = diff; 1340 minLbPosition = lbPos; 1341 minUbPosition = ubPos; 1342 } 1343 } 1344 } 1345 if (lb && minDiff.hasValue()) { 1346 // Set lb to the symbolic lower bound. 1347 lb->resize(getNumSymbolIds() + 1); 1348 if (ub) 1349 ub->resize(getNumSymbolIds() + 1); 1350 // The lower bound is the ceildiv of the lb constraint over the coefficient 1351 // of the variable at 'pos'. We express the ceildiv equivalently as a floor 1352 // for uniformity. For eg., if the lower bound constraint was: 32*d0 - N + 1353 // 31 >= 0, the lower bound for d0 is ceil(N - 31, 32), i.e., floor(N, 32). 1354 *boundFloorDivisor = atIneq(minLbPosition, pos); 1355 assert(*boundFloorDivisor == -atIneq(minUbPosition, pos)); 1356 for (unsigned c = 0, e = getNumSymbolIds() + 1; c < e; c++) { 1357 (*lb)[c] = -atIneq(minLbPosition, getNumDimIds() + c); 1358 } 1359 if (ub) { 1360 for (unsigned c = 0, e = getNumSymbolIds() + 1; c < e; c++) 1361 (*ub)[c] = atIneq(minUbPosition, getNumDimIds() + c); 1362 } 1363 // The lower bound leads to a ceildiv while the upper bound is a floordiv 1364 // whenever the coefficient at pos != 1. ceildiv (val / d) = floordiv (val + 1365 // d - 1 / d); hence, the addition of 'atIneq(minLbPosition, pos) - 1' to 1366 // the constant term for the lower bound. 1367 (*lb)[getNumSymbolIds()] += atIneq(minLbPosition, pos) - 1; 1368 } 1369 if (minLbPos) 1370 *minLbPos = minLbPosition; 1371 if (minUbPos) 1372 *minUbPos = minUbPosition; 1373 return minDiff; 1374 } 1375 1376 template <bool isLower> 1377 Optional<int64_t> 1378 IntegerRelation::computeConstantLowerOrUpperBound(unsigned pos) { 1379 assert(pos < getNumIds() && "invalid position"); 1380 // Project to 'pos'. 1381 projectOut(0, pos); 1382 projectOut(1, getNumIds() - 1); 1383 // Check if there's an equality equating the '0'^th identifier to a constant. 1384 int eqRowIdx = findEqualityToConstant(*this, 0, /*symbolic=*/false); 1385 if (eqRowIdx != -1) 1386 // atEq(rowIdx, 0) is either -1 or 1. 1387 return -atEq(eqRowIdx, getNumCols() - 1) / atEq(eqRowIdx, 0); 1388 1389 // Check if the identifier appears at all in any of the inequalities. 1390 unsigned r, e; 1391 for (r = 0, e = getNumInequalities(); r < e; r++) { 1392 if (atIneq(r, 0) != 0) 1393 break; 1394 } 1395 if (r == e) 1396 // If it doesn't, there isn't a bound on it. 1397 return None; 1398 1399 Optional<int64_t> minOrMaxConst = None; 1400 1401 // Take the max across all const lower bounds (or min across all constant 1402 // upper bounds). 1403 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) { 1404 if (isLower) { 1405 if (atIneq(r, 0) <= 0) 1406 // Not a lower bound. 1407 continue; 1408 } else if (atIneq(r, 0) >= 0) { 1409 // Not an upper bound. 1410 continue; 1411 } 1412 unsigned c, f; 1413 for (c = 0, f = getNumCols() - 1; c < f; c++) 1414 if (c != 0 && atIneq(r, c) != 0) 1415 break; 1416 if (c < getNumCols() - 1) 1417 // Not a constant bound. 1418 continue; 1419 1420 int64_t boundConst = 1421 isLower ? mlir::ceilDiv(-atIneq(r, getNumCols() - 1), atIneq(r, 0)) 1422 : mlir::floorDiv(atIneq(r, getNumCols() - 1), -atIneq(r, 0)); 1423 if (isLower) { 1424 if (minOrMaxConst == None || boundConst > minOrMaxConst) 1425 minOrMaxConst = boundConst; 1426 } else { 1427 if (minOrMaxConst == None || boundConst < minOrMaxConst) 1428 minOrMaxConst = boundConst; 1429 } 1430 } 1431 return minOrMaxConst; 1432 } 1433 1434 Optional<int64_t> IntegerRelation::getConstantBound(BoundType type, 1435 unsigned pos) const { 1436 if (type == BoundType::LB) 1437 return IntegerRelation(*this) 1438 .computeConstantLowerOrUpperBound</*isLower=*/true>(pos); 1439 if (type == BoundType::UB) 1440 return IntegerRelation(*this) 1441 .computeConstantLowerOrUpperBound</*isLower=*/false>(pos); 1442 1443 assert(type == BoundType::EQ && "expected EQ"); 1444 Optional<int64_t> lb = 1445 IntegerRelation(*this).computeConstantLowerOrUpperBound</*isLower=*/true>( 1446 pos); 1447 Optional<int64_t> ub = 1448 IntegerRelation(*this) 1449 .computeConstantLowerOrUpperBound</*isLower=*/false>(pos); 1450 return (lb && ub && *lb == *ub) ? Optional<int64_t>(*ub) : None; 1451 } 1452 1453 // A simple (naive and conservative) check for hyper-rectangularity. 1454 bool IntegerRelation::isHyperRectangular(unsigned pos, unsigned num) const { 1455 assert(pos < getNumCols() - 1); 1456 // Check for two non-zero coefficients in the range [pos, pos + sum). 1457 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) { 1458 unsigned sum = 0; 1459 for (unsigned c = pos; c < pos + num; c++) { 1460 if (atIneq(r, c) != 0) 1461 sum++; 1462 } 1463 if (sum > 1) 1464 return false; 1465 } 1466 for (unsigned r = 0, e = getNumEqualities(); r < e; r++) { 1467 unsigned sum = 0; 1468 for (unsigned c = pos; c < pos + num; c++) { 1469 if (atEq(r, c) != 0) 1470 sum++; 1471 } 1472 if (sum > 1) 1473 return false; 1474 } 1475 return true; 1476 } 1477 1478 /// Removes duplicate constraints, trivially true constraints, and constraints 1479 /// that can be detected as redundant as a result of differing only in their 1480 /// constant term part. A constraint of the form <non-negative constant> >= 0 is 1481 /// considered trivially true. 1482 // Uses a DenseSet to hash and detect duplicates followed by a linear scan to 1483 // remove duplicates in place. 1484 void IntegerRelation::removeTrivialRedundancy() { 1485 gcdTightenInequalities(); 1486 normalizeConstraintsByGCD(); 1487 1488 // A map used to detect redundancy stemming from constraints that only differ 1489 // in their constant term. The value stored is <row position, const term> 1490 // for a given row. 1491 SmallDenseMap<ArrayRef<int64_t>, std::pair<unsigned, int64_t>> 1492 rowsWithoutConstTerm; 1493 // To unique rows. 1494 SmallDenseSet<ArrayRef<int64_t>, 8> rowSet; 1495 1496 // Check if constraint is of the form <non-negative-constant> >= 0. 1497 auto isTriviallyValid = [&](unsigned r) -> bool { 1498 for (unsigned c = 0, e = getNumCols() - 1; c < e; c++) { 1499 if (atIneq(r, c) != 0) 1500 return false; 1501 } 1502 return atIneq(r, getNumCols() - 1) >= 0; 1503 }; 1504 1505 // Detect and mark redundant constraints. 1506 SmallVector<bool, 256> redunIneq(getNumInequalities(), false); 1507 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) { 1508 int64_t *rowStart = &inequalities(r, 0); 1509 auto row = ArrayRef<int64_t>(rowStart, getNumCols()); 1510 if (isTriviallyValid(r) || !rowSet.insert(row).second) { 1511 redunIneq[r] = true; 1512 continue; 1513 } 1514 1515 // Among constraints that only differ in the constant term part, mark 1516 // everything other than the one with the smallest constant term redundant. 1517 // (eg: among i - 16j - 5 >= 0, i - 16j - 1 >=0, i - 16j - 7 >= 0, the 1518 // former two are redundant). 1519 int64_t constTerm = atIneq(r, getNumCols() - 1); 1520 auto rowWithoutConstTerm = ArrayRef<int64_t>(rowStart, getNumCols() - 1); 1521 const auto &ret = 1522 rowsWithoutConstTerm.insert({rowWithoutConstTerm, {r, constTerm}}); 1523 if (!ret.second) { 1524 // Check if the other constraint has a higher constant term. 1525 auto &val = ret.first->second; 1526 if (val.second > constTerm) { 1527 // The stored row is redundant. Mark it so, and update with this one. 1528 redunIneq[val.first] = true; 1529 val = {r, constTerm}; 1530 } else { 1531 // The one stored makes this one redundant. 1532 redunIneq[r] = true; 1533 } 1534 } 1535 } 1536 1537 // Scan to get rid of all rows marked redundant, in-place. 1538 unsigned pos = 0; 1539 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) 1540 if (!redunIneq[r]) 1541 inequalities.copyRow(r, pos++); 1542 1543 inequalities.resizeVertically(pos); 1544 1545 // TODO: consider doing this for equalities as well, but probably not worth 1546 // the savings. 1547 } 1548 1549 #undef DEBUG_TYPE 1550 #define DEBUG_TYPE "fm" 1551 1552 /// Eliminates identifier at the specified position using Fourier-Motzkin 1553 /// variable elimination. This technique is exact for rational spaces but 1554 /// conservative (in "rare" cases) for integer spaces. The operation corresponds 1555 /// to a projection operation yielding the (convex) set of integer points 1556 /// contained in the rational shadow of the set. An emptiness test that relies 1557 /// on this method will guarantee emptiness, i.e., it disproves the existence of 1558 /// a solution if it says it's empty. 1559 /// If a non-null isResultIntegerExact is passed, it is set to true if the 1560 /// result is also integer exact. If it's set to false, the obtained solution 1561 /// *may* not be exact, i.e., it may contain integer points that do not have an 1562 /// integer pre-image in the original set. 1563 /// 1564 /// Eg: 1565 /// j >= 0, j <= i + 1 1566 /// i >= 0, i <= N + 1 1567 /// Eliminating i yields, 1568 /// j >= 0, 0 <= N + 1, j - 1 <= N + 1 1569 /// 1570 /// If darkShadow = true, this method computes the dark shadow on elimination; 1571 /// the dark shadow is a convex integer subset of the exact integer shadow. A 1572 /// non-empty dark shadow proves the existence of an integer solution. The 1573 /// elimination in such a case could however be an under-approximation, and thus 1574 /// should not be used for scanning sets or used by itself for dependence 1575 /// checking. 1576 /// 1577 /// Eg: 2-d set, * represents grid points, 'o' represents a point in the set. 1578 /// ^ 1579 /// | 1580 /// | * * * * o o 1581 /// i | * * o o o o 1582 /// | o * * * * * 1583 /// ---------------> 1584 /// j -> 1585 /// 1586 /// Eliminating i from this system (projecting on the j dimension): 1587 /// rational shadow / integer light shadow: 1 <= j <= 6 1588 /// dark shadow: 3 <= j <= 6 1589 /// exact integer shadow: j = 1 \union 3 <= j <= 6 1590 /// holes/splinters: j = 2 1591 /// 1592 /// darkShadow = false, isResultIntegerExact = nullptr are default values. 1593 // TODO: a slight modification to yield dark shadow version of FM (tightened), 1594 // which can prove the existence of a solution if there is one. 1595 void IntegerRelation::fourierMotzkinEliminate(unsigned pos, bool darkShadow, 1596 bool *isResultIntegerExact) { 1597 LLVM_DEBUG(llvm::dbgs() << "FM input (eliminate pos " << pos << "):\n"); 1598 LLVM_DEBUG(dump()); 1599 assert(pos < getNumIds() && "invalid position"); 1600 assert(hasConsistentState()); 1601 1602 // Check if this identifier can be eliminated through a substitution. 1603 for (unsigned r = 0, e = getNumEqualities(); r < e; r++) { 1604 if (atEq(r, pos) != 0) { 1605 // Use Gaussian elimination here (since we have an equality). 1606 LogicalResult ret = gaussianEliminateId(pos); 1607 (void)ret; 1608 assert(succeeded(ret) && "Gaussian elimination guaranteed to succeed"); 1609 LLVM_DEBUG(llvm::dbgs() << "FM output (through Gaussian elimination):\n"); 1610 LLVM_DEBUG(dump()); 1611 return; 1612 } 1613 } 1614 1615 // A fast linear time tightening. 1616 gcdTightenInequalities(); 1617 1618 // Check if the identifier appears at all in any of the inequalities. 1619 if (isColZero(pos)) { 1620 // If it doesn't appear, just remove the column and return. 1621 // TODO: refactor removeColumns to use it from here. 1622 removeId(pos); 1623 LLVM_DEBUG(llvm::dbgs() << "FM output:\n"); 1624 LLVM_DEBUG(dump()); 1625 return; 1626 } 1627 1628 // Positions of constraints that are lower bounds on the variable. 1629 SmallVector<unsigned, 4> lbIndices; 1630 // Positions of constraints that are lower bounds on the variable. 1631 SmallVector<unsigned, 4> ubIndices; 1632 // Positions of constraints that do not involve the variable. 1633 std::vector<unsigned> nbIndices; 1634 nbIndices.reserve(getNumInequalities()); 1635 1636 // Gather all lower bounds and upper bounds of the variable. Since the 1637 // canonical form c_1*x_1 + c_2*x_2 + ... + c_0 >= 0, a constraint is a lower 1638 // bound for x_i if c_i >= 1, and an upper bound if c_i <= -1. 1639 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) { 1640 if (atIneq(r, pos) == 0) { 1641 // Id does not appear in bound. 1642 nbIndices.push_back(r); 1643 } else if (atIneq(r, pos) >= 1) { 1644 // Lower bound. 1645 lbIndices.push_back(r); 1646 } else { 1647 // Upper bound. 1648 ubIndices.push_back(r); 1649 } 1650 } 1651 1652 // Set the number of dimensions, symbols, locals in the resulting system. 1653 unsigned newNumDomain = 1654 getNumDomainIds() - getIdKindOverlap(IdKind::Domain, pos, pos + 1); 1655 unsigned newNumRange = 1656 getNumRangeIds() - getIdKindOverlap(IdKind::Range, pos, pos + 1); 1657 unsigned newNumSymbols = 1658 getNumSymbolIds() - getIdKindOverlap(IdKind::Symbol, pos, pos + 1); 1659 unsigned newNumLocals = 1660 getNumLocalIds() - getIdKindOverlap(IdKind::Local, pos, pos + 1); 1661 1662 /// Create the new system which has one identifier less. 1663 IntegerRelation newRel(lbIndices.size() * ubIndices.size() + nbIndices.size(), 1664 getNumEqualities(), getNumCols() - 1, newNumDomain, 1665 newNumRange, newNumSymbols, newNumLocals); 1666 1667 // This will be used to check if the elimination was integer exact. 1668 unsigned lcmProducts = 1; 1669 1670 // Let x be the variable we are eliminating. 1671 // For each lower bound, lb <= c_l*x, and each upper bound c_u*x <= ub, (note 1672 // that c_l, c_u >= 1) we have: 1673 // lb*lcm(c_l, c_u)/c_l <= lcm(c_l, c_u)*x <= ub*lcm(c_l, c_u)/c_u 1674 // We thus generate a constraint: 1675 // lcm(c_l, c_u)/c_l*lb <= lcm(c_l, c_u)/c_u*ub. 1676 // Note if c_l = c_u = 1, all integer points captured by the resulting 1677 // constraint correspond to integer points in the original system (i.e., they 1678 // have integer pre-images). Hence, if the lcm's are all 1, the elimination is 1679 // integer exact. 1680 for (auto ubPos : ubIndices) { 1681 for (auto lbPos : lbIndices) { 1682 SmallVector<int64_t, 4> ineq; 1683 ineq.reserve(newRel.getNumCols()); 1684 int64_t lbCoeff = atIneq(lbPos, pos); 1685 // Note that in the comments above, ubCoeff is the negation of the 1686 // coefficient in the canonical form as the view taken here is that of the 1687 // term being moved to the other size of '>='. 1688 int64_t ubCoeff = -atIneq(ubPos, pos); 1689 // TODO: refactor this loop to avoid all branches inside. 1690 for (unsigned l = 0, e = getNumCols(); l < e; l++) { 1691 if (l == pos) 1692 continue; 1693 assert(lbCoeff >= 1 && ubCoeff >= 1 && "bounds wrongly identified"); 1694 int64_t lcm = mlir::lcm(lbCoeff, ubCoeff); 1695 ineq.push_back(atIneq(ubPos, l) * (lcm / ubCoeff) + 1696 atIneq(lbPos, l) * (lcm / lbCoeff)); 1697 lcmProducts *= lcm; 1698 } 1699 if (darkShadow) { 1700 // The dark shadow is a convex subset of the exact integer shadow. If 1701 // there is a point here, it proves the existence of a solution. 1702 ineq[ineq.size() - 1] += lbCoeff * ubCoeff - lbCoeff - ubCoeff + 1; 1703 } 1704 // TODO: we need to have a way to add inequalities in-place in 1705 // IntegerRelation instead of creating and copying over. 1706 newRel.addInequality(ineq); 1707 } 1708 } 1709 1710 LLVM_DEBUG(llvm::dbgs() << "FM isResultIntegerExact: " << (lcmProducts == 1) 1711 << "\n"); 1712 if (lcmProducts == 1 && isResultIntegerExact) 1713 *isResultIntegerExact = true; 1714 1715 // Copy over the constraints not involving this variable. 1716 for (auto nbPos : nbIndices) { 1717 SmallVector<int64_t, 4> ineq; 1718 ineq.reserve(getNumCols() - 1); 1719 for (unsigned l = 0, e = getNumCols(); l < e; l++) { 1720 if (l == pos) 1721 continue; 1722 ineq.push_back(atIneq(nbPos, l)); 1723 } 1724 newRel.addInequality(ineq); 1725 } 1726 1727 assert(newRel.getNumConstraints() == 1728 lbIndices.size() * ubIndices.size() + nbIndices.size()); 1729 1730 // Copy over the equalities. 1731 for (unsigned r = 0, e = getNumEqualities(); r < e; r++) { 1732 SmallVector<int64_t, 4> eq; 1733 eq.reserve(newRel.getNumCols()); 1734 for (unsigned l = 0, e = getNumCols(); l < e; l++) { 1735 if (l == pos) 1736 continue; 1737 eq.push_back(atEq(r, l)); 1738 } 1739 newRel.addEquality(eq); 1740 } 1741 1742 // GCD tightening and normalization allows detection of more trivially 1743 // redundant constraints. 1744 newRel.gcdTightenInequalities(); 1745 newRel.normalizeConstraintsByGCD(); 1746 newRel.removeTrivialRedundancy(); 1747 clearAndCopyFrom(newRel); 1748 LLVM_DEBUG(llvm::dbgs() << "FM output:\n"); 1749 LLVM_DEBUG(dump()); 1750 } 1751 1752 #undef DEBUG_TYPE 1753 #define DEBUG_TYPE "presburger" 1754 1755 void IntegerRelation::projectOut(unsigned pos, unsigned num) { 1756 if (num == 0) 1757 return; 1758 1759 // 'pos' can be at most getNumCols() - 2 if num > 0. 1760 assert((getNumCols() < 2 || pos <= getNumCols() - 2) && "invalid position"); 1761 assert(pos + num < getNumCols() && "invalid range"); 1762 1763 // Eliminate as many identifiers as possible using Gaussian elimination. 1764 unsigned currentPos = pos; 1765 unsigned numToEliminate = num; 1766 unsigned numGaussianEliminated = 0; 1767 1768 while (currentPos < getNumIds()) { 1769 unsigned curNumEliminated = 1770 gaussianEliminateIds(currentPos, currentPos + numToEliminate); 1771 ++currentPos; 1772 numToEliminate -= curNumEliminated + 1; 1773 numGaussianEliminated += curNumEliminated; 1774 } 1775 1776 // Eliminate the remaining using Fourier-Motzkin. 1777 for (unsigned i = 0; i < num - numGaussianEliminated; i++) { 1778 unsigned numToEliminate = num - numGaussianEliminated - i; 1779 fourierMotzkinEliminate( 1780 getBestIdToEliminate(*this, pos, pos + numToEliminate)); 1781 } 1782 1783 // Fast/trivial simplifications. 1784 gcdTightenInequalities(); 1785 // Normalize constraints after tightening since the latter impacts this, but 1786 // not the other way round. 1787 normalizeConstraintsByGCD(); 1788 } 1789 1790 namespace { 1791 1792 enum BoundCmpResult { Greater, Less, Equal, Unknown }; 1793 1794 /// Compares two affine bounds whose coefficients are provided in 'first' and 1795 /// 'second'. The last coefficient is the constant term. 1796 static BoundCmpResult compareBounds(ArrayRef<int64_t> a, ArrayRef<int64_t> b) { 1797 assert(a.size() == b.size()); 1798 1799 // For the bounds to be comparable, their corresponding identifier 1800 // coefficients should be equal; the constant terms are then compared to 1801 // determine less/greater/equal. 1802 1803 if (!std::equal(a.begin(), a.end() - 1, b.begin())) 1804 return Unknown; 1805 1806 if (a.back() == b.back()) 1807 return Equal; 1808 1809 return a.back() < b.back() ? Less : Greater; 1810 } 1811 } // namespace 1812 1813 // Returns constraints that are common to both A & B. 1814 static void getCommonConstraints(const IntegerRelation &a, 1815 const IntegerRelation &b, IntegerRelation &c) { 1816 c = IntegerRelation(a.getNumDomainIds(), a.getNumRangeIds(), 1817 a.getNumSymbolIds(), a.getNumLocalIds()); 1818 // a naive O(n^2) check should be enough here given the input sizes. 1819 for (unsigned r = 0, e = a.getNumInequalities(); r < e; ++r) { 1820 for (unsigned s = 0, f = b.getNumInequalities(); s < f; ++s) { 1821 if (a.getInequality(r) == b.getInequality(s)) { 1822 c.addInequality(a.getInequality(r)); 1823 break; 1824 } 1825 } 1826 } 1827 for (unsigned r = 0, e = a.getNumEqualities(); r < e; ++r) { 1828 for (unsigned s = 0, f = b.getNumEqualities(); s < f; ++s) { 1829 if (a.getEquality(r) == b.getEquality(s)) { 1830 c.addEquality(a.getEquality(r)); 1831 break; 1832 } 1833 } 1834 } 1835 } 1836 1837 // Computes the bounding box with respect to 'other' by finding the min of the 1838 // lower bounds and the max of the upper bounds along each of the dimensions. 1839 LogicalResult 1840 IntegerRelation::unionBoundingBox(const IntegerRelation &otherCst) { 1841 assert(PresburgerLocalSpace::isEqual(otherCst) && "Spaces should match."); 1842 assert(getNumLocalIds() == 0 && "local ids not supported yet here"); 1843 1844 // Get the constraints common to both systems; these will be added as is to 1845 // the union. 1846 IntegerRelation commonCst; 1847 getCommonConstraints(*this, otherCst, commonCst); 1848 1849 std::vector<SmallVector<int64_t, 8>> boundingLbs; 1850 std::vector<SmallVector<int64_t, 8>> boundingUbs; 1851 boundingLbs.reserve(2 * getNumDimIds()); 1852 boundingUbs.reserve(2 * getNumDimIds()); 1853 1854 // To hold lower and upper bounds for each dimension. 1855 SmallVector<int64_t, 4> lb, otherLb, ub, otherUb; 1856 // To compute min of lower bounds and max of upper bounds for each dimension. 1857 SmallVector<int64_t, 4> minLb(getNumSymbolIds() + 1); 1858 SmallVector<int64_t, 4> maxUb(getNumSymbolIds() + 1); 1859 // To compute final new lower and upper bounds for the union. 1860 SmallVector<int64_t, 8> newLb(getNumCols()), newUb(getNumCols()); 1861 1862 int64_t lbFloorDivisor, otherLbFloorDivisor; 1863 for (unsigned d = 0, e = getNumDimIds(); d < e; ++d) { 1864 auto extent = getConstantBoundOnDimSize(d, &lb, &lbFloorDivisor, &ub); 1865 if (!extent.hasValue()) 1866 // TODO: symbolic extents when necessary. 1867 // TODO: handle union if a dimension is unbounded. 1868 return failure(); 1869 1870 auto otherExtent = otherCst.getConstantBoundOnDimSize( 1871 d, &otherLb, &otherLbFloorDivisor, &otherUb); 1872 if (!otherExtent.hasValue() || lbFloorDivisor != otherLbFloorDivisor) 1873 // TODO: symbolic extents when necessary. 1874 return failure(); 1875 1876 assert(lbFloorDivisor > 0 && "divisor always expected to be positive"); 1877 1878 auto res = compareBounds(lb, otherLb); 1879 // Identify min. 1880 if (res == BoundCmpResult::Less || res == BoundCmpResult::Equal) { 1881 minLb = lb; 1882 // Since the divisor is for a floordiv, we need to convert to ceildiv, 1883 // i.e., i >= expr floordiv div <=> i >= (expr - div + 1) ceildiv div <=> 1884 // div * i >= expr - div + 1. 1885 minLb.back() -= lbFloorDivisor - 1; 1886 } else if (res == BoundCmpResult::Greater) { 1887 minLb = otherLb; 1888 minLb.back() -= otherLbFloorDivisor - 1; 1889 } else { 1890 // Uncomparable - check for constant lower/upper bounds. 1891 auto constLb = getConstantBound(BoundType::LB, d); 1892 auto constOtherLb = otherCst.getConstantBound(BoundType::LB, d); 1893 if (!constLb.hasValue() || !constOtherLb.hasValue()) 1894 return failure(); 1895 std::fill(minLb.begin(), minLb.end(), 0); 1896 minLb.back() = std::min(constLb.getValue(), constOtherLb.getValue()); 1897 } 1898 1899 // Do the same for ub's but max of upper bounds. Identify max. 1900 auto uRes = compareBounds(ub, otherUb); 1901 if (uRes == BoundCmpResult::Greater || uRes == BoundCmpResult::Equal) { 1902 maxUb = ub; 1903 } else if (uRes == BoundCmpResult::Less) { 1904 maxUb = otherUb; 1905 } else { 1906 // Uncomparable - check for constant lower/upper bounds. 1907 auto constUb = getConstantBound(BoundType::UB, d); 1908 auto constOtherUb = otherCst.getConstantBound(BoundType::UB, d); 1909 if (!constUb.hasValue() || !constOtherUb.hasValue()) 1910 return failure(); 1911 std::fill(maxUb.begin(), maxUb.end(), 0); 1912 maxUb.back() = std::max(constUb.getValue(), constOtherUb.getValue()); 1913 } 1914 1915 std::fill(newLb.begin(), newLb.end(), 0); 1916 std::fill(newUb.begin(), newUb.end(), 0); 1917 1918 // The divisor for lb, ub, otherLb, otherUb at this point is lbDivisor, 1919 // and so it's the divisor for newLb and newUb as well. 1920 newLb[d] = lbFloorDivisor; 1921 newUb[d] = -lbFloorDivisor; 1922 // Copy over the symbolic part + constant term. 1923 std::copy(minLb.begin(), minLb.end(), newLb.begin() + getNumDimIds()); 1924 std::transform(newLb.begin() + getNumDimIds(), newLb.end(), 1925 newLb.begin() + getNumDimIds(), std::negate<int64_t>()); 1926 std::copy(maxUb.begin(), maxUb.end(), newUb.begin() + getNumDimIds()); 1927 1928 boundingLbs.push_back(newLb); 1929 boundingUbs.push_back(newUb); 1930 } 1931 1932 // Clear all constraints and add the lower/upper bounds for the bounding box. 1933 clearConstraints(); 1934 for (unsigned d = 0, e = getNumDimIds(); d < e; ++d) { 1935 addInequality(boundingLbs[d]); 1936 addInequality(boundingUbs[d]); 1937 } 1938 1939 // Add the constraints that were common to both systems. 1940 append(commonCst); 1941 removeTrivialRedundancy(); 1942 1943 // TODO: copy over pure symbolic constraints from this and 'other' over to the 1944 // union (since the above are just the union along dimensions); we shouldn't 1945 // be discarding any other constraints on the symbols. 1946 1947 return success(); 1948 } 1949 1950 bool IntegerRelation::isColZero(unsigned pos) const { 1951 unsigned rowPos; 1952 return !findConstraintWithNonZeroAt(pos, /*isEq=*/false, &rowPos) && 1953 !findConstraintWithNonZeroAt(pos, /*isEq=*/true, &rowPos); 1954 } 1955 1956 /// Find positions of inequalities and equalities that do not have a coefficient 1957 /// for [pos, pos + num) identifiers. 1958 static void getIndependentConstraints(const IntegerRelation &cst, unsigned pos, 1959 unsigned num, 1960 SmallVectorImpl<unsigned> &nbIneqIndices, 1961 SmallVectorImpl<unsigned> &nbEqIndices) { 1962 assert(pos < cst.getNumIds() && "invalid start position"); 1963 assert(pos + num <= cst.getNumIds() && "invalid limit"); 1964 1965 for (unsigned r = 0, e = cst.getNumInequalities(); r < e; r++) { 1966 // The bounds are to be independent of [offset, offset + num) columns. 1967 unsigned c; 1968 for (c = pos; c < pos + num; ++c) { 1969 if (cst.atIneq(r, c) != 0) 1970 break; 1971 } 1972 if (c == pos + num) 1973 nbIneqIndices.push_back(r); 1974 } 1975 1976 for (unsigned r = 0, e = cst.getNumEqualities(); r < e; r++) { 1977 // The bounds are to be independent of [offset, offset + num) columns. 1978 unsigned c; 1979 for (c = pos; c < pos + num; ++c) { 1980 if (cst.atEq(r, c) != 0) 1981 break; 1982 } 1983 if (c == pos + num) 1984 nbEqIndices.push_back(r); 1985 } 1986 } 1987 1988 void IntegerRelation::removeIndependentConstraints(unsigned pos, unsigned num) { 1989 assert(pos + num <= getNumIds() && "invalid range"); 1990 1991 // Remove constraints that are independent of these identifiers. 1992 SmallVector<unsigned, 4> nbIneqIndices, nbEqIndices; 1993 getIndependentConstraints(*this, /*pos=*/0, num, nbIneqIndices, nbEqIndices); 1994 1995 // Iterate in reverse so that indices don't have to be updated. 1996 // TODO: This method can be made more efficient (because removal of each 1997 // inequality leads to much shifting/copying in the underlying buffer). 1998 for (auto nbIndex : llvm::reverse(nbIneqIndices)) 1999 removeInequality(nbIndex); 2000 for (auto nbIndex : llvm::reverse(nbEqIndices)) 2001 removeEquality(nbIndex); 2002 } 2003 2004 void IntegerRelation::printSpace(raw_ostream &os) const { 2005 PresburgerLocalSpace::print(os); 2006 os << getNumConstraints() << " constraints\n"; 2007 } 2008 2009 void IntegerRelation::print(raw_ostream &os) const { 2010 assert(hasConsistentState()); 2011 printSpace(os); 2012 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) { 2013 for (unsigned j = 0, f = getNumCols(); j < f; ++j) { 2014 os << atEq(i, j) << " "; 2015 } 2016 os << "= 0\n"; 2017 } 2018 for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) { 2019 for (unsigned j = 0, f = getNumCols(); j < f; ++j) { 2020 os << atIneq(i, j) << " "; 2021 } 2022 os << ">= 0\n"; 2023 } 2024 os << '\n'; 2025 } 2026 2027 void IntegerRelation::dump() const { print(llvm::errs()); } 2028 2029 unsigned IntegerPolyhedron::insertId(IdKind kind, unsigned pos, unsigned num) { 2030 assert((kind != IdKind::Domain || num == 0) && 2031 "Domain has to be zero in a set"); 2032 return IntegerRelation::insertId(kind, pos, num); 2033 } 2034