/home/arjun/llvm-project/mlir/include/mlir/Analysis/AffineStructures.h
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | //===- AffineStructures.h - MLIR Affine Structures 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 |  | // Structures for affine/polyhedral analysis of ML functions. | 
| 10 |  | // | 
| 11 |  | //===----------------------------------------------------------------------===// | 
| 12 |  |  | 
| 13 |  | #ifndef MLIR_ANALYSIS_AFFINE_STRUCTURES_H | 
| 14 |  | #define MLIR_ANALYSIS_AFFINE_STRUCTURES_H | 
| 15 |  |  | 
| 16 |  | #include "mlir/IR/AffineExpr.h" | 
| 17 |  | #include "mlir/IR/OpDefinition.h" | 
| 18 |  | #include "mlir/Support/LogicalResult.h" | 
| 19 |  |  | 
| 20 |  | namespace mlir { | 
| 21 |  |  | 
| 22 |  | class AffineCondition; | 
| 23 |  | class AffineForOp; | 
| 24 |  | class AffineMap; | 
| 25 |  | class AffineValueMap; | 
| 26 |  | class IntegerSet; | 
| 27 |  | class MLIRContext; | 
| 28 |  | class Value; | 
| 29 |  | class MemRefType; | 
| 30 |  | struct MutableAffineMap; | 
| 31 |  |  | 
| 32 |  | /// A flat list of affine equalities and inequalities in the form. | 
| 33 |  | /// Inequality: c_0*x_0 + c_1*x_1 + .... + c_{n-1}*x_{n-1} >= 0 | 
| 34 |  | /// Equality: c_0*x_0 + c_1*x_1 + .... + c_{n-1}*x_{n-1} == 0 | 
| 35 |  | /// | 
| 36 |  | /// FlatAffineConstraints stores coefficients in a contiguous buffer (one buffer | 
| 37 |  | /// for equalities and one for inequalities). The size of each buffer is | 
| 38 |  | /// numReservedCols * number of inequalities (or equalities). The reserved size | 
| 39 |  | /// is numReservedCols * numReservedInequalities (or numReservedEqualities). A | 
| 40 |  | /// coefficient (r, c) lives at the location numReservedCols * r + c in the | 
| 41 |  | /// buffer. The extra space between getNumCols() and numReservedCols exists to | 
| 42 |  | /// prevent frequent movement of data when adding columns, especially at the | 
| 43 |  | /// end. | 
| 44 |  | /// | 
| 45 |  | /// The identifiers x_0, x_1, ... appear in the order: dimensional identifiers, | 
| 46 |  | /// symbolic identifiers, and local identifiers.  The local identifiers | 
| 47 |  | /// correspond to local/internal variables created when converting from | 
| 48 |  | /// AffineExpr's containing mod's and div's; they are thus needed to increase | 
| 49 |  | /// representational power. Each local identifier is always (by construction) a | 
| 50 |  | /// floordiv of a pure add/mul affine function of dimensional, symbolic, and | 
| 51 |  | /// other local identifiers, in a non-mutually recursive way. Hence, every local | 
| 52 |  | /// identifier can ultimately always be recovered as an affine function of | 
| 53 |  | /// dimensional and symbolic identifiers (involving floordiv's); note however | 
| 54 |  | /// that some floordiv combinations are converted to mod's by AffineExpr | 
| 55 |  | /// construction. | 
| 56 |  | /// | 
| 57 |  | class FlatAffineConstraints { | 
| 58 |  | public: | 
| 59 |  |   enum IdKind { Dimension, Symbol, Local }; | 
| 60 |  |  | 
| 61 |  |   /// Constructs a constraint system reserving memory for the specified number | 
| 62 |  |   /// of constraints and identifiers.. | 
| 63 |  |   FlatAffineConstraints(unsigned numReservedInequalities, | 
| 64 |  |                         unsigned numReservedEqualities, | 
| 65 |  |                         unsigned numReservedCols, unsigned numDims = 0, | 
| 66 |  |                         unsigned numSymbols = 0, unsigned numLocals = 0, | 
| 67 |  |                         ArrayRef<Optional<Value>> idArgs = {}) | 
| 68 |  |       : numReservedCols(numReservedCols), numDims(numDims), | 
| 69 | 31 |         numSymbols(numSymbols) { | 
| 70 | 31 |     assert(numReservedCols >= numDims + numSymbols + 1); | 
| 71 | 31 |     assert(idArgs.empty() || idArgs.size() == numDims + numSymbols + numLocals); | 
| 72 | 31 |     equalities.reserve(numReservedCols * numReservedEqualities); | 
| 73 | 31 |     inequalities.reserve(numReservedCols * numReservedInequalities); | 
| 74 | 31 |     numIds = numDims + numSymbols + numLocals; | 
| 75 | 31 |     ids.reserve(numReservedCols); | 
| 76 | 31 |     if (idArgs.empty()) | 
| 77 | 31 |       ids.resize(numIds, None); | 
| 78 | 0 |     else | 
| 79 | 0 |       ids.append(idArgs.begin(), idArgs.end()); | 
| 80 | 31 |   } | 
| 81 |  |  | 
| 82 |  |   /// Constructs a constraint system with the specified number of | 
| 83 |  |   /// dimensions and symbols. | 
| 84 |  |   FlatAffineConstraints(unsigned numDims = 0, unsigned numSymbols = 0, | 
| 85 |  |                         unsigned numLocals = 0, | 
| 86 |  |                         ArrayRef<Optional<Value>> idArgs = {}) | 
| 87 |  |       : numReservedCols(numDims + numSymbols + numLocals + 1), numDims(numDims), | 
| 88 | 0 |         numSymbols(numSymbols) { | 
| 89 | 0 |     assert(numReservedCols >= numDims + numSymbols + 1); | 
| 90 | 0 |     assert(idArgs.empty() || idArgs.size() == numDims + numSymbols + numLocals); | 
| 91 | 0 |     numIds = numDims + numSymbols + numLocals; | 
| 92 | 0 |     ids.reserve(numIds); | 
| 93 | 0 |     if (idArgs.empty()) | 
| 94 | 0 |       ids.resize(numIds, None); | 
| 95 | 0 |     else | 
| 96 | 0 |       ids.append(idArgs.begin(), idArgs.end()); | 
| 97 | 0 |   } | 
| 98 |  |  | 
| 99 |  |   /// Create a flat affine constraint system from an AffineValueMap or a list of | 
| 100 |  |   /// these. The constructed system will only include equalities. | 
| 101 |  |   // TODO(bondhugula) | 
| 102 |  |   explicit FlatAffineConstraints(const AffineValueMap &avm); | 
| 103 |  |   explicit FlatAffineConstraints(ArrayRef<const AffineValueMap *> avmRef); | 
| 104 |  |  | 
| 105 |  |   /// Creates an affine constraint system from an IntegerSet. | 
| 106 |  |   explicit FlatAffineConstraints(IntegerSet set); | 
| 107 |  |  | 
| 108 |  |   FlatAffineConstraints(const FlatAffineConstraints &other); | 
| 109 |  |  | 
| 110 |  |   FlatAffineConstraints(ArrayRef<const AffineValueMap *> avmRef, | 
| 111 |  |                         IntegerSet set); | 
| 112 |  |  | 
| 113 |  |   FlatAffineConstraints(const MutableAffineMap &map); | 
| 114 |  |  | 
| 115 | 31 |   ~FlatAffineConstraints() {} | 
| 116 |  |  | 
| 117 |  |   // Clears any existing data and reserves memory for the specified constraints. | 
| 118 |  |   void reset(unsigned numReservedInequalities, unsigned numReservedEqualities, | 
| 119 |  |              unsigned numReservedCols, unsigned numDims, unsigned numSymbols, | 
| 120 |  |              unsigned numLocals = 0, ArrayRef<Value> idArgs = {}); | 
| 121 |  |  | 
| 122 |  |   void reset(unsigned numDims = 0, unsigned numSymbols = 0, | 
| 123 |  |              unsigned numLocals = 0, ArrayRef<Value> idArgs = {}); | 
| 124 |  |  | 
| 125 |  |   /// Appends constraints from 'other' into this. This is equivalent to an | 
| 126 |  |   /// intersection with no simplification of any sort attempted. | 
| 127 |  |   void append(const FlatAffineConstraints &other); | 
| 128 |  |  | 
| 129 |  |   /// Checks for emptiness by performing variable elimination on all | 
| 130 |  |   /// identifiers, running the GCD test on each equality constraint, and | 
| 131 |  |   /// checking for invalid constraints. Returns true if the GCD test fails for | 
| 132 |  |   /// any equality, or if any invalid constraints are discovered on any row. | 
| 133 |  |   /// Returns false otherwise. | 
| 134 |  |   bool isEmpty() const; | 
| 135 |  |  | 
| 136 |  |   /// Runs the GCD test on all equality constraints. Returns 'true' if this test | 
| 137 |  |   /// fails on any equality. Returns 'false' otherwise. | 
| 138 |  |   /// This test can be used to disprove the existence of a solution. If it | 
| 139 |  |   /// returns true, no integer solution to the equality constraints can exist. | 
| 140 |  |   bool isEmptyByGCDTest() const; | 
| 141 |  |  | 
| 142 |  |   /// Runs the GCD test heuristic. If it proves inconclusive, falls back to | 
| 143 |  |   /// generalized basis reduction if the set is bounded. | 
| 144 |  |   /// | 
| 145 |  |   /// Returns true if the set of constraints is found to have no solution, | 
| 146 |  |   /// false if a solution exists or all tests were inconclusive. | 
| 147 |  |   bool isIntegerEmpty() const; | 
| 148 |  |  | 
| 149 |  |   /// Find a sample point satisfying the constraints. This uses a branch and | 
| 150 |  |   /// bound algorithm with generalized basis reduction, which always works if | 
| 151 |  |   /// the set is bounded. This should not be called for unbounded sets. | 
| 152 |  |   /// | 
| 153 |  |   /// Returns such a point if one exists, or an empty Optional otherwise. | 
| 154 |  |   Optional<SmallVector<int64_t, 8>> findIntegerSample() const; | 
| 155 |  |  | 
| 156 |  |   // Clones this object. | 
| 157 |  |   std::unique_ptr<FlatAffineConstraints> clone() const; | 
| 158 |  |  | 
| 159 |  |   /// Returns the value at the specified equality row and column. | 
| 160 | 30 |   inline int64_t atEq(unsigned i, unsigned j) const { | 
| 161 | 30 |     return equalities[i * numReservedCols + j]; | 
| 162 | 30 |   } | 
| 163 | 0 |   inline int64_t &atEq(unsigned i, unsigned j) { | 
| 164 | 0 |     return equalities[i * numReservedCols + j]; | 
| 165 | 0 |   } | 
| 166 |  |  | 
| 167 | 0 |   inline int64_t atIneq(unsigned i, unsigned j) const { | 
| 168 | 0 |     return inequalities[i * numReservedCols + j]; | 
| 169 | 0 |   } | 
| 170 |  |  | 
| 171 | 0 |   inline int64_t &atIneq(unsigned i, unsigned j) { | 
| 172 | 0 |     return inequalities[i * numReservedCols + j]; | 
| 173 | 0 |   } | 
| 174 |  |  | 
| 175 |  |   /// Returns the number of columns in the constraint system. | 
| 176 | 293 |   inline unsigned getNumCols() const { return numIds + 1; } | 
| 177 |  |  | 
| 178 | 62 |   inline unsigned getNumEqualities() const { | 
| 179 | 62 |     assert(equalities.size() % numReservedCols == 0 && | 
| 180 | 62 |            "inconsistent equality buffer size"); | 
| 181 | 62 |     return equalities.size() / numReservedCols; | 
| 182 | 62 |   } | 
| 183 |  |  | 
| 184 | 97 |   inline unsigned getNumInequalities() const { | 
| 185 | 97 |     assert(inequalities.size() % numReservedCols == 0 && | 
| 186 | 97 |            "inconsistent inequality buffer size"); | 
| 187 | 97 |     return inequalities.size() / numReservedCols; | 
| 188 | 97 |   } | 
| 189 |  |  | 
| 190 | 0 |   inline unsigned getNumReservedEqualities() const { | 
| 191 | 0 |     return equalities.capacity() / numReservedCols; | 
| 192 | 0 |   } | 
| 193 |  |  | 
| 194 | 0 |   inline unsigned getNumReservedInequalities() const { | 
| 195 | 0 |     return inequalities.capacity() / numReservedCols; | 
| 196 | 0 |   } | 
| 197 |  |  | 
| 198 | 21 |   inline ArrayRef<int64_t> getEquality(unsigned idx) const { | 
| 199 | 21 |     return ArrayRef<int64_t>(&equalities[idx * numReservedCols], getNumCols()); | 
| 200 | 21 |   } | 
| 201 |  |  | 
| 202 | 148 |   inline ArrayRef<int64_t> getInequality(unsigned idx) const { | 
| 203 | 148 |     return ArrayRef<int64_t>(&inequalities[idx * numReservedCols], | 
| 204 | 148 |                              getNumCols()); | 
| 205 | 148 |   } | 
| 206 |  |  | 
| 207 |  |   /// Adds constraints (lower and upper bounds) for the specified 'affine.for' | 
| 208 |  |   /// operation's Value using IR information stored in its bound maps. The | 
| 209 |  |   /// right identifier is first looked up using forOp's Value. Asserts if the | 
| 210 |  |   /// Value corresponding to the 'affine.for' operation isn't found in the | 
| 211 |  |   /// constraint system. Returns failure for the yet unimplemented/unsupported | 
| 212 |  |   /// cases.  Any new identifiers that are found in the bound operands of the | 
| 213 |  |   /// 'affine.for' operation are added as trailing identifiers (either | 
| 214 |  |   /// dimensional or symbolic depending on whether the operand is a valid | 
| 215 |  |   /// symbol). | 
| 216 |  |   //  TODO(bondhugula): add support for non-unit strides. | 
| 217 |  |   LogicalResult addAffineForOpDomain(AffineForOp forOp); | 
| 218 |  |  | 
| 219 |  |   /// Adds a lower or an upper bound for the identifier at the specified | 
| 220 |  |   /// position with constraints being drawn from the specified bound map and | 
| 221 |  |   /// operands. If `eq` is true, add a single equality equal to the bound map's | 
| 222 |  |   /// first result expr. | 
| 223 |  |   LogicalResult addLowerOrUpperBound(unsigned pos, AffineMap boundMap, | 
| 224 |  |                                      ValueRange operands, bool eq, | 
| 225 |  |                                      bool lower = true); | 
| 226 |  |  | 
| 227 |  |   /// Returns the bound for the identifier at `pos` from the inequality at | 
| 228 |  |   /// `ineqPos` as a 1-d affine value map (affine map + operands). The returned | 
| 229 |  |   /// affine value map can either be a lower bound or an upper bound depending | 
| 230 |  |   /// on the sign of atIneq(ineqPos, pos). Asserts if the row at `ineqPos` does | 
| 231 |  |   /// not involve the `pos`th identifier. | 
| 232 |  |   void getIneqAsAffineValueMap(unsigned pos, unsigned ineqPos, | 
| 233 |  |                                AffineValueMap &vmap, | 
| 234 |  |                                MLIRContext *context) const; | 
| 235 |  |  | 
| 236 |  |   /// Returns the constraint system as an integer set. Returns a null integer | 
| 237 |  |   /// set if the system has no constraints, or if an integer set couldn't be | 
| 238 |  |   /// constructed as a result of a local variable's explicit representation not | 
| 239 |  |   /// being known and such a local variable appearing in any of the constraints. | 
| 240 |  |   IntegerSet getAsIntegerSet(MLIRContext *context) const; | 
| 241 |  |  | 
| 242 |  |   /// Computes the lower and upper bounds of the first 'num' dimensional | 
| 243 |  |   /// identifiers (starting at 'offset') as an affine map of the remaining | 
| 244 |  |   /// identifiers (dimensional and symbolic). This method is able to detect | 
| 245 |  |   /// identifiers as floordiv's and mod's of affine expressions of other | 
| 246 |  |   /// identifiers with respect to (positive) constants. Sets bound map to a | 
| 247 |  |   /// null AffineMap if such a bound can't be found (or yet unimplemented). | 
| 248 |  |   void getSliceBounds(unsigned offset, unsigned num, MLIRContext *context, | 
| 249 |  |                       SmallVectorImpl<AffineMap> *lbMaps, | 
| 250 |  |                       SmallVectorImpl<AffineMap> *ubMaps); | 
| 251 |  |  | 
| 252 |  |   /// Adds slice lower bounds represented by lower bounds in 'lbMaps' and upper | 
| 253 |  |   /// bounds in 'ubMaps' to each identifier in the constraint system which has | 
| 254 |  |   /// a value in 'values'. Note that both lower/upper bounds share the same | 
| 255 |  |   /// operand list 'operands'. | 
| 256 |  |   /// This function assumes 'values.size' == 'lbMaps.size' == 'ubMaps.size'. | 
| 257 |  |   /// Note that both lower/upper bounds use operands from 'operands'. | 
| 258 |  |   LogicalResult addSliceBounds(ArrayRef<Value> values, | 
| 259 |  |                                ArrayRef<AffineMap> lbMaps, | 
| 260 |  |                                ArrayRef<AffineMap> ubMaps, | 
| 261 |  |                                ArrayRef<Value> operands); | 
| 262 |  |  | 
| 263 |  |   // Adds an inequality (>= 0) from the coefficients specified in inEq. | 
| 264 |  |   void addInequality(ArrayRef<int64_t> inEq); | 
| 265 |  |   // Adds an equality from the coefficients specified in eq. | 
| 266 |  |   void addEquality(ArrayRef<int64_t> eq); | 
| 267 |  |  | 
| 268 |  |   /// Adds a constant lower bound constraint for the specified identifier. | 
| 269 |  |   void addConstantLowerBound(unsigned pos, int64_t lb); | 
| 270 |  |   /// Adds a constant upper bound constraint for the specified identifier. | 
| 271 |  |   void addConstantUpperBound(unsigned pos, int64_t ub); | 
| 272 |  |  | 
| 273 |  |   /// Adds a new local identifier as the floordiv of an affine function of other | 
| 274 |  |   /// identifiers, the coefficients of which are provided in 'dividend' and with | 
| 275 |  |   /// respect to a positive constant 'divisor'. Two constraints are added to the | 
| 276 |  |   /// system to capture equivalence with the floordiv: | 
| 277 |  |   /// q = dividend floordiv c    <=>   c*q <= dividend <= c*q + c - 1. | 
| 278 |  |   void addLocalFloorDiv(ArrayRef<int64_t> dividend, int64_t divisor); | 
| 279 |  |  | 
| 280 |  |   /// Adds a constant lower bound constraint for the specified expression. | 
| 281 |  |   void addConstantLowerBound(ArrayRef<int64_t> expr, int64_t lb); | 
| 282 |  |   /// Adds a constant upper bound constraint for the specified expression. | 
| 283 |  |   void addConstantUpperBound(ArrayRef<int64_t> expr, int64_t ub); | 
| 284 |  |  | 
| 285 |  |   /// Sets the identifier at the specified position to a constant. | 
| 286 |  |   void setIdToConstant(unsigned pos, int64_t val); | 
| 287 |  |  | 
| 288 |  |   /// Sets the identifier corresponding to the specified Value id to a | 
| 289 |  |   /// constant. Asserts if the 'id' is not found. | 
| 290 |  |   void setIdToConstant(Value id, int64_t val); | 
| 291 |  |  | 
| 292 |  |   /// Looks up the position of the identifier with the specified Value. Returns | 
| 293 |  |   /// true if found (false otherwise). `pos' is set to the (column) position of | 
| 294 |  |   /// the identifier. | 
| 295 |  |   bool findId(Value id, unsigned *pos) const; | 
| 296 |  |  | 
| 297 |  |   /// Returns true if an identifier with the specified Value exists, false | 
| 298 |  |   /// otherwise. | 
| 299 |  |   bool containsId(Value id) const; | 
| 300 |  |  | 
| 301 |  |   // Add identifiers of the specified kind - specified positions are relative to | 
| 302 |  |   // the kind of identifier. The coefficient column corresponding to the added | 
| 303 |  |   // identifier is initialized to zero. 'id' is the Value corresponding to the | 
| 304 |  |   // identifier that can optionally be provided. | 
| 305 |  |   void addDimId(unsigned pos, Value id = nullptr); | 
| 306 |  |   void addSymbolId(unsigned pos, Value id = nullptr); | 
| 307 |  |   void addLocalId(unsigned pos); | 
| 308 |  |   void addId(IdKind kind, unsigned pos, Value id = nullptr); | 
| 309 |  |  | 
| 310 |  |   /// Add the specified values as a dim or symbol id depending on its nature, if | 
| 311 |  |   /// it already doesn't exist in the system. `id' has to be either a terminal | 
| 312 |  |   /// symbol or a loop IV, i.e., it cannot be the result affine.apply of any | 
| 313 |  |   /// symbols or loop IVs. The identifier is added to the end of the existing | 
| 314 |  |   /// dims or symbols. Additional information on the identifier is extracted | 
| 315 |  |   /// from the IR and added to the constraint system. | 
| 316 |  |   void addInductionVarOrTerminalSymbol(Value id); | 
| 317 |  |  | 
| 318 |  |   /// Composes the affine value map with this FlatAffineConstrains, adding the | 
| 319 |  |   /// results of the map as dimensions at the front [0, vMap->getNumResults()) | 
| 320 |  |   /// and with the dimensions set to the equalities specified by the value map. | 
| 321 |  |   /// Returns failure if the composition fails (when vMap is a semi-affine map). | 
| 322 |  |   /// The vMap's operand Value's are used to look up the right positions in | 
| 323 |  |   /// the FlatAffineConstraints with which to associate. The dimensional and | 
| 324 |  |   /// symbolic operands of vMap should match 1:1 (in the same order) with those | 
| 325 |  |   /// of this constraint system, but the latter could have additional trailing | 
| 326 |  |   /// operands. | 
| 327 |  |   LogicalResult composeMap(const AffineValueMap *vMap); | 
| 328 |  |  | 
| 329 |  |   /// Composes an affine map whose dimensions match one to one to the | 
| 330 |  |   /// dimensions of this FlatAffineConstraints. The results of the map 'other' | 
| 331 |  |   /// are added as the leading dimensions of this constraint system. Returns | 
| 332 |  |   /// failure if 'other' is a semi-affine map. | 
| 333 |  |   LogicalResult composeMatchingMap(AffineMap other); | 
| 334 |  |  | 
| 335 |  |   /// Projects out (aka eliminates) 'num' identifiers starting at position | 
| 336 |  |   /// 'pos'. The resulting constraint system is the shadow along the dimensions | 
| 337 |  |   /// that still exist. This method may not always be integer exact. | 
| 338 |  |   // TODO(bondhugula): deal with integer exactness when necessary - can return a | 
| 339 |  |   // value to mark exactness for example. | 
| 340 |  |   void projectOut(unsigned pos, unsigned num); | 
| 341 | 0 |   inline void projectOut(unsigned pos) { return projectOut(pos, 1); } | 
| 342 |  |  | 
| 343 |  |   /// Projects out the identifier that is associate with Value . | 
| 344 |  |   void projectOut(Value id); | 
| 345 |  |  | 
| 346 |  |   /// Removes the specified identifier from the system. | 
| 347 |  |   void removeId(unsigned pos); | 
| 348 |  |  | 
| 349 |  |   void removeEquality(unsigned pos); | 
| 350 |  |   void removeInequality(unsigned pos); | 
| 351 |  |  | 
| 352 |  |   /// Changes the partition between dimensions and symbols. Depending on the new | 
| 353 |  |   /// symbol count, either a chunk of trailing dimensional identifiers becomes | 
| 354 |  |   /// symbols, or some of the leading symbols become dimensions. | 
| 355 |  |   void setDimSymbolSeparation(unsigned newSymbolCount); | 
| 356 |  |  | 
| 357 |  |   /// Changes all symbol identifiers which are loop IVs to dim identifiers. | 
| 358 |  |   void convertLoopIVSymbolsToDims(); | 
| 359 |  |  | 
| 360 |  |   /// Sets the specified identifier to a constant and removes it. | 
| 361 |  |   void setAndEliminate(unsigned pos, int64_t constVal); | 
| 362 |  |  | 
| 363 |  |   /// Tries to fold the specified identifier to a constant using a trivial | 
| 364 |  |   /// equality detection; if successful, the constant is substituted for the | 
| 365 |  |   /// identifier everywhere in the constraint system and then removed from the | 
| 366 |  |   /// system. | 
| 367 |  |   LogicalResult constantFoldId(unsigned pos); | 
| 368 |  |  | 
| 369 |  |   /// This method calls constantFoldId for the specified range of identifiers, | 
| 370 |  |   /// 'num' identifiers starting at position 'pos'. | 
| 371 |  |   void constantFoldIdRange(unsigned pos, unsigned num); | 
| 372 |  |  | 
| 373 |  |   /// Updates the constraints to be the smallest bounding (enclosing) box that | 
| 374 |  |   /// contains the points of 'this' set and that of 'other', with the symbols | 
| 375 |  |   /// being treated specially. For each of the dimensions, the min of the lower | 
| 376 |  |   /// bounds (symbolic) and the max of the upper bounds (symbolic) is computed | 
| 377 |  |   /// to determine such a bounding box. `other' is expected to have the same | 
| 378 |  |   /// dimensional identifiers as this constraint system (in the same order). | 
| 379 |  |   /// | 
| 380 |  |   /// Eg: if 'this' is {0 <= d0 <= 127}, 'other' is {16 <= d0 <= 192}, the | 
| 381 |  |   ///      output is {0 <= d0 <= 192}. | 
| 382 |  |   /// 2) 'this' = {s0 + 5 <= d0 <= s0 + 20}, 'other' is {s0 + 1 <= d0 <= s0 + | 
| 383 |  |   ///     9}, output = {s0 + 1 <= d0 <= s0 + 20}. | 
| 384 |  |   /// 3) 'this' = {0 <= d0 <= 5, 1 <= d1 <= 9}, 'other' = {2 <= d0 <= 6, 5 <= d1 | 
| 385 |  |   ///     <= 15}, output = {0 <= d0 <= 6, 1 <= d1 <= 15}. | 
| 386 |  |   LogicalResult unionBoundingBox(const FlatAffineConstraints &other); | 
| 387 |  |  | 
| 388 |  |   /// Returns 'true' if this constraint system and 'other' are in the same | 
| 389 |  |   /// space, i.e., if they are associated with the same set of identifiers, | 
| 390 |  |   /// appearing in the same order. Returns 'false' otherwise. | 
| 391 |  |   bool areIdsAlignedWithOther(const FlatAffineConstraints &other); | 
| 392 |  |  | 
| 393 |  |   /// Merge and align the identifiers of 'this' and 'other' starting at | 
| 394 |  |   /// 'offset', so that both constraint systems get the union of the contained | 
| 395 |  |   /// identifiers that is dimension-wise and symbol-wise unique; both | 
| 396 |  |   /// constraint systems are updated so that they have the union of all | 
| 397 |  |   /// identifiers, with this's original identifiers appearing first followed by | 
| 398 |  |   /// any of other's identifiers that didn't appear in 'this'. Local | 
| 399 |  |   /// identifiers of each system are by design separate/local and are placed | 
| 400 |  |   /// one after other (this's followed by other's). | 
| 401 |  |   //  Eg: Input: 'this'  has ((%i %j) [%M %N]) | 
| 402 |  |   //             'other' has (%k, %j) [%P, %N, %M]) | 
| 403 |  |   //      Output: both 'this', 'other' have (%i, %j, %k) [%M, %N, %P] | 
| 404 |  |   // | 
| 405 |  |   void mergeAndAlignIdsWithOther(unsigned offset, FlatAffineConstraints *other); | 
| 406 |  |  | 
| 407 | 0 |   unsigned getNumConstraints() const { | 
| 408 | 0 |     return getNumInequalities() + getNumEqualities(); | 
| 409 | 0 |   } | 
| 410 | 37 |   inline unsigned getNumIds() const { return numIds; } | 
| 411 | 0 |   inline unsigned getNumDimIds() const { return numDims; } | 
| 412 | 0 |   inline unsigned getNumSymbolIds() const { return numSymbols; } | 
| 413 | 0 |   inline unsigned getNumDimAndSymbolIds() const { return numDims + numSymbols; } | 
| 414 | 0 |   inline unsigned getNumLocalIds() const { | 
| 415 | 0 |     return numIds - numDims - numSymbols; | 
| 416 | 0 |   } | 
| 417 |  |  | 
| 418 | 0 |   inline ArrayRef<Optional<Value>> getIds() const { | 
| 419 | 0 |     return {ids.data(), ids.size()}; | 
| 420 | 0 |   } | 
| 421 | 0 |   inline MutableArrayRef<Optional<Value>> getIds() { | 
| 422 | 0 |     return {ids.data(), ids.size()}; | 
| 423 | 0 |   } | 
| 424 |  |  | 
| 425 |  |   /// Returns the optional Value corresponding to the pos^th identifier. | 
| 426 | 0 |   inline Optional<Value> getId(unsigned pos) const { return ids[pos]; } | 
| 427 | 0 |   inline Optional<Value> &getId(unsigned pos) { return ids[pos]; } | 
| 428 |  |  | 
| 429 |  |   /// Returns the Value associated with the pos^th identifier. Asserts if | 
| 430 |  |   /// no Value identifier was associated. | 
| 431 | 0 |   inline Value getIdValue(unsigned pos) const { | 
| 432 | 0 |     assert(ids[pos].hasValue() && "identifier's Value not set"); | 
| 433 | 0 |     return ids[pos].getValue(); | 
| 434 | 0 |   } | 
| 435 |  |  | 
| 436 |  |   /// Returns the Values associated with identifiers in range [start, end). | 
| 437 |  |   /// Asserts if no Value was associated with one of these identifiers. | 
| 438 |  |   void getIdValues(unsigned start, unsigned end, | 
| 439 |  |                    SmallVectorImpl<Value> *values) const { | 
| 440 |  |     assert((start < numIds || start == end) && "invalid start position"); | 
| 441 |  |     assert(end <= numIds && "invalid end position"); | 
| 442 |  |     values->clear(); | 
| 443 |  |     values->reserve(end - start); | 
| 444 |  |     for (unsigned i = start; i < end; i++) { | 
| 445 |  |       values->push_back(getIdValue(i)); | 
| 446 |  |     } | 
| 447 |  |   } | 
| 448 | 0 |   inline void getAllIdValues(SmallVectorImpl<Value> *values) const { | 
| 449 | 0 |     getIdValues(0, numIds, values); | 
| 450 | 0 |   } | 
| 451 |  |  | 
| 452 |  |   /// Sets Value associated with the pos^th identifier. | 
| 453 | 0 |   inline void setIdValue(unsigned pos, Value val) { | 
| 454 | 0 |     assert(pos < numIds && "invalid id position"); | 
| 455 | 0 |     ids[pos] = val; | 
| 456 | 0 |   } | 
| 457 |  |   /// Sets Values associated with identifiers in the range [start, end). | 
| 458 |  |   void setIdValues(unsigned start, unsigned end, ArrayRef<Value> values) { | 
| 459 |  |     assert((start < numIds || end == start) && "invalid start position"); | 
| 460 |  |     assert(end <= numIds && "invalid end position"); | 
| 461 |  |     assert(values.size() == end - start); | 
| 462 |  |     for (unsigned i = start; i < end; ++i) | 
| 463 |  |       ids[i] = values[i - start]; | 
| 464 |  |   } | 
| 465 |  |  | 
| 466 |  |   /// Clears this list of constraints and copies other into it. | 
| 467 |  |   void clearAndCopyFrom(const FlatAffineConstraints &other); | 
| 468 |  |  | 
| 469 |  |   /// Returns the smallest known constant bound for the extent of the specified | 
| 470 |  |   /// identifier (pos^th), i.e., the smallest known constant that is greater | 
| 471 |  |   /// than or equal to 'exclusive upper bound' - 'lower bound' of the | 
| 472 |  |   /// identifier. Returns None if it's not a constant. This method employs | 
| 473 |  |   /// trivial (low complexity / cost) checks and detection. Symbolic identifiers | 
| 474 |  |   /// are treated specially, i.e., it looks for constant differences between | 
| 475 |  |   /// affine expressions involving only the symbolic identifiers. `lb` and | 
| 476 |  |   /// `ub` (along with the `boundFloorDivisor`) are set to represent the lower | 
| 477 |  |   /// and upper bound associated with the constant difference: `lb`, `ub` have | 
| 478 |  |   /// the coefficients, and boundFloorDivisor, their divisor. `minLbPos` and | 
| 479 |  |   /// `minUbPos` if non-null are set to the position of the constant lower bound | 
| 480 |  |   /// and upper bound respectively (to the same if they are from an equality). | 
| 481 |  |   /// Ex: if the lower bound is [(s0 + s2 - 1) floordiv 32] for a system with | 
| 482 |  |   /// three symbolic identifiers, *lb = [1, 0, 1], lbDivisor = 32. See comments | 
| 483 |  |   /// at function definition for examples. | 
| 484 |  |   Optional<int64_t> getConstantBoundOnDimSize( | 
| 485 |  |       unsigned pos, SmallVectorImpl<int64_t> *lb = nullptr, | 
| 486 |  |       int64_t *boundFloorDivisor = nullptr, | 
| 487 |  |       SmallVectorImpl<int64_t> *ub = nullptr, unsigned *minLbPos = nullptr, | 
| 488 |  |       unsigned *minUbPos = nullptr) const; | 
| 489 |  |  | 
| 490 |  |   /// Returns the constant lower bound for the pos^th identifier if there is | 
| 491 |  |   /// one; None otherwise. | 
| 492 |  |   Optional<int64_t> getConstantLowerBound(unsigned pos) const; | 
| 493 |  |  | 
| 494 |  |   /// Returns the constant upper bound for the pos^th identifier if there is | 
| 495 |  |   /// one; None otherwise. | 
| 496 |  |   Optional<int64_t> getConstantUpperBound(unsigned pos) const; | 
| 497 |  |  | 
| 498 |  |   /// Gets the lower and upper bound of the `offset` + `pos`th identifier | 
| 499 |  |   /// treating [0, offset) U [offset + num, symStartPos) as dimensions and | 
| 500 |  |   /// [symStartPos, getNumDimAndSymbolIds) as symbols, and `pos` lies in | 
| 501 |  |   /// [0, num). The multi-dimensional maps in the returned pair represent the | 
| 502 |  |   /// max and min of potentially multiple affine expressions. The upper bound is | 
| 503 |  |   /// exclusive. `localExprs` holds pre-computed AffineExpr's for all local | 
| 504 |  |   /// identifiers in the system. | 
| 505 |  |   std::pair<AffineMap, AffineMap> | 
| 506 |  |   getLowerAndUpperBound(unsigned pos, unsigned offset, unsigned num, | 
| 507 |  |                         unsigned symStartPos, ArrayRef<AffineExpr> localExprs, | 
| 508 |  |                         MLIRContext *context) const; | 
| 509 |  |  | 
| 510 |  |   /// Gather positions of all lower and upper bounds of the identifier at `pos`, | 
| 511 |  |   /// and optionally any equalities on it. In addition, the bounds are to be | 
| 512 |  |   /// independent of identifiers in position range [`offset`, `offset` + `num`). | 
| 513 |  |   void | 
| 514 |  |   getLowerAndUpperBoundIndices(unsigned pos, | 
| 515 |  |                                SmallVectorImpl<unsigned> *lbIndices, | 
| 516 |  |                                SmallVectorImpl<unsigned> *ubIndices, | 
| 517 |  |                                SmallVectorImpl<unsigned> *eqIndices = nullptr, | 
| 518 |  |                                unsigned offset = 0, unsigned num = 0) const; | 
| 519 |  |  | 
| 520 |  |   /// Removes constraints that are independent of (i.e., do not have a | 
| 521 |  |   /// coefficient for) for identifiers in the range [pos, pos + num). | 
| 522 |  |   void removeIndependentConstraints(unsigned pos, unsigned num); | 
| 523 |  |  | 
| 524 |  |   /// Returns true if the set can be trivially detected as being | 
| 525 |  |   /// hyper-rectangular on the specified contiguous set of identifiers. | 
| 526 |  |   bool isHyperRectangular(unsigned pos, unsigned num) const; | 
| 527 |  |  | 
| 528 |  |   /// Removes duplicate constraints, trivially true constraints, and constraints | 
| 529 |  |   /// that can be detected as redundant as a result of differing only in their | 
| 530 |  |   /// constant term part. A constraint of the form <non-negative constant> >= 0 | 
| 531 |  |   /// is considered trivially true. This method is a linear time method on the | 
| 532 |  |   /// constraints, does a single scan, and updates in place. It also normalizes | 
| 533 |  |   /// constraints by their GCD and performs GCD tightening on inequalities. | 
| 534 |  |   void removeTrivialRedundancy(); | 
| 535 |  |  | 
| 536 |  |   /// A more expensive check to detect redundant inequalities thatn | 
| 537 |  |   /// removeTrivialRedundancy. | 
| 538 |  |   void removeRedundantInequalities(); | 
| 539 |  |  | 
| 540 |  |   // Removes all equalities and inequalities. | 
| 541 |  |   void clearConstraints(); | 
| 542 |  |  | 
| 543 |  |   void print(raw_ostream &os) const; | 
| 544 |  |   void dump() const; | 
| 545 |  |  | 
| 546 |  | private: | 
| 547 |  |   /// Returns false if the fields corresponding to various identifier counts, or | 
| 548 |  |   /// equality/inequality buffer sizes aren't consistent; true otherwise. This | 
| 549 |  |   /// is meant to be used within an assert internally. | 
| 550 |  |   bool hasConsistentState() const; | 
| 551 |  |  | 
| 552 |  |   /// Checks all rows of equality/inequality constraints for trivial | 
| 553 |  |   /// contradictions (for example: 1 == 0, 0 >= 1), which may have surfaced | 
| 554 |  |   /// after elimination. Returns 'true' if an invalid constraint is found; | 
| 555 |  |   /// 'false'otherwise. | 
| 556 |  |   bool hasInvalidConstraint() const; | 
| 557 |  |  | 
| 558 |  |   /// Returns the constant lower bound bound if isLower is true, and the upper | 
| 559 |  |   /// bound if isLower is false. | 
| 560 |  |   template <bool isLower> | 
| 561 |  |   Optional<int64_t> computeConstantLowerOrUpperBound(unsigned pos); | 
| 562 |  |  | 
| 563 |  |   // Eliminates a single identifier at 'position' from equality and inequality | 
| 564 |  |   // constraints. Returns 'success' if the identifier was eliminated, and | 
| 565 |  |   // 'failure' otherwise. | 
| 566 | 0 |   inline LogicalResult gaussianEliminateId(unsigned position) { | 
| 567 | 0 |     return success(gaussianEliminateIds(position, position + 1) == 1); | 
| 568 | 0 |   } | 
| 569 |  |  | 
| 570 |  |   // Eliminates identifiers from equality and inequality constraints | 
| 571 |  |   // in column range [posStart, posLimit). | 
| 572 |  |   // Returns the number of variables eliminated. | 
| 573 |  |   unsigned gaussianEliminateIds(unsigned posStart, unsigned posLimit); | 
| 574 |  |  | 
| 575 |  |   /// Eliminates identifier at the specified position using Fourier-Motzkin | 
| 576 |  |   /// variable elimination, but uses Gaussian elimination if there is an | 
| 577 |  |   /// equality involving that identifier. If the result of the elimination is | 
| 578 |  |   /// integer exact, *isResultIntegerExact is set to true. If 'darkShadow' is | 
| 579 |  |   /// set to true, a potential under approximation (subset) of the rational | 
| 580 |  |   /// shadow / exact integer shadow is computed. | 
| 581 |  |   // See implementation comments for more details. | 
| 582 |  |   void FourierMotzkinEliminate(unsigned pos, bool darkShadow = false, | 
| 583 |  |                                bool *isResultIntegerExact = nullptr); | 
| 584 |  |  | 
| 585 |  |   /// Tightens inequalities given that we are dealing with integer spaces. This | 
| 586 |  |   /// is similar to the GCD test but applied to inequalities. The constant term | 
| 587 |  |   /// can be reduced to the preceding multiple of the GCD of the coefficients, | 
| 588 |  |   /// i.e., | 
| 589 |  |   ///  64*i - 100 >= 0  =>  64*i - 128 >= 0 (since 'i' is an integer). This is a | 
| 590 |  |   /// fast method (linear in the number of coefficients). | 
| 591 |  |   void GCDTightenInequalities(); | 
| 592 |  |  | 
| 593 |  |   /// Normalized each constraints by the GCD of its coefficients. | 
| 594 |  |   void normalizeConstraintsByGCD(); | 
| 595 |  |  | 
| 596 |  |   /// Removes identifiers in the column range [idStart, idLimit), and copies any | 
| 597 |  |   /// remaining valid data into place, updates member variables, and resizes | 
| 598 |  |   /// arrays as needed. | 
| 599 |  |   void removeIdRange(unsigned idStart, unsigned idLimit); | 
| 600 |  |  | 
| 601 |  |   /// Coefficients of affine equalities (in == 0 form). | 
| 602 |  |   SmallVector<int64_t, 64> equalities; | 
| 603 |  |  | 
| 604 |  |   /// Coefficients of affine inequalities (in >= 0 form). | 
| 605 |  |   SmallVector<int64_t, 64> inequalities; | 
| 606 |  |  | 
| 607 |  |   /// Number of columns reserved. Actual ones in used are returned by | 
| 608 |  |   /// getNumCols(). | 
| 609 |  |   unsigned numReservedCols; | 
| 610 |  |  | 
| 611 |  |   /// Total number of identifiers. | 
| 612 |  |   unsigned numIds; | 
| 613 |  |  | 
| 614 |  |   /// Number of identifiers corresponding to real dimensions. | 
| 615 |  |   unsigned numDims; | 
| 616 |  |  | 
| 617 |  |   /// Number of identifiers corresponding to symbols (unknown but constant for | 
| 618 |  |   /// analysis). | 
| 619 |  |   unsigned numSymbols; | 
| 620 |  |  | 
| 621 |  |   /// Values corresponding to the (column) identifiers of this constraint | 
| 622 |  |   /// system appearing in the order the identifiers correspond to columns. | 
| 623 |  |   /// Temporary ones or those that aren't associated to any Value are set to | 
| 624 |  |   /// None. | 
| 625 |  |   SmallVector<Optional<Value>, 8> ids; | 
| 626 |  |  | 
| 627 |  |   /// A parameter that controls detection of an unrealistic number of | 
| 628 |  |   /// constraints. If the number of constraints is this many times the number of | 
| 629 |  |   /// variables, we consider such a system out of line with the intended use | 
| 630 |  |   /// case of FlatAffineConstraints. | 
| 631 |  |   // The rationale for 32 is that in the typical simplest of cases, an | 
| 632 |  |   // identifier is expected to have one lower bound and one upper bound | 
| 633 |  |   // constraint. With a level of tiling or a connection to another identifier | 
| 634 |  |   // through a div or mod, an extra pair of bounds gets added. As a limit, we | 
| 635 |  |   // don't expect an identifier to have more than 32 lower/upper/equality | 
| 636 |  |   // constraints. This is conservatively set low and can be raised if needed. | 
| 637 |  |   constexpr static unsigned kExplosionFactor = 32; | 
| 638 |  | }; | 
| 639 |  |  | 
| 640 |  | /// Flattens 'expr' into 'flattenedExpr', which contains the coefficients of the | 
| 641 |  | /// dimensions, symbols, and additional variables that represent floor divisions | 
| 642 |  | /// of dimensions, symbols, and in turn other floor divisions.  Returns failure | 
| 643 |  | /// if 'expr' could not be flattened (i.e., semi-affine is not yet handled). | 
| 644 |  | /// 'cst' contains constraints that connect newly introduced local identifiers | 
| 645 |  | /// to existing dimensional and symbolic identifiers. See documentation for | 
| 646 |  | /// AffineExprFlattener on how mod's and div's are flattened. | 
| 647 |  | LogicalResult getFlattenedAffineExpr(AffineExpr expr, unsigned numDims, | 
| 648 |  |                                      unsigned numSymbols, | 
| 649 |  |                                      SmallVectorImpl<int64_t> *flattenedExpr, | 
| 650 |  |                                      FlatAffineConstraints *cst = nullptr); | 
| 651 |  |  | 
| 652 |  | /// Flattens the result expressions of the map to their corresponding flattened | 
| 653 |  | /// forms and set in 'flattenedExprs'. Returns failure if any expression in the | 
| 654 |  | /// map could not be flattened (i.e., semi-affine is not yet handled). 'cst' | 
| 655 |  | /// contains constraints that connect newly introduced local identifiers to | 
| 656 |  | /// existing dimensional and / symbolic identifiers. See documentation for | 
| 657 |  | /// AffineExprFlattener on how mod's and div's are flattened. For all affine | 
| 658 |  | /// expressions that share the same operands (like those of an affine map), this | 
| 659 |  | /// method should be used instead of repeatedly calling getFlattenedAffineExpr | 
| 660 |  | /// since local variables added to deal with div's and mod's will be reused | 
| 661 |  | /// across expressions. | 
| 662 |  | LogicalResult | 
| 663 |  | getFlattenedAffineExprs(AffineMap map, | 
| 664 |  |                         std::vector<SmallVector<int64_t, 8>> *flattenedExprs, | 
| 665 |  |                         FlatAffineConstraints *cst = nullptr); | 
| 666 |  | LogicalResult | 
| 667 |  | getFlattenedAffineExprs(IntegerSet set, | 
| 668 |  |                         std::vector<SmallVector<int64_t, 8>> *flattenedExprs, | 
| 669 |  |                         FlatAffineConstraints *cst = nullptr); | 
| 670 |  |  | 
| 671 |  | } // end namespace mlir. | 
| 672 |  |  | 
| 673 |  | #endif // MLIR_ANALYSIS_AFFINE_STRUCTURES_H |