1 //===- IntegerRelation.h - MLIR IntegerRelation Class ---------*- C++ -*---===// 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 a relation over integer tuples. A relation is 10 // represented as a constraint system over a space of tuples of integer valued 11 // variables supporting symbolic variables and existential quantification. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef MLIR_ANALYSIS_PRESBURGER_INTEGERRELATION_H 16 #define MLIR_ANALYSIS_PRESBURGER_INTEGERRELATION_H 17 18 #include "mlir/Analysis/Presburger/Fraction.h" 19 #include "mlir/Analysis/Presburger/Matrix.h" 20 #include "mlir/Analysis/Presburger/PresburgerSpace.h" 21 #include "mlir/Analysis/Presburger/Utils.h" 22 #include "mlir/Support/LogicalResult.h" 23 24 namespace mlir { 25 namespace presburger { 26 27 class IntegerRelation; 28 class IntegerPolyhedron; 29 class PresburgerSet; 30 class PresburgerRelation; 31 struct SymbolicLexMin; 32 33 /// An IntegerRelation represents the set of points from a PresburgerSpace that 34 /// satisfy a list of affine constraints. Affine constraints can be inequalities 35 /// or equalities in the form: 36 /// 37 /// Inequality: c_0*x_0 + c_1*x_1 + .... + c_{n-1}*x_{n-1} + c_n >= 0 38 /// Equality : c_0*x_0 + c_1*x_1 + .... + c_{n-1}*x_{n-1} + c_n == 0 39 /// 40 /// where c_0, c_1, ..., c_n are integers and n is the total number of 41 /// variables in the space. 42 /// 43 /// Such a relation corresponds to the set of integer points lying in a convex 44 /// polyhedron. For example, consider the relation: 45 /// (x) -> (y) : (1 <= x <= 7, x = 2y) 46 /// These can be thought of as points in the polyhedron: 47 /// (x, y) : (1 <= x <= 7, x = 2y) 48 /// This relation contains the pairs (2, 1), (4, 2), and (6, 3). 49 /// 50 /// Since IntegerRelation makes a distinction between dimensions, VarKind::Range 51 /// and VarKind::Domain should be used to refer to dimension variables. 52 class IntegerRelation { 53 public: 54 /// All derived classes of IntegerRelation. 55 enum class Kind { 56 FlatAffineConstraints, 57 FlatAffineValueConstraints, 58 IntegerRelation, 59 IntegerPolyhedron, 60 }; 61 62 /// Constructs a relation reserving memory for the specified number 63 /// of constraints and variables. IntegerRelation(unsigned numReservedInequalities,unsigned numReservedEqualities,unsigned numReservedCols,const PresburgerSpace & space)64 IntegerRelation(unsigned numReservedInequalities, 65 unsigned numReservedEqualities, unsigned numReservedCols, 66 const PresburgerSpace &space) 67 : space(space), equalities(0, space.getNumVars() + 1, 68 numReservedEqualities, numReservedCols), 69 inequalities(0, space.getNumVars() + 1, numReservedInequalities, 70 numReservedCols) { 71 assert(numReservedCols >= space.getNumVars() + 1); 72 } 73 74 /// Constructs a relation with the specified number of dimensions and symbols. IntegerRelation(const PresburgerSpace & space)75 explicit IntegerRelation(const PresburgerSpace &space) 76 : IntegerRelation(/*numReservedInequalities=*/0, 77 /*numReservedEqualities=*/0, 78 /*numReservedCols=*/space.getNumVars() + 1, space) {} 79 80 virtual ~IntegerRelation() = default; 81 82 /// Return a system with no constraints, i.e., one which is satisfied by all 83 /// points. getUniverse(const PresburgerSpace & space)84 static IntegerRelation getUniverse(const PresburgerSpace &space) { 85 return IntegerRelation(space); 86 } 87 88 /// Return the kind of this IntegerRelation. getKind()89 virtual Kind getKind() const { return Kind::IntegerRelation; } 90 classof(const IntegerRelation * cst)91 static bool classof(const IntegerRelation *cst) { return true; } 92 93 // Clones this object. 94 std::unique_ptr<IntegerRelation> clone() const; 95 96 /// Returns a reference to the underlying space. getSpace()97 const PresburgerSpace &getSpace() const { return space; } 98 99 /// Set the space to `oSpace`, which should have the same number of ids as 100 /// the current space. 101 void setSpace(const PresburgerSpace &oSpace); 102 103 /// Set the space to `oSpace`, which should not have any local ids. 104 /// `oSpace` can have fewer ids than the current space; in that case, the 105 /// the extra ids in `this` that are not accounted for by `oSpace` will be 106 /// considered as local ids. `oSpace` should not have more ids than the 107 /// current space; this will result in an assert failure. 108 void setSpaceExceptLocals(const PresburgerSpace &oSpace); 109 110 /// Returns a copy of the space without locals. getSpaceWithoutLocals()111 PresburgerSpace getSpaceWithoutLocals() const { 112 return PresburgerSpace::getRelationSpace(space.getNumDomainVars(), 113 space.getNumRangeVars(), 114 space.getNumSymbolVars()); 115 } 116 117 /// Appends constraints from `other` into `this`. This is equivalent to an 118 /// intersection with no simplification of any sort attempted. 119 void append(const IntegerRelation &other); 120 121 /// Return the intersection of the two relations. 122 /// If there are locals, they will be merged. 123 IntegerRelation intersect(IntegerRelation other) const; 124 125 /// Return whether `this` and `other` are equal. This is integer-exact 126 /// and somewhat expensive, since it uses the integer emptiness check 127 /// (see IntegerRelation::findIntegerSample()). 128 bool isEqual(const IntegerRelation &other) const; 129 130 /// Return whether this is a subset of the given IntegerRelation. This is 131 /// integer-exact and somewhat expensive, since it uses the integer emptiness 132 /// check (see IntegerRelation::findIntegerSample()). 133 bool isSubsetOf(const IntegerRelation &other) const; 134 135 /// Returns the value at the specified equality row and column. atEq(unsigned i,unsigned j)136 inline int64_t atEq(unsigned i, unsigned j) const { return equalities(i, j); } atEq(unsigned i,unsigned j)137 inline int64_t &atEq(unsigned i, unsigned j) { return equalities(i, j); } 138 139 /// Returns the value at the specified inequality row and column. atIneq(unsigned i,unsigned j)140 inline int64_t atIneq(unsigned i, unsigned j) const { 141 return inequalities(i, j); 142 } atIneq(unsigned i,unsigned j)143 inline int64_t &atIneq(unsigned i, unsigned j) { return inequalities(i, j); } 144 getNumConstraints()145 unsigned getNumConstraints() const { 146 return getNumInequalities() + getNumEqualities(); 147 } 148 getNumDomainVars()149 unsigned getNumDomainVars() const { return space.getNumDomainVars(); } getNumRangeVars()150 unsigned getNumRangeVars() const { return space.getNumRangeVars(); } getNumSymbolVars()151 unsigned getNumSymbolVars() const { return space.getNumSymbolVars(); } getNumLocalVars()152 unsigned getNumLocalVars() const { return space.getNumLocalVars(); } 153 getNumDimVars()154 unsigned getNumDimVars() const { return space.getNumDimVars(); } getNumDimAndSymbolVars()155 unsigned getNumDimAndSymbolVars() const { 156 return space.getNumDimAndSymbolVars(); 157 } getNumVars()158 unsigned getNumVars() const { return space.getNumVars(); } 159 160 /// Returns the number of columns in the constraint system. getNumCols()161 inline unsigned getNumCols() const { return space.getNumVars() + 1; } 162 getNumEqualities()163 inline unsigned getNumEqualities() const { return equalities.getNumRows(); } 164 getNumInequalities()165 inline unsigned getNumInequalities() const { 166 return inequalities.getNumRows(); 167 } 168 getNumReservedEqualities()169 inline unsigned getNumReservedEqualities() const { 170 return equalities.getNumReservedRows(); 171 } 172 getNumReservedInequalities()173 inline unsigned getNumReservedInequalities() const { 174 return inequalities.getNumReservedRows(); 175 } 176 getEquality(unsigned idx)177 inline ArrayRef<int64_t> getEquality(unsigned idx) const { 178 return equalities.getRow(idx); 179 } 180 getInequality(unsigned idx)181 inline ArrayRef<int64_t> getInequality(unsigned idx) const { 182 return inequalities.getRow(idx); 183 } 184 185 /// Get the number of vars of the specified kind. getNumVarKind(VarKind kind)186 unsigned getNumVarKind(VarKind kind) const { 187 return space.getNumVarKind(kind); 188 }; 189 190 /// Return the index at which the specified kind of vars starts. getVarKindOffset(VarKind kind)191 unsigned getVarKindOffset(VarKind kind) const { 192 return space.getVarKindOffset(kind); 193 }; 194 195 /// Return the index at Which the specified kind of vars ends. getVarKindEnd(VarKind kind)196 unsigned getVarKindEnd(VarKind kind) const { 197 return space.getVarKindEnd(kind); 198 }; 199 200 /// Get the number of elements of the specified kind in the range 201 /// [varStart, varLimit). getVarKindOverlap(VarKind kind,unsigned varStart,unsigned varLimit)202 unsigned getVarKindOverlap(VarKind kind, unsigned varStart, 203 unsigned varLimit) const { 204 return space.getVarKindOverlap(kind, varStart, varLimit); 205 }; 206 207 /// Return the VarKind of the var at the specified position. getVarKindAt(unsigned pos)208 VarKind getVarKindAt(unsigned pos) const { return space.getVarKindAt(pos); }; 209 210 /// The struct CountsSnapshot stores the count of each VarKind, and also of 211 /// each constraint type. getCounts() returns a CountsSnapshot object 212 /// describing the current state of the IntegerRelation. truncate() truncates 213 /// all vars of each VarKind and all constraints of both kinds beyond the 214 /// counts in the specified CountsSnapshot object. This can be used to achieve 215 /// rudimentary rollback support. As long as none of the existing constraints 216 /// or vars are disturbed, and only additional vars or constraints are added, 217 /// this addition can be rolled back using truncate. 218 struct CountsSnapshot { 219 public: CountsSnapshotCountsSnapshot220 CountsSnapshot(const PresburgerSpace &space, unsigned numIneqs, 221 unsigned numEqs) 222 : space(space), numIneqs(numIneqs), numEqs(numEqs) {} getSpaceCountsSnapshot223 const PresburgerSpace &getSpace() const { return space; }; getNumIneqsCountsSnapshot224 unsigned getNumIneqs() const { return numIneqs; } getNumEqsCountsSnapshot225 unsigned getNumEqs() const { return numEqs; } 226 227 private: 228 PresburgerSpace space; 229 unsigned numIneqs, numEqs; 230 }; 231 CountsSnapshot getCounts() const; 232 void truncate(const CountsSnapshot &counts); 233 234 /// Insert `num` variables of the specified kind at position `pos`. 235 /// Positions are relative to the kind of variable. The coefficient columns 236 /// corresponding to the added variables are initialized to zero. Return the 237 /// absolute column position (i.e., not relative to the kind of variable) 238 /// of the first added variable. 239 virtual unsigned insertVar(VarKind kind, unsigned pos, unsigned num = 1); 240 241 /// Append `num` variables of the specified kind after the last variable. 242 /// of that kind. Return the position of the first appended column relative to 243 /// the kind of variable. The coefficient columns corresponding to the added 244 /// variables are initialized to zero. 245 unsigned appendVar(VarKind kind, unsigned num = 1); 246 247 /// Adds an inequality (>= 0) from the coefficients specified in `inEq`. 248 void addInequality(ArrayRef<int64_t> inEq); 249 /// Adds an equality from the coefficients specified in `eq`. 250 void addEquality(ArrayRef<int64_t> eq); 251 252 /// Eliminate the `posB^th` local variable, replacing every instance of it 253 /// with the `posA^th` local variable. This should be used when the two 254 /// local variables are known to always take the same values. 255 virtual void eliminateRedundantLocalVar(unsigned posA, unsigned posB); 256 257 /// Removes variables of the specified kind with the specified pos (or 258 /// within the specified range) from the system. The specified location is 259 /// relative to the first variable of the specified kind. 260 void removeVar(VarKind kind, unsigned pos); 261 virtual void removeVarRange(VarKind kind, unsigned varStart, 262 unsigned varLimit); 263 264 /// Removes the specified variable from the system. 265 void removeVar(unsigned pos); 266 267 void removeEquality(unsigned pos); 268 void removeInequality(unsigned pos); 269 270 /// Remove the (in)equalities at positions [start, end). 271 void removeEqualityRange(unsigned start, unsigned end); 272 void removeInequalityRange(unsigned start, unsigned end); 273 274 /// Get the lexicographically minimum rational point satisfying the 275 /// constraints. Returns an empty optional if the relation is empty or if 276 /// the lexmin is unbounded. Symbols are not supported and will result in 277 /// assert-failure. Note that Domain is minimized first, then range. 278 MaybeOptimum<SmallVector<Fraction, 8>> findRationalLexMin() const; 279 280 /// Same as above, but returns lexicographically minimal integer point. 281 /// Note: this should be used only when the lexmin is really required. 282 /// For a generic integer sampling operation, findIntegerSample is more 283 /// robust and should be preferred. Note that Domain is minimized first, then 284 /// range. 285 MaybeOptimum<SmallVector<int64_t, 8>> findIntegerLexMin() const; 286 287 /// Swap the posA^th variable with the posB^th variable. 288 virtual void swapVar(unsigned posA, unsigned posB); 289 290 /// Removes all equalities and inequalities. 291 void clearConstraints(); 292 293 /// Sets the `values.size()` variables starting at `po`s to the specified 294 /// values and removes them. 295 void setAndEliminate(unsigned pos, ArrayRef<int64_t> values); 296 297 /// Replaces the contents of this IntegerRelation with `other`. 298 virtual void clearAndCopyFrom(const IntegerRelation &other); 299 300 /// Gather positions of all lower and upper bounds of the variable at `pos`, 301 /// and optionally any equalities on it. In addition, the bounds are to be 302 /// independent of variables in position range [`offset`, `offset` + `num`). 303 void 304 getLowerAndUpperBoundIndices(unsigned pos, 305 SmallVectorImpl<unsigned> *lbIndices, 306 SmallVectorImpl<unsigned> *ubIndices, 307 SmallVectorImpl<unsigned> *eqIndices = nullptr, 308 unsigned offset = 0, unsigned num = 0) const; 309 310 /// Checks for emptiness by performing variable elimination on all 311 /// variables, running the GCD test on each equality constraint, and 312 /// checking for invalid constraints. Returns true if the GCD test fails for 313 /// any equality, or if any invalid constraints are discovered on any row. 314 /// Returns false otherwise. 315 bool isEmpty() const; 316 317 /// Runs the GCD test on all equality constraints. Returns true if this test 318 /// fails on any equality. Returns false otherwise. 319 /// This test can be used to disprove the existence of a solution. If it 320 /// returns true, no integer solution to the equality constraints can exist. 321 bool isEmptyByGCDTest() const; 322 323 /// Returns true if the set of constraints is found to have no solution, 324 /// false if a solution exists. Uses the same algorithm as 325 /// `findIntegerSample`. 326 bool isIntegerEmpty() const; 327 328 /// Returns a matrix where each row is a vector along which the polytope is 329 /// bounded. The span of the returned vectors is guaranteed to contain all 330 /// such vectors. The returned vectors are NOT guaranteed to be linearly 331 /// independent. This function should not be called on empty sets. 332 Matrix getBoundedDirections() const; 333 334 /// Find an integer sample point satisfying the constraints using a 335 /// branch and bound algorithm with generalized basis reduction, with some 336 /// additional processing using Simplex for unbounded sets. 337 /// 338 /// Returns an integer sample point if one exists, or an empty Optional 339 /// otherwise. 340 Optional<SmallVector<int64_t, 8>> findIntegerSample() const; 341 342 /// Compute an overapproximation of the number of integer points in the 343 /// relation. Symbol vars currently not supported. If the computed 344 /// overapproximation is infinite, an empty optional is returned. 345 Optional<uint64_t> computeVolume() const; 346 347 /// Returns true if the given point satisfies the constraints, or false 348 /// otherwise. Takes the values of all vars including locals. 349 bool containsPoint(ArrayRef<int64_t> point) const; 350 /// Given the values of non-local vars, return a satisfying assignment to the 351 /// local if one exists, or an empty optional otherwise. 352 Optional<SmallVector<int64_t, 8>> 353 containsPointNoLocal(ArrayRef<int64_t> point) const; 354 355 /// Returns a `DivisonRepr` representing the division representation of local 356 /// variables in the constraint system. 357 /// 358 /// If `repr` is not `nullptr`, the equality and pairs of inequality 359 /// constraints identified by their position indices using which an explicit 360 /// representation for each local variable can be computed are set in `repr` 361 /// in the form of a `MaybeLocalRepr` struct. If no such inequality 362 /// pair/equality can be found, the kind attribute in `MaybeLocalRepr` is set 363 /// to None. 364 DivisionRepr getLocalReprs(std::vector<MaybeLocalRepr> *repr = nullptr) const; 365 366 /// The type of bound: equal, lower bound or upper bound. 367 enum BoundType { EQ, LB, UB }; 368 369 /// Adds a constant bound for the specified variable. 370 void addBound(BoundType type, unsigned pos, int64_t value); 371 372 /// Adds a constant bound for the specified expression. 373 void addBound(BoundType type, ArrayRef<int64_t> expr, int64_t value); 374 375 /// Adds a new local variable as the floordiv of an affine function of other 376 /// variables, the coefficients of which are provided in `dividend` and with 377 /// respect to a positive constant `divisor`. Two constraints are added to the 378 /// system to capture equivalence with the floordiv: 379 /// q = dividend floordiv c <=> c*q <= dividend <= c*q + c - 1. 380 void addLocalFloorDiv(ArrayRef<int64_t> dividend, int64_t divisor); 381 382 /// Projects out (aka eliminates) `num` variables starting at position 383 /// `pos`. The resulting constraint system is the shadow along the dimensions 384 /// that still exist. This method may not always be integer exact. 385 // TODO: deal with integer exactness when necessary - can return a value to 386 // mark exactness for example. 387 void projectOut(unsigned pos, unsigned num); projectOut(unsigned pos)388 inline void projectOut(unsigned pos) { return projectOut(pos, 1); } 389 390 /// Tries to fold the specified variable to a constant using a trivial 391 /// equality detection; if successful, the constant is substituted for the 392 /// variable everywhere in the constraint system and then removed from the 393 /// system. 394 LogicalResult constantFoldVar(unsigned pos); 395 396 /// This method calls `constantFoldVar` for the specified range of variables, 397 /// `num` variables starting at position `pos`. 398 void constantFoldVarRange(unsigned pos, unsigned num); 399 400 /// Updates the constraints to be the smallest bounding (enclosing) box that 401 /// contains the points of `this` set and that of `other`, with the symbols 402 /// being treated specially. For each of the dimensions, the min of the lower 403 /// bounds (symbolic) and the max of the upper bounds (symbolic) is computed 404 /// to determine such a bounding box. `other` is expected to have the same 405 /// dimensional variables as this constraint system (in the same order). 406 /// 407 /// E.g.: 408 /// 1) this = {0 <= d0 <= 127}, 409 /// other = {16 <= d0 <= 192}, 410 /// output = {0 <= d0 <= 192} 411 /// 2) this = {s0 + 5 <= d0 <= s0 + 20}, 412 /// other = {s0 + 1 <= d0 <= s0 + 9}, 413 /// output = {s0 + 1 <= d0 <= s0 + 20} 414 /// 3) this = {0 <= d0 <= 5, 1 <= d1 <= 9} 415 /// other = {2 <= d0 <= 6, 5 <= d1 <= 15}, 416 /// output = {0 <= d0 <= 6, 1 <= d1 <= 15} 417 LogicalResult unionBoundingBox(const IntegerRelation &other); 418 419 /// Returns the smallest known constant bound for the extent of the specified 420 /// variable (pos^th), i.e., the smallest known constant that is greater 421 /// than or equal to 'exclusive upper bound' - 'lower bound' of the 422 /// variable. This constant bound is guaranteed to be non-negative. Returns 423 /// None if it's not a constant. This method employs trivial (low complexity / 424 /// cost) checks and detection. Symbolic variables are treated specially, 425 /// i.e., it looks for constant differences between affine expressions 426 /// involving only the symbolic variables. `lb` and `ub` (along with the 427 /// `boundFloorDivisor`) are set to represent the lower and upper bound 428 /// associated with the constant difference: `lb`, `ub` have the coefficients, 429 /// and `boundFloorDivisor`, their divisor. `minLbPos` and `minUbPos` if 430 /// non-null are set to the position of the constant lower bound and upper 431 /// bound respectively (to the same if they are from an equality). Ex: if the 432 /// lower bound is [(s0 + s2 - 1) floordiv 32] for a system with three 433 /// symbolic variables, *lb = [1, 0, 1], lbDivisor = 32. See comments at 434 /// function definition for examples. 435 Optional<int64_t> getConstantBoundOnDimSize( 436 unsigned pos, SmallVectorImpl<int64_t> *lb = nullptr, 437 int64_t *boundFloorDivisor = nullptr, 438 SmallVectorImpl<int64_t> *ub = nullptr, unsigned *minLbPos = nullptr, 439 unsigned *minUbPos = nullptr) const; 440 441 /// Returns the constant bound for the pos^th variable if there is one; 442 /// None otherwise. 443 Optional<int64_t> getConstantBound(BoundType type, unsigned pos) const; 444 445 /// Removes constraints that are independent of (i.e., do not have a 446 /// coefficient) variables in the range [pos, pos + num). 447 void removeIndependentConstraints(unsigned pos, unsigned num); 448 449 /// Returns true if the set can be trivially detected as being 450 /// hyper-rectangular on the specified contiguous set of variables. 451 bool isHyperRectangular(unsigned pos, unsigned num) const; 452 453 /// Removes duplicate constraints, trivially true constraints, and constraints 454 /// that can be detected as redundant as a result of differing only in their 455 /// constant term part. A constraint of the form <non-negative constant> >= 0 456 /// is considered trivially true. This method is a linear time method on the 457 /// constraints, does a single scan, and updates in place. It also normalizes 458 /// constraints by their GCD and performs GCD tightening on inequalities. 459 void removeTrivialRedundancy(); 460 461 /// A more expensive check than `removeTrivialRedundancy` to detect redundant 462 /// inequalities. 463 void removeRedundantInequalities(); 464 465 /// Removes redundant constraints using Simplex. Although the algorithm can 466 /// theoretically take exponential time in the worst case (rare), it is known 467 /// to perform much better in the average case. If V is the number of vertices 468 /// in the polytope and C is the number of constraints, the algorithm takes 469 /// O(VC) time. 470 void removeRedundantConstraints(); 471 472 void removeDuplicateDivs(); 473 474 /// Converts variables of kind srcKind in the range [varStart, varLimit) to 475 /// variables of kind dstKind. If `pos` is given, the variables are placed at 476 /// position `pos` of dstKind, otherwise they are placed after all the other 477 /// variables of kind dstKind. The internal ordering among the moved variables 478 /// is preserved. 479 void convertVarKind(VarKind srcKind, unsigned varStart, unsigned varLimit, 480 VarKind dstKind, unsigned pos); convertVarKind(VarKind srcKind,unsigned varStart,unsigned varLimit,VarKind dstKind)481 void convertVarKind(VarKind srcKind, unsigned varStart, unsigned varLimit, 482 VarKind dstKind) { 483 convertVarKind(srcKind, varStart, varLimit, dstKind, 484 getNumVarKind(dstKind)); 485 } convertToLocal(VarKind kind,unsigned varStart,unsigned varLimit)486 void convertToLocal(VarKind kind, unsigned varStart, unsigned varLimit) { 487 convertVarKind(kind, varStart, varLimit, VarKind::Local); 488 } 489 490 /// Adds additional local vars to the sets such that they both have the union 491 /// of the local vars in each set, without changing the set of points that 492 /// lie in `this` and `other`. 493 /// 494 /// While taking union, if a local var in `other` has a division 495 /// representation which is a duplicate of division representation, of another 496 /// local var, it is not added to the final union of local vars and is instead 497 /// merged. The new ordering of local vars is: 498 /// 499 /// [Local vars of `this`] [Non-merged local vars of `other`] 500 /// 501 /// The relative ordering of local vars is same as before. 502 /// 503 /// After merging, if the `i^th` local variable in one set has a known 504 /// division representation, then the `i^th` local variable in the other set 505 /// either has the same division representation or no known division 506 /// representation. 507 /// 508 /// The spaces of both relations should be compatible. 509 /// 510 /// Returns the number of non-merged local vars of `other`, i.e. the number of 511 /// locals that have been added to `this`. 512 unsigned mergeLocalVars(IntegerRelation &other); 513 514 /// Check whether all local ids have a division representation. 515 bool hasOnlyDivLocals() const; 516 517 /// Changes the partition between dimensions and symbols. Depending on the new 518 /// symbol count, either a chunk of dimensional variables immediately before 519 /// the split become symbols, or some of the symbols immediately after the 520 /// split become dimensions. setDimSymbolSeparation(unsigned newSymbolCount)521 void setDimSymbolSeparation(unsigned newSymbolCount) { 522 space.setVarSymbolSeperation(newSymbolCount); 523 } 524 525 /// Return a set corresponding to all points in the domain of the relation. 526 IntegerPolyhedron getDomainSet() const; 527 528 /// Return a set corresponding to all points in the range of the relation. 529 IntegerPolyhedron getRangeSet() const; 530 531 /// Intersect the given `poly` with the domain in-place. 532 /// 533 /// Formally, let the relation `this` be R: A -> B and poly is C, then this 534 /// operation modifies R to be (A intersection C) -> B. 535 void intersectDomain(const IntegerPolyhedron &poly); 536 537 /// Intersect the given `poly` with the range in-place. 538 /// 539 /// Formally, let the relation `this` be R: A -> B and poly is C, then this 540 /// operation modifies R to be A -> (B intersection C). 541 void intersectRange(const IntegerPolyhedron &poly); 542 543 /// Invert the relation i.e., swap its domain and range. 544 /// 545 /// Formally, let the relation `this` be R: A -> B, then this operation 546 /// modifies R to be B -> A. 547 void inverse(); 548 549 /// Let the relation `this` be R1, and the relation `rel` be R2. Modifies R1 550 /// to be the composition of R1 and R2: R1;R2. 551 /// 552 /// Formally, if R1: A -> B, and R2: B -> C, then this function returns a 553 /// relation R3: A -> C such that a point (a, c) belongs to R3 iff there 554 /// exists b such that (a, b) is in R1 and, (b, c) is in R2. 555 void compose(const IntegerRelation &rel); 556 557 /// Given a relation `rel`, apply the relation to the domain of this relation. 558 /// 559 /// R1: i -> j : (0 <= i < 2, j = i) 560 /// R2: i -> k : (k = i floordiv 2) 561 /// R3: k -> j : (0 <= k < 1, 2k <= j <= 2k + 1) 562 /// 563 /// R1 = {(0, 0), (1, 1)}. R2 maps both 0 and 1 to 0. 564 /// So R3 = {(0, 0), (0, 1)}. 565 /// 566 /// Formally, R1.applyDomain(R2) = R2.inverse().compose(R1). 567 void applyDomain(const IntegerRelation &rel); 568 569 /// Given a relation `rel`, apply the relation to the range of this relation. 570 /// 571 /// Formally, R1.applyRange(R2) is the same as R1.compose(R2) but we provide 572 /// this for uniformity with `applyDomain`. 573 void applyRange(const IntegerRelation &rel); 574 575 /// Compute an equivalent representation of the same set, such that all local 576 /// vars in all disjuncts have division representations. This representation 577 /// may involve local vars that correspond to divisions, and may also be a 578 /// union of convex disjuncts. 579 PresburgerRelation computeReprWithOnlyDivLocals() const; 580 581 /// Compute the symbolic integer lexmin of the relation. 582 /// 583 /// This finds, for every assignment to the symbols and domain, 584 /// the lexicographically minimum value attained by the range. 585 /// 586 /// For example, the symbolic lexmin of the set 587 /// 588 /// (x, y)[a, b, c] : (a <= x, b <= x, x <= c) 589 /// 590 /// can be written as 591 /// 592 /// x = a if b <= a, a <= c 593 /// x = b if a < b, b <= c 594 /// 595 /// This function is stored in the `lexmin` function in the result. 596 /// Some assignments to the symbols might make the set empty. 597 /// Such points are not part of the function's domain. 598 /// In the above example, this happens when max(a, b) > c. 599 /// 600 /// For some values of the symbols, the lexmin may be unbounded. 601 /// `SymbolicLexMin` stores these parts of the symbolic domain in a separate 602 /// `PresburgerSet`, `unboundedDomain`. 603 SymbolicLexMin findSymbolicIntegerLexMin() const; 604 605 /// Return the set difference of this set and the given set, i.e., 606 /// return `this \ set`. 607 PresburgerRelation subtract(const PresburgerRelation &set) const; 608 609 void print(raw_ostream &os) const; 610 void dump() const; 611 612 protected: 613 /// Checks all rows of equality/inequality constraints for trivial 614 /// contradictions (for example: 1 == 0, 0 >= 1), which may have surfaced 615 /// after elimination. Returns true if an invalid constraint is found; 616 /// false otherwise. 617 bool hasInvalidConstraint() const; 618 619 /// Returns the constant lower bound bound if isLower is true, and the upper 620 /// bound if isLower is false. 621 template <bool isLower> 622 Optional<int64_t> computeConstantLowerOrUpperBound(unsigned pos); 623 624 /// Eliminates a single variable at `position` from equality and inequality 625 /// constraints. Returns `success` if the variable was eliminated, and 626 /// `failure` otherwise. gaussianEliminateVar(unsigned position)627 inline LogicalResult gaussianEliminateVar(unsigned position) { 628 return success(gaussianEliminateVars(position, position + 1) == 1); 629 } 630 631 /// Removes local variables using equalities. Each equality is checked if it 632 /// can be reduced to the form: `e = affine-expr`, where `e` is a local 633 /// variable and `affine-expr` is an affine expression not containing `e`. 634 /// If an equality satisfies this form, the local variable is replaced in 635 /// each constraint and then removed. The equality used to replace this local 636 /// variable is also removed. 637 void removeRedundantLocalVars(); 638 639 /// Eliminates variables from equality and inequality constraints 640 /// in column range [posStart, posLimit). 641 /// Returns the number of variables eliminated. 642 unsigned gaussianEliminateVars(unsigned posStart, unsigned posLimit); 643 644 /// Eliminates the variable at the specified position using Fourier-Motzkin 645 /// variable elimination, but uses Gaussian elimination if there is an 646 /// equality involving that variable. If the result of the elimination is 647 /// integer exact, `*isResultIntegerExact` is set to true. If `darkShadow` is 648 /// set to true, a potential under approximation (subset) of the rational 649 /// shadow / exact integer shadow is computed. 650 // See implementation comments for more details. 651 virtual void fourierMotzkinEliminate(unsigned pos, bool darkShadow = false, 652 bool *isResultIntegerExact = nullptr); 653 654 /// Tightens inequalities given that we are dealing with integer spaces. This 655 /// is similar to the GCD test but applied to inequalities. The constant term 656 /// can be reduced to the preceding multiple of the GCD of the coefficients, 657 /// i.e., 658 /// 64*i - 100 >= 0 => 64*i - 128 >= 0 (since 'i' is an integer). This is a 659 /// fast method (linear in the number of coefficients). 660 void gcdTightenInequalities(); 661 662 /// Normalized each constraints by the GCD of its coefficients. 663 void normalizeConstraintsByGCD(); 664 665 /// Searches for a constraint with a non-zero coefficient at `colIdx` in 666 /// equality (isEq=true) or inequality (isEq=false) constraints. 667 /// Returns true and sets row found in search in `rowIdx`, false otherwise. 668 bool findConstraintWithNonZeroAt(unsigned colIdx, bool isEq, 669 unsigned *rowIdx) const; 670 671 /// Returns true if the pos^th column is all zero for both inequalities and 672 /// equalities. 673 bool isColZero(unsigned pos) const; 674 675 /// Returns false if the fields corresponding to various variable counts, or 676 /// equality/inequality buffer sizes aren't consistent; true otherwise. This 677 /// is meant to be used within an assert internally. 678 virtual bool hasConsistentState() const; 679 680 /// Prints the number of constraints, dimensions, symbols and locals in the 681 /// IntegerRelation. 682 virtual void printSpace(raw_ostream &os) const; 683 684 /// Removes variables in the column range [varStart, varLimit), and copies any 685 /// remaining valid data into place, updates member variables, and resizes 686 /// arrays as needed. 687 void removeVarRange(unsigned varStart, unsigned varLimit); 688 689 /// Truncate the vars of the specified kind to the specified number by 690 /// dropping some vars at the end. `num` must be less than the current number. 691 void truncateVarKind(VarKind kind, unsigned num); 692 693 /// Truncate the vars to the number in the space of the specified 694 /// CountsSnapshot. 695 void truncateVarKind(VarKind kind, const CountsSnapshot &counts); 696 697 /// A parameter that controls detection of an unrealistic number of 698 /// constraints. If the number of constraints is this many times the number of 699 /// variables, we consider such a system out of line with the intended use 700 /// case of IntegerRelation. 701 // The rationale for 32 is that in the typical simplest of cases, an 702 // variable is expected to have one lower bound and one upper bound 703 // constraint. With a level of tiling or a connection to another variable 704 // through a div or mod, an extra pair of bounds gets added. As a limit, we 705 // don't expect a variable to have more than 32 lower/upper/equality 706 // constraints. This is conservatively set low and can be raised if needed. 707 constexpr static unsigned kExplosionFactor = 32; 708 709 PresburgerSpace space; 710 711 /// Coefficients of affine equalities (in == 0 form). 712 Matrix equalities; 713 714 /// Coefficients of affine inequalities (in >= 0 form). 715 Matrix inequalities; 716 }; 717 718 /// An IntegerPolyhedron represents the set of points from a PresburgerSpace 719 /// that satisfy a list of affine constraints. Affine constraints can be 720 /// inequalities or equalities in the form: 721 /// 722 /// Inequality: c_0*x_0 + c_1*x_1 + .... + c_{n-1}*x_{n-1} + c_n >= 0 723 /// Equality : c_0*x_0 + c_1*x_1 + .... + c_{n-1}*x_{n-1} + c_n == 0 724 /// 725 /// where c_0, c_1, ..., c_n are integers and n is the total number of 726 /// variables in the space. 727 /// 728 /// An IntegerPolyhedron is similar to an IntegerRelation but it does not make a 729 /// distinction between Domain and Range variables. Internally, 730 /// IntegerPolyhedron is implemented as a IntegerRelation with zero domain vars. 731 /// 732 /// Since IntegerPolyhedron does not make a distinction between kinds of 733 /// dimensions, VarKind::SetDim should be used to refer to dimension 734 /// variables. 735 class IntegerPolyhedron : public IntegerRelation { 736 public: 737 /// Constructs a set reserving memory for the specified number 738 /// of constraints and variables. IntegerPolyhedron(unsigned numReservedInequalities,unsigned numReservedEqualities,unsigned numReservedCols,const PresburgerSpace & space)739 IntegerPolyhedron(unsigned numReservedInequalities, 740 unsigned numReservedEqualities, unsigned numReservedCols, 741 const PresburgerSpace &space) 742 : IntegerRelation(numReservedInequalities, numReservedEqualities, 743 numReservedCols, space) { 744 assert(space.getNumDomainVars() == 0 && 745 "Number of domain vars should be zero in Set kind space."); 746 } 747 748 /// Constructs a relation with the specified number of dimensions and 749 /// symbols. IntegerPolyhedron(const PresburgerSpace & space)750 explicit IntegerPolyhedron(const PresburgerSpace &space) 751 : IntegerPolyhedron(/*numReservedInequalities=*/0, 752 /*numReservedEqualities=*/0, 753 /*numReservedCols=*/space.getNumVars() + 1, space) {} 754 755 /// Construct a set from an IntegerRelation. The relation should have 756 /// no domain vars. IntegerPolyhedron(const IntegerRelation & rel)757 explicit IntegerPolyhedron(const IntegerRelation &rel) 758 : IntegerRelation(rel) { 759 assert(space.getNumDomainVars() == 0 && 760 "Number of domain vars should be zero in Set kind space."); 761 } 762 763 /// Construct a set from an IntegerRelation, but instead of creating a copy, 764 /// use move constructor. The relation should have no domain vars. IntegerPolyhedron(IntegerRelation && rel)765 explicit IntegerPolyhedron(IntegerRelation &&rel) : IntegerRelation(rel) { 766 assert(space.getNumDomainVars() == 0 && 767 "Number of domain vars should be zero in Set kind space."); 768 } 769 770 /// Return a system with no constraints, i.e., one which is satisfied by all 771 /// points. getUniverse(const PresburgerSpace & space)772 static IntegerPolyhedron getUniverse(const PresburgerSpace &space) { 773 return IntegerPolyhedron(space); 774 } 775 776 /// Return the kind of this IntegerRelation. getKind()777 Kind getKind() const override { return Kind::IntegerPolyhedron; } 778 classof(const IntegerRelation * cst)779 static bool classof(const IntegerRelation *cst) { 780 return cst->getKind() == Kind::IntegerPolyhedron; 781 } 782 783 // Clones this object. 784 std::unique_ptr<IntegerPolyhedron> clone() const; 785 786 /// Insert `num` variables of the specified kind at position `pos`. 787 /// Positions are relative to the kind of variable. Return the absolute 788 /// column position (i.e., not relative to the kind of variable) of the 789 /// first added variable. 790 unsigned insertVar(VarKind kind, unsigned pos, unsigned num = 1) override; 791 792 /// Return the intersection of the two relations. 793 /// If there are locals, they will be merged. 794 IntegerPolyhedron intersect(const IntegerPolyhedron &other) const; 795 796 /// Return the set difference of this set and the given set, i.e., 797 /// return `this \ set`. 798 PresburgerSet subtract(const PresburgerSet &other) const; 799 }; 800 801 } // namespace presburger 802 } // namespace mlir 803 804 #endif // MLIR_ANALYSIS_PRESBURGER_INTEGERRELATION_H 805