1 //===- PresburgerRelation.cpp - MLIR PresburgerRelation 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 #include "mlir/Analysis/Presburger/PresburgerRelation.h" 10 #include "mlir/Analysis/Presburger/Simplex.h" 11 #include "mlir/Analysis/Presburger/Utils.h" 12 #include "llvm/ADT/STLExtras.h" 13 #include "llvm/ADT/ScopeExit.h" 14 #include "llvm/ADT/SmallBitVector.h" 15 16 using namespace mlir; 17 using namespace presburger; 18 19 PresburgerRelation::PresburgerRelation(const IntegerRelation &disjunct) 20 : PresburgerSpace(disjunct) { 21 unionInPlace(disjunct); 22 } 23 24 unsigned PresburgerRelation::getNumDisjuncts() const { 25 return integerRelations.size(); 26 } 27 28 ArrayRef<IntegerRelation> PresburgerRelation::getAllDisjuncts() const { 29 return integerRelations; 30 } 31 32 const IntegerRelation &PresburgerRelation::getDisjunct(unsigned index) const { 33 assert(index < integerRelations.size() && "index out of bounds!"); 34 return integerRelations[index]; 35 } 36 37 /// Mutate this set, turning it into the union of this set and the given 38 /// IntegerRelation. 39 void PresburgerRelation::unionInPlace(const IntegerRelation &disjunct) { 40 assert(PresburgerSpace::isEqual(disjunct) && "Spaces should match"); 41 integerRelations.push_back(disjunct); 42 } 43 44 /// Mutate this set, turning it into the union of this set and the given set. 45 /// 46 /// This is accomplished by simply adding all the disjuncts of the given set 47 /// to this set. 48 void PresburgerRelation::unionInPlace(const PresburgerRelation &set) { 49 assert(PresburgerSpace::isEqual(set) && "Spaces should match"); 50 for (const IntegerRelation &disjunct : set.integerRelations) 51 unionInPlace(disjunct); 52 } 53 54 /// Return the union of this set and the given set. 55 PresburgerRelation 56 PresburgerRelation::unionSet(const PresburgerRelation &set) const { 57 assert(PresburgerSpace::isEqual(set) && "Spaces should match"); 58 PresburgerRelation result = *this; 59 result.unionInPlace(set); 60 return result; 61 } 62 63 /// A point is contained in the union iff any of the parts contain the point. 64 bool PresburgerRelation::containsPoint(ArrayRef<int64_t> point) const { 65 return llvm::any_of(integerRelations, [&](const IntegerRelation &disjunct) { 66 return (disjunct.containsPoint(point)); 67 }); 68 } 69 70 PresburgerRelation PresburgerRelation::getUniverse(unsigned numDomain, 71 unsigned numRange, 72 unsigned numSymbols) { 73 PresburgerRelation result(numDomain, numRange, numSymbols); 74 result.unionInPlace( 75 IntegerRelation::getUniverse(numDomain, numRange, numSymbols)); 76 return result; 77 } 78 79 PresburgerRelation PresburgerRelation::getEmpty(unsigned numDomain, 80 unsigned numRange, 81 unsigned numSymbols) { 82 return PresburgerRelation(numDomain, numRange, numSymbols); 83 } 84 85 // Return the intersection of this set with the given set. 86 // 87 // We directly compute (S_1 or S_2 ...) and (T_1 or T_2 ...) 88 // as (S_1 and T_1) or (S_1 and T_2) or ... 89 // 90 // If S_i or T_j have local variables, then S_i and T_j contains the local 91 // variables of both. 92 PresburgerRelation 93 PresburgerRelation::intersect(const PresburgerRelation &set) const { 94 assert(PresburgerSpace::isEqual(set) && "Spaces should match"); 95 96 PresburgerRelation result(getNumDomainIds(), getNumRangeIds(), 97 getNumSymbolIds()); 98 for (const IntegerRelation &csA : integerRelations) { 99 for (const IntegerRelation &csB : set.integerRelations) { 100 IntegerRelation csACopy = csA, csBCopy = csB; 101 csACopy.mergeLocalIds(csBCopy); 102 csACopy.append(csBCopy); 103 if (!csACopy.isEmpty()) 104 result.unionInPlace(csACopy); 105 } 106 } 107 return result; 108 } 109 110 /// Return `coeffs` with all the elements negated. 111 static SmallVector<int64_t, 8> getNegatedCoeffs(ArrayRef<int64_t> coeffs) { 112 SmallVector<int64_t, 8> negatedCoeffs; 113 negatedCoeffs.reserve(coeffs.size()); 114 for (int64_t coeff : coeffs) 115 negatedCoeffs.emplace_back(-coeff); 116 return negatedCoeffs; 117 } 118 119 /// Return the complement of the given inequality. 120 /// 121 /// The complement of a_1 x_1 + ... + a_n x_ + c >= 0 is 122 /// a_1 x_1 + ... + a_n x_ + c < 0, i.e., -a_1 x_1 - ... - a_n x_ - c - 1 >= 0, 123 /// since all the variables are constrained to be integers. 124 static SmallVector<int64_t, 8> getComplementIneq(ArrayRef<int64_t> ineq) { 125 SmallVector<int64_t, 8> coeffs; 126 coeffs.reserve(ineq.size()); 127 for (int64_t coeff : ineq) 128 coeffs.emplace_back(-coeff); 129 --coeffs.back(); 130 return coeffs; 131 } 132 133 /// Return the set difference b \ s and accumulate the result into `result`. 134 /// `simplex` must correspond to b. 135 /// 136 /// In the following, U denotes union, ^ denotes intersection, \ denotes set 137 /// difference and ~ denotes complement. 138 /// Let b be the IntegerRelation and s = (U_i s_i) be the set. We want 139 /// b \ (U_i s_i). 140 /// 141 /// Let s_i = ^_j s_ij, where each s_ij is a single inequality. To compute 142 /// b \ s_i = b ^ ~s_i, we partition s_i based on the first violated inequality: 143 /// ~s_i = (~s_i1) U (s_i1 ^ ~s_i2) U (s_i1 ^ s_i2 ^ ~s_i3) U ... 144 /// And the required result is (b ^ ~s_i1) U (b ^ s_i1 ^ ~s_i2) U ... 145 /// We recurse by subtracting U_{j > i} S_j from each of these parts and 146 /// returning the union of the results. Each equality is handled as a 147 /// conjunction of two inequalities. 148 /// 149 /// Note that the same approach works even if an inequality involves a floor 150 /// division. For example, the complement of x <= 7*floor(x/7) is still 151 /// x > 7*floor(x/7). Since b \ s_i contains the inequalities of both b and s_i 152 /// (or the complements of those inequalities), b \ s_i may contain the 153 /// divisions present in both b and s_i. Therefore, we need to add the local 154 /// division variables of both b and s_i to each part in the result. This means 155 /// adding the local variables of both b and s_i, as well as the corresponding 156 /// division inequalities to each part. Since the division inequalities are 157 /// added to each part, we can skip the parts where the complement of any 158 /// division inequality is added, as these parts will become empty anyway. 159 /// 160 /// As a heuristic, we try adding all the constraints and check if simplex 161 /// says that the intersection is empty. If it is, then subtracting this 162 /// disjuncts is a no-op and we just skip it. Also, in the process we find out 163 /// that some constraints are redundant. These redundant constraints are 164 /// ignored. 165 /// 166 /// b and simplex are callee saved, i.e., their values on return are 167 /// semantically equivalent to their values when the function is called. 168 static void subtractRecursively(IntegerRelation &b, Simplex &simplex, 169 const PresburgerRelation &s, unsigned i, 170 PresburgerRelation &result) { 171 if (i == s.getNumDisjuncts()) { 172 result.unionInPlace(b); 173 return; 174 } 175 IntegerRelation sI = s.getDisjunct(i); 176 177 // Below, we append some additional constraints and ids to b. We want to 178 // rollback b to its initial state before returning, which we will do by 179 // removing all constraints beyond the original number of inequalities 180 // and equalities, so we store these counts first. 181 const unsigned bInitNumIneqs = b.getNumInequalities(); 182 const unsigned bInitNumEqs = b.getNumEqualities(); 183 const unsigned bInitNumLocals = b.getNumLocalIds(); 184 // Similarly, we also want to rollback simplex to its original state. 185 const unsigned initialSnapshot = simplex.getSnapshot(); 186 187 auto restoreState = [&]() { 188 b.removeIdRange(IdKind::Local, bInitNumLocals, b.getNumLocalIds()); 189 b.removeInequalityRange(bInitNumIneqs, b.getNumInequalities()); 190 b.removeEqualityRange(bInitNumEqs, b.getNumEqualities()); 191 simplex.rollback(initialSnapshot); 192 }; 193 194 // Automatically restore the original state when we return. 195 auto stateRestorer = llvm::make_scope_exit(restoreState); 196 197 // Find out which inequalities of sI correspond to division inequalities for 198 // the local variables of sI. 199 std::vector<MaybeLocalRepr> repr(sI.getNumLocalIds()); 200 sI.getLocalReprs(repr); 201 202 // Add sI's locals to b, after b's locals. Also add b's locals to sI, before 203 // sI's locals. 204 b.mergeLocalIds(sI); 205 206 // Mark which inequalities of sI are division inequalities and add all such 207 // inequalities to b. 208 llvm::SmallBitVector isDivInequality(sI.getNumInequalities()); 209 for (MaybeLocalRepr &maybeInequality : repr) { 210 assert(maybeInequality.kind == ReprKind::Inequality && 211 "Subtraction is not supported when a representation of the local " 212 "variables of the subtrahend cannot be found!"); 213 auto lb = maybeInequality.repr.inequalityPair.lowerBoundIdx; 214 auto ub = maybeInequality.repr.inequalityPair.upperBoundIdx; 215 216 b.addInequality(sI.getInequality(lb)); 217 b.addInequality(sI.getInequality(ub)); 218 219 assert(lb != ub && 220 "Upper and lower bounds must be different inequalities!"); 221 isDivInequality[lb] = true; 222 isDivInequality[ub] = true; 223 } 224 225 unsigned offset = simplex.getNumConstraints(); 226 unsigned numLocalsAdded = b.getNumLocalIds() - bInitNumLocals; 227 simplex.appendVariable(numLocalsAdded); 228 229 unsigned snapshotBeforeIntersect = simplex.getSnapshot(); 230 simplex.intersectIntegerRelation(sI); 231 232 if (simplex.isEmpty()) { 233 // b ^ s_i is empty, so b \ s_i = b. We move directly to i + 1. 234 // We are ignoring level i completely, so we restore the state 235 // *before* going to level i + 1. 236 restoreState(); 237 subtractRecursively(b, simplex, s, i + 1, result); 238 239 // We already restored the state above and the recursive call should have 240 // restored to the same state before returning, so we don't need to restore 241 // the state again. 242 stateRestorer.release(); 243 return; 244 } 245 246 simplex.detectRedundant(); 247 248 // Equalities are added to simplex as a pair of inequalities. 249 unsigned totalNewSimplexInequalities = 250 2 * sI.getNumEqualities() + sI.getNumInequalities(); 251 llvm::SmallBitVector isMarkedRedundant(totalNewSimplexInequalities); 252 for (unsigned j = 0; j < totalNewSimplexInequalities; j++) 253 isMarkedRedundant[j] = simplex.isMarkedRedundant(offset + j); 254 255 simplex.rollback(snapshotBeforeIntersect); 256 257 // Recurse with the part b ^ ~ineq. Note that b is modified throughout 258 // subtractRecursively. At the time this function is called, the current b is 259 // actually equal to b ^ s_i1 ^ s_i2 ^ ... ^ s_ij, and ineq is the next 260 // inequality, s_{i,j+1}. This function recurses into the next level i + 1 261 // with the part b ^ s_i1 ^ s_i2 ^ ... ^ s_ij ^ ~s_{i,j+1}. 262 auto recurseWithInequality = [&, i](ArrayRef<int64_t> ineq) { 263 size_t snapshot = simplex.getSnapshot(); 264 b.addInequality(ineq); 265 simplex.addInequality(ineq); 266 subtractRecursively(b, simplex, s, i + 1, result); 267 b.removeInequality(b.getNumInequalities() - 1); 268 simplex.rollback(snapshot); 269 }; 270 271 // For each inequality ineq, we first recurse with the part where ineq 272 // is not satisfied, and then add the ineq to b and simplex because 273 // ineq must be satisfied by all later parts. 274 auto processInequality = [&](ArrayRef<int64_t> ineq) { 275 recurseWithInequality(getComplementIneq(ineq)); 276 b.addInequality(ineq); 277 simplex.addInequality(ineq); 278 }; 279 280 // Process all the inequalities, ignoring redundant inequalities and division 281 // inequalities. The result is correct whether or not we ignore these, but 282 // ignoring them makes the result simpler. 283 for (unsigned j = 0, e = sI.getNumInequalities(); j < e; j++) { 284 if (isMarkedRedundant[j]) 285 continue; 286 if (isDivInequality[j]) 287 continue; 288 processInequality(sI.getInequality(j)); 289 } 290 291 offset = sI.getNumInequalities(); 292 for (unsigned j = 0, e = sI.getNumEqualities(); j < e; ++j) { 293 ArrayRef<int64_t> coeffs = sI.getEquality(j); 294 // For each equality, process the positive and negative inequalities that 295 // make up this equality. If Simplex found an inequality to be redundant, we 296 // skip it as above to make the result simpler. Divisions are always 297 // represented in terms of inequalities and not equalities, so we do not 298 // check for division inequalities here. 299 if (!isMarkedRedundant[offset + 2 * j]) 300 processInequality(coeffs); 301 if (!isMarkedRedundant[offset + 2 * j + 1]) 302 processInequality(getNegatedCoeffs(coeffs)); 303 } 304 } 305 306 /// Return the set difference disjunct \ set. 307 /// 308 /// The disjunct here is modified in subtractRecursively, so it cannot be a 309 /// const reference even though it is restored to its original state before 310 /// returning from that function. 311 static PresburgerRelation getSetDifference(IntegerRelation disjunct, 312 const PresburgerRelation &set) { 313 assert(disjunct.PresburgerSpace::isEqual(set) && "Spaces should match"); 314 if (disjunct.isEmptyByGCDTest()) 315 return PresburgerRelation::getEmpty(disjunct.getNumDomainIds(), 316 disjunct.getNumRangeIds(), 317 disjunct.getNumSymbolIds()); 318 319 PresburgerRelation result = PresburgerRelation::getEmpty( 320 disjunct.getNumDomainIds(), disjunct.getNumRangeIds(), 321 disjunct.getNumSymbolIds()); 322 Simplex simplex(disjunct); 323 subtractRecursively(disjunct, simplex, set, 0, result); 324 return result; 325 } 326 327 /// Return the complement of this set. 328 PresburgerRelation PresburgerRelation::complement() const { 329 return getSetDifference(IntegerRelation::getUniverse(getNumDomainIds(), 330 getNumRangeIds(), 331 getNumSymbolIds()), 332 *this); 333 } 334 335 /// Return the result of subtract the given set from this set, i.e., 336 /// return `this \ set`. 337 PresburgerRelation 338 PresburgerRelation::subtract(const PresburgerRelation &set) const { 339 assert(PresburgerSpace::isEqual(set) && "Spaces should match"); 340 PresburgerRelation result(getNumDomainIds(), getNumRangeIds(), 341 getNumSymbolIds()); 342 // We compute (U_i t_i) \ (U_i set_i) as U_i (t_i \ V_i set_i). 343 for (const IntegerRelation &disjunct : integerRelations) 344 result.unionInPlace(getSetDifference(disjunct, set)); 345 return result; 346 } 347 348 /// T is a subset of S iff T \ S is empty, since if T \ S contains a 349 /// point then this is a point that is contained in T but not S, and 350 /// if T contains a point that is not in S, this also lies in T \ S. 351 bool PresburgerRelation::isSubsetOf(const PresburgerRelation &set) const { 352 return this->subtract(set).isIntegerEmpty(); 353 } 354 355 /// Two sets are equal iff they are subsets of each other. 356 bool PresburgerRelation::isEqual(const PresburgerRelation &set) const { 357 assert(PresburgerSpace::isEqual(set) && "Spaces should match"); 358 return this->isSubsetOf(set) && set.isSubsetOf(*this); 359 } 360 361 /// Return true if all the sets in the union are known to be integer empty, 362 /// false otherwise. 363 bool PresburgerRelation::isIntegerEmpty() const { 364 // The set is empty iff all of the disjuncts are empty. 365 return std::all_of(integerRelations.begin(), integerRelations.end(), 366 [](const IntegerRelation &disjunct) { 367 return disjunct.isIntegerEmpty(); 368 }); 369 } 370 371 bool PresburgerRelation::findIntegerSample(SmallVectorImpl<int64_t> &sample) { 372 // A sample exists iff any of the disjuncts contains a sample. 373 for (const IntegerRelation &disjunct : integerRelations) { 374 if (Optional<SmallVector<int64_t, 8>> opt = disjunct.findIntegerSample()) { 375 sample = std::move(*opt); 376 return true; 377 } 378 } 379 return false; 380 } 381 382 Optional<uint64_t> PresburgerRelation::computeVolume() const { 383 assert(getNumSymbolIds() == 0 && "Symbols are not yet supported!"); 384 // The sum of the volumes of the disjuncts is a valid overapproximation of the 385 // volume of their union, even if they overlap. 386 uint64_t result = 0; 387 for (const IntegerRelation &disjunct : integerRelations) { 388 Optional<uint64_t> volume = disjunct.computeVolume(); 389 if (!volume) 390 return {}; 391 result += *volume; 392 } 393 return result; 394 } 395 396 /// The SetCoalescer class contains all functionality concerning the coalesce 397 /// heuristic. It is built from a `PresburgerRelation` and has the `coalesce()` 398 /// function as its main API. The coalesce heuristic simplifies the 399 /// representation of a PresburgerRelation. In particular, it removes all 400 /// disjuncts which are subsets of other disjuncts in the union and it combines 401 /// sets that overlap and can be combined in a convex way. 402 class presburger::SetCoalescer { 403 404 public: 405 /// Simplifies the representation of a PresburgerSet. 406 PresburgerRelation coalesce(); 407 408 /// Construct a SetCoalescer from a PresburgerSet. 409 SetCoalescer(const PresburgerRelation &s); 410 411 private: 412 /// The dimensionality of the set the SetCoalescer is coalescing. 413 unsigned numDomainIds; 414 unsigned numRangeIds; 415 unsigned numSymbolIds; 416 417 /// The current list of `IntegerRelation`s that the currently coalesced set is 418 /// the union of. 419 SmallVector<IntegerRelation, 2> disjuncts; 420 /// The list of `Simplex`s constructed from the elements of `disjuncts`. 421 SmallVector<Simplex, 2> simplices; 422 423 /// The list of all inversed equalities during typing. This ensures that 424 /// the constraints exist even after the typing function has concluded. 425 SmallVector<SmallVector<int64_t, 2>, 2> negEqs; 426 427 /// `redundantIneqsA` is the inequalities of `a` that are redundant for `b` 428 /// (similarly for `cuttingIneqsA`, `redundantIneqsB`, and `cuttingIneqsB`). 429 SmallVector<ArrayRef<int64_t>, 2> redundantIneqsA; 430 SmallVector<ArrayRef<int64_t>, 2> cuttingIneqsA; 431 432 SmallVector<ArrayRef<int64_t>, 2> redundantIneqsB; 433 SmallVector<ArrayRef<int64_t>, 2> cuttingIneqsB; 434 435 /// Given a Simplex `simp` and one of its inequalities `ineq`, check 436 /// that the facet of `simp` where `ineq` holds as an equality is contained 437 /// within `a`. 438 bool isFacetContained(ArrayRef<int64_t> ineq, Simplex &simp); 439 440 /// Adds `disjunct` to `disjuncts` and removes the disjuncts at position `i` 441 /// and `j`. Updates `simplices` to reflect the changes. `i` and `j` cannot 442 /// be equal. 443 void addCoalescedDisjunct(unsigned i, unsigned j, 444 const IntegerRelation &disjunct); 445 446 /// Checks whether `a` and `b` can be combined in a convex sense, if there 447 /// exist cutting inequalities. 448 /// 449 /// An example of this case: 450 /// ___________ ___________ 451 /// / / | / / / 452 /// \ \ | / ==> \ / 453 /// \ \ | / \ / 454 /// \___\|/ \_____/ 455 /// 456 /// 457 LogicalResult coalescePairCutCase(unsigned i, unsigned j); 458 459 /// Types the inequality `ineq` according to its `IneqType` for `simp` into 460 /// `redundantIneqsB` and `cuttingIneqsB`. Returns success, if no separate 461 /// inequalities were encountered. Otherwise, returns failure. 462 LogicalResult typeInequality(ArrayRef<int64_t> ineq, Simplex &simp); 463 464 /// Types the equality `eq`, i.e. for `eq` == 0, types both `eq` >= 0 and 465 /// -`eq` >= 0 according to their `IneqType` for `simp` into 466 /// `redundantIneqsB` and `cuttingIneqsB`. Returns success, if no separate 467 /// inequalities were encountered. Otherwise, returns failure. 468 LogicalResult typeEquality(ArrayRef<int64_t> eq, Simplex &simp); 469 470 /// Replaces the element at position `i` with the last element and erases 471 /// the last element for both `disjuncts` and `simplices`. 472 void eraseDisjunct(unsigned i); 473 474 /// Attempts to coalesce the two IntegerRelations at position `i` and `j` 475 /// in `disjuncts` in-place. Returns whether the disjuncts were 476 /// successfully coalesced. The simplices in `simplices` need to be the ones 477 /// constructed from `disjuncts`. At this point, there are no empty 478 /// disjuncts in `disjuncts` left. 479 LogicalResult coalescePair(unsigned i, unsigned j); 480 }; 481 482 /// Constructs a `SetCoalescer` from a `PresburgerRelation`. Only adds non-empty 483 /// `IntegerRelation`s to the `disjuncts` vector. 484 SetCoalescer::SetCoalescer(const PresburgerRelation &s) { 485 486 disjuncts = s.integerRelations; 487 488 simplices.reserve(s.getNumDisjuncts()); 489 // Note that disjuncts.size() changes during the loop. 490 for (unsigned i = 0; i < disjuncts.size();) { 491 Simplex simp(disjuncts[i]); 492 if (simp.isEmpty()) { 493 disjuncts[i] = disjuncts[disjuncts.size() - 1]; 494 disjuncts.pop_back(); 495 continue; 496 } 497 ++i; 498 simplices.push_back(simp); 499 } 500 numDomainIds = s.getNumDomainIds(); 501 numRangeIds = s.getNumRangeIds(); 502 numSymbolIds = s.getNumSymbolIds(); 503 } 504 505 /// Simplifies the representation of a PresburgerSet. 506 PresburgerRelation SetCoalescer::coalesce() { 507 // For all tuples of IntegerRelations, check whether they can be 508 // coalesced. When coalescing is successful, the contained IntegerRelation 509 // is swapped with the last element of `disjuncts` and subsequently erased 510 // and similarly for simplices. 511 for (unsigned i = 0; i < disjuncts.size();) { 512 513 // TODO: This does some comparisons two times (index 0 with 1 and index 1 514 // with 0). 515 bool broken = false; 516 for (unsigned j = 0, e = disjuncts.size(); j < e; ++j) { 517 negEqs.clear(); 518 redundantIneqsA.clear(); 519 redundantIneqsB.clear(); 520 cuttingIneqsA.clear(); 521 cuttingIneqsB.clear(); 522 if (i == j) 523 continue; 524 if (coalescePair(i, j).succeeded()) { 525 broken = true; 526 break; 527 } 528 } 529 530 // Only if the inner loop was not broken, i is incremented. This is 531 // required as otherwise, if a coalescing occurs, the IntegerRelation 532 // now at position i is not compared. 533 if (!broken) 534 ++i; 535 } 536 537 PresburgerRelation newSet = 538 PresburgerRelation::getEmpty(numDomainIds, numRangeIds, numSymbolIds); 539 for (unsigned i = 0, e = disjuncts.size(); i < e; ++i) 540 newSet.unionInPlace(disjuncts[i]); 541 542 return newSet; 543 } 544 545 /// Given a Simplex `simp` and one of its inequalities `ineq`, check 546 /// that all inequalities of `cuttingIneqsB` are redundant for the facet of 547 /// `simp` where `ineq` holds as an equality is contained within `a`. 548 bool SetCoalescer::isFacetContained(ArrayRef<int64_t> ineq, Simplex &simp) { 549 unsigned snapshot = simp.getSnapshot(); 550 simp.addEquality(ineq); 551 if (llvm::any_of(cuttingIneqsB, [&simp](ArrayRef<int64_t> curr) { 552 return !simp.isRedundantInequality(curr); 553 })) { 554 simp.rollback(snapshot); 555 return false; 556 } 557 simp.rollback(snapshot); 558 return true; 559 } 560 561 void SetCoalescer::addCoalescedDisjunct(unsigned i, unsigned j, 562 const IntegerRelation &disjunct) { 563 assert(i != j && "The indices must refer to different disjuncts"); 564 unsigned n = disjuncts.size(); 565 if (j == n - 1) { 566 // This case needs special handling since position `n` - 1 is removed 567 // from the vector, hence the `IntegerRelation` at position `n` - 2 is 568 // lost otherwise. 569 disjuncts[i] = disjuncts[n - 2]; 570 disjuncts.pop_back(); 571 disjuncts[n - 2] = disjunct; 572 573 simplices[i] = simplices[n - 2]; 574 simplices.pop_back(); 575 simplices[n - 2] = Simplex(disjunct); 576 577 } else { 578 // Other possible edge cases are correct since for `j` or `i` == `n` - 579 // 2, the `IntegerRelation` at position `n` - 2 should be lost. The 580 // case `i` == `n` - 1 makes the first following statement a noop. 581 // Hence, in this case the same thing is done as above, but with `j` 582 // rather than `i`. 583 disjuncts[i] = disjuncts[n - 1]; 584 disjuncts[j] = disjuncts[n - 2]; 585 disjuncts.pop_back(); 586 disjuncts[n - 2] = disjunct; 587 588 simplices[i] = simplices[n - 1]; 589 simplices[j] = simplices[n - 2]; 590 simplices.pop_back(); 591 simplices[n - 2] = Simplex(disjunct); 592 } 593 } 594 595 /// Given two polyhedra `a` and `b` at positions `i` and `j` in 596 /// `disjuncts` and `redundantIneqsA` being the inequalities of `a` that 597 /// are redundant for `b` (similarly for `cuttingIneqsA`, `redundantIneqsB`, 598 /// and `cuttingIneqsB`), Checks whether the facets of all cutting 599 /// inequalites of `a` are contained in `b`. If so, a new polyhedron 600 /// consisting of all redundant inequalites of `a` and `b` and all 601 /// equalities of both is created. 602 /// 603 /// An example of this case: 604 /// ___________ ___________ 605 /// / / | / / / 606 /// \ \ | / ==> \ / 607 /// \ \ | / \ / 608 /// \___\|/ \_____/ 609 /// 610 /// 611 LogicalResult SetCoalescer::coalescePairCutCase(unsigned i, unsigned j) { 612 /// All inequalities of `b` need to be redundant. We already know that the 613 /// redundant ones are, so only the cutting ones remain to be checked. 614 Simplex &simp = simplices[i]; 615 IntegerRelation &disjunct = disjuncts[i]; 616 if (llvm::any_of(cuttingIneqsA, [this, &simp](ArrayRef<int64_t> curr) { 617 return !isFacetContained(curr, simp); 618 })) 619 return failure(); 620 IntegerRelation newSet(disjunct.getNumDomainIds(), disjunct.getNumRangeIds(), 621 disjunct.getNumSymbolIds(), disjunct.getNumLocalIds()); 622 623 for (ArrayRef<int64_t> curr : redundantIneqsA) 624 newSet.addInequality(curr); 625 626 for (ArrayRef<int64_t> curr : redundantIneqsB) 627 newSet.addInequality(curr); 628 629 addCoalescedDisjunct(i, j, newSet); 630 return success(); 631 } 632 633 LogicalResult SetCoalescer::typeInequality(ArrayRef<int64_t> ineq, 634 Simplex &simp) { 635 Simplex::IneqType type = simp.findIneqType(ineq); 636 if (type == Simplex::IneqType::Redundant) 637 redundantIneqsB.push_back(ineq); 638 else if (type == Simplex::IneqType::Cut) 639 cuttingIneqsB.push_back(ineq); 640 else 641 return failure(); 642 return success(); 643 } 644 645 LogicalResult SetCoalescer::typeEquality(ArrayRef<int64_t> eq, Simplex &simp) { 646 if (typeInequality(eq, simp).failed()) 647 return failure(); 648 negEqs.push_back(getNegatedCoeffs(eq)); 649 ArrayRef<int64_t> inv(negEqs.back()); 650 if (typeInequality(inv, simp).failed()) 651 return failure(); 652 return success(); 653 } 654 655 void SetCoalescer::eraseDisjunct(unsigned i) { 656 assert(simplices.size() == disjuncts.size() && 657 "simplices and disjuncts must be equally as long"); 658 disjuncts[i] = disjuncts.back(); 659 disjuncts.pop_back(); 660 simplices[i] = simplices.back(); 661 simplices.pop_back(); 662 } 663 664 LogicalResult SetCoalescer::coalescePair(unsigned i, unsigned j) { 665 666 IntegerRelation &a = disjuncts[i]; 667 IntegerRelation &b = disjuncts[j]; 668 /// Handling of local ids is not yet implemented, so these cases are 669 /// skipped. 670 /// TODO: implement local id support. 671 if (a.getNumLocalIds() != 0 || b.getNumLocalIds() != 0) 672 return failure(); 673 Simplex &simpA = simplices[i]; 674 Simplex &simpB = simplices[j]; 675 676 // Organize all inequalities and equalities of `a` according to their type 677 // for `b` into `redundantIneqsA` and `cuttingIneqsA` (and vice versa for 678 // all inequalities of `b` according to their type in `a`). If a separate 679 // inequality is encountered during typing, the two IntegerRelations 680 // cannot be coalesced. 681 for (int k = 0, e = a.getNumInequalities(); k < e; ++k) 682 if (typeInequality(a.getInequality(k), simpB).failed()) 683 return failure(); 684 685 for (int k = 0, e = a.getNumEqualities(); k < e; ++k) 686 if (typeEquality(a.getEquality(k), simpB).failed()) 687 return failure(); 688 689 std::swap(redundantIneqsA, redundantIneqsB); 690 std::swap(cuttingIneqsA, cuttingIneqsB); 691 692 for (int k = 0, e = b.getNumInequalities(); k < e; ++k) 693 if (typeInequality(b.getInequality(k), simpA).failed()) 694 return failure(); 695 696 for (int k = 0, e = b.getNumEqualities(); k < e; ++k) 697 if (typeEquality(b.getEquality(k), simpA).failed()) 698 return failure(); 699 700 // If there are no cutting inequalities of `a`, `b` is contained 701 // within `a`. 702 if (cuttingIneqsA.empty()) { 703 eraseDisjunct(j); 704 return success(); 705 } 706 707 // Try to apply the cut case 708 if (coalescePairCutCase(i, j).succeeded()) 709 return success(); 710 711 // Swap the vectors to compare the pair (j,i) instead of (i,j). 712 std::swap(redundantIneqsA, redundantIneqsB); 713 std::swap(cuttingIneqsA, cuttingIneqsB); 714 715 // If there are no cutting inequalities of `a`, `b` is contained 716 // within `a`. 717 if (cuttingIneqsA.empty()) { 718 eraseDisjunct(i); 719 return success(); 720 } 721 722 // Try to apply the cut case 723 if (coalescePairCutCase(j, i).succeeded()) 724 return success(); 725 726 return failure(); 727 } 728 729 PresburgerRelation PresburgerRelation::coalesce() const { 730 return SetCoalescer(*this).coalesce(); 731 } 732 733 void PresburgerRelation::print(raw_ostream &os) const { 734 os << "Number of Disjuncts: " << getNumDisjuncts() << "\n"; 735 for (const IntegerRelation &disjunct : integerRelations) { 736 disjunct.print(os); 737 os << '\n'; 738 } 739 } 740 741 void PresburgerRelation::dump() const { print(llvm::errs()); } 742 743 PresburgerSet PresburgerSet::getUniverse(unsigned numDims, 744 unsigned numSymbols) { 745 PresburgerSet result(numDims, numSymbols); 746 result.unionInPlace(IntegerPolyhedron::getUniverse(numDims, numSymbols)); 747 return result; 748 } 749 750 PresburgerSet PresburgerSet::getEmpty(unsigned numDims, unsigned numSymbols) { 751 return PresburgerSet(numDims, numSymbols); 752 } 753 754 PresburgerSet::PresburgerSet(const IntegerPolyhedron &disjunct) 755 : PresburgerRelation(disjunct) {} 756 757 PresburgerSet::PresburgerSet(const PresburgerRelation &set) 758 : PresburgerRelation(set) {} 759 760 PresburgerSet PresburgerSet::unionSet(const PresburgerRelation &set) const { 761 return PresburgerSet(PresburgerRelation::unionSet(set)); 762 } 763 764 PresburgerSet PresburgerSet::intersect(const PresburgerRelation &set) const { 765 return PresburgerSet(PresburgerRelation::intersect(set)); 766 } 767 768 PresburgerSet PresburgerSet::complement() const { 769 return PresburgerSet(PresburgerRelation::complement()); 770 } 771 772 PresburgerSet PresburgerSet::subtract(const PresburgerRelation &set) const { 773 return PresburgerSet(PresburgerRelation::subtract(set)); 774 } 775 776 PresburgerSet PresburgerSet::coalesce() const { 777 return PresburgerSet(PresburgerRelation::coalesce()); 778 } 779