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 /// Given an IntegerRelation `p` and one of its inequalities `ineq`, check 397 /// that all inequalities of `cuttingIneqs` are redundant for the facet of `p` 398 /// where `ineq` holds as an equality. `simp` must be the Simplex constructed 399 /// from `p`. 400 static bool isFacetContained(ArrayRef<int64_t> ineq, Simplex &simp, 401 IntegerRelation &p, 402 ArrayRef<ArrayRef<int64_t>> cuttingIneqs) { 403 unsigned snapshot = simp.getSnapshot(); 404 simp.addEquality(ineq); 405 if (llvm::any_of(cuttingIneqs, [&simp](ArrayRef<int64_t> curr) { 406 return !simp.isRedundantInequality(curr); 407 })) { 408 simp.rollback(snapshot); 409 return false; 410 } 411 simp.rollback(snapshot); 412 return true; 413 } 414 415 /// Adds `disjunct` to `disjuncts` and removes the disjuncts at position `i` and 416 /// `j`. Updates `simplices` to reflect the changes. `i` and `j` cannot be 417 /// equal. 418 static void addCoalescedDisjunct(SmallVectorImpl<IntegerRelation> &disjuncts, 419 unsigned i, unsigned j, 420 const IntegerRelation &disjunct, 421 SmallVectorImpl<Simplex> &simplices) { 422 assert(i != j && "The indices must refer to different disjuncts"); 423 424 unsigned n = disjuncts.size(); 425 if (j == n - 1) { 426 // This case needs special handling since position `n` - 1 is removed from 427 // the vector, hence the `IntegerRelation` at position `n` - 2 is lost 428 // otherwise. 429 disjuncts[i] = disjuncts[n - 2]; 430 disjuncts.pop_back(); 431 disjuncts[n - 2] = disjunct; 432 433 simplices[i] = simplices[n - 2]; 434 simplices.pop_back(); 435 simplices[n - 2] = Simplex(disjunct); 436 437 } else { 438 // Other possible edge cases are correct since for `j` or `i` == `n` - 2, 439 // the `IntegerRelation` at position `n` - 2 should be lost. The case 440 // `i` == `n` - 1 makes the first following statement a noop. Hence, in this 441 // case the same thing is done as above, but with `j` rather than `i`. 442 disjuncts[i] = disjuncts[n - 1]; 443 disjuncts[j] = disjuncts[n - 2]; 444 disjuncts.pop_back(); 445 disjuncts[n - 2] = disjunct; 446 447 simplices[i] = simplices[n - 1]; 448 simplices[j] = simplices[n - 2]; 449 simplices.pop_back(); 450 simplices[n - 2] = Simplex(disjunct); 451 } 452 } 453 454 /// Given two disjuncts `a` and `b` at positions `i` and `j` in `disjuncts` 455 /// and `redundantIneqsA` being the inequalities of `a` that are redundant for 456 /// `b` (similarly for `cuttingIneqsA`, `redundantIneqsB`, and `cuttingIneqsB`), 457 /// checks whether the facets of all cutting inequalites of `a` are contained in 458 /// `b`. If so, a new disjunct consisting of all redundant inequalites of `a` 459 /// and `b` and all equalities of both is created. 460 /// 461 /// An example of this case: 462 /// ___________ ___________ 463 /// / / | / / / 464 /// \ \ | / ==> \ / 465 /// \ \ | / \ / 466 /// \___\|/ \_____/ 467 /// 468 /// 469 static LogicalResult 470 coalescePairCutCase(SmallVectorImpl<IntegerRelation> &disjuncts, 471 SmallVectorImpl<Simplex> &simplices, unsigned i, unsigned j, 472 ArrayRef<ArrayRef<int64_t>> redundantIneqsA, 473 ArrayRef<ArrayRef<int64_t>> cuttingIneqsA, 474 ArrayRef<ArrayRef<int64_t>> redundantIneqsB, 475 ArrayRef<ArrayRef<int64_t>> cuttingIneqsB) { 476 /// All inequalities of `b` need to be redundant. We already know that the 477 /// redundant ones are, so only the cutting ones remain to be checked. 478 Simplex &simp = simplices[i]; 479 IntegerRelation &disjunct = disjuncts[i]; 480 if (llvm::any_of(cuttingIneqsA, [&simp, &disjunct, 481 &cuttingIneqsB](ArrayRef<int64_t> curr) { 482 return !isFacetContained(curr, simp, disjunct, cuttingIneqsB); 483 })) 484 return failure(); 485 IntegerRelation newSet(disjunct.getNumDomainIds(), disjunct.getNumRangeIds(), 486 disjunct.getNumSymbolIds(), disjunct.getNumLocalIds()); 487 488 for (ArrayRef<int64_t> curr : redundantIneqsA) 489 newSet.addInequality(curr); 490 491 for (ArrayRef<int64_t> curr : redundantIneqsB) 492 newSet.addInequality(curr); 493 494 addCoalescedDisjunct(disjuncts, i, j, newSet, simplices); 495 return success(); 496 } 497 498 /// Types the inequality `ineq` according to its `IneqType` for `simp` into 499 /// `redundantIneqs` and `cuttingIneqs`. Returns success, if no separate 500 /// inequalities were encountered. Otherwise, returns failure. 501 static LogicalResult 502 typeInequality(ArrayRef<int64_t> ineq, Simplex &simp, 503 SmallVectorImpl<ArrayRef<int64_t>> &redundantIneqs, 504 SmallVectorImpl<ArrayRef<int64_t>> &cuttingIneqs) { 505 Simplex::IneqType type = simp.findIneqType(ineq); 506 if (type == Simplex::IneqType::Redundant) 507 redundantIneqs.push_back(ineq); 508 else if (type == Simplex::IneqType::Cut) 509 cuttingIneqs.push_back(ineq); 510 else 511 return failure(); 512 return success(); 513 } 514 515 /// Types the equality `eq`, i.e. for `eq` == 0, types both `eq` >= 0 and -`eq` 516 /// >= 0 according to their `IneqType` for `simp` into `redundantIneqs` and 517 /// `cuttingIneqs`. Returns success, if no separate inequalities were 518 /// encountered. Otherwise, returns failure. 519 static LogicalResult 520 typeEquality(ArrayRef<int64_t> eq, Simplex &simp, 521 SmallVectorImpl<ArrayRef<int64_t>> &redundantIneqs, 522 SmallVectorImpl<ArrayRef<int64_t>> &cuttingIneqs, 523 SmallVectorImpl<SmallVector<int64_t, 2>> &negEqs) { 524 if (typeInequality(eq, simp, redundantIneqs, cuttingIneqs).failed()) 525 return failure(); 526 negEqs.push_back(getNegatedCoeffs(eq)); 527 ArrayRef<int64_t> inv(negEqs.back()); 528 if (typeInequality(inv, simp, redundantIneqs, cuttingIneqs).failed()) 529 return failure(); 530 return success(); 531 } 532 533 /// Replaces the element at position `i` with the last element and erases the 534 /// last element for both `disjuncts` and `simplices`. 535 static void eraseDisjunct(unsigned i, 536 SmallVectorImpl<IntegerRelation> &disjuncts, 537 SmallVectorImpl<Simplex> &simplices) { 538 assert(simplices.size() == disjuncts.size() && 539 "simplices and disjuncts must be equally as long"); 540 disjuncts[i] = disjuncts.back(); 541 disjuncts.pop_back(); 542 simplices[i] = simplices.back(); 543 simplices.pop_back(); 544 } 545 546 /// Attempts to coalesce the two IntegerRelations at position `i` and `j` in 547 /// `disjuncts` in-place. Returns whether the disjuncts were successfully 548 /// coalesced. The simplices in `simplices` need to be the ones constructed from 549 /// `disjuncts`. At this point, there are no empty disjuncts in 550 /// `disjuncts` left. 551 static LogicalResult coalescePair(unsigned i, unsigned j, 552 SmallVectorImpl<IntegerRelation> &disjuncts, 553 SmallVectorImpl<Simplex> &simplices) { 554 555 IntegerRelation &a = disjuncts[i]; 556 IntegerRelation &b = disjuncts[j]; 557 /// Handling of local ids is not yet implemented, so these cases are skipped. 558 /// TODO: implement local id support. 559 if (a.getNumLocalIds() != 0 || b.getNumLocalIds() != 0) 560 return failure(); 561 Simplex &simpA = simplices[i]; 562 Simplex &simpB = simplices[j]; 563 564 SmallVector<ArrayRef<int64_t>, 2> redundantIneqsA; 565 SmallVector<ArrayRef<int64_t>, 2> cuttingIneqsA; 566 SmallVector<SmallVector<int64_t, 2>, 2> negEqs; 567 568 // Organize all inequalities and equalities of `a` according to their type for 569 // `b` into `redundantIneqsA` and `cuttingIneqsA` (and vice versa for all 570 // inequalities of `b` according to their type in `a`). If a separate 571 // inequality is encountered during typing, the two IntegerRelations cannot 572 // be coalesced. 573 for (int k = 0, e = a.getNumInequalities(); k < e; ++k) 574 if (typeInequality(a.getInequality(k), simpB, redundantIneqsA, 575 cuttingIneqsA) 576 .failed()) 577 return failure(); 578 579 for (int k = 0, e = a.getNumEqualities(); k < e; ++k) 580 if (typeEquality(a.getEquality(k), simpB, redundantIneqsA, cuttingIneqsA, 581 negEqs) 582 .failed()) 583 return failure(); 584 585 SmallVector<ArrayRef<int64_t>, 2> redundantIneqsB; 586 SmallVector<ArrayRef<int64_t>, 2> cuttingIneqsB; 587 for (int k = 0, e = b.getNumInequalities(); k < e; ++k) 588 if (typeInequality(b.getInequality(k), simpA, redundantIneqsB, 589 cuttingIneqsB) 590 .failed()) 591 return failure(); 592 593 for (int k = 0, e = b.getNumEqualities(); k < e; ++k) 594 if (typeEquality(b.getEquality(k), simpA, redundantIneqsB, cuttingIneqsB, 595 negEqs) 596 .failed()) 597 return failure(); 598 599 // If there are no cutting inequalities of `a`, `b` is contained 600 // within `a` (and vice versa for `b`). 601 if (cuttingIneqsA.empty()) { 602 eraseDisjunct(j, disjuncts, simplices); 603 return success(); 604 } 605 606 if (cuttingIneqsB.empty()) { 607 eraseDisjunct(i, disjuncts, simplices); 608 return success(); 609 } 610 611 // Try to apply the cut case 612 if (coalescePairCutCase(disjuncts, simplices, i, j, redundantIneqsA, 613 cuttingIneqsA, redundantIneqsB, cuttingIneqsB) 614 .succeeded()) 615 return success(); 616 617 if (coalescePairCutCase(disjuncts, simplices, j, i, redundantIneqsB, 618 cuttingIneqsB, redundantIneqsA, cuttingIneqsA) 619 .succeeded()) 620 return success(); 621 622 return failure(); 623 } 624 625 PresburgerRelation PresburgerRelation::coalesce() const { 626 PresburgerRelation newSet = PresburgerRelation::getEmpty( 627 getNumDomainIds(), getNumRangeIds(), getNumSymbolIds()); 628 SmallVector<IntegerRelation, 2> disjuncts = integerRelations; 629 SmallVector<Simplex, 2> simplices; 630 631 simplices.reserve(getNumDisjuncts()); 632 // Note that disjuncts.size() changes during the loop. 633 for (unsigned i = 0; i < disjuncts.size();) { 634 Simplex simp(disjuncts[i]); 635 if (simp.isEmpty()) { 636 disjuncts[i] = disjuncts[disjuncts.size() - 1]; 637 disjuncts.pop_back(); 638 continue; 639 } 640 ++i; 641 simplices.push_back(simp); 642 } 643 644 // For all tuples of IntegerRelations, check whether they can be coalesced. 645 // When coalescing is successful, the contained IntegerRelation is swapped 646 // with the last element of `disjuncts` and subsequently erased and 647 // similarly for simplices. 648 for (unsigned i = 0; i < disjuncts.size();) { 649 650 // TODO: This does some comparisons two times (index 0 with 1 and index 1 651 // with 0). 652 bool broken = false; 653 for (unsigned j = 0, e = disjuncts.size(); j < e; ++j) { 654 if (i == j) 655 continue; 656 if (coalescePair(i, j, disjuncts, simplices).succeeded()) { 657 broken = true; 658 break; 659 } 660 } 661 662 // Only if the inner loop was not broken, i is incremented. This is 663 // required as otherwise, if a coalescing occurs, the IntegerRelation 664 // now at position i is not compared. 665 if (!broken) 666 ++i; 667 } 668 669 for (unsigned i = 0, e = disjuncts.size(); i < e; ++i) 670 newSet.unionInPlace(disjuncts[i]); 671 672 return newSet; 673 } 674 675 void PresburgerRelation::print(raw_ostream &os) const { 676 os << "Number of Disjuncts: " << getNumDisjuncts() << "\n"; 677 for (const IntegerRelation &disjunct : integerRelations) { 678 disjunct.print(os); 679 os << '\n'; 680 } 681 } 682 683 void PresburgerRelation::dump() const { print(llvm::errs()); } 684 685 PresburgerSet PresburgerSet::getUniverse(unsigned numDims, 686 unsigned numSymbols) { 687 PresburgerSet result(numDims, numSymbols); 688 result.unionInPlace(IntegerPolyhedron::getUniverse(numDims, numSymbols)); 689 return result; 690 } 691 692 PresburgerSet PresburgerSet::getEmpty(unsigned numDims, unsigned numSymbols) { 693 return PresburgerSet(numDims, numSymbols); 694 } 695 696 PresburgerSet::PresburgerSet(const IntegerPolyhedron &disjunct) 697 : PresburgerRelation(disjunct) {} 698 699 PresburgerSet::PresburgerSet(const PresburgerRelation &set) 700 : PresburgerRelation(set) {} 701 702 PresburgerSet PresburgerSet::unionSet(const PresburgerRelation &set) const { 703 return PresburgerSet(PresburgerRelation::unionSet(set)); 704 } 705 706 PresburgerSet PresburgerSet::intersect(const PresburgerRelation &set) const { 707 return PresburgerSet(PresburgerRelation::intersect(set)); 708 } 709 710 PresburgerSet PresburgerSet::complement() const { 711 return PresburgerSet(PresburgerRelation::complement()); 712 } 713 714 PresburgerSet PresburgerSet::subtract(const PresburgerRelation &set) const { 715 return PresburgerSet(PresburgerRelation::subtract(set)); 716 } 717 718 PresburgerSet PresburgerSet::coalesce() const { 719 return PresburgerSet(PresburgerRelation::coalesce()); 720 } 721