1 //===- FlatLinearValueConstraints.h - Linear Constraints --------*- 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 #ifndef MLIR_ANALYSIS_FLATLINEARVALUECONSTRAINTS_H 10 #define MLIR_ANALYSIS_FLATLINEARVALUECONSTRAINTS_H 11 12 #include "mlir/Analysis/Presburger/IntegerRelation.h" 13 #include "mlir/Analysis/Presburger/Matrix.h" 14 #include "mlir/IR/AffineExpr.h" 15 #include "mlir/IR/OpDefinition.h" 16 #include <optional> 17 18 namespace mlir { 19 20 class AffineMap; 21 class IntegerSet; 22 class MLIRContext; 23 class Value; 24 class MemRefType; 25 struct MutableAffineMap; 26 27 namespace presburger { 28 class MultiAffineFunction; 29 } // namespace presburger 30 31 /// FlatLinearConstraints is an extension of IntegerPolyhedron. It provides an 32 /// AffineExpr-based API. 33 class FlatLinearConstraints : public presburger::IntegerPolyhedron { 34 public: 35 /// Constructs a constraint system reserving memory for the specified number 36 /// of constraints and variables. `valArgs` are the optional SSA values 37 /// associated with each dimension/symbol. These must either be empty or match 38 /// the number of dimensions and symbols. FlatLinearConstraints(unsigned numReservedInequalities,unsigned numReservedEqualities,unsigned numReservedCols,unsigned numDims,unsigned numSymbols,unsigned numLocals)39 FlatLinearConstraints(unsigned numReservedInequalities, 40 unsigned numReservedEqualities, 41 unsigned numReservedCols, unsigned numDims, 42 unsigned numSymbols, unsigned numLocals) 43 : IntegerPolyhedron(numReservedInequalities, numReservedEqualities, 44 numReservedCols, 45 presburger::PresburgerSpace::getSetSpace( 46 numDims, numSymbols, numLocals)) { 47 assert(numReservedCols >= getNumVars() + 1); 48 } 49 50 /// Constructs a constraint system with the specified number of dimensions 51 /// and symbols. `valArgs` are the optional SSA values associated with each 52 /// dimension/symbol. These must either be empty or match the number of 53 /// dimensions and symbols. 54 FlatLinearConstraints(unsigned numDims = 0, unsigned numSymbols = 0, 55 unsigned numLocals = 0) 56 : FlatLinearConstraints(/*numReservedInequalities=*/0, 57 /*numReservedEqualities=*/0, 58 /*numReservedCols=*/numDims + numSymbols + 59 numLocals + 1, 60 numDims, numSymbols, numLocals) {} 61 FlatLinearConstraints(const IntegerPolyhedron & fac)62 FlatLinearConstraints(const IntegerPolyhedron &fac) 63 : IntegerPolyhedron(fac) {} 64 65 /// Return the kind of this object. getKind()66 Kind getKind() const override { return Kind::FlatLinearConstraints; } 67 68 /// Flag to control if conservative semi-affine bounds should be added in 69 /// `addBound()`. 70 enum class AddConservativeSemiAffineBounds { No = 0, Yes }; 71 72 /// Adds a bound for the variable at the specified position with constraints 73 /// being drawn from the specified bound map. In case of an EQ bound, the 74 /// bound map is expected to have exactly one result. In case of a LB/UB, the 75 /// bound map may have more than one result, for each of which an inequality 76 /// is added. 77 /// 78 /// The bound can be added as open or closed by specifying isClosedBound. In 79 /// case of a LB/UB, isClosedBound = false means the bound is added internally 80 /// as a closed bound by +1/-1 respectively. In case of an EQ bound, it can 81 /// only be added as a closed bound. 82 /// 83 /// Conservative bounds for semi-affine expressions will be added if 84 /// `AddConservativeSemiAffineBounds` is set to `Yes`. This currently only 85 /// covers semi-affine `mod` expressions, so `addBound()` will still fail if 86 /// it encounters a semi-affine `floordiv`, `ceildiv`, or `mul`. Note: If 87 /// enabled it is possible for the resulting constraint set to become empty if 88 /// a precondition of a conservative bound is found not to hold. 89 /// 90 /// Note: The dimensions/symbols of this FlatLinearConstraints must match the 91 /// dimensions/symbols of the affine map. 92 LogicalResult addBound( 93 presburger::BoundType type, unsigned pos, AffineMap boundMap, 94 bool isClosedBound, 95 AddConservativeSemiAffineBounds = AddConservativeSemiAffineBounds::No); 96 97 /// Adds a bound for the variable at the specified position with constraints 98 /// being drawn from the specified bound map. In case of an EQ bound, the 99 /// bound map is expected to have exactly one result. In case of a LB/UB, the 100 /// bound map may have more than one result, for each of which an inequality 101 /// is added. 102 /// 103 /// Conservative bounds for semi-affine expressions will be added if 104 /// `AddConservativeSemiAffineBounds` is set to `Yes`. This currently only 105 /// covers semi-affine `mod` expressions, so `addBound()` will still fail if 106 /// it encounters a semi-affine `floordiv`, `ceildiv`, or `mul`. Note: If 107 /// enabled it is possible for the resulting constraint set to become empty if 108 /// a precondition of a conservative bound is found not to hold. 109 /// 110 /// Note: The dimensions/symbols of this FlatLinearConstraints must match the 111 /// dimensions/symbols of the affine map. By default the lower bound is closed 112 /// and the upper bound is open. 113 LogicalResult addBound( 114 presburger::BoundType type, unsigned pos, AffineMap boundMap, 115 AddConservativeSemiAffineBounds = AddConservativeSemiAffineBounds::No); 116 117 /// The `addBound` overload above hides the inherited overloads by default, so 118 /// we explicitly introduce them here. 119 using IntegerPolyhedron::addBound; 120 121 /// Returns the constraint system as an integer set. Returns a null integer 122 /// set if the system has no constraints, or if an integer set couldn't be 123 /// constructed as a result of a local variable's explicit representation not 124 /// being known and such a local variable appearing in any of the constraints. 125 IntegerSet getAsIntegerSet(MLIRContext *context) const; 126 127 /// Computes the lower and upper bounds of the first `num` dimensional 128 /// variables (starting at `offset`) as an affine map of the remaining 129 /// variables (dimensional and symbolic). This method is able to detect 130 /// variables as floordiv's and mod's of affine expressions of other 131 /// variables with respect to (positive) constants. Sets bound map to a 132 /// null AffineMap if such a bound can't be found (or yet unimplemented). 133 /// 134 /// By default the returned lower bounds are closed and upper bounds are open. 135 /// If `closedUb` is true, the upper bound is closed. 136 void getSliceBounds(unsigned offset, unsigned num, MLIRContext *context, 137 SmallVectorImpl<AffineMap> *lbMaps, 138 SmallVectorImpl<AffineMap> *ubMaps, 139 bool closedUB = false); 140 141 /// Composes an affine map whose dimensions and symbols match one to one with 142 /// the dimensions and symbols of this FlatLinearConstraints. The results of 143 /// the map `other` are added as the leading dimensions of this constraint 144 /// system. Returns failure if `other` is a semi-affine map. 145 LogicalResult composeMatchingMap(AffineMap other); 146 147 /// Gets the lower and upper bound of the `offset` + `pos`th variable 148 /// treating [0, offset) U [offset + num, symStartPos) as dimensions and 149 /// [symStartPos, getNumDimAndSymbolVars) as symbols, and `pos` lies in 150 /// [0, num). The multi-dimensional maps in the returned pair represent the 151 /// max and min of potentially multiple affine expressions. `localExprs` holds 152 /// pre-computed AffineExpr's for all local variables in the system. 153 /// 154 /// By default the returned lower bounds are closed and upper bounds are open. 155 /// If `closedUb` is true, the upper bound is closed. 156 std::pair<AffineMap, AffineMap> 157 getLowerAndUpperBound(unsigned pos, unsigned offset, unsigned num, 158 unsigned symStartPos, ArrayRef<AffineExpr> localExprs, 159 MLIRContext *context, bool closedUB = false) const; 160 161 /// Insert variables of the specified kind at position `pos`. Positions are 162 /// relative to the kind of variable. The coefficient columns corresponding 163 /// to the added variables are initialized to zero. `vals` are the Values 164 /// corresponding to the variables. Values should not be used with 165 /// VarKind::Local since values can only be attached to non-local variables. 166 /// Return the absolute column position (i.e., not relative to the kind of 167 /// variable) of the first added variable. 168 /// 169 /// Note: Empty Values are allowed in `vals`. 170 unsigned insertDimVar(unsigned pos, unsigned num = 1) { 171 return insertVar(VarKind::SetDim, pos, num); 172 } 173 unsigned insertSymbolVar(unsigned pos, unsigned num = 1) { 174 return insertVar(VarKind::Symbol, pos, num); 175 } 176 unsigned insertLocalVar(unsigned pos, unsigned num = 1) { 177 return insertVar(VarKind::Local, pos, num); 178 } 179 180 /// Append variables of the specified kind after the last variable of that 181 /// kind. The coefficient columns corresponding to the added variables are 182 /// initialized to zero. `vals` are the Values corresponding to the 183 /// variables. Return the absolute column position (i.e., not relative to the 184 /// kind of variable) of the first appended variable. 185 /// 186 /// Note: Empty Values are allowed in `vals`. 187 unsigned appendDimVar(unsigned num = 1) { 188 return appendVar(VarKind::SetDim, num); 189 } 190 unsigned appendSymbolVar(unsigned num = 1) { 191 return appendVar(VarKind::Symbol, num); 192 } 193 unsigned appendLocalVar(unsigned num = 1) { 194 return appendVar(VarKind::Local, num); 195 } 196 197 protected: 198 using VarKind = presburger::VarKind; 199 200 /// Compute an explicit representation for local vars. For all systems coming 201 /// from MLIR integer sets, maps, or expressions where local vars were 202 /// introduced to model floordivs and mods, this always succeeds. 203 LogicalResult computeLocalVars(SmallVectorImpl<AffineExpr> &memo, 204 MLIRContext *context) const; 205 206 /// Given an affine map that is aligned with this constraint system: 207 /// * Flatten the map. 208 /// * Add newly introduced local columns at the beginning of this constraint 209 /// system (local column pos 0). 210 /// * Add equalities that define the new local columns to this constraint 211 /// system. 212 /// * Return the flattened expressions via `flattenedExprs`. 213 /// 214 /// Note: This is a shared helper function of `addLowerOrUpperBound` and 215 /// `composeMatchingMap`. 216 LogicalResult flattenAlignedMapAndMergeLocals( 217 AffineMap map, std::vector<SmallVector<int64_t, 8>> *flattenedExprs, 218 bool addConservativeSemiAffineBounds = false); 219 220 /// Prints the number of constraints, dimensions, symbols and locals in the 221 /// FlatLinearConstraints. Also, prints for each variable whether there is 222 /// an SSA Value attached to it. 223 void printSpace(raw_ostream &os) const override; 224 }; 225 226 /// FlatLinearValueConstraints represents an extension of FlatLinearConstraints 227 /// where each non-local variable can have an SSA Value attached to it. 228 class FlatLinearValueConstraints : public FlatLinearConstraints { 229 public: 230 /// The SSA Values attached to each non-local variable are stored as 231 /// identifiers in the constraint system's space. 232 using Identifier = presburger::Identifier; 233 234 /// Constructs a constraint system reserving memory for the specified number 235 /// of constraints and variables. `valArgs` are the optional SSA values 236 /// associated with each dimension/symbol. These must either be empty or match 237 /// the number of dimensions and symbols. FlatLinearValueConstraints(unsigned numReservedInequalities,unsigned numReservedEqualities,unsigned numReservedCols,unsigned numDims,unsigned numSymbols,unsigned numLocals,ArrayRef<std::optional<Value>> valArgs)238 FlatLinearValueConstraints(unsigned numReservedInequalities, 239 unsigned numReservedEqualities, 240 unsigned numReservedCols, unsigned numDims, 241 unsigned numSymbols, unsigned numLocals, 242 ArrayRef<std::optional<Value>> valArgs) 243 : FlatLinearConstraints(numReservedInequalities, numReservedEqualities, 244 numReservedCols, numDims, numSymbols, numLocals) { 245 assert(valArgs.empty() || valArgs.size() == getNumDimAndSymbolVars()); 246 for (unsigned i = 0, e = valArgs.size(); i < e; ++i) 247 if (valArgs[i]) 248 setValue(i, *valArgs[i]); 249 } 250 251 /// Constructs a constraint system reserving memory for the specified number 252 /// of constraints and variables. `valArgs` are the optional SSA values 253 /// associated with each dimension/symbol. These must either be empty or match 254 /// the number of dimensions and symbols. FlatLinearValueConstraints(unsigned numReservedInequalities,unsigned numReservedEqualities,unsigned numReservedCols,unsigned numDims,unsigned numSymbols,unsigned numLocals,ArrayRef<Value> valArgs)255 FlatLinearValueConstraints(unsigned numReservedInequalities, 256 unsigned numReservedEqualities, 257 unsigned numReservedCols, unsigned numDims, 258 unsigned numSymbols, unsigned numLocals, 259 ArrayRef<Value> valArgs) 260 : FlatLinearConstraints(numReservedInequalities, numReservedEqualities, 261 numReservedCols, numDims, numSymbols, numLocals) { 262 assert(valArgs.empty() || valArgs.size() == getNumDimAndSymbolVars()); 263 for (unsigned i = 0, e = valArgs.size(); i < e; ++i) 264 if (valArgs[i]) 265 setValue(i, valArgs[i]); 266 } 267 268 /// Constructs a constraint system with the specified number of dimensions 269 /// and symbols. `valArgs` are the optional SSA values associated with each 270 /// dimension/symbol. These must either be empty or match the number of 271 /// dimensions and symbols. FlatLinearValueConstraints(unsigned numDims,unsigned numSymbols,unsigned numLocals,ArrayRef<std::optional<Value>> valArgs)272 FlatLinearValueConstraints(unsigned numDims, unsigned numSymbols, 273 unsigned numLocals, 274 ArrayRef<std::optional<Value>> valArgs) 275 : FlatLinearValueConstraints(/*numReservedInequalities=*/0, 276 /*numReservedEqualities=*/0, 277 /*numReservedCols=*/numDims + numSymbols + 278 numLocals + 1, 279 numDims, numSymbols, numLocals, valArgs) {} 280 281 /// Constructs a constraint system with the specified number of dimensions 282 /// and symbols. `valArgs` are the optional SSA values associated with each 283 /// dimension/symbol. These must either be empty or match the number of 284 /// dimensions and symbols. 285 FlatLinearValueConstraints(unsigned numDims = 0, unsigned numSymbols = 0, 286 unsigned numLocals = 0, 287 ArrayRef<Value> valArgs = {}) 288 : FlatLinearValueConstraints(/*numReservedInequalities=*/0, 289 /*numReservedEqualities=*/0, 290 /*numReservedCols=*/numDims + numSymbols + 291 numLocals + 1, 292 numDims, numSymbols, numLocals, valArgs) {} 293 294 FlatLinearValueConstraints(const IntegerPolyhedron &fac, 295 ArrayRef<std::optional<Value>> valArgs = {}) FlatLinearConstraints(fac)296 : FlatLinearConstraints(fac) { 297 if (valArgs.empty()) 298 return; 299 assert(valArgs.size() == getNumDimAndSymbolVars()); 300 for (unsigned i = 0, e = valArgs.size(); i < e; ++i) 301 if (valArgs[i]) 302 setValue(i, *valArgs[i]); 303 } 304 305 /// Creates an affine constraint system from an IntegerSet. 306 explicit FlatLinearValueConstraints(IntegerSet set, ValueRange operands = {}); 307 308 /// Return the kind of this object. getKind()309 Kind getKind() const override { return Kind::FlatLinearValueConstraints; } 310 classof(const IntegerRelation * cst)311 static bool classof(const IntegerRelation *cst) { 312 return cst->getKind() >= Kind::FlatLinearValueConstraints && 313 cst->getKind() <= Kind::FlatAffineRelation; 314 } 315 316 /// Adds a constant bound for the variable associated with the given Value. 317 void addBound(presburger::BoundType type, Value val, int64_t value); 318 using FlatLinearConstraints::addBound; 319 320 /// Returns the Value associated with the pos^th variable. Asserts if 321 /// no Value variable was associated. getValue(unsigned pos)322 inline Value getValue(unsigned pos) const { 323 assert(pos < getNumDimAndSymbolVars() && "Invalid position"); 324 assert(hasValue(pos) && "variable's Value not set"); 325 VarKind kind = getVarKindAt(pos); 326 unsigned relativePos = pos - getVarKindOffset(kind); 327 return space.getId(kind, relativePos).getValue<Value>(); 328 } 329 330 /// Returns the Values associated with variables in range [start, end). 331 /// Asserts if no Value was associated with one of these variables. getValues(unsigned start,unsigned end,SmallVectorImpl<Value> * values)332 inline void getValues(unsigned start, unsigned end, 333 SmallVectorImpl<Value> *values) const { 334 assert(end <= getNumDimAndSymbolVars() && "invalid end position"); 335 assert(start <= end && "invalid start position"); 336 values->clear(); 337 values->reserve(end - start); 338 for (unsigned i = start; i < end; ++i) 339 values->push_back(getValue(i)); 340 } 341 getMaybeValues()342 inline SmallVector<std::optional<Value>> getMaybeValues() const { 343 SmallVector<std::optional<Value>> maybeValues; 344 maybeValues.reserve(getNumDimAndSymbolVars()); 345 for (unsigned i = 0, e = getNumDimAndSymbolVars(); i < e; ++i) 346 if (hasValue(i)) { 347 maybeValues.push_back(getValue(i)); 348 } else { 349 maybeValues.push_back(std::nullopt); 350 } 351 return maybeValues; 352 } 353 354 inline SmallVector<std::optional<Value>> getMaybeValues(presburger::VarKind kind)355 getMaybeValues(presburger::VarKind kind) const { 356 assert(kind != VarKind::Local && 357 "Local variables do not have any value attached to them."); 358 SmallVector<std::optional<Value>> maybeValues; 359 maybeValues.reserve(getNumVarKind(kind)); 360 const unsigned offset = space.getVarKindOffset(kind); 361 for (unsigned i = 0, e = getNumVarKind(kind); i < e; ++i) { 362 if (hasValue(offset + i)) 363 maybeValues.push_back(getValue(offset + i)); 364 else 365 maybeValues.push_back(std::nullopt); 366 } 367 return maybeValues; 368 } 369 370 /// Returns true if the pos^th variable has an associated Value. hasValue(unsigned pos)371 inline bool hasValue(unsigned pos) const { 372 assert(pos < getNumDimAndSymbolVars() && "Invalid position"); 373 VarKind kind = getVarKindAt(pos); 374 unsigned relativePos = pos - getVarKindOffset(kind); 375 return space.getId(kind, relativePos).hasValue(); 376 } 377 378 unsigned appendDimVar(ValueRange vals); 379 using FlatLinearConstraints::appendDimVar; 380 381 unsigned appendSymbolVar(ValueRange vals); 382 using FlatLinearConstraints::appendSymbolVar; 383 384 unsigned insertDimVar(unsigned pos, ValueRange vals); 385 using FlatLinearConstraints::insertDimVar; 386 387 unsigned insertSymbolVar(unsigned pos, ValueRange vals); 388 using FlatLinearConstraints::insertSymbolVar; 389 390 unsigned insertVar(presburger::VarKind kind, unsigned pos, 391 unsigned num = 1) override; 392 unsigned insertVar(presburger::VarKind kind, unsigned pos, ValueRange vals); 393 394 /// Removes variables in the column range [varStart, varLimit), and copies any 395 /// remaining valid data into place, updates member variables, and resizes 396 /// arrays as needed. 397 void removeVarRange(presburger::VarKind kind, unsigned varStart, 398 unsigned varLimit) override; 399 using IntegerPolyhedron::removeVarRange; 400 401 /// Sets the Value associated with the pos^th variable. 402 /// Stores the Value in the space's identifiers. setValue(unsigned pos,Value val)403 inline void setValue(unsigned pos, Value val) { 404 assert(pos < getNumDimAndSymbolVars() && "invalid var position"); 405 VarKind kind = getVarKindAt(pos); 406 unsigned relativePos = pos - getVarKindOffset(kind); 407 space.setId(kind, relativePos, presburger::Identifier(val)); 408 } 409 410 /// Sets the Values associated with the variables in the range [start, end). 411 /// The range must contain only dim and symbol variables. setValues(unsigned start,unsigned end,ArrayRef<Value> values)412 void setValues(unsigned start, unsigned end, ArrayRef<Value> values) { 413 assert(end <= getNumVars() && "invalid end position"); 414 assert(start <= end && "invalid start position"); 415 assert(values.size() == end - start && 416 "value should be provided for each variable in the range."); 417 for (unsigned i = start; i < end; ++i) 418 setValue(i, values[i - start]); 419 } 420 421 /// Looks up the position of the variable with the specified Value starting 422 /// with variables at offset `offset`. Returns true if found (false 423 /// otherwise). `pos` is set to the (column) position of the variable. 424 bool findVar(Value val, unsigned *pos, unsigned offset = 0) const; 425 426 /// Returns true if a variable with the specified Value exists, false 427 /// otherwise. 428 bool containsVar(Value val) const; 429 430 /// Projects out the variable that is associate with Value. 431 void projectOut(Value val); 432 using IntegerPolyhedron::projectOut; 433 434 /// Prints the number of constraints, dimensions, symbols and locals in the 435 /// FlatAffineValueConstraints. Also, prints for each variable whether there 436 /// is an SSA Value attached to it. 437 void printSpace(raw_ostream &os) const override; 438 439 /// Align `map` with this constraint system based on `operands`. Each operand 440 /// must already have a corresponding dim/symbol in this constraint system. 441 AffineMap computeAlignedMap(AffineMap map, ValueRange operands) const; 442 443 /// Merge and align the variables of `this` and `other` starting at 444 /// `offset`, so that both constraint systems get the union of the contained 445 /// variables that is dimension-wise and symbol-wise unique; both 446 /// constraint systems are updated so that they have the union of all 447 /// variables, with `this`'s original variables appearing first followed 448 /// by any of `other`'s variables that didn't appear in `this`. Local 449 /// variables in `other` that have the same division representation as local 450 /// variables in `this` are merged into one. 451 // E.g.: Input: `this` has (%i, %j) [%M, %N] 452 // `other` has (%k, %j) [%P, %N, %M] 453 // Output: both `this`, `other` have (%i, %j, %k) [%M, %N, %P] 454 // 455 void mergeAndAlignVarsWithOther(unsigned offset, 456 FlatLinearValueConstraints *other); 457 458 /// Merge and align symbols of `this` and `other` such that both get union of 459 /// of symbols that are unique. Symbols in `this` and `other` should be 460 /// unique. Symbols with Value as `None` are considered to be inequal to all 461 /// other symbols. 462 void mergeSymbolVars(FlatLinearValueConstraints &other); 463 464 /// Returns true if this constraint system and `other` are in the same 465 /// space, i.e., if they are associated with the same set of variables, 466 /// appearing in the same order. Returns false otherwise. 467 bool areVarsAlignedWithOther(const FlatLinearConstraints &other); 468 469 /// Updates the constraints to be the smallest bounding (enclosing) box that 470 /// contains the points of `this` set and that of `other`, with the symbols 471 /// being treated specially. For each of the dimensions, the min of the lower 472 /// bounds (symbolic) and the max of the upper bounds (symbolic) is computed 473 /// to determine such a bounding box. `other` is expected to have the same 474 /// dimensional variables as this constraint system (in the same order). 475 /// 476 /// E.g.: 477 /// 1) this = {0 <= d0 <= 127}, 478 /// other = {16 <= d0 <= 192}, 479 /// output = {0 <= d0 <= 192} 480 /// 2) this = {s0 + 5 <= d0 <= s0 + 20}, 481 /// other = {s0 + 1 <= d0 <= s0 + 9}, 482 /// output = {s0 + 1 <= d0 <= s0 + 20} 483 /// 3) this = {0 <= d0 <= 5, 1 <= d1 <= 9} 484 /// other = {2 <= d0 <= 6, 5 <= d1 <= 15}, 485 /// output = {0 <= d0 <= 6, 1 <= d1 <= 15} 486 LogicalResult unionBoundingBox(const FlatLinearValueConstraints &other); 487 using IntegerPolyhedron::unionBoundingBox; 488 }; 489 490 /// Flattens 'expr' into 'flattenedExpr', which contains the coefficients of the 491 /// dimensions, symbols, and additional variables that represent floor divisions 492 /// of dimensions, symbols, and in turn other floor divisions. Returns failure 493 /// if 'expr' could not be flattened (i.e., an unhandled semi-affine was found). 494 /// 'cst' contains constraints that connect newly introduced local variables 495 /// to existing dimensional and symbolic variables. See documentation for 496 /// AffineExprFlattener on how mod's and div's are flattened. 497 LogicalResult 498 getFlattenedAffineExpr(AffineExpr expr, unsigned numDims, unsigned numSymbols, 499 SmallVectorImpl<int64_t> *flattenedExpr, 500 FlatLinearConstraints *cst = nullptr, 501 bool addConservativeSemiAffineBounds = false); 502 503 /// Flattens the result expressions of the map to their corresponding flattened 504 /// forms and set in 'flattenedExprs'. Returns failure if any expression in the 505 /// map could not be flattened (i.e., an unhandled semi-affine was found). 'cst' 506 /// contains constraints that connect newly introduced local variables to 507 /// existing dimensional and / symbolic variables. See documentation for 508 /// AffineExprFlattener on how mod's and div's are flattened. For all affine 509 /// expressions that share the same operands (like those of an affine map), this 510 /// method should be used instead of repeatedly calling getFlattenedAffineExpr 511 /// since local variables added to deal with div's and mod's will be reused 512 /// across expressions. 513 LogicalResult 514 getFlattenedAffineExprs(AffineMap map, 515 std::vector<SmallVector<int64_t, 8>> *flattenedExprs, 516 FlatLinearConstraints *cst = nullptr, 517 bool addConservativeSemiAffineBounds = false); 518 LogicalResult 519 getFlattenedAffineExprs(IntegerSet set, 520 std::vector<SmallVector<int64_t, 8>> *flattenedExprs, 521 FlatLinearConstraints *cst = nullptr); 522 523 LogicalResult 524 getMultiAffineFunctionFromMap(AffineMap map, 525 presburger::MultiAffineFunction &multiAff); 526 527 /// Re-indexes the dimensions and symbols of an affine map with given `operands` 528 /// values to align with `dims` and `syms` values. 529 /// 530 /// Each dimension/symbol of the map, bound to an operand `o`, is replaced with 531 /// dimension `i`, where `i` is the position of `o` within `dims`. If `o` is not 532 /// in `dims`, replace it with symbol `i`, where `i` is the position of `o` 533 /// within `syms`. If `o` is not in `syms` either, replace it with a new symbol. 534 /// 535 /// Note: If a value appears multiple times as a dimension/symbol (or both), all 536 /// corresponding dim/sym expressions are replaced with the first dimension 537 /// bound to that value (or first symbol if no such dimension exists). 538 /// 539 /// The resulting affine map has `dims.size()` many dimensions and at least 540 /// `syms.size()` many symbols. 541 /// 542 /// The SSA values of the symbols of the resulting map are optionally returned 543 /// via `newSyms`. This is a concatenation of `syms` with the SSA values of the 544 /// newly added symbols. 545 /// 546 /// Note: As part of this re-indexing, dimensions may turn into symbols, or vice 547 /// versa. 548 AffineMap alignAffineMapWithValues(AffineMap map, ValueRange operands, 549 ValueRange dims, ValueRange syms, 550 SmallVector<Value> *newSyms = nullptr); 551 552 } // namespace mlir 553 554 #endif // MLIR_ANALYSIS_FLATLINEARVALUECONSTRAINTS_H 555