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