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