MLIR 24.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
19#include "mlir/IR/IntegerSet.h"
20#include "mlir/Support/LLVM.h"
21#include "llvm/ADT/SmallVector.h"
22#include "llvm/Support/Debug.h"
23#include "llvm/Support/raw_ostream.h"
24#include <optional>
25
26#define DEBUG_TYPE "affine-structures"
27
28using namespace mlir;
29using namespace affine;
30using namespace presburger;
31
32FailureOr<FlatAffineValueConstraints>
34 bool error = false;
35 FlatAffineValueConstraints cst(set, operands, &error);
36 if (error)
37 return failure();
38 return cst;
39}
40
41LogicalResult
43 if (containsVar(val))
44 return success();
45
46 // Caller is expected to fully compose map/operands if necessary.
47 if (val.getDefiningOp<affine::AffineApplyOp>() ||
48 (!isValidSymbol(val) && !isAffineInductionVar(val))) {
49 LLVM_DEBUG(llvm::dbgs()
50 << "only valid terminal symbols and affine IVs supported\n");
51 return failure();
52 }
53 // Outer loop IVs could be used in forOp's bounds.
54 if (auto loop = getForInductionVarOwner(val)) {
55 appendDimVar(val);
56 if (failed(this->addAffineForOpDomain(loop))) {
57 LLVM_DEBUG(
58 loop.emitWarning("failed to add domain info to constraint system"));
59 return failure();
60 }
61 return success();
62 }
63
64 if (auto parallel = getAffineParallelInductionVarOwner(val)) {
65 appendDimVar(parallel.getIVs());
66 if (failed(this->addAffineParallelOpDomain(parallel))) {
67 LLVM_DEBUG(parallel.emitWarning(
68 "failed to add domain info to constraint system"));
69 return failure();
70 }
71 return success();
72 }
73
74 // Add top level symbol.
75 appendSymbolVar(val);
76 // Check if the symbol is a constant.
77 if (std::optional<int64_t> constOp = getConstantIntValue(val))
78 addBound(BoundType::EQ, val, constOp.value());
79 return success();
80}
81
82LogicalResult
84 unsigned pos;
85 // Pre-condition for this method.
86 if (!findVar(forOp.getInductionVar(), &pos)) {
87 assert(false && "Value not found");
88 return failure();
89 }
90
91 int64_t step = forOp.getStepAsInt();
92 if (step != 1) {
93 if (!forOp.hasConstantLowerBound())
94 LLVM_DEBUG(forOp.emitWarning("domain conservatively approximated"));
95 else {
96 // Add constraints for the stride.
97 // (iv - lb) % step = 0 can be written as:
98 // (iv - lb) - step * q = 0 where q = (iv - lb) / step.
99 // Add local variable 'q' and add the above equality.
100 // The first constraint is q = (iv - lb) floordiv step
101 SmallVector<int64_t, 8> dividend(getNumCols(), 0);
102 int64_t lb = forOp.getConstantLowerBound();
103 dividend[pos] = 1;
104 dividend.back() -= lb;
105 unsigned qPos = addLocalFloorDiv(dividend, step);
106 // Second constraint: (iv - lb) - step * q = 0.
108 eq[pos] = 1;
109 eq.back() -= lb;
110 // For the local var just added above.
111 eq[qPos] = -step;
112 addEquality(eq);
113 }
114 }
115
116 if (forOp.hasConstantLowerBound()) {
117 addBound(BoundType::LB, pos, forOp.getConstantLowerBound());
118 } else {
119 // Non-constant lower bound case.
120 if (failed(addBound(BoundType::LB, pos, forOp.getLowerBoundMap(),
121 forOp.getLowerBoundOperands())))
122 return failure();
123 }
124
125 if (forOp.hasConstantUpperBound()) {
126 addBound(BoundType::UB, pos, forOp.getConstantUpperBound() - 1);
127 return success();
128 }
129 // Non-constant upper bound case.
130 return addBound(BoundType::UB, pos, forOp.getUpperBoundMap(),
131 forOp.getUpperBoundOperands());
132}
133
135 AffineParallelOp parallelOp) {
136 size_t ivPos = 0;
137 for (Value iv : parallelOp.getIVs()) {
138 unsigned pos;
139 if (!findVar(iv, &pos)) {
140 assert(false && "variable expected for the IV value");
141 return failure();
142 }
143
144 AffineMap lowerBound = parallelOp.getLowerBoundMap(ivPos);
145 if (lowerBound.isSingleConstant())
146 addBound(BoundType::LB, pos, lowerBound.getSingleConstantResult());
147 else if (failed(addBound(BoundType::LB, pos, lowerBound,
148 parallelOp.getLowerBoundsOperands())))
149 return failure();
150
151 auto upperBound = parallelOp.getUpperBoundMap(ivPos);
152 if (upperBound.isSingleConstant())
153 addBound(BoundType::UB, pos, upperBound.getSingleConstantResult() - 1);
154 else if (failed(addBound(BoundType::UB, pos, upperBound,
155 parallelOp.getUpperBoundsOperands())))
156 return failure();
157 ++ivPos;
158 }
159 return success();
160}
161
162LogicalResult
164 ArrayRef<AffineMap> ubMaps,
165 ArrayRef<Value> operands) {
166 assert(lbMaps.size() == ubMaps.size());
167 assert(lbMaps.size() <= getNumDimVars());
168
169 for (unsigned i = 0, e = lbMaps.size(); i < e; ++i) {
170 AffineMap lbMap = lbMaps[i];
171 AffineMap ubMap = ubMaps[i];
172 assert(!lbMap || lbMap.getNumInputs() == operands.size());
173 assert(!ubMap || ubMap.getNumInputs() == operands.size());
174
175 // Check if this slice is just an equality along this dimension. If so,
176 // retrieve the existing loop it equates to and add it to the system.
177 if (lbMap && ubMap && lbMap.getNumResults() == 1 &&
178 ubMap.getNumResults() == 1 &&
179 lbMap.getResult(0) + 1 == ubMap.getResult(0) &&
180 // The condition above will be true for maps describing a single
181 // iteration (e.g., lbMap.getResult(0) = 0, ubMap.getResult(0) = 1).
182 // Make sure we skip those cases by checking that the lb result is not
183 // just a constant.
184 !isa<AffineConstantExpr>(lbMap.getResult(0))) {
185 // Limited support: we expect the lb result to be just a loop dimension.
186 // Not supported otherwise for now.
187 AffineDimExpr result = dyn_cast<AffineDimExpr>(lbMap.getResult(0));
188 if (!result)
189 return failure();
190
191 AffineForOp loop =
192 getForInductionVarOwner(operands[result.getPosition()]);
193 if (!loop)
194 return failure();
195
196 if (failed(addAffineForOpDomain(loop)))
197 return failure();
198 continue;
199 }
200
201 // This slice refers to a loop that doesn't exist in the IR yet. Add its
202 // bounds to the system assuming its dimension variable position is the
203 // same as the position of the loop in the loop nest.
204 if (lbMap && failed(addBound(BoundType::LB, i, lbMap, operands)))
205 return failure();
206 if (ubMap && failed(addBound(BoundType::UB, i, ubMap, operands)))
207 return failure();
208 }
209 return success();
210}
211
213 IntegerSet set = ifOp.getIntegerSet();
214 // Canonicalize set and operands to ensure unique values for
215 // FlatAffineValueConstraints below and for early simplification.
216 SmallVector<Value> operands(ifOp.getOperands());
217 canonicalizeSetAndOperands(&set, &operands);
218
219 // Create the base constraints from the integer set attached to ifOp.
220 FailureOr<FlatAffineValueConstraints> cst =
222 if (failed(cst)) {
223 assert(false && "semi-affine integer sets are unsupported here");
224 return;
225 }
226
227 // Merge the constraints from ifOp to the current domain. We need first merge
228 // and align the IDs from both constraints, and then append the constraints
229 // from the ifOp into the current one.
231 append(*cst);
232}
233
234LogicalResult FlatAffineValueConstraints::addBound(BoundType type, unsigned pos,
235 AffineMap boundMap,
236 ValueRange boundOperands) {
237 // Fully compose map and operands; canonicalize and simplify so that we
238 // transitively get to terminal symbols or loop IVs.
239 auto map = boundMap;
240 SmallVector<Value, 4> operands(boundOperands.begin(), boundOperands.end());
241 fullyComposeAffineMapAndOperands(&map, &operands);
242 map = simplifyAffineMap(map);
243 canonicalizeMapAndOperands(&map, &operands);
244 for (Value operand : operands) {
245 if (failed(addInductionVarOrTerminalSymbol(operand)))
246 return failure();
247 }
248 return addBound(type, pos, computeAlignedMap(map, operands));
249}
250
251// Adds slice lower bounds represented by lower bounds in 'lbMaps' and upper
252// bounds in 'ubMaps' to each value in `values' that appears in the constraint
253// system. Note that both lower/upper bounds share the same operand list
254// 'operands'.
255// This function assumes 'values.size' == 'lbMaps.size' == 'ubMaps.size', and
256// skips any null AffineMaps in 'lbMaps' or 'ubMaps'.
257// Note that both lower/upper bounds use operands from 'operands'.
258// Returns failure for unimplemented cases such as semi-affine expressions or
259// expressions with mod/floordiv.
262 ArrayRef<AffineMap> ubMaps, ArrayRef<Value> operands) {
263 assert(values.size() == lbMaps.size());
264 assert(lbMaps.size() == ubMaps.size());
265
266 for (unsigned i = 0, e = lbMaps.size(); i < e; ++i) {
267 unsigned pos;
268 if (!findVar(values[i], &pos))
269 continue;
270
271 AffineMap lbMap = lbMaps[i];
272 AffineMap ubMap = ubMaps[i];
273 assert(!lbMap || lbMap.getNumInputs() == operands.size());
274 assert(!ubMap || ubMap.getNumInputs() == operands.size());
275
276 // Check if this slice is just an equality along this dimension.
277 if (lbMap && ubMap && lbMap.getNumResults() == 1 &&
278 ubMap.getNumResults() == 1 &&
279 lbMap.getResult(0) + 1 == ubMap.getResult(0)) {
280 if (failed(addBound(BoundType::EQ, pos, lbMap, operands)))
281 return failure();
282 continue;
283 }
284
285 // If lower or upper bound maps are null or provide no results, it implies
286 // that the source loop was not at all sliced, and the entire loop will be a
287 // part of the slice.
288 if (lbMap && lbMap.getNumResults() != 0 && ubMap &&
289 ubMap.getNumResults() != 0) {
290 if (failed(addBound(BoundType::LB, pos, lbMap, operands)))
291 return failure();
292 if (failed(addBound(BoundType::UB, pos, ubMap, operands)))
293 return failure();
294 } else {
295 auto loop = getForInductionVarOwner(values[i]);
296 if (failed(this->addAffineForOpDomain(loop)))
297 return failure();
298 }
299 }
300 return success();
301}
302
303LogicalResult
308
309// Turn a symbol into a dimension.
311 unsigned pos;
312 if (cst->findVar(value, &pos) && pos >= cst->getNumDimVars() &&
313 pos < cst->getNumDimAndSymbolVars()) {
314 cst->swapVar(pos, cst->getNumDimVars());
316 }
317}
318
319// Changes all symbol variables which are loop IVs to dim variables.
321 // Gather all symbols which are loop IVs.
322 SmallVector<Value, 4> loopIVs;
323 for (unsigned i = getNumDimVars(), e = getNumDimAndSymbolVars(); i < e; i++) {
325 loopIVs.push_back(getValue(i));
326 }
327 // Turn each symbol in 'loopIVs' into a dim variable.
328 for (auto iv : loopIVs) {
329 turnSymbolIntoDim(this, iv);
330 }
331}
332
334 unsigned pos, unsigned ineqPos, AffineValueMap &vmap,
335 MLIRContext *context) const {
336 unsigned numDims = getNumDimVars();
337 unsigned numSyms = getNumSymbolVars();
338
339 assert(pos < numDims && "invalid position");
340 assert(ineqPos < getNumInequalities() && "invalid inequality position");
341
342 // Get expressions for local vars.
344 if (failed(computeLocalVars(memo, context)))
345 assert(false &&
346 "one or more local exprs do not have an explicit representation");
347 auto localExprs = ArrayRef<AffineExpr>(memo).take_back(getNumLocalVars());
348
349 // Compute the AffineExpr lower/upper bound for this inequality.
350 SmallVector<int64_t, 8> inequality = getInequality64(ineqPos);
352 bound.reserve(getNumCols() - 1);
353 // Everything other than the coefficient at `pos`.
354 bound.append(inequality.begin(), inequality.begin() + pos);
355 bound.append(inequality.begin() + pos + 1, inequality.end());
356
357 if (inequality[pos] > 0)
358 // Lower bound.
359 llvm::transform(bound, bound.begin(), std::negate<int64_t>());
360 else
361 // Upper bound (which is exclusive).
362 bound.back() += 1;
363
364 // Convert to AffineExpr (tree) form.
365 auto boundExpr = getAffineExprFromFlatForm(bound, numDims - 1, numSyms,
366 localExprs, context);
367
368 // Get the values to bind to this affine expr (all dims and symbols).
369 SmallVector<Value, 4> operands;
370 getValues(0, pos, &operands);
371 SmallVector<Value, 4> trailingOperands;
372 getValues(pos + 1, getNumDimAndSymbolVars(), &trailingOperands);
373 operands.append(trailingOperands.begin(), trailingOperands.end());
374 vmap.reset(AffineMap::get(numDims - 1, numSyms, boundExpr), operands);
375}
376
378 FlatAffineValueConstraints domain = *this;
379 // Convert all range variables to local variables.
380 domain.convertToLocal(VarKind::SetDim, getNumDomainDims(),
382 return domain;
383}
384
386 FlatAffineValueConstraints range = *this;
387 // Convert all domain variables to local variables.
388 range.convertToLocal(VarKind::SetDim, 0, getNumDomainDims());
389 return range;
390}
391
393 assert(getNumDomainDims() == other.getNumRangeDims() &&
394 "Domain of this and range of other do not match");
395 assert(space.getDomainSpace().isAligned(other.getSpace().getRangeSpace()) &&
396 "Values of domain of this and range of other do not match");
397
398 FlatAffineRelation rel = other;
399
400 // Convert `rel` from
401 // [otherDomain] -> [otherRange]
402 // to
403 // [otherDomain] -> [otherRange thisRange]
404 // and `this` from
405 // [thisDomain] -> [thisRange]
406 // to
407 // [otherDomain thisDomain] -> [thisRange].
408 unsigned removeDims = rel.getNumRangeDims();
411
412 // Merge symbol and local variables.
413 mergeSymbolVars(rel);
414 mergeLocalVars(rel);
415
416 // Convert `rel` from [otherDomain] -> [otherRange thisRange] to
417 // [otherDomain] -> [thisRange] by converting first otherRange range vars
418 // to local vars.
419 rel.convertToLocal(VarKind::SetDim, rel.getNumDomainDims(),
420 rel.getNumDomainDims() + removeDims);
421 // Convert `this` from [otherDomain thisDomain] -> [thisRange] to
422 // [otherDomain] -> [thisRange] by converting last thisDomain domain vars
423 // to local vars.
424 convertToLocal(VarKind::SetDim, getNumDomainDims() - removeDims,
426
427 auto thisMaybeValues = getMaybeValues(VarKind::SetDim);
428 auto relMaybeValues = rel.getMaybeValues(VarKind::SetDim);
429
430 // Add and match domain of `rel` to domain of `this`.
431 for (unsigned i = 0, e = rel.getNumDomainDims(); i < e; ++i)
432 if (relMaybeValues[i].has_value())
433 setValue(i, *relMaybeValues[i]);
434 // Add and match range of `this` to range of `rel`.
435 for (unsigned i = 0, e = getNumRangeDims(); i < e; ++i) {
436 unsigned rangeIdx = rel.getNumDomainDims() + i;
437 if (thisMaybeValues[rangeIdx].has_value())
438 rel.setValue(rangeIdx, *thisMaybeValues[rangeIdx]);
439 }
440
441 // Append `this` to `rel` and simplify constraints.
442 rel.append(*this);
444
445 *this = rel;
446}
447
449 unsigned oldDomain = getNumDomainDims();
450 unsigned oldRange = getNumRangeDims();
451 // Add new range vars.
452 appendRangeVar(oldDomain);
453 // Swap new vars with domain.
454 for (unsigned i = 0; i < oldDomain; ++i)
455 swapVar(i, oldDomain + oldRange + i);
456 // Remove the swapped domain.
457 removeVarRange(0, oldDomain);
458 // Set domain and range as inverse.
459 numDomainDims = oldRange;
460 numRangeDims = oldDomain;
461}
462
463void FlatAffineRelation::insertDomainVar(unsigned pos, unsigned num) {
464 assert(pos <= getNumDomainDims() &&
465 "Var cannot be inserted at invalid position");
466 insertDimVar(pos, num);
467 numDomainDims += num;
468}
469
470void FlatAffineRelation::insertRangeVar(unsigned pos, unsigned num) {
471 assert(pos <= getNumRangeDims() &&
472 "Var cannot be inserted at invalid position");
473 insertDimVar(getNumDomainDims() + pos, num);
474 numRangeDims += num;
475}
476
479 numDomainDims += num;
480}
481
484 numRangeDims += num;
485}
486
487void FlatAffineRelation::removeVarRange(VarKind kind, unsigned varStart,
488 unsigned varLimit) {
489 assert(varLimit <= getNumVarKind(kind));
490 if (varStart >= varLimit)
491 return;
492
493 FlatAffineValueConstraints::removeVarRange(kind, varStart, varLimit);
494
495 // If kind is not SetDim, domain and range don't need to be updated.
496 if (kind != VarKind::SetDim)
497 return;
498
499 // Compute number of domain and range variables to remove. This is done by
500 // intersecting the range of domain/range vars with range of vars to remove.
501 unsigned intersectDomainLHS = std::min(varLimit, getNumDomainDims());
502 unsigned intersectDomainRHS = varStart;
503 unsigned intersectRangeLHS = std::min(varLimit, getNumDimVars());
504 unsigned intersectRangeRHS = std::max(varStart, getNumDomainDims());
505
506 if (intersectDomainLHS > intersectDomainRHS)
507 numDomainDims -= intersectDomainLHS - intersectDomainRHS;
508 if (intersectRangeLHS > intersectRangeRHS)
509 numRangeDims -= intersectRangeLHS - intersectRangeRHS;
510}
511
513 IntegerRelation &rel) {
514 // Get flattened affine expressions.
515 std::vector<SmallVector<int64_t, 8>> flatExprs;
516 FlatAffineValueConstraints localVarCst;
517 if (failed(getFlattenedAffineExprs(map, &flatExprs, &localVarCst)))
518 return failure();
519
520 const unsigned oldDimNum = localVarCst.getNumDimVars();
521 const unsigned oldCols = localVarCst.getNumCols();
522 const unsigned numRangeVars = map.getNumResults();
523 const unsigned numDomainVars = map.getNumDims();
524
525 // Add range as the new expressions.
526 localVarCst.appendDimVar(numRangeVars);
527
528 // Add identifiers to the local constraints as getFlattenedAffineExprs creates
529 // a FlatLinearConstraints with no identifiers.
530 for (unsigned i = 0, e = localVarCst.getNumDimAndSymbolVars(); i < e; ++i)
531 localVarCst.setValue(i, Value());
532
533 // Add equalities between source and range.
534 SmallVector<int64_t, 8> eq(localVarCst.getNumCols());
535 for (unsigned i = 0, e = map.getNumResults(); i < e; ++i) {
536 // Zero fill.
537 llvm::fill(eq, 0);
538 // Fill equality.
539 for (unsigned j = 0, f = oldDimNum; j < f; ++j)
540 eq[j] = flatExprs[i][j];
541 for (unsigned j = oldDimNum, f = oldCols; j < f; ++j)
542 eq[j + numRangeVars] = flatExprs[i][j];
543 // Set this dimension to -1 to equate lhs and rhs and add equality.
544 eq[numDomainVars + i] = -1;
545 localVarCst.addEquality(eq);
546 }
547
548 rel = localVarCst;
549 return success();
550}
551
553 IntegerRelation &rel) {
554
555 AffineMap affineMap = map.getAffineMap();
556 if (failed(getRelationFromMap(affineMap, rel)))
557 return failure();
558
559 // Set identifiers for domain and symbol variables.
560 for (unsigned i = 0, e = affineMap.getNumDims(); i < e; ++i)
561 rel.setId(VarKind::SetDim, i, Identifier(map.getOperand(i)));
562
563 const unsigned mapNumResults = affineMap.getNumResults();
564 for (unsigned i = 0, e = rel.getNumSymbolVars(); i < e; ++i)
565 rel.setId(
566 VarKind::Symbol, i,
567 Identifier(map.getOperand(rel.getNumDimVars() + i - mapNumResults)));
568
569 return success();
570}
return success()
static void turnSymbolIntoDim(FlatAffineValueConstraints *cst, Value value)
A dimensional identifier appearing in an affine expression.
Definition AffineExpr.h:223
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.
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
bool isSingleConstant() const
Returns true if this affine map is a single result constant function.
unsigned getNumDims() const
unsigned getNumResults() const
unsigned getNumInputs() const
AffineExpr getResult(unsigned idx) const
LogicalResult composeMatchingMap(AffineMap other)
Composes an affine map whose dimensions and symbols match one to one with the dimensions and symbols ...
LogicalResult computeLocalVars(SmallVectorImpl< AffineExpr > &memo, MLIRContext *context) const
Compute an explicit representation for local vars.
unsigned insertDimVar(unsigned pos, ValueRange vals)
void mergeAndAlignVarsWithOther(unsigned offset, FlatLinearValueConstraints *other)
Merge and align the variables of this and other starting at offset, so that both constraint systems g...
bool hasValue(unsigned pos) const
Returns true if the pos^th variable has an associated Value.
Value getValue(unsigned pos) const
Returns the Value associated with the pos^th variable.
void mergeSymbolVars(FlatLinearValueConstraints &other)
Merge and align symbols of this and other such that both get union of of symbols that are unique.
bool containsVar(Value val) const
Returns true if a variable with the specified Value exists, false otherwise.
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...
AffineMap computeAlignedMap(AffineMap map, ValueRange operands) const
Align map with this constraint system based on operands.
void getValues(unsigned start, unsigned end, SmallVectorImpl< Value > *values) const
Returns the Values associated with variables in range [start, end).
void setValue(unsigned pos, Value val)
Sets the Value associated with the pos^th variable.
SmallVector< std::optional< Value > > getMaybeValues() const
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:63
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:389
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:18
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={})
FlatAffineRelation(unsigned numReservedInequalities, unsigned numReservedEqualities, unsigned numReservedCols, unsigned numDomainDims, unsigned numRangeDims, unsigned numSymbols, unsigned numLocals, ArrayRef< std::optional< Value > > valArgs={})
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...
LogicalResult addBound(presburger::BoundType type, unsigned pos, AffineMap boundMap, ValueRange operands)
Adds a bound for the variable at the specified position with constraints being drawn from the specifi...
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...
static FailureOr< FlatAffineValueConstraints > create(IntegerSet set, ValueRange operands={})
Creates an affine constraint system from an IntegerSet.
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.
SmallVector< int64_t, 8 > getInequality64(unsigned idx) const
unsigned getNumVarKind(VarKind kind) const
Get the number of vars of the specified kind.
void convertToLocal(VarKind kind, unsigned varStart, unsigned varLimit)
const PresburgerSpace & getSpace() const
Returns a reference to the underlying space.
void append(const IntegerRelation &other)
Appends constraints from other into this.
unsigned addLocalFloorDiv(ArrayRef< DynamicAPInt > dividend, const DynamicAPInt &divisor)
Adds a new local variable as the floordiv of an affine function of other variables,...
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.
unsigned mergeLocalVars(IntegerRelation &other)
Adds additional local vars to the sets such that they both have the union of the local vars in each s...
PresburgerSpace getRangeSpace() const
bool isAffineInductionVar(Value val)
Returns true if the provided value is the induction variable of an AffineForOp or AffineParallelOp.
AffineForOp getForInductionVarOwner(Value val)
Returns the loop parent of an induction variable.
void canonicalizeMapAndOperands(AffineMap *map, SmallVectorImpl< Value > *operands)
Modifies both map and operands in-place so as to:
void fullyComposeAffineMapAndOperands(AffineMap *map, SmallVectorImpl< Value > *operands, bool composeAffineMin=false)
Given an affine map map and its input operands, this method composes into map, maps of AffineApplyOps...
void canonicalizeSetAndOperands(IntegerSet *set, SmallVectorImpl< Value > *operands)
Canonicalizes an integer set the same way canonicalizeMapAndOperands does for affine maps.
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...
AffineParallelOp getAffineParallelInductionVarOwner(Value val)
Returns true if the provided value is among the induction variables of an AffineParallelOp.
BoundType
The type of bound: equal, lower bound or upper bound.
Include the generated interface declarations.
AffineMap simplifyAffineMap(AffineMap map)
Simplifies an affine map by simplifying its underlying AffineExpr results.
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.