MLIR  21.0.0git
AffineStructures.cpp
Go to the documentation of this file.
1 //===- AffineStructures.cpp - MLIR Affine Structures Class-----------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Structures for affine/polyhedral analysis of affine dialect ops.
10 //
11 //===----------------------------------------------------------------------===//
12 
22 #include "mlir/IR/IntegerSet.h"
23 #include "mlir/Support/LLVM.h"
24 #include "llvm/ADT/STLExtras.h"
25 #include "llvm/ADT/SmallPtrSet.h"
26 #include "llvm/ADT/SmallVector.h"
27 #include "llvm/Support/Debug.h"
28 #include "llvm/Support/raw_ostream.h"
29 #include <optional>
30 
31 #define DEBUG_TYPE "affine-structures"
32 
33 using namespace mlir;
34 using namespace affine;
35 using namespace presburger;
36 
37 LogicalResult
39  if (containsVar(val))
40  return success();
41 
42  // Caller is expected to fully compose map/operands if necessary.
43  if (val.getDefiningOp<affine::AffineApplyOp>() ||
44  (!isValidSymbol(val) && !isAffineInductionVar(val))) {
45  LLVM_DEBUG(llvm::dbgs()
46  << "only valid terminal symbols and affine IVs supported\n");
47  return failure();
48  }
49  // Outer loop IVs could be used in forOp's bounds.
50  if (auto loop = getForInductionVarOwner(val)) {
51  appendDimVar(val);
52  if (failed(this->addAffineForOpDomain(loop))) {
53  LLVM_DEBUG(
54  loop.emitWarning("failed to add domain info to constraint system"));
55  return failure();
56  }
57  return success();
58  }
59 
60  if (auto parallel = getAffineParallelInductionVarOwner(val)) {
61  appendDimVar(parallel.getIVs());
62  if (failed(this->addAffineParallelOpDomain(parallel))) {
63  LLVM_DEBUG(parallel.emitWarning(
64  "failed to add domain info to constraint system"));
65  return failure();
66  }
67  return success();
68  }
69 
70  // Add top level symbol.
71  appendSymbolVar(val);
72  // Check if the symbol is a constant.
73  if (std::optional<int64_t> constOp = getConstantIntValue(val))
74  addBound(BoundType::EQ, val, constOp.value());
75  return success();
76 }
77 
78 LogicalResult
80  unsigned pos;
81  // Pre-condition for this method.
82  if (!findVar(forOp.getInductionVar(), &pos)) {
83  assert(false && "Value not found");
84  return failure();
85  }
86 
87  int64_t step = forOp.getStepAsInt();
88  if (step != 1) {
89  if (!forOp.hasConstantLowerBound())
90  LLVM_DEBUG(forOp.emitWarning("domain conservatively approximated"));
91  else {
92  // Add constraints for the stride.
93  // (iv - lb) % step = 0 can be written as:
94  // (iv - lb) - step * q = 0 where q = (iv - lb) / step.
95  // Add local variable 'q' and add the above equality.
96  // The first constraint is q = (iv - lb) floordiv step
97  SmallVector<int64_t, 8> dividend(getNumCols(), 0);
98  int64_t lb = forOp.getConstantLowerBound();
99  dividend[pos] = 1;
100  dividend.back() -= lb;
101  addLocalFloorDiv(dividend, step);
102  // Second constraint: (iv - lb) - step * q = 0.
103  SmallVector<int64_t, 8> eq(getNumCols(), 0);
104  eq[pos] = 1;
105  eq.back() -= lb;
106  // For the local var just added above.
107  eq[getNumCols() - 2] = -step;
108  addEquality(eq);
109  }
110  }
111 
112  if (forOp.hasConstantLowerBound()) {
113  addBound(BoundType::LB, pos, forOp.getConstantLowerBound());
114  } else {
115  // Non-constant lower bound case.
116  if (failed(addBound(BoundType::LB, pos, forOp.getLowerBoundMap(),
117  forOp.getLowerBoundOperands())))
118  return failure();
119  }
120 
121  if (forOp.hasConstantUpperBound()) {
122  addBound(BoundType::UB, pos, forOp.getConstantUpperBound() - 1);
123  return success();
124  }
125  // Non-constant upper bound case.
126  return addBound(BoundType::UB, pos, forOp.getUpperBoundMap(),
127  forOp.getUpperBoundOperands());
128 }
129 
131  AffineParallelOp parallelOp) {
132  size_t ivPos = 0;
133  for (Value iv : parallelOp.getIVs()) {
134  unsigned pos;
135  if (!findVar(iv, &pos)) {
136  assert(false && "variable expected for the IV value");
137  return failure();
138  }
139 
140  AffineMap lowerBound = parallelOp.getLowerBoundMap(ivPos);
141  if (lowerBound.isConstant())
142  addBound(BoundType::LB, pos, lowerBound.getSingleConstantResult());
143  else if (failed(addBound(BoundType::LB, pos, lowerBound,
144  parallelOp.getLowerBoundsOperands())))
145  return failure();
146 
147  auto upperBound = parallelOp.getUpperBoundMap(ivPos);
148  if (upperBound.isConstant())
149  addBound(BoundType::UB, pos, upperBound.getSingleConstantResult() - 1);
150  else if (failed(addBound(BoundType::UB, pos, upperBound,
151  parallelOp.getUpperBoundsOperands())))
152  return failure();
153  ++ivPos;
154  }
155  return success();
156 }
157 
158 LogicalResult
160  ArrayRef<AffineMap> ubMaps,
161  ArrayRef<Value> operands) {
162  assert(lbMaps.size() == ubMaps.size());
163  assert(lbMaps.size() <= getNumDimVars());
164 
165  for (unsigned i = 0, e = lbMaps.size(); i < e; ++i) {
166  AffineMap lbMap = lbMaps[i];
167  AffineMap ubMap = ubMaps[i];
168  assert(!lbMap || lbMap.getNumInputs() == operands.size());
169  assert(!ubMap || ubMap.getNumInputs() == operands.size());
170 
171  // Check if this slice is just an equality along this dimension. If so,
172  // retrieve the existing loop it equates to and add it to the system.
173  if (lbMap && ubMap && lbMap.getNumResults() == 1 &&
174  ubMap.getNumResults() == 1 &&
175  lbMap.getResult(0) + 1 == ubMap.getResult(0) &&
176  // The condition above will be true for maps describing a single
177  // iteration (e.g., lbMap.getResult(0) = 0, ubMap.getResult(0) = 1).
178  // Make sure we skip those cases by checking that the lb result is not
179  // just a constant.
180  !isa<AffineConstantExpr>(lbMap.getResult(0))) {
181  // Limited support: we expect the lb result to be just a loop dimension.
182  // Not supported otherwise for now.
183  AffineDimExpr result = dyn_cast<AffineDimExpr>(lbMap.getResult(0));
184  if (!result)
185  return failure();
186 
187  AffineForOp loop =
188  getForInductionVarOwner(operands[result.getPosition()]);
189  if (!loop)
190  return failure();
191 
192  if (failed(addAffineForOpDomain(loop)))
193  return failure();
194  continue;
195  }
196 
197  // This slice refers to a loop that doesn't exist in the IR yet. Add its
198  // bounds to the system assuming its dimension variable position is the
199  // same as the position of the loop in the loop nest.
200  if (lbMap && failed(addBound(BoundType::LB, i, lbMap, operands)))
201  return failure();
202  if (ubMap && failed(addBound(BoundType::UB, i, ubMap, operands)))
203  return failure();
204  }
205  return success();
206 }
207 
209  IntegerSet set = ifOp.getIntegerSet();
210  // Canonicalize set and operands to ensure unique values for
211  // FlatAffineValueConstraints below and for early simplification.
212  SmallVector<Value> operands(ifOp.getOperands());
213  canonicalizeSetAndOperands(&set, &operands);
214 
215  // Create the base constraints from the integer set attached to ifOp.
216  FlatAffineValueConstraints cst(set, operands);
217 
218  // Merge the constraints from ifOp to the current domain. We need first merge
219  // and align the IDs from both constraints, and then append the constraints
220  // from the ifOp into the current one.
221  mergeAndAlignVarsWithOther(0, &cst);
222  append(cst);
223 }
224 
225 LogicalResult FlatAffineValueConstraints::addBound(BoundType type, unsigned pos,
226  AffineMap boundMap,
227  ValueRange boundOperands) {
228  // Fully compose map and operands; canonicalize and simplify so that we
229  // transitively get to terminal symbols or loop IVs.
230  auto map = boundMap;
231  SmallVector<Value, 4> operands(boundOperands.begin(), boundOperands.end());
232  fullyComposeAffineMapAndOperands(&map, &operands);
233  map = simplifyAffineMap(map);
234  canonicalizeMapAndOperands(&map, &operands);
235  for (Value operand : operands) {
236  if (failed(addInductionVarOrTerminalSymbol(operand)))
237  return failure();
238  }
239  return addBound(type, pos, computeAlignedMap(map, operands));
240 }
241 
242 // Adds slice lower bounds represented by lower bounds in 'lbMaps' and upper
243 // bounds in 'ubMaps' to each value in `values' that appears in the constraint
244 // system. Note that both lower/upper bounds share the same operand list
245 // 'operands'.
246 // This function assumes 'values.size' == 'lbMaps.size' == 'ubMaps.size', and
247 // skips any null AffineMaps in 'lbMaps' or 'ubMaps'.
248 // Note that both lower/upper bounds use operands from 'operands'.
249 // Returns failure for unimplemented cases such as semi-affine expressions or
250 // expressions with mod/floordiv.
252  ArrayRef<Value> values, ArrayRef<AffineMap> lbMaps,
253  ArrayRef<AffineMap> ubMaps, ArrayRef<Value> operands) {
254  assert(values.size() == lbMaps.size());
255  assert(lbMaps.size() == ubMaps.size());
256 
257  for (unsigned i = 0, e = lbMaps.size(); i < e; ++i) {
258  unsigned pos;
259  if (!findVar(values[i], &pos))
260  continue;
261 
262  AffineMap lbMap = lbMaps[i];
263  AffineMap ubMap = ubMaps[i];
264  assert(!lbMap || lbMap.getNumInputs() == operands.size());
265  assert(!ubMap || ubMap.getNumInputs() == operands.size());
266 
267  // Check if this slice is just an equality along this dimension.
268  if (lbMap && ubMap && lbMap.getNumResults() == 1 &&
269  ubMap.getNumResults() == 1 &&
270  lbMap.getResult(0) + 1 == ubMap.getResult(0)) {
271  if (failed(addBound(BoundType::EQ, pos, lbMap, operands)))
272  return failure();
273  continue;
274  }
275 
276  // If lower or upper bound maps are null or provide no results, it implies
277  // that the source loop was not at all sliced, and the entire loop will be a
278  // part of the slice.
279  if (lbMap && lbMap.getNumResults() != 0 && ubMap &&
280  ubMap.getNumResults() != 0) {
281  if (failed(addBound(BoundType::LB, pos, lbMap, operands)))
282  return failure();
283  if (failed(addBound(BoundType::UB, pos, ubMap, operands)))
284  return failure();
285  } else {
286  auto loop = getForInductionVarOwner(values[i]);
287  if (failed(this->addAffineForOpDomain(loop)))
288  return failure();
289  }
290  }
291  return success();
292 }
293 
294 LogicalResult
296  return composeMatchingMap(
297  computeAlignedMap(vMap->getAffineMap(), vMap->getOperands()));
298 }
299 
300 // Turn a symbol into a dimension.
302  unsigned pos;
303  if (cst->findVar(value, &pos) && pos >= cst->getNumDimVars() &&
304  pos < cst->getNumDimAndSymbolVars()) {
305  cst->swapVar(pos, cst->getNumDimVars());
306  cst->setDimSymbolSeparation(cst->getNumSymbolVars() - 1);
307  }
308 }
309 
310 // Changes all symbol variables which are loop IVs to dim variables.
312  // Gather all symbols which are loop IVs.
313  SmallVector<Value, 4> loopIVs;
314  for (unsigned i = getNumDimVars(), e = getNumDimAndSymbolVars(); i < e; i++) {
315  if (hasValue(i) && getForInductionVarOwner(getValue(i)))
316  loopIVs.push_back(getValue(i));
317  }
318  // Turn each symbol in 'loopIVs' into a dim variable.
319  for (auto iv : loopIVs) {
320  turnSymbolIntoDim(this, iv);
321  }
322 }
323 
325  unsigned pos, unsigned ineqPos, AffineValueMap &vmap,
326  MLIRContext *context) const {
327  unsigned numDims = getNumDimVars();
328  unsigned numSyms = getNumSymbolVars();
329 
330  assert(pos < numDims && "invalid position");
331  assert(ineqPos < getNumInequalities() && "invalid inequality position");
332 
333  // Get expressions for local vars.
334  SmallVector<AffineExpr, 8> memo(getNumVars(), AffineExpr());
335  if (failed(computeLocalVars(memo, context)))
336  assert(false &&
337  "one or more local exprs do not have an explicit representation");
338  auto localExprs = ArrayRef<AffineExpr>(memo).take_back(getNumLocalVars());
339 
340  // Compute the AffineExpr lower/upper bound for this inequality.
341  SmallVector<int64_t, 8> inequality = getInequality64(ineqPos);
343  bound.reserve(getNumCols() - 1);
344  // Everything other than the coefficient at `pos`.
345  bound.append(inequality.begin(), inequality.begin() + pos);
346  bound.append(inequality.begin() + pos + 1, inequality.end());
347 
348  if (inequality[pos] > 0)
349  // Lower bound.
350  std::transform(bound.begin(), bound.end(), bound.begin(),
351  std::negate<int64_t>());
352  else
353  // Upper bound (which is exclusive).
354  bound.back() += 1;
355 
356  // Convert to AffineExpr (tree) form.
357  auto boundExpr = getAffineExprFromFlatForm(bound, numDims - 1, numSyms,
358  localExprs, context);
359 
360  // Get the values to bind to this affine expr (all dims and symbols).
361  SmallVector<Value, 4> operands;
362  getValues(0, pos, &operands);
363  SmallVector<Value, 4> trailingOperands;
364  getValues(pos + 1, getNumDimAndSymbolVars(), &trailingOperands);
365  operands.append(trailingOperands.begin(), trailingOperands.end());
366  vmap.reset(AffineMap::get(numDims - 1, numSyms, boundExpr), operands);
367 }
368 
370  FlatAffineValueConstraints domain = *this;
371  // Convert all range variables to local variables.
372  domain.convertToLocal(VarKind::SetDim, getNumDomainDims(),
373  getNumDomainDims() + getNumRangeDims());
374  return domain;
375 }
376 
378  FlatAffineValueConstraints range = *this;
379  // Convert all domain variables to local variables.
380  range.convertToLocal(VarKind::SetDim, 0, getNumDomainDims());
381  return range;
382 }
383 
385  assert(getNumDomainDims() == other.getNumRangeDims() &&
386  "Domain of this and range of other do not match");
387  assert(space.getDomainSpace().isAligned(other.getSpace().getRangeSpace()) &&
388  "Values of domain of this and range of other do not match");
389 
390  FlatAffineRelation rel = other;
391 
392  // Convert `rel` from
393  // [otherDomain] -> [otherRange]
394  // to
395  // [otherDomain] -> [otherRange thisRange]
396  // and `this` from
397  // [thisDomain] -> [thisRange]
398  // to
399  // [otherDomain thisDomain] -> [thisRange].
400  unsigned removeDims = rel.getNumRangeDims();
401  insertDomainVar(0, rel.getNumDomainDims());
402  rel.appendRangeVar(getNumRangeDims());
403 
404  // Merge symbol and local variables.
405  mergeSymbolVars(rel);
406  mergeLocalVars(rel);
407 
408  // Convert `rel` from [otherDomain] -> [otherRange thisRange] to
409  // [otherDomain] -> [thisRange] by converting first otherRange range vars
410  // to local vars.
411  rel.convertToLocal(VarKind::SetDim, rel.getNumDomainDims(),
412  rel.getNumDomainDims() + removeDims);
413  // Convert `this` from [otherDomain thisDomain] -> [thisRange] to
414  // [otherDomain] -> [thisRange] by converting last thisDomain domain vars
415  // to local vars.
416  convertToLocal(VarKind::SetDim, getNumDomainDims() - removeDims,
417  getNumDomainDims());
418 
419  auto thisMaybeValues = getMaybeValues(VarKind::SetDim);
420  auto relMaybeValues = rel.getMaybeValues(VarKind::SetDim);
421 
422  // Add and match domain of `rel` to domain of `this`.
423  for (unsigned i = 0, e = rel.getNumDomainDims(); i < e; ++i)
424  if (relMaybeValues[i].has_value())
425  setValue(i, *relMaybeValues[i]);
426  // Add and match range of `this` to range of `rel`.
427  for (unsigned i = 0, e = getNumRangeDims(); i < e; ++i) {
428  unsigned rangeIdx = rel.getNumDomainDims() + i;
429  if (thisMaybeValues[rangeIdx].has_value())
430  rel.setValue(rangeIdx, *thisMaybeValues[rangeIdx]);
431  }
432 
433  // Append `this` to `rel` and simplify constraints.
434  rel.append(*this);
436 
437  *this = rel;
438 }
439 
441  unsigned oldDomain = getNumDomainDims();
442  unsigned oldRange = getNumRangeDims();
443  // Add new range vars.
444  appendRangeVar(oldDomain);
445  // Swap new vars with domain.
446  for (unsigned i = 0; i < oldDomain; ++i)
447  swapVar(i, oldDomain + oldRange + i);
448  // Remove the swapped domain.
449  removeVarRange(0, oldDomain);
450  // Set domain and range as inverse.
451  numDomainDims = oldRange;
452  numRangeDims = oldDomain;
453 }
454 
455 void FlatAffineRelation::insertDomainVar(unsigned pos, unsigned num) {
456  assert(pos <= getNumDomainDims() &&
457  "Var cannot be inserted at invalid position");
458  insertDimVar(pos, num);
459  numDomainDims += num;
460 }
461 
462 void FlatAffineRelation::insertRangeVar(unsigned pos, unsigned num) {
463  assert(pos <= getNumRangeDims() &&
464  "Var cannot be inserted at invalid position");
465  insertDimVar(getNumDomainDims() + pos, num);
466  numRangeDims += num;
467 }
468 
470  insertDimVar(getNumDomainDims(), num);
471  numDomainDims += num;
472 }
473 
475  insertDimVar(getNumDimVars(), num);
476  numRangeDims += num;
477 }
478 
480  unsigned varLimit) {
481  assert(varLimit <= getNumVarKind(kind));
482  if (varStart >= varLimit)
483  return;
484 
486 
487  // If kind is not SetDim, domain and range don't need to be updated.
488  if (kind != VarKind::SetDim)
489  return;
490 
491  // Compute number of domain and range variables to remove. This is done by
492  // intersecting the range of domain/range vars with range of vars to remove.
493  unsigned intersectDomainLHS = std::min(varLimit, getNumDomainDims());
494  unsigned intersectDomainRHS = varStart;
495  unsigned intersectRangeLHS = std::min(varLimit, getNumDimVars());
496  unsigned intersectRangeRHS = std::max(varStart, getNumDomainDims());
497 
498  if (intersectDomainLHS > intersectDomainRHS)
499  numDomainDims -= intersectDomainLHS - intersectDomainRHS;
500  if (intersectRangeLHS > intersectRangeRHS)
501  numRangeDims -= intersectRangeLHS - intersectRangeRHS;
502 }
503 
505  IntegerRelation &rel) {
506  // Get flattened affine expressions.
507  std::vector<SmallVector<int64_t, 8>> flatExprs;
508  FlatAffineValueConstraints localVarCst;
509  if (failed(getFlattenedAffineExprs(map, &flatExprs, &localVarCst)))
510  return failure();
511 
512  const unsigned oldDimNum = localVarCst.getNumDimVars();
513  const unsigned oldCols = localVarCst.getNumCols();
514  const unsigned numRangeVars = map.getNumResults();
515  const unsigned numDomainVars = map.getNumDims();
516 
517  // Add range as the new expressions.
518  localVarCst.appendDimVar(numRangeVars);
519 
520  // Add identifiers to the local constraints as getFlattenedAffineExprs creates
521  // a FlatLinearConstraints with no identifiers.
522  for (unsigned i = 0, e = localVarCst.getNumDimAndSymbolVars(); i < e; ++i)
523  localVarCst.setValue(i, Value());
524 
525  // Add equalities between source and range.
526  SmallVector<int64_t, 8> eq(localVarCst.getNumCols());
527  for (unsigned i = 0, e = map.getNumResults(); i < e; ++i) {
528  // Zero fill.
529  std::fill(eq.begin(), eq.end(), 0);
530  // Fill equality.
531  for (unsigned j = 0, f = oldDimNum; j < f; ++j)
532  eq[j] = flatExprs[i][j];
533  for (unsigned j = oldDimNum, f = oldCols; j < f; ++j)
534  eq[j + numRangeVars] = flatExprs[i][j];
535  // Set this dimension to -1 to equate lhs and rhs and add equality.
536  eq[numDomainVars + i] = -1;
537  localVarCst.addEquality(eq);
538  }
539 
540  rel = localVarCst;
541  return success();
542 }
543 
545  IntegerRelation &rel) {
546 
547  AffineMap affineMap = map.getAffineMap();
548  if (failed(getRelationFromMap(affineMap, rel)))
549  return failure();
550 
551  // Set identifiers for domain and symbol variables.
552  for (unsigned i = 0, e = affineMap.getNumDims(); i < e; ++i)
553  rel.setId(VarKind::SetDim, i, Identifier(map.getOperand(i)));
554 
555  const unsigned mapNumResults = affineMap.getNumResults();
556  for (unsigned i = 0, e = rel.getNumSymbolVars(); i < e; ++i)
557  rel.setId(
558  VarKind::Symbol, i,
559  Identifier(map.getOperand(rel.getNumDimVars() + i - mapNumResults)));
560 
561  return success();
562 }
static void turnSymbolIntoDim(FlatAffineValueConstraints *cst, Value value)
union mlir::linalg::@1183::ArityGroupAndKind::Kind kind
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
static Value min(ImplicitLocOpBuilder &builder, Value value, Value bound)
A dimensional identifier appearing in an affine expression.
Definition: AffineExpr.h:236
unsigned getPosition() const
Definition: AffineExpr.cpp:348
Base type for affine expression.
Definition: AffineExpr.h:68
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition: AffineMap.h:46
int64_t getSingleConstantResult() const
Returns the constant result of this map.
Definition: AffineMap.cpp:381
bool isConstant() const
Returns true if this affine map has only constant results.
Definition: AffineMap.cpp:377
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
unsigned getNumDims() const
Definition: AffineMap.cpp:394
unsigned getNumResults() const
Definition: AffineMap.cpp:402
unsigned getNumInputs() const
Definition: AffineMap.cpp:403
AffineExpr getResult(unsigned idx) const
Definition: AffineMap.cpp:411
SmallVector< std::optional< Value > > getMaybeValues() const
void removeVarRange(presburger::VarKind kind, unsigned varStart, unsigned varLimit) override
Removes variables in the column range [varStart, varLimit), and copies any remaining valid data into ...
bool findVar(Value val, unsigned *pos, unsigned offset=0) const
Looks up the position of the variable with the specified Value starting with variables at offset offs...
void setValue(unsigned pos, Value val)
Sets the Value associated with the pos^th variable.
An integer set representing a conjunction of one or more affine equalities and inequalities.
Definition: IntegerSet.h:44
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:381
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
Definition: Value.cpp:20
An AffineValueMap is an affine map plus its ML value operands and results for analysis purposes.
Value getOperand(unsigned i) const
ArrayRef< Value > getOperands() const
void reset(AffineMap map, ValueRange operands, ValueRange results={})
A FlatAffineRelation represents a set of ordered pairs (domain -> range) where "domain" and "range" a...
void appendDomainVar(unsigned num=1)
Append num variables of the specified kind after the last variable of that kind.
void compose(const FlatAffineRelation &other)
Given affine relation other: (domainOther -> rangeOther), this operation takes the composition of oth...
unsigned getNumDomainDims() const
Returns the number of variables corresponding to domain/range of relation.
void inverse()
Swap domain and range of the relation.
FlatAffineValueConstraints getDomainSet() const
Returns a set corresponding to the domain/range of the affine relation.
void removeVarRange(VarKind kind, unsigned varStart, unsigned varLimit) override
Removes variables in the column range [varStart, varLimit), and copies any remaining valid data into ...
FlatAffineValueConstraints getRangeSet() const
void insertRangeVar(unsigned pos, unsigned num=1)
void insertDomainVar(unsigned pos, unsigned num=1)
Insert num variables of the specified kind after the pos variable of that kind.
FlatAffineValueConstraints is an extension of FlatLinearValueConstraints with helper functions for Af...
void addAffineIfOpDomain(AffineIfOp ifOp)
Adds constraints imposed by the affine.if operation.
void convertLoopIVSymbolsToDims()
Changes all symbol variables which are loop IVs to dim variables.
LogicalResult addDomainFromSliceMaps(ArrayRef< AffineMap > lbMaps, ArrayRef< AffineMap > ubMaps, ArrayRef< Value > operands)
Adds constraints (lower and upper bounds) for each loop in the loop nest described by the bound maps ...
LogicalResult addAffineParallelOpDomain(AffineParallelOp parallelOp)
Add constraints (lower and upper bounds) for the specified 'affine.parallel' operation's Value using ...
LogicalResult addAffineForOpDomain(AffineForOp forOp)
Adds constraints (lower and upper bounds) for the specified 'affine.for' operation's Value using IR i...
void addBound(presburger::BoundType type, Value val, int64_t value)
Adds a constant bound for the variable associated with the given Value.
void getIneqAsAffineValueMap(unsigned pos, unsigned ineqPos, AffineValueMap &vmap, MLIRContext *context) const
Returns the bound for the variable at pos from the inequality at ineqPos as a 1-d affine value map (a...
LogicalResult addSliceBounds(ArrayRef< Value > values, ArrayRef< AffineMap > lbMaps, ArrayRef< AffineMap > ubMaps, ArrayRef< Value > operands)
Adds slice lower bounds represented by lower bounds in lbMaps and upper bounds in ubMaps to each vari...
LogicalResult composeMap(const AffineValueMap *vMap)
Composes the affine value map with this FlatAffineValueConstrains, adding the results of the map as d...
LogicalResult addInductionVarOrTerminalSymbol(Value val)
Add the specified values as a dim or symbol var depending on its nature, if it already doesn't exist ...
An Identifier stores a pointer to an object, such as a Value or an Operation.
An IntegerRelation represents the set of points from a PresburgerSpace that satisfy a list of affine ...
void setId(VarKind kind, unsigned i, Identifier id)
Set the identifier for the ith variable of the specified kind of the IntegerRelation's PresburgerSpac...
virtual void swapVar(unsigned posA, unsigned posB)
Swap the posA^th variable with the posB^th variable.
void convertToLocal(VarKind kind, unsigned varStart, unsigned varLimit)
void append(const IntegerRelation &other)
Appends constraints from other into this.
void addEquality(ArrayRef< DynamicAPInt > eq)
Adds an equality from the coefficients specified in eq.
void setDimSymbolSeparation(unsigned newSymbolCount)
Changes the partition between dimensions and symbols.
unsigned getNumCols() const
Returns the number of columns in the constraint system.
void removeRedundantLocalVars()
Removes local variables using equalities.
const PresburgerSpace & getSpace() const
Returns a reference to the underlying space.
PresburgerSpace getRangeSpace() const
void fullyComposeAffineMapAndOperands(AffineMap *map, SmallVectorImpl< Value > *operands)
Given an affine map map and its input operands, this method composes into map, maps of AffineApplyOps...
Definition: AffineOps.cpp:1148
bool isAffineInductionVar(Value val)
Returns true if the provided value is the induction variable of an AffineForOp or AffineParallelOp.
Definition: AffineOps.cpp:2581
AffineForOp getForInductionVarOwner(Value val)
Returns the loop parent of an induction variable.
Definition: AffineOps.cpp:2585
void canonicalizeMapAndOperands(AffineMap *map, SmallVectorImpl< Value > *operands)
Modifies both map and operands in-place so as to:
Definition: AffineOps.cpp:1447
void canonicalizeSetAndOperands(IntegerSet *set, SmallVectorImpl< Value > *operands)
Canonicalizes an integer set the same way canonicalizeMapAndOperands does for affine maps.
Definition: AffineOps.cpp:1452
LogicalResult getRelationFromMap(AffineMap &map, presburger::IntegerRelation &rel)
Builds a relation from the given AffineMap/AffineValueMap map, containing all pairs of the form opera...
bool isValidSymbol(Value value)
Returns true if the given value can be used as a symbol in the region of the closest surrounding op t...
Definition: AffineOps.cpp:402
AffineParallelOp getAffineParallelInductionVarOwner(Value val)
Returns true if the provided value is among the induction variables of an AffineParallelOp.
Definition: AffineOps.cpp:2596
BoundType
The type of bound: equal, lower bound or upper bound.
VarKind
Kind of variable.
void mergeLocalVars(IntegerRelation &relA, IntegerRelation &relB, llvm::function_ref< bool(unsigned i, unsigned j)> merge)
Given two relations, A and B, add additional local vars to the sets such that both have the union of ...
Definition: Utils.cpp:289
Include the generated interface declarations.
AffineMap simplifyAffineMap(AffineMap map)
Simplifies an affine map by simplifying its underlying AffineExpr results.
Definition: AffineMap.cpp:773
std::optional< int64_t > getConstantIntValue(OpFoldResult ofr)
If ofr is a constant integer or an IntegerAttr, return the integer.
AffineExpr getAffineExprFromFlatForm(ArrayRef< int64_t > flatExprs, unsigned numDims, unsigned numSymbols, ArrayRef< AffineExpr > localExprs, MLIRContext *context)
Constructs an affine expression from a flat ArrayRef.
LogicalResult getFlattenedAffineExprs(AffineMap map, std::vector< SmallVector< int64_t, 8 >> *flattenedExprs, FlatLinearConstraints *cst=nullptr, bool addConservativeSemiAffineBounds=false)
Flattens the result expressions of the map to their corresponding flattened forms and set in 'flatten...
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.