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