MLIR  19.0.0git
AffineMap.cpp
Go to the documentation of this file.
1 //===- AffineMap.cpp - MLIR Affine Map Classes ----------------------------===//
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 #include "mlir/IR/AffineMap.h"
10 #include "AffineMapDetail.h"
11 #include "mlir/IR/AffineExpr.h"
12 #include "mlir/IR/Builders.h"
14 #include "mlir/IR/BuiltinTypes.h"
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/ADT/SmallBitVector.h"
19 #include "llvm/ADT/SmallSet.h"
20 #include "llvm/ADT/SmallVector.h"
21 #include "llvm/ADT/StringRef.h"
22 #include "llvm/Support/raw_ostream.h"
23 #include <iterator>
24 #include <numeric>
25 #include <optional>
26 #include <type_traits>
27 
28 using namespace mlir;
29 
30 namespace {
31 
32 // AffineExprConstantFolder evaluates an affine expression using constant
33 // operands passed in 'operandConsts'. Returns an IntegerAttr attribute
34 // representing the constant value of the affine expression evaluated on
35 // constant 'operandConsts', or nullptr if it can't be folded.
36 class AffineExprConstantFolder {
37 public:
38  AffineExprConstantFolder(unsigned numDims, ArrayRef<Attribute> operandConsts)
39  : numDims(numDims), operandConsts(operandConsts) {}
40 
41  /// Attempt to constant fold the specified affine expr, or return null on
42  /// failure.
43  IntegerAttr constantFold(AffineExpr expr) {
44  if (auto result = constantFoldImpl(expr))
45  return IntegerAttr::get(IndexType::get(expr.getContext()), *result);
46  return nullptr;
47  }
48 
49  bool hasPoison() const { return hasPoison_; }
50 
51 private:
52  std::optional<int64_t> constantFoldImpl(AffineExpr expr) {
53  switch (expr.getKind()) {
55  return constantFoldBinExpr(
56  expr, [](int64_t lhs, int64_t rhs) { return lhs + rhs; });
58  return constantFoldBinExpr(
59  expr, [](int64_t lhs, int64_t rhs) { return lhs * rhs; });
61  return constantFoldBinExpr(
62  expr, [this](int64_t lhs, int64_t rhs) -> std::optional<int64_t> {
63  if (rhs < 1) {
64  hasPoison_ = true;
65  return std::nullopt;
66  }
67  return mod(lhs, rhs);
68  });
70  return constantFoldBinExpr(
71  expr, [this](int64_t lhs, int64_t rhs) -> std::optional<int64_t> {
72  if (rhs == 0) {
73  hasPoison_ = true;
74  return std::nullopt;
75  }
76  return floorDiv(lhs, rhs);
77  });
79  return constantFoldBinExpr(
80  expr, [this](int64_t lhs, int64_t rhs) -> std::optional<int64_t> {
81  if (rhs == 0) {
82  hasPoison_ = true;
83  return std::nullopt;
84  }
85  return ceilDiv(lhs, rhs);
86  });
88  return cast<AffineConstantExpr>(expr).getValue();
90  if (auto attr = llvm::dyn_cast_or_null<IntegerAttr>(
91  operandConsts[cast<AffineDimExpr>(expr).getPosition()]))
92  return attr.getInt();
93  return std::nullopt;
95  if (auto attr = llvm::dyn_cast_or_null<IntegerAttr>(
96  operandConsts[numDims +
97  cast<AffineSymbolExpr>(expr).getPosition()]))
98  return attr.getInt();
99  return std::nullopt;
100  }
101  llvm_unreachable("Unknown AffineExpr");
102  }
103 
104  // TODO: Change these to operate on APInts too.
105  std::optional<int64_t> constantFoldBinExpr(
106  AffineExpr expr,
107  llvm::function_ref<std::optional<int64_t>(int64_t, int64_t)> op) {
108  auto binOpExpr = cast<AffineBinaryOpExpr>(expr);
109  if (auto lhs = constantFoldImpl(binOpExpr.getLHS()))
110  if (auto rhs = constantFoldImpl(binOpExpr.getRHS()))
111  return op(*lhs, *rhs);
112  return std::nullopt;
113  }
114 
115  // The number of dimension operands in AffineMap containing this expression.
116  unsigned numDims;
117  // The constant valued operands used to evaluate this AffineExpr.
118  ArrayRef<Attribute> operandConsts;
119  bool hasPoison_{false};
120 };
121 
122 } // namespace
123 
124 /// Returns a single constant result affine map.
126  return get(/*dimCount=*/0, /*symbolCount=*/0,
127  {getAffineConstantExpr(val, context)});
128 }
129 
130 /// Returns an identity affine map (d0, ..., dn) -> (dp, ..., dn) on the most
131 /// minor dimensions.
132 AffineMap AffineMap::getMinorIdentityMap(unsigned dims, unsigned results,
133  MLIRContext *context) {
134  assert(dims >= results && "Dimension mismatch");
135  auto id = AffineMap::getMultiDimIdentityMap(dims, context);
136  return AffineMap::get(dims, 0, id.getResults().take_back(results), context);
137 }
138 
140  MLIRContext *ctx, unsigned numDims,
141  llvm::function_ref<bool(AffineDimExpr)> keepDimFilter) {
142  auto identityMap = getMultiDimIdentityMap(numDims, ctx);
143 
144  // Apply filter to results.
145  llvm::SmallBitVector dropDimResults(numDims);
146  for (auto [idx, resultExpr] : llvm::enumerate(identityMap.getResults()))
147  dropDimResults[idx] = !keepDimFilter(cast<AffineDimExpr>(resultExpr));
148 
149  return identityMap.dropResults(dropDimResults);
150 }
151 
153  return getNumDims() >= getNumResults() &&
154  *this ==
156 }
157 
158 /// Returns true if this affine map is a minor identity up to broadcasted
159 /// dimensions which are indicated by value 0 in the result.
161  SmallVectorImpl<unsigned> *broadcastedDims) const {
162  if (broadcastedDims)
163  broadcastedDims->clear();
164  if (getNumDims() < getNumResults())
165  return false;
166  unsigned suffixStart = getNumDims() - getNumResults();
167  for (const auto &idxAndExpr : llvm::enumerate(getResults())) {
168  unsigned resIdx = idxAndExpr.index();
169  AffineExpr expr = idxAndExpr.value();
170  if (auto constExpr = dyn_cast<AffineConstantExpr>(expr)) {
171  // Each result may be either a constant 0 (broadcasted dimension).
172  if (constExpr.getValue() != 0)
173  return false;
174  if (broadcastedDims)
175  broadcastedDims->push_back(resIdx);
176  } else if (auto dimExpr = dyn_cast<AffineDimExpr>(expr)) {
177  // Or it may be the input dimension corresponding to this result position.
178  if (dimExpr.getPosition() != suffixStart + resIdx)
179  return false;
180  } else {
181  return false;
182  }
183  }
184  return true;
185 }
186 
187 /// Return true if this affine map can be converted to a minor identity with
188 /// broadcast by doing a permute. Return a permutation (there may be
189 /// several) to apply to get to a minor identity with broadcasts.
190 /// Ex:
191 /// * (d0, d1, d2) -> (0, d1) maps to minor identity (d1, 0 = d2) with
192 /// perm = [1, 0] and broadcast d2
193 /// * (d0, d1, d2) -> (d0, 0) cannot be mapped to a minor identity by
194 /// permutation + broadcast
195 /// * (d0, d1, d2, d3) -> (0, d1, d3) maps to minor identity (d1, 0 = d2, d3)
196 /// with perm = [1, 0, 2] and broadcast d2
197 /// * (d0, d1) -> (d1, 0, 0, d0) maps to minor identity (d0, d1) with extra
198 /// leading broadcat dimensions. The map returned would be (0, 0, d0, d1) with
199 /// perm = [3, 0, 1, 2]
201  SmallVectorImpl<unsigned> &permutedDims) const {
202  unsigned projectionStart =
204  permutedDims.clear();
205  SmallVector<unsigned> broadcastDims;
206  permutedDims.resize(getNumResults(), 0);
207  // If there are more results than input dimensions we want the new map to
208  // start with broadcast dimensions in order to be a minor identity with
209  // broadcasting.
210  unsigned leadingBroadcast =
212  llvm::SmallBitVector dimFound(std::max(getNumInputs(), getNumResults()),
213  false);
214  for (const auto &idxAndExpr : llvm::enumerate(getResults())) {
215  unsigned resIdx = idxAndExpr.index();
216  AffineExpr expr = idxAndExpr.value();
217  // Each result may be either a constant 0 (broadcast dimension) or a
218  // dimension.
219  if (auto constExpr = dyn_cast<AffineConstantExpr>(expr)) {
220  if (constExpr.getValue() != 0)
221  return false;
222  broadcastDims.push_back(resIdx);
223  } else if (auto dimExpr = dyn_cast<AffineDimExpr>(expr)) {
224  if (dimExpr.getPosition() < projectionStart)
225  return false;
226  unsigned newPosition =
227  dimExpr.getPosition() - projectionStart + leadingBroadcast;
228  permutedDims[resIdx] = newPosition;
229  dimFound[newPosition] = true;
230  } else {
231  return false;
232  }
233  }
234  // Find a permuation for the broadcast dimension. Since they are broadcasted
235  // any valid permutation is acceptable. We just permute the dim into a slot
236  // without an existing dimension.
237  unsigned pos = 0;
238  for (auto dim : broadcastDims) {
239  while (pos < dimFound.size() && dimFound[pos]) {
240  pos++;
241  }
242  permutedDims[dim] = pos++;
243  }
244  return true;
245 }
246 
247 /// Returns an AffineMap representing a permutation.
249  MLIRContext *context) {
250  assert(!permutation.empty() &&
251  "Cannot create permutation map from empty permutation vector");
252  const auto *m = llvm::max_element(permutation);
253  auto permutationMap = getMultiDimMapWithTargets(*m + 1, permutation, context);
254  assert(permutationMap.isPermutation() && "Invalid permutation vector");
255  return permutationMap;
256 }
258  MLIRContext *context) {
259  SmallVector<unsigned> perm = llvm::map_to_vector(
260  permutation, [](int64_t i) { return static_cast<unsigned>(i); });
261  return AffineMap::getPermutationMap(perm, context);
262 }
263 
265  ArrayRef<unsigned> targets,
266  MLIRContext *context) {
268  for (unsigned t : targets)
269  affExprs.push_back(getAffineDimExpr(t, context));
270  AffineMap result = AffineMap::get(/*dimCount=*/numDims, /*symbolCount=*/0,
271  affExprs, context);
272  return result;
273 }
274 
275 /// Creates an affine map each for each list of AffineExpr's in `exprsList`
276 /// while inferring the right number of dimensional and symbolic inputs needed
277 /// based on the maximum dimensional and symbolic identifier appearing in the
278 /// expressions.
279 template <typename AffineExprContainer>
282  MLIRContext *context) {
283  if (exprsList.empty())
284  return {};
285  int64_t maxDim = -1, maxSym = -1;
286  getMaxDimAndSymbol(exprsList, maxDim, maxSym);
288  maps.reserve(exprsList.size());
289  for (const auto &exprs : exprsList)
290  maps.push_back(AffineMap::get(/*dimCount=*/maxDim + 1,
291  /*symbolCount=*/maxSym + 1, exprs, context));
292  return maps;
293 }
294 
297  MLIRContext *context) {
298  return ::inferFromExprList(exprsList, context);
299 }
300 
303  MLIRContext *context) {
304  return ::inferFromExprList(exprsList, context);
305 }
306 
308  uint64_t gcd = 0;
309  for (AffineExpr resultExpr : getResults()) {
310  uint64_t thisGcd = resultExpr.getLargestKnownDivisor();
311  gcd = std::gcd(gcd, thisGcd);
312  }
313  if (gcd == 0)
315  return gcd;
316 }
317 
319  MLIRContext *context) {
321  dimExprs.reserve(numDims);
322  for (unsigned i = 0; i < numDims; ++i)
323  dimExprs.push_back(mlir::getAffineDimExpr(i, context));
324  return get(/*dimCount=*/numDims, /*symbolCount=*/0, dimExprs, context);
325 }
326 
327 MLIRContext *AffineMap::getContext() const { return map->context; }
328 
329 bool AffineMap::isIdentity() const {
330  if (getNumDims() != getNumResults())
331  return false;
332  ArrayRef<AffineExpr> results = getResults();
333  for (unsigned i = 0, numDims = getNumDims(); i < numDims; ++i) {
334  auto expr = dyn_cast<AffineDimExpr>(results[i]);
335  if (!expr || expr.getPosition() != i)
336  return false;
337  }
338  return true;
339 }
340 
342  if (getNumSymbols() != getNumResults())
343  return false;
344  ArrayRef<AffineExpr> results = getResults();
345  for (unsigned i = 0, numSymbols = getNumSymbols(); i < numSymbols; ++i) {
346  auto expr = dyn_cast<AffineDimExpr>(results[i]);
347  if (!expr || expr.getPosition() != i)
348  return false;
349  }
350  return true;
351 }
352 
353 bool AffineMap::isEmpty() const {
354  return getNumDims() == 0 && getNumSymbols() == 0 && getNumResults() == 0;
355 }
356 
358  return getNumResults() == 1 && isa<AffineConstantExpr>(getResult(0));
359 }
360 
361 bool AffineMap::isConstant() const {
362  return llvm::all_of(getResults(), llvm::IsaPred<AffineConstantExpr>);
363 }
364 
366  assert(isSingleConstant() && "map must have a single constant result");
367  return cast<AffineConstantExpr>(getResult(0)).getValue();
368 }
369 
371  assert(isConstant() && "map must have only constant results");
372  SmallVector<int64_t> result;
373  for (auto expr : getResults())
374  result.emplace_back(cast<AffineConstantExpr>(expr).getValue());
375  return result;
376 }
377 
378 unsigned AffineMap::getNumDims() const {
379  assert(map && "uninitialized map storage");
380  return map->numDims;
381 }
382 unsigned AffineMap::getNumSymbols() const {
383  assert(map && "uninitialized map storage");
384  return map->numSymbols;
385 }
386 unsigned AffineMap::getNumResults() const { return getResults().size(); }
387 unsigned AffineMap::getNumInputs() const {
388  assert(map && "uninitialized map storage");
389  return map->numDims + map->numSymbols;
390 }
392  assert(map && "uninitialized map storage");
393  return map->results();
394 }
395 AffineExpr AffineMap::getResult(unsigned idx) const {
396  return getResults()[idx];
397 }
398 
399 unsigned AffineMap::getDimPosition(unsigned idx) const {
400  return cast<AffineDimExpr>(getResult(idx)).getPosition();
401 }
402 
403 std::optional<unsigned> AffineMap::getResultPosition(AffineExpr input) const {
404  if (!isa<AffineDimExpr>(input))
405  return std::nullopt;
406 
407  for (unsigned i = 0, numResults = getNumResults(); i < numResults; i++) {
408  if (getResult(i) == input)
409  return i;
410  }
411 
412  return std::nullopt;
413 }
414 
415 /// Folds the results of the application of an affine map on the provided
416 /// operands to a constant if possible. Returns false if the folding happens,
417 /// true otherwise.
420  bool *hasPoison) const {
421  // Attempt partial folding.
422  SmallVector<int64_t, 2> integers;
423  partialConstantFold(operandConstants, &integers, hasPoison);
424 
425  // If all expressions folded to a constant, populate results with attributes
426  // containing those constants.
427  if (integers.empty())
428  return failure();
429 
430  auto range = llvm::map_range(integers, [this](int64_t i) {
432  });
433  results.append(range.begin(), range.end());
434  return success();
435 }
436 
438  SmallVectorImpl<int64_t> *results,
439  bool *hasPoison) const {
440  assert(getNumInputs() == operandConstants.size());
441 
442  // Fold each of the result expressions.
443  AffineExprConstantFolder exprFolder(getNumDims(), operandConstants);
445  exprs.reserve(getNumResults());
446 
447  for (auto expr : getResults()) {
448  auto folded = exprFolder.constantFold(expr);
449  if (exprFolder.hasPoison() && hasPoison) {
450  *hasPoison = true;
451  return {};
452  }
453  // If did not fold to a constant, keep the original expression, and clear
454  // the integer results vector.
455  if (folded) {
456  exprs.push_back(
457  getAffineConstantExpr(folded.getInt(), folded.getContext()));
458  if (results)
459  results->push_back(folded.getInt());
460  } else {
461  exprs.push_back(expr);
462  if (results) {
463  results->clear();
464  results = nullptr;
465  }
466  }
467  }
468 
469  return get(getNumDims(), getNumSymbols(), exprs, getContext());
470 }
471 
472 /// Walk all of the AffineExpr's in this mapping. Each node in an expression
473 /// tree is visited in postorder.
475  for (auto expr : getResults())
476  expr.walk(callback);
477 }
478 
479 /// This method substitutes any uses of dimensions and symbols (e.g.
480 /// dim#0 with dimReplacements[0]) in subexpressions and returns the modified
481 /// expression mapping. Because this can be used to eliminate dims and
482 /// symbols, the client needs to specify the number of dims and symbols in
483 /// the result. The returned map always has the same number of results.
485  ArrayRef<AffineExpr> symReplacements,
486  unsigned numResultDims,
487  unsigned numResultSyms) const {
489  results.reserve(getNumResults());
490  for (auto expr : getResults())
491  results.push_back(
492  expr.replaceDimsAndSymbols(dimReplacements, symReplacements));
493  return get(numResultDims, numResultSyms, results, getContext());
494 }
495 
496 /// Sparse replace method. Apply AffineExpr::replace(`expr`, `replacement`) to
497 /// each of the results and return a new AffineMap with the new results and
498 /// with the specified number of dims and symbols.
500  unsigned numResultDims,
501  unsigned numResultSyms) const {
502  SmallVector<AffineExpr, 4> newResults;
503  newResults.reserve(getNumResults());
504  for (AffineExpr e : getResults())
505  newResults.push_back(e.replace(expr, replacement));
506  return AffineMap::get(numResultDims, numResultSyms, newResults, getContext());
507 }
508 
509 /// Sparse replace method. Apply AffineExpr::replace(`map`) to each of the
510 /// results and return a new AffineMap with the new results and with the
511 /// specified number of dims and symbols.
513  unsigned numResultDims,
514  unsigned numResultSyms) const {
515  SmallVector<AffineExpr, 4> newResults;
516  newResults.reserve(getNumResults());
517  for (AffineExpr e : getResults())
518  newResults.push_back(e.replace(map));
519  return AffineMap::get(numResultDims, numResultSyms, newResults, getContext());
520 }
521 
522 AffineMap
524  SmallVector<AffineExpr, 4> newResults;
525  newResults.reserve(getNumResults());
526  for (AffineExpr e : getResults())
527  newResults.push_back(e.replace(map));
528  return AffineMap::inferFromExprList(newResults, getContext()).front();
529 }
530 
531 AffineMap AffineMap::dropResults(const llvm::SmallBitVector &positions) const {
532  auto exprs = llvm::to_vector<4>(getResults());
533  // TODO: this is a pretty terrible API .. is there anything better?
534  for (auto pos = positions.find_last(); pos != -1;
535  pos = positions.find_prev(pos))
536  exprs.erase(exprs.begin() + pos);
537  return AffineMap::get(getNumDims(), getNumSymbols(), exprs, getContext());
538 }
539 
541  assert(getNumDims() == map.getNumResults() && "Number of results mismatch");
542  // Prepare `map` by concatenating the symbols and rewriting its exprs.
543  unsigned numDims = map.getNumDims();
544  unsigned numSymbolsThisMap = getNumSymbols();
545  unsigned numSymbols = numSymbolsThisMap + map.getNumSymbols();
546  SmallVector<AffineExpr, 8> newDims(numDims);
547  for (unsigned idx = 0; idx < numDims; ++idx) {
548  newDims[idx] = getAffineDimExpr(idx, getContext());
549  }
550  SmallVector<AffineExpr, 8> newSymbols(numSymbols - numSymbolsThisMap);
551  for (unsigned idx = numSymbolsThisMap; idx < numSymbols; ++idx) {
552  newSymbols[idx - numSymbolsThisMap] =
554  }
555  auto newMap =
556  map.replaceDimsAndSymbols(newDims, newSymbols, numDims, numSymbols);
558  exprs.reserve(getResults().size());
559  for (auto expr : getResults())
560  exprs.push_back(expr.compose(newMap));
561  return AffineMap::get(numDims, numSymbols, exprs, map.getContext());
562 }
563 
565  assert(getNumSymbols() == 0 && "Expected symbol-less map");
567  exprs.reserve(values.size());
568  MLIRContext *ctx = getContext();
569  for (auto v : values)
570  exprs.push_back(getAffineConstantExpr(v, ctx));
571  auto resMap = compose(AffineMap::get(0, 0, exprs, ctx));
573  res.reserve(resMap.getNumResults());
574  for (auto e : resMap.getResults())
575  res.push_back(cast<AffineConstantExpr>(e).getValue());
576  return res;
577 }
578 
579 bool AffineMap::isProjectedPermutation(bool allowZeroInResults) const {
580  if (getNumSymbols() > 0)
581  return false;
582 
583  // Having more results than inputs means that results have duplicated dims or
584  // zeros that can't be mapped to input dims.
585  if (getNumResults() > getNumInputs())
586  return false;
587 
588  SmallVector<bool, 8> seen(getNumInputs(), false);
589  // A projected permutation can have, at most, only one instance of each input
590  // dimension in the result expressions. Zeros are allowed as long as the
591  // number of result expressions is lower or equal than the number of input
592  // expressions.
593  for (auto expr : getResults()) {
594  if (auto dim = dyn_cast<AffineDimExpr>(expr)) {
595  if (seen[dim.getPosition()])
596  return false;
597  seen[dim.getPosition()] = true;
598  } else {
599  auto constExpr = dyn_cast<AffineConstantExpr>(expr);
600  if (!allowZeroInResults || !constExpr || constExpr.getValue() != 0)
601  return false;
602  }
603  }
604 
605  // Results are either dims or zeros and zeros can be mapped to input dims.
606  return true;
607 }
608 
610  if (getNumDims() != getNumResults())
611  return false;
612  return isProjectedPermutation();
613 }
614 
617  exprs.reserve(resultPos.size());
618  for (auto idx : resultPos)
619  exprs.push_back(getResult(idx));
620  return AffineMap::get(getNumDims(), getNumSymbols(), exprs, getContext());
621 }
622 
623 AffineMap AffineMap::getSliceMap(unsigned start, unsigned length) const {
625  getResults().slice(start, length), getContext());
626 }
627 
628 AffineMap AffineMap::getMajorSubMap(unsigned numResults) const {
629  if (numResults == 0)
630  return AffineMap();
631  if (numResults > getNumResults())
632  return *this;
633  return getSliceMap(0, numResults);
634 }
635 
636 AffineMap AffineMap::getMinorSubMap(unsigned numResults) const {
637  if (numResults == 0)
638  return AffineMap();
639  if (numResults > getNumResults())
640  return *this;
641  return getSliceMap(getNumResults() - numResults, numResults);
642 }
643 
644 /// Implementation detail to compress multiple affine maps with a compressionFun
645 /// that is expected to be either compressUnusedDims or compressUnusedSymbols.
646 /// The implementation keeps track of num dims and symbols across the different
647 /// affine maps.
649  ArrayRef<AffineMap> maps,
650  llvm::function_ref<AffineMap(AffineMap)> compressionFun) {
651  if (maps.empty())
652  return SmallVector<AffineMap>();
653  SmallVector<AffineExpr> allExprs;
654  allExprs.reserve(maps.size() * maps.front().getNumResults());
655  unsigned numDims = maps.front().getNumDims(),
656  numSymbols = maps.front().getNumSymbols();
657  for (auto m : maps) {
658  assert(numDims == m.getNumDims() && numSymbols == m.getNumSymbols() &&
659  "expected maps with same num dims and symbols");
660  llvm::append_range(allExprs, m.getResults());
661  }
662  AffineMap unifiedMap = compressionFun(
663  AffineMap::get(numDims, numSymbols, allExprs, maps.front().getContext()));
664  unsigned unifiedNumDims = unifiedMap.getNumDims(),
665  unifiedNumSymbols = unifiedMap.getNumSymbols();
666  ArrayRef<AffineExpr> unifiedResults = unifiedMap.getResults();
668  res.reserve(maps.size());
669  for (auto m : maps) {
670  res.push_back(AffineMap::get(unifiedNumDims, unifiedNumSymbols,
671  unifiedResults.take_front(m.getNumResults()),
672  m.getContext()));
673  unifiedResults = unifiedResults.drop_front(m.getNumResults());
674  }
675  return res;
676 }
677 
679  const llvm::SmallBitVector &unusedDims) {
680  return projectDims(map, unusedDims, /*compressDimsFlag=*/true);
681 }
682 
684  return compressDims(map, getUnusedDimsBitVector({map}));
685 }
686 
688  return compressUnusedListImpl(
689  maps, [](AffineMap m) { return compressUnusedDims(m); });
690 }
691 
693  const llvm::SmallBitVector &unusedSymbols) {
694  return projectSymbols(map, unusedSymbols, /*compressSymbolsFlag=*/true);
695 }
696 
698  return compressSymbols(map, getUnusedSymbolsBitVector({map}));
699 }
700 
702  return compressUnusedListImpl(
703  maps, [](AffineMap m) { return compressUnusedSymbols(m); });
704 }
705 
707  ArrayRef<OpFoldResult> operands,
708  SmallVector<Value> &remainingValues) {
709  SmallVector<AffineExpr> dimReplacements, symReplacements;
710  int64_t numDims = 0;
711  for (int64_t i = 0; i < map.getNumDims(); ++i) {
712  if (auto attr = operands[i].dyn_cast<Attribute>()) {
713  dimReplacements.push_back(
714  b.getAffineConstantExpr(cast<IntegerAttr>(attr).getInt()));
715  } else {
716  dimReplacements.push_back(b.getAffineDimExpr(numDims++));
717  remainingValues.push_back(operands[i].get<Value>());
718  }
719  }
720  int64_t numSymbols = 0;
721  for (int64_t i = 0; i < map.getNumSymbols(); ++i) {
722  if (auto attr = operands[i + map.getNumDims()].dyn_cast<Attribute>()) {
723  symReplacements.push_back(
724  b.getAffineConstantExpr(cast<IntegerAttr>(attr).getInt()));
725  } else {
726  symReplacements.push_back(b.getAffineSymbolExpr(numSymbols++));
727  remainingValues.push_back(operands[i + map.getNumDims()].get<Value>());
728  }
729  }
730  return map.replaceDimsAndSymbols(dimReplacements, symReplacements, numDims,
731  numSymbols);
732 }
733 
736  for (auto e : map.getResults()) {
737  exprs.push_back(
738  simplifyAffineExpr(e, map.getNumDims(), map.getNumSymbols()));
739  }
740  return AffineMap::get(map.getNumDims(), map.getNumSymbols(), exprs,
741  map.getContext());
742 }
743 
745  auto results = map.getResults();
746  SmallVector<AffineExpr, 4> uniqueExprs(results.begin(), results.end());
747  uniqueExprs.erase(std::unique(uniqueExprs.begin(), uniqueExprs.end()),
748  uniqueExprs.end());
749  return AffineMap::get(map.getNumDims(), map.getNumSymbols(), uniqueExprs,
750  map.getContext());
751 }
752 
754  if (map.isEmpty())
755  return map;
756  assert(map.getNumSymbols() == 0 && "expected map without symbols");
758  for (const auto &en : llvm::enumerate(map.getResults())) {
759  auto expr = en.value();
760  // Skip non-permutations.
761  if (auto d = dyn_cast<AffineDimExpr>(expr)) {
762  if (exprs[d.getPosition()])
763  continue;
764  exprs[d.getPosition()] = getAffineDimExpr(en.index(), d.getContext());
765  }
766  }
767  SmallVector<AffineExpr, 4> seenExprs;
768  seenExprs.reserve(map.getNumDims());
769  for (auto expr : exprs)
770  if (expr)
771  seenExprs.push_back(expr);
772  if (seenExprs.size() != map.getNumInputs())
773  return AffineMap();
774  return AffineMap::get(map.getNumResults(), 0, seenExprs, map.getContext());
775 }
776 
778  assert(map.isProjectedPermutation(/*allowZeroInResults=*/true));
779  MLIRContext *context = map.getContext();
780  AffineExpr zero = mlir::getAffineConstantExpr(0, context);
781  // Start with all the results as 0.
782  SmallVector<AffineExpr, 4> exprs(map.getNumInputs(), zero);
783  for (unsigned i : llvm::seq(unsigned(0), map.getNumResults())) {
784  // Skip zeros from input map. 'exprs' is already initialized to zero.
785  if (auto constExpr = dyn_cast<AffineConstantExpr>(map.getResult(i))) {
786  assert(constExpr.getValue() == 0 &&
787  "Unexpected constant in projected permutation");
788  (void)constExpr;
789  continue;
790  }
791 
792  // Reverse each dimension existing in the original map result.
793  exprs[map.getDimPosition(i)] = getAffineDimExpr(i, context);
794  }
795  return AffineMap::get(map.getNumResults(), /*symbolCount=*/0, exprs, context);
796 }
797 
799  unsigned numResults = 0, numDims = 0, numSymbols = 0;
800  for (auto m : maps)
801  numResults += m.getNumResults();
803  results.reserve(numResults);
804  for (auto m : maps) {
805  for (auto res : m.getResults())
806  results.push_back(res.shiftSymbols(m.getNumSymbols(), numSymbols));
807 
808  numSymbols += m.getNumSymbols();
809  numDims = std::max(m.getNumDims(), numDims);
810  }
811  return AffineMap::get(numDims, numSymbols, results,
812  maps.front().getContext());
813 }
814 
815 /// Common implementation to project out dimensions or symbols from an affine
816 /// map based on the template type.
817 /// Additionally, if 'compress' is true, the projected out dimensions or symbols
818 /// are also dropped from the resulting map.
819 template <typename AffineDimOrSymExpr>
821  const llvm::SmallBitVector &toProject,
822  bool compress) {
823  static_assert(llvm::is_one_of<AffineDimOrSymExpr, AffineDimExpr,
824  AffineSymbolExpr>::value,
825  "expected AffineDimExpr or AffineSymbolExpr");
826 
827  constexpr bool isDim = std::is_same<AffineDimOrSymExpr, AffineDimExpr>::value;
828  int64_t numDimOrSym = (isDim) ? map.getNumDims() : map.getNumSymbols();
829  SmallVector<AffineExpr> replacements;
830  replacements.reserve(numDimOrSym);
831 
832  auto createNewDimOrSym = (isDim) ? getAffineDimExpr : getAffineSymbolExpr;
833 
834  using replace_fn_ty =
835  std::function<AffineExpr(AffineExpr, ArrayRef<AffineExpr>)>;
836  replace_fn_ty replaceDims = [](AffineExpr e,
837  ArrayRef<AffineExpr> replacements) {
838  return e.replaceDims(replacements);
839  };
840  replace_fn_ty replaceSymbols = [](AffineExpr e,
841  ArrayRef<AffineExpr> replacements) {
842  return e.replaceSymbols(replacements);
843  };
844  replace_fn_ty replaceNewDimOrSym = (isDim) ? replaceDims : replaceSymbols;
845 
846  MLIRContext *context = map.getContext();
847  int64_t newNumDimOrSym = 0;
848  for (unsigned dimOrSym = 0; dimOrSym < numDimOrSym; ++dimOrSym) {
849  if (toProject.test(dimOrSym)) {
850  replacements.push_back(getAffineConstantExpr(0, context));
851  continue;
852  }
853  int64_t newPos = compress ? newNumDimOrSym++ : dimOrSym;
854  replacements.push_back(createNewDimOrSym(newPos, context));
855  }
856  SmallVector<AffineExpr> resultExprs;
857  resultExprs.reserve(map.getNumResults());
858  for (auto e : map.getResults())
859  resultExprs.push_back(replaceNewDimOrSym(e, replacements));
860 
861  int64_t numDims = (compress && isDim) ? newNumDimOrSym : map.getNumDims();
862  int64_t numSyms = (compress && !isDim) ? newNumDimOrSym : map.getNumSymbols();
863  return AffineMap::get(numDims, numSyms, resultExprs, context);
864 }
865 
867  const llvm::SmallBitVector &projectedDimensions,
868  bool compressDimsFlag) {
869  return projectCommonImpl<AffineDimExpr>(map, projectedDimensions,
870  compressDimsFlag);
871 }
872 
874  const llvm::SmallBitVector &projectedSymbols,
875  bool compressSymbolsFlag) {
876  return projectCommonImpl<AffineSymbolExpr>(map, projectedSymbols,
877  compressSymbolsFlag);
878 }
879 
881  const llvm::SmallBitVector &projectedDimensions,
882  bool compressDimsFlag,
883  bool compressSymbolsFlag) {
884  map = projectDims(map, projectedDimensions, compressDimsFlag);
885  if (compressSymbolsFlag)
886  map = compressUnusedSymbols(map);
887  return map;
888 }
889 
891  unsigned numDims = maps[0].getNumDims();
892  llvm::SmallBitVector numDimsBitVector(numDims, true);
893  for (AffineMap m : maps) {
894  for (unsigned i = 0; i < numDims; ++i) {
895  if (m.isFunctionOfDim(i))
896  numDimsBitVector.reset(i);
897  }
898  }
899  return numDimsBitVector;
900 }
901 
903  unsigned numSymbols = maps[0].getNumSymbols();
904  llvm::SmallBitVector numSymbolsBitVector(numSymbols, true);
905  for (AffineMap m : maps) {
906  for (unsigned i = 0; i < numSymbols; ++i) {
907  if (m.isFunctionOfSymbol(i))
908  numSymbolsBitVector.reset(i);
909  }
910  }
911  return numSymbolsBitVector;
912 }
913 
914 AffineMap
916  const llvm::SmallBitVector &projectedDimensions) {
917  auto id = AffineMap::getMultiDimIdentityMap(rank, map.getContext());
918  AffineMap proj = id.dropResults(projectedDimensions);
919  return map.compose(proj);
920 }
921 
922 //===----------------------------------------------------------------------===//
923 // MutableAffineMap.
924 //===----------------------------------------------------------------------===//
925 
927  : results(map.getResults().begin(), map.getResults().end()),
928  numDims(map.getNumDims()), numSymbols(map.getNumSymbols()),
929  context(map.getContext()) {}
930 
932  results.clear();
933  numDims = map.getNumDims();
934  numSymbols = map.getNumSymbols();
935  context = map.getContext();
936  llvm::append_range(results, map.getResults());
937 }
938 
939 bool MutableAffineMap::isMultipleOf(unsigned idx, int64_t factor) const {
940  return results[idx].isMultipleOf(factor);
941 }
942 
943 // Simplifies the result affine expressions of this map. The expressions
944 // have to be pure for the simplification implemented.
946  // Simplify each of the results if possible.
947  // TODO: functional-style map
948  for (unsigned i = 0, e = getNumResults(); i < e; i++) {
949  results[i] = simplifyAffineExpr(getResult(i), numDims, numSymbols);
950  }
951 }
952 
954  return AffineMap::get(numDims, numSymbols, results, context);
955 }
static SmallVector< AffineMap > compressUnusedListImpl(ArrayRef< AffineMap > maps, llvm::function_ref< AffineMap(AffineMap)> compressionFun)
Implementation detail to compress multiple affine maps with a compressionFun that is expected to be e...
Definition: AffineMap.cpp:648
static SmallVector< AffineMap, 4 > inferFromExprList(ArrayRef< AffineExprContainer > exprsList, MLIRContext *context)
Creates an affine map each for each list of AffineExpr's in exprsList while inferring the right numbe...
Definition: AffineMap.cpp:281
static AffineMap projectCommonImpl(AffineMap map, const llvm::SmallBitVector &toProject, bool compress)
Common implementation to project out dimensions or symbols from an affine map based on the template t...
Definition: AffineMap.cpp:820
static MLIRContext * getContext(OpFoldResult val)
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
A dimensional identifier appearing in an affine expression.
Definition: AffineExpr.h:237
Base type for affine expression.
Definition: AffineExpr.h:69
AffineExpr replaceDimsAndSymbols(ArrayRef< AffineExpr > dimReplacements, ArrayRef< AffineExpr > symReplacements) const
This method substitutes any uses of dimensions and symbols (e.g.
Definition: AffineExpr.cpp:81
RetT walk(FnT &&callback) const
Walk all of the AffineExpr's in this expression in postorder.
Definition: AffineExpr.h:131
AffineExprKind getKind() const
Return the classification for this type.
Definition: AffineExpr.cpp:27
AffineExpr compose(AffineMap map) const
Compose with an AffineMap.
Definition: AffineExpr.cpp:994
AffineExpr replaceDims(ArrayRef< AffineExpr > dimReplacements) const
Dim-only version of replaceDimsAndSymbols.
Definition: AffineExpr.cpp:114
MLIRContext * getContext() const
Definition: AffineExpr.cpp:25
AffineExpr replaceSymbols(ArrayRef< AffineExpr > symReplacements) const
Symbol-only version of replaceDimsAndSymbols.
Definition: AffineExpr.cpp:119
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition: AffineMap.h:47
int64_t getSingleConstantResult() const
Returns the constant result of this map.
Definition: AffineMap.cpp:365
static AffineMap getMinorIdentityMap(unsigned dims, unsigned results, MLIRContext *context)
Returns an identity affine map (d0, ..., dn) -> (dp, ..., dn) on the most minor dimensions.
Definition: AffineMap.cpp:132
AffineMap dropResults(ArrayRef< int64_t > positions) const
Definition: AffineMap.h:292
AffineMap getSliceMap(unsigned start, unsigned length) const
Returns the map consisting of length expressions starting from start.
Definition: AffineMap.cpp:623
AffineMap getMajorSubMap(unsigned numResults) const
Returns the map consisting of the most major numResults results.
Definition: AffineMap.cpp:628
MLIRContext * getContext() const
Definition: AffineMap.cpp:327
bool isMinorIdentity() const
Returns true if this affine map is a minor identity, i.e.
Definition: AffineMap.cpp:152
unsigned getDimPosition(unsigned idx) const
Extracts the position of the dimensional expression at the given result, when the caller knows it is ...
Definition: AffineMap.cpp:399
bool isConstant() const
Returns true if this affine map has only constant results.
Definition: AffineMap.cpp:361
static AffineMap getMultiDimIdentityMap(unsigned numDims, MLIRContext *context)
Returns an AffineMap with 'numDims' identity result dim exprs.
Definition: AffineMap.cpp:318
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.
Definition: AffineMap.cpp:357
bool isProjectedPermutation(bool allowZeroInResults=false) const
Returns true if the AffineMap represents a subset (i.e.
Definition: AffineMap.cpp:579
AffineMap getMinorSubMap(unsigned numResults) const
Returns the map consisting of the most minor numResults results.
Definition: AffineMap.cpp:636
uint64_t getLargestKnownDivisorOfMapExprs()
Get the largest known divisor of all map expressions.
Definition: AffineMap.cpp:307
constexpr AffineMap()=default
bool isEmpty() const
Returns true if this affine map is an empty map, i.e., () -> ().
Definition: AffineMap.cpp:353
std::optional< unsigned > getResultPosition(AffineExpr input) const
Extracts the first result position where input dimension resides.
Definition: AffineMap.cpp:403
unsigned getNumSymbols() const
Definition: AffineMap.cpp:382
bool isMinorIdentityWithBroadcasting(SmallVectorImpl< unsigned > *broadcastedDims=nullptr) const
Returns true if this affine map is a minor identity up to broadcasted dimensions which are indicated ...
Definition: AffineMap.cpp:160
unsigned getNumDims() const
Definition: AffineMap.cpp:378
ArrayRef< AffineExpr > getResults() const
Definition: AffineMap.cpp:391
SmallVector< int64_t > getConstantResults() const
Returns the constant results of this map.
Definition: AffineMap.cpp:370
bool isPermutationOfMinorIdentityWithBroadcasting(SmallVectorImpl< unsigned > &permutedDims) const
Return true if this affine map can be converted to a minor identity with broadcast by doing a permute...
Definition: AffineMap.cpp:200
bool isSymbolIdentity() const
Returns true if this affine map is an identity affine map on the symbol identifiers.
Definition: AffineMap.cpp:341
unsigned getNumResults() const
Definition: AffineMap.cpp:386
AffineMap replaceDimsAndSymbols(ArrayRef< AffineExpr > dimReplacements, ArrayRef< AffineExpr > symReplacements, unsigned numResultDims, unsigned numResultSyms) const
This method substitutes any uses of dimensions and symbols (e.g.
Definition: AffineMap.cpp:484
unsigned getNumInputs() const
Definition: AffineMap.cpp:387
AffineExpr getResult(unsigned idx) const
Definition: AffineMap.cpp:395
static AffineMap getFilteredIdentityMap(MLIRContext *ctx, unsigned numDims, llvm::function_ref< bool(AffineDimExpr)> keepDimFilter)
Returns an identity affine map with numDims input dimensions and filtered results using keepDimFilter...
Definition: AffineMap.cpp:139
AffineMap replace(AffineExpr expr, AffineExpr replacement, unsigned numResultDims, unsigned numResultSyms) const
Sparse replace method.
Definition: AffineMap.cpp:499
static AffineMap getPermutationMap(ArrayRef< unsigned > permutation, MLIRContext *context)
Returns an AffineMap representing a permutation.
Definition: AffineMap.cpp:248
void walkExprs(llvm::function_ref< void(AffineExpr)> callback) const
Walk all of the AffineExpr's in this mapping.
Definition: AffineMap.cpp:474
AffineMap partialConstantFold(ArrayRef< Attribute > operandConstants, SmallVectorImpl< int64_t > *results=nullptr, bool *hasPoison=nullptr) const
Propagates the constant operands into this affine map.
Definition: AffineMap.cpp:437
static AffineMap getConstantMap(int64_t val, MLIRContext *context)
Returns a single constant result affine map.
Definition: AffineMap.cpp:125
static AffineMap getMultiDimMapWithTargets(unsigned numDims, ArrayRef< unsigned > targets, MLIRContext *context)
Returns an affine map with numDims input dimensions and results specified by targets.
Definition: AffineMap.cpp:264
AffineMap getSubMap(ArrayRef< unsigned > resultPos) const
Returns the map consisting of the resultPos subset.
Definition: AffineMap.cpp:615
LogicalResult constantFold(ArrayRef< Attribute > operandConstants, SmallVectorImpl< Attribute > &results, bool *hasPoison=nullptr) const
Folds the results of the application of an affine map on the provided operands to a constant if possi...
Definition: AffineMap.cpp:418
AffineMap compose(AffineMap map) const
Returns the AffineMap resulting from composing this with map.
Definition: AffineMap.cpp:540
bool isIdentity() const
Returns true if this affine map is an identity affine map.
Definition: AffineMap.cpp:329
bool isPermutation() const
Returns true if the AffineMap represents a symbol-less permutation map.
Definition: AffineMap.cpp:609
static SmallVector< AffineMap, 4 > inferFromExprList(ArrayRef< ArrayRef< AffineExpr >> exprsList, MLIRContext *context)
Returns a vector of AffineMaps; each with as many results as exprs.size(), as many dims as the larges...
Definition: AffineMap.cpp:296
A symbolic identifier appearing in an affine expression.
Definition: AffineExpr.h:245
Attributes are known-constant values of operations.
Definition: Attributes.h:25
This class is a general helper class for creating context-global objects like types,...
Definition: Builders.h:50
AffineExpr getAffineSymbolExpr(unsigned position)
Definition: Builders.cpp:375
AffineExpr getAffineConstantExpr(int64_t constant)
Definition: Builders.cpp:379
AffineExpr getAffineDimExpr(unsigned position)
Definition: Builders.cpp:371
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Definition: Matchers.h:285
LLVM_ATTRIBUTE_ALWAYS_INLINE MPInt gcd(const MPInt &a, const MPInt &b)
Definition: MPInt.h:399
Include the generated interface declarations.
AffineMap simplifyAffineMap(AffineMap map)
Simplifies an affine map by simplifying its underlying AffineExpr results.
Definition: AffineMap.cpp:734
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
AffineMap expandDimsToRank(AffineMap map, int64_t rank, const llvm::SmallBitVector &projectedDimensions)
Expand map to operate on rank dims while projecting out the dims in projectedDimensions.
Definition: AffineMap.cpp:915
AffineMap removeDuplicateExprs(AffineMap map)
Returns a map with the same dimension and symbol count as map, but whose results are the unique affin...
Definition: AffineMap.cpp:744
llvm::SmallBitVector getUnusedSymbolsBitVector(ArrayRef< AffineMap > maps)
Definition: AffineMap.cpp:902
AffineMap inverseAndBroadcastProjectedPermutation(AffineMap map)
Return the reverse map of a projected permutation where the projected dimensions are transformed into...
Definition: AffineMap.cpp:777
int64_t floorDiv(int64_t lhs, int64_t rhs)
Returns the result of MLIR's floordiv operation on constants.
Definition: MathExtras.h:33
int64_t ceilDiv(int64_t lhs, int64_t rhs)
Returns the result of MLIR's ceildiv operation on constants.
Definition: MathExtras.h:23
AffineMap inversePermutation(AffineMap map)
Returns a map of codomain to domain dimensions such that the first codomain dimension for a particula...
Definition: AffineMap.cpp:753
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
AffineMap concatAffineMaps(ArrayRef< AffineMap > maps)
Concatenates a list of maps into a single AffineMap, stepping over potentially empty maps.
Definition: AffineMap.cpp:798
@ CeilDiv
RHS of ceildiv is always a constant or a symbolic expression.
@ Mul
RHS of mul is always a constant or a symbolic expression.
@ Mod
RHS of mod is always a constant or a symbolic expression with a positive value.
@ DimId
Dimensional identifier.
@ FloorDiv
RHS of floordiv is always a constant or a symbolic expression.
@ Constant
Constant integer.
@ SymbolId
Symbolic identifier.
AffineMap compressSymbols(AffineMap map, const llvm::SmallBitVector &unusedSymbols)
Drop the symbols that are listed in unusedSymbols.
Definition: AffineMap.cpp:692
static void getMaxDimAndSymbol(ArrayRef< AffineExprContainer > exprsList, int64_t &maxDim, int64_t &maxSym)
Calculates maximum dimension and symbol positions from the expressions in exprsLists and stores them ...
Definition: AffineMap.h:672
AffineMap compressUnusedDims(AffineMap map)
Drop the dims that are not used.
Definition: AffineMap.cpp:683
AffineMap compressDims(AffineMap map, const llvm::SmallBitVector &unusedDims)
Drop the dims that are listed in unusedDims.
Definition: AffineMap.cpp:678
AffineExpr getAffineConstantExpr(int64_t constant, MLIRContext *context)
Definition: AffineExpr.cpp:623
AffineMap getProjectedMap(AffineMap map, const llvm::SmallBitVector &projectedDimensions, bool compressDimsFlag=true, bool compressSymbolsFlag=true)
Calls projectDims(map, projectedDimensions, compressDimsFlag).
Definition: AffineMap.cpp:880
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
llvm::SmallBitVector getUnusedDimsBitVector(ArrayRef< AffineMap > maps)
Definition: AffineMap.cpp:890
AffineExpr simplifyAffineExpr(AffineExpr expr, unsigned numDims, unsigned numSymbols)
Simplify an affine expression by flattening and some amount of simple analysis.
AffineExpr getAffineDimExpr(unsigned position, MLIRContext *context)
These free functions allow clients of the API to not use classes in detail.
Definition: AffineExpr.cpp:599
AffineMap projectDims(AffineMap map, const llvm::SmallBitVector &projectedDimensions, bool compressDimsFlag=false)
Returns the map that results from projecting out the dimensions specified in projectedDimensions.
Definition: AffineMap.cpp:866
AffineMap compressUnusedSymbols(AffineMap map)
Drop the symbols that are not used.
Definition: AffineMap.cpp:697
AffineMap projectSymbols(AffineMap map, const llvm::SmallBitVector &projectedSymbols, bool compressSymbolsFlag=false)
Symbol counterpart of projectDims.
Definition: AffineMap.cpp:873
AffineMap foldAttributesIntoMap(Builder &b, AffineMap map, ArrayRef< OpFoldResult > operands, SmallVector< Value > &remainingValues)
Fold all attributes among the given operands into the affine map.
Definition: AffineMap.cpp:706
AffineExpr getAffineSymbolExpr(unsigned position, MLIRContext *context)
Definition: AffineExpr.cpp:609
int64_t mod(int64_t lhs, int64_t rhs)
Returns MLIR's mod operation on constants.
Definition: MathExtras.h:45
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
void reset(AffineMap map)
Resets this MutableAffineMap with 'map'.
Definition: AffineMap.cpp:931
AffineMap getAffineMap() const
Get the AffineMap corresponding to this MutableAffineMap.
Definition: AffineMap.cpp:953
AffineExpr getResult(unsigned idx) const
Definition: AffineMap.h:411
bool isMultipleOf(unsigned idx, int64_t factor) const
Returns true if the idx'th result expression is a multiple of factor.
Definition: AffineMap.cpp:939
unsigned getNumResults() const
Definition: AffineMap.h:413
void simplify()
Simplify the (result) expressions in this map using analysis (used by.
Definition: AffineMap.cpp:945
ArrayRef< AffineExpr > results() const
The affine expressions for this (multi-dimensional) map.