xref: /llvm-project/mlir/include/mlir/Analysis/FlatLinearValueConstraints.h (revision db791b278a414fb6df1acc1799adcf11d8fb9169)
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