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