MLIR  20.0.0git
AffineMap.h
Go to the documentation of this file.
1 //===- AffineMap.h - MLIR Affine Map Class ----------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Affine maps are mathematical functions which map a list of dimension
10 // identifiers and symbols, to multidimensional affine expressions.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef MLIR_IR_AFFINEMAP_H
15 #define MLIR_IR_AFFINEMAP_H
16 
17 #include "mlir/IR/AffineExpr.h"
18 #include "mlir/IR/Value.h"
19 #include "mlir/Support/LLVM.h"
20 #include "llvm/ADT/ArrayRef.h"
21 #include "llvm/ADT/DenseMapInfo.h"
22 #include "llvm/ADT/SmallBitVector.h"
23 #include "llvm/ADT/SmallVectorExtras.h"
24 #include <optional>
25 
26 namespace llvm {
27 class SmallBitVector;
28 } // namespace llvm
29 
30 namespace mlir {
31 
32 namespace detail {
33 struct AffineMapStorage;
34 } // namespace detail
35 
36 class Attribute;
37 class Builder;
38 class OpFoldResult;
39 class MLIRContext;
40 
41 /// A multi-dimensional affine map
42 /// Affine map's are immutable like Type's, and they are uniqued.
43 /// Eg: (d0, d1) -> (d0/128, d0 mod 128, d1)
44 /// The names used (d0, d1) don't matter - it's the mathematical function that
45 /// is unique to this affine map.
46 class AffineMap {
47 public:
49 
50  constexpr AffineMap() = default;
51  explicit AffineMap(ImplType *map) : map(map) {}
52 
53  /// Returns a zero result affine map with no dimensions or symbols: () -> ().
54  static AffineMap get(MLIRContext *context);
55 
56  /// Returns a zero result affine map with `dimCount` dimensions and
57  /// `symbolCount` symbols, e.g.: `(...) -> ()`.
58  static AffineMap get(unsigned dimCount, unsigned symbolCount,
59  MLIRContext *context);
60 
61  /// Returns an affine map with `dimCount` dimensions and `symbolCount` mapping
62  /// to a single output dimension
63  static AffineMap get(unsigned dimCount, unsigned symbolCount,
64  AffineExpr result);
65 
66  /// Returns an affine map with `dimCount` dimensions and `symbolCount` mapping
67  /// to the given results.
68  static AffineMap get(unsigned dimCount, unsigned symbolCount,
69  ArrayRef<AffineExpr> results, MLIRContext *context);
70 
71  /// Returns a single constant result affine map.
72  static AffineMap getConstantMap(int64_t val, MLIRContext *context);
73 
74  /// Returns an AffineMap with 'numDims' identity result dim exprs.
75  static AffineMap getMultiDimIdentityMap(unsigned numDims,
76  MLIRContext *context);
77 
78  /// Returns an identity affine map (d0, ..., dn) -> (dp, ..., dn) on the most
79  /// minor dimensions.
80  static AffineMap getMinorIdentityMap(unsigned dims, unsigned results,
81  MLIRContext *context);
82 
83  /// Returns an identity affine map with `numDims` input dimensions and
84  /// filtered results using `keepDimFilter`. If `keepDimFilter` returns true
85  /// for a dimension, the dimension is kept in the affine map results.
86  /// Otherwise, the dimension is dropped from the results.
87  ///
88  /// Examples:
89  /// * getFilteredIdentityMap(4, [false, true, false, true])
90  /// -> affine_map<(d0, d1, d2, d3) -> (d1, d3)>
91  /// * getFilteredIdentityMap(3, [false, false, true])
92  /// -> affine_map<(d0, d1, d2) -> (d2)>
93  static AffineMap
94  getFilteredIdentityMap(MLIRContext *ctx, unsigned numDims,
95  llvm::function_ref<bool(AffineDimExpr)> keepDimFilter);
96 
97  /// Returns an AffineMap representing a permutation.
98  /// The permutation is expressed as a non-empty vector of integers.
99  /// E.g. the permutation `(i,j,k) -> (j,k,i)` will be expressed with
100  /// `permutation = [1,2,0]`. All values in `permutation` must be
101  /// integers, in the range 0..`permutation.size()-1` without duplications
102  /// (i.e. `[1,1,2]` is an invalid permutation).
104  MLIRContext *context);
105  static AffineMap getPermutationMap(ArrayRef<int64_t> permutation,
106  MLIRContext *context);
107 
108  /// Returns an affine map with `numDims` input dimensions and results
109  /// specified by `targets`.
110  ///
111  /// Examples:
112  /// * getMultiDimMapWithTargets(3, [0, 2, 1])
113  /// -> affine_map<(d0, d1, d2) -> (d0, d2, d1)>
114  /// * getMultiDimMapWithTargets(3, [2, 1])
115  /// -> affine_map<(d0, d1, d2) -> (d2, d1)>
116  static AffineMap getMultiDimMapWithTargets(unsigned numDims,
117  ArrayRef<unsigned> targets,
118  MLIRContext *context);
119 
120  /// Returns a vector of AffineMaps; each with as many results as
121  /// `exprs.size()`, as many dims as the largest dim in `exprs` and as many
122  /// symbols as the largest symbol in `exprs`.
125  MLIRContext *context);
128  MLIRContext *context);
129 
130  MLIRContext *getContext() const;
131 
132  explicit operator bool() const { return map != nullptr; }
133  bool operator==(AffineMap other) const { return other.map == map; }
134  bool operator!=(AffineMap other) const { return !(other.map == map); }
135 
136  /// Returns true if this affine map is an identity affine map.
137  /// An identity affine map corresponds to an identity affine function on the
138  /// dimensional identifiers.
139  bool isIdentity() const;
140 
141  /// Returns true if this affine map is an identity affine map on the symbol
142  /// identifiers.
143  bool isSymbolIdentity() const;
144 
145  /// Returns true if this affine map is a minor identity, i.e. an identity
146  /// affine map (d0, ..., dn) -> (dp, ..., dn) on the most minor dimensions.
147  bool isMinorIdentity() const;
148 
149  /// Returns the list of broadcast dimensions (i.e. dims indicated by value 0
150  /// in the result).
151  /// Ex:
152  /// * (d0, d1, d2) -> (0, d1) gives [0]
153  /// * (d0, d1, d2) -> (d2, d1) gives []
154  /// * (d0, d1, d2, d4) -> (d0, 0, d1, 0) gives [1, 3]
156 
157  /// Returns true if this affine map is a minor identity up to broadcasted
158  /// dimensions which are indicated by value 0 in the result. If
159  /// `broadcastedDims` is not null, it will be populated with the indices of
160  /// the broadcasted dimensions in the result array.
161  /// Example: affine_map<(d0, d1, d2, d3, d4) -> (0, d2, 0, d4)>
162  /// (`broadcastedDims` will contain [0, 2])
164  SmallVectorImpl<unsigned> *broadcastedDims = nullptr) const;
165 
166  /// Return true if this affine map can be converted to a minor identity with
167  /// broadcast by doing a permute. Return a permutation (there may be
168  /// several) to apply to get to a minor identity with broadcasts.
169  /// Ex:
170  /// * (d0, d1, d2) -> (0, d1) maps to minor identity (d1, 0 = d2) with
171  /// perm = [1, 0] and broadcast d2
172  /// * (d0, d1, d2) -> (d0, 0) cannot be mapped to a minor identity by
173  /// permutation + broadcast
174  /// * (d0, d1, d2, d3) -> (0, d1, d3) maps to minor identity (d1, 0 = d2, d3)
175  /// with perm = [1, 0, 2] and broadcast d2
176  /// * (d0, d1) -> (d1, 0, 0, d0) maps to minor identity (d0, d1) with extra
177  /// leading broadcat dimensions. The map returned would be (0, 0, d0, d1)
178  /// with perm = [3, 0, 1, 2]
180  SmallVectorImpl<unsigned> &permutedDims) const;
181 
182  /// Returns true if this affine map is an empty map, i.e., () -> ().
183  bool isEmpty() const;
184 
185  /// Returns true if this affine map is a single result constant function.
186  bool isSingleConstant() const;
187 
188  /// Returns true if this affine map has only constant results.
189  bool isConstant() const;
190 
191  /// Returns the constant result of this map. This methods asserts that the map
192  /// has a single constant result.
193  int64_t getSingleConstantResult() const;
194 
195  /// Returns the constant results of this map. This method asserts that the map
196  /// has all constant results.
198 
199  // Prints affine map to 'os'.
200  void print(raw_ostream &os) const;
201  void dump() const;
202 
203  unsigned getNumDims() const;
204  unsigned getNumSymbols() const;
205  unsigned getNumResults() const;
206  unsigned getNumInputs() const;
207 
209  AffineExpr getResult(unsigned idx) const;
210 
211  /// Extracts the position of the dimensional expression at the given result,
212  /// when the caller knows it is safe to do so.
213  unsigned getDimPosition(unsigned idx) const;
214 
215  /// Extracts the first result position where `input` dimension resides.
216  /// Returns `std::nullopt` if `input` is not a dimension expression or cannot
217  /// be found in results.
218  std::optional<unsigned> getResultPosition(AffineExpr input) const;
219 
220  /// Return true if any affine expression involves AffineDimExpr `position`.
221  bool isFunctionOfDim(unsigned position) const {
222  return llvm::any_of(getResults(), [&](AffineExpr e) {
223  return e.isFunctionOfDim(position);
224  });
225  }
226 
227  /// Return true if any affine expression involves AffineSymbolExpr `position`.
228  bool isFunctionOfSymbol(unsigned position) const {
229  return llvm::any_of(getResults(), [&](AffineExpr e) {
230  return e.isFunctionOfSymbol(position);
231  });
232  }
233 
234  /// Walk all of the AffineExpr's in this mapping. Each node in an expression
235  /// tree is visited in postorder.
236  void walkExprs(llvm::function_ref<void(AffineExpr)> callback) const;
237 
238  /// This method substitutes any uses of dimensions and symbols (e.g.
239  /// dim#0 with dimReplacements[0]) in subexpressions and returns the modified
240  /// expression mapping. Because this can be used to eliminate dims and
241  /// symbols, the client needs to specify the number of dims and symbols in
242  /// the result. The returned map always has the same number of results.
244  ArrayRef<AffineExpr> symReplacements,
245  unsigned numResultDims,
246  unsigned numResultSyms) const;
247 
248  /// Sparse replace method. Apply AffineExpr::replace(`expr`, `replacement`) to
249  /// each of the results and return a new AffineMap with the new results and
250  /// with the specified number of dims and symbols.
251  AffineMap replace(AffineExpr expr, AffineExpr replacement,
252  unsigned numResultDims, unsigned numResultSyms) const;
253 
254  /// Sparse replace method. Apply AffineExpr::replace(`map`) to each of the
255  /// results and return a new AffineMap with the new results and with inferred
256  /// number of dims and symbols.
258 
259  /// Sparse replace method. Apply AffineExpr::replace(`map`) to each of the
260  /// results and return a new AffineMap with the new results and with the
261  /// specified number of dims and symbols.
263  unsigned numResultDims, unsigned numResultSyms) const;
264 
265  /// Replace dims[offset ... numDims)
266  /// by dims[offset + shift ... shift + numDims).
267  AffineMap shiftDims(unsigned shift, unsigned offset = 0) const {
268  assert(offset <= getNumDims());
269  return AffineMap::get(getNumDims() + shift, getNumSymbols(),
270  llvm::map_to_vector<4>(
271  getResults(),
272  [&](AffineExpr e) {
273  return e.shiftDims(getNumDims(), shift, offset);
274  }),
275  getContext());
276  }
277 
278  /// Replace symbols[offset ... numSymbols)
279  /// by symbols[offset + shift ... shift + numSymbols).
280  AffineMap shiftSymbols(unsigned shift, unsigned offset = 0) const {
281  return AffineMap::get(getNumDims(), getNumSymbols() + shift,
282  llvm::map_to_vector<4>(getResults(),
283  [&](AffineExpr e) {
284  return e.shiftSymbols(
285  getNumSymbols(), shift,
286  offset);
287  }),
288  getContext());
289  }
290 
291  /// Returns a new AffineMap with the same number of dims and symbols and one
292  /// less result at `pos`, dropped.
293  AffineMap dropResult(int64_t pos) const {
294  return dropResults(ArrayRef({pos}));
295  }
296 
297  // Returns a new AffineMap with the same number of dims and symbols, but all
298  // results in `positions` dropped.
300  SmallVector<int64_t> reverse_sorted_positions = llvm::to_vector(positions);
301  llvm::sort(reverse_sorted_positions, std::greater<int64_t>());
302 
303  auto exprs = llvm::to_vector<4>(getResults());
304  for (int64_t pos : reverse_sorted_positions)
305  exprs.erase(exprs.begin() + pos);
306  return AffineMap::get(getNumDims(), getNumSymbols(), exprs, getContext());
307  }
308 
309  // Returns a new AffineMap with the same number of dims and symbols, but all
310  // results in `positions` dropped.
311  AffineMap dropResults(const llvm::SmallBitVector &positions) const;
312 
313  /// Returns a new AffineMap with the same number of dims and symbols and an
314  /// extra result inserted at `pos`.
315  AffineMap insertResult(AffineExpr expr, unsigned pos) const {
316  auto exprs = llvm::to_vector<4>(getResults());
317  exprs.insert(exprs.begin() + pos, expr);
318  return AffineMap::get(getNumDims(), getNumSymbols(), exprs, getContext());
319  }
320 
321  /// Folds the results of the application of an affine map on the provided
322  /// operands to a constant if possible.
323  LogicalResult constantFold(ArrayRef<Attribute> operandConstants,
325  bool *hasPoison = nullptr) const;
326 
327  /// Propagates the constant operands into this affine map. Operands are
328  /// allowed to be null, at which point they are treated as non-constant. This
329  /// does not change the number of symbols and dimensions. Returns a new map,
330  /// which may be equal to the old map if no folding happened. If `results` is
331  /// provided and if all expressions in the map were folded to constants,
332  /// `results` will contain the values of these constants.
334  SmallVectorImpl<int64_t> *results = nullptr,
335  bool *hasPoison = nullptr) const;
336 
337  /// Returns the AffineMap resulting from composing `this` with `map`.
338  /// The resulting AffineMap has as many AffineDimExpr as `map` and as many
339  /// AffineSymbolExpr as the concatenation of `this` and `map` (in which case
340  /// the symbols of `this` map come first).
341  ///
342  /// Prerequisites:
343  /// The maps are composable, i.e. that the number of AffineDimExpr of `this`
344  /// matches the number of results of `map`.
345  ///
346  /// Example:
347  /// map1: `(d0, d1)[s0, s1] -> (d0 + 1 + s1, d1 - 1 - s0)`
348  /// map2: `(d0)[s0] -> (d0 + s0, d0 - s0)`
349  /// map1.compose(map2):
350  /// `(d0)[s0, s1, s2] -> (d0 + s1 + s2 + 1, d0 - s0 - s2 - 1)`
351  AffineMap compose(AffineMap map) const;
352 
353  /// Applies composition by the dims of `this` to the integer `values` and
354  /// returns the resulting values. `this` must be symbol-less.
356 
357  /// Returns true if the AffineMap represents a subset (i.e. a projection) of a
358  /// symbol-less permutation map. `allowZeroInResults` allows projected
359  /// permutation maps with constant zero result expressions.
360  /// TODO: Remove `allowZeroInResults` when constant zero result expressions
361  /// are broadly supported.
362  bool isProjectedPermutation(bool allowZeroInResults = false) const;
363 
364  /// Returns true if the AffineMap represents a symbol-less permutation map.
365  bool isPermutation() const;
366 
367  /// Returns the map consisting of the `resultPos` subset.
368  AffineMap getSubMap(ArrayRef<unsigned> resultPos) const;
369 
370  /// Returns the map consisting of `length` expressions starting from `start`.
371  AffineMap getSliceMap(unsigned start, unsigned length) const;
372 
373  /// Returns the map consisting of the most major `numResults` results.
374  /// Returns the null AffineMap if `numResults` == 0.
375  /// Returns `*this` if `numResults` >= `this->getNumResults()`.
376  AffineMap getMajorSubMap(unsigned numResults) const;
377 
378  /// Returns the map consisting of the most minor `numResults` results.
379  /// Returns the null AffineMap if `numResults` == 0.
380  /// Returns `*this` if `numResults` >= `this->getNumResults()`.
381  AffineMap getMinorSubMap(unsigned numResults) const;
382 
383  /// Get the largest known divisor of all map expressions.
384  /// For eg: for (d0, d1) -> (8*d0 + 4, 4*d1 + 2), the result is 2.
385  /// In the case of maps with no expressions or all zero constant expressions,
386  /// the largest known divisor is trivially the max uint64_t value.
388 
389  friend ::llvm::hash_code hash_value(AffineMap arg);
390 
391  /// Methods supporting C API.
392  const void *getAsOpaquePointer() const {
393  return static_cast<const void *>(map);
394  }
395  static AffineMap getFromOpaquePointer(const void *pointer) {
396  return AffineMap(reinterpret_cast<ImplType *>(const_cast<void *>(pointer)));
397  }
398 
399 private:
400  ImplType *map{nullptr};
401 
402  static AffineMap getImpl(unsigned dimCount, unsigned symbolCount,
403  ArrayRef<AffineExpr> results, MLIRContext *context);
404 };
405 
406 // Make AffineExpr hashable.
407 inline ::llvm::hash_code hash_value(AffineMap arg) {
408  return ::llvm::hash_value(arg.map);
409 }
410 
411 /// A mutable affine map. Its affine expressions are however unique.
413 public:
414  MutableAffineMap() = default;
416 
417  ArrayRef<AffineExpr> getResults() const { return results; }
418  AffineExpr getResult(unsigned idx) const { return results[idx]; }
419  void setResult(unsigned idx, AffineExpr result) { results[idx] = result; }
420  unsigned getNumResults() const { return results.size(); }
421  unsigned getNumDims() const { return numDims; }
422  void setNumDims(unsigned d) { numDims = d; }
423  unsigned getNumSymbols() const { return numSymbols; }
424  void setNumSymbols(unsigned d) { numSymbols = d; }
425  MLIRContext *getContext() const { return context; }
426 
427  /// Returns true if the idx'th result expression is a multiple of factor.
428  bool isMultipleOf(unsigned idx, int64_t factor) const;
429 
430  /// Resets this MutableAffineMap with 'map'.
431  void reset(AffineMap map);
432 
433  /// Simplify the (result) expressions in this map using analysis (used by
434  //-simplify-affine-expr pass).
435  void simplify();
436  /// Get the AffineMap corresponding to this MutableAffineMap. Note that an
437  /// AffineMap will be uniqued and stored in context, while a mutable one
438  /// isn't.
439  AffineMap getAffineMap() const;
440 
441 private:
442  // Same meaning as AffineMap's fields.
444  unsigned numDims = 0;
445  unsigned numSymbols = 0;
446  /// A pointer to the IR's context to store all newly created
447  /// AffineExprStorage's.
448  MLIRContext *context = nullptr;
449 };
450 
451 /// Simplifies an affine map by simplifying its underlying AffineExpr results.
452 AffineMap simplifyAffineMap(AffineMap map);
453 
454 /// Drop the dims that are listed in `unusedDims`.
455 AffineMap compressDims(AffineMap map, const llvm::SmallBitVector &unusedDims);
456 
457 /// Drop the dims that are not used.
458 AffineMap compressUnusedDims(AffineMap map);
459 
460 /// Drop the dims that are not used by any of the individual maps in `maps`.
461 /// Asserts that all maps in `maps` are normalized to the same number of
462 /// dims and symbols.
463 SmallVector<AffineMap> compressUnusedDims(ArrayRef<AffineMap> maps);
464 
465 /// Drop the symbols that are listed in `unusedSymbols`.
466 AffineMap compressSymbols(AffineMap map,
467  const llvm::SmallBitVector &unusedSymbols);
468 
469 /// Drop the symbols that are not used.
470 AffineMap compressUnusedSymbols(AffineMap map);
471 
472 /// Drop the symbols that are not used by any of the individual maps in `maps`.
473 /// Asserts that all maps in `maps` are normalized to the same number of
474 /// dims and symbols.
475 SmallVector<AffineMap> compressUnusedSymbols(ArrayRef<AffineMap> maps);
476 
477 /// Fold all attributes among the given operands into the affine map. Return the
478 /// folded affine map. Return all remaining values via `remainingValues`.
479 AffineMap foldAttributesIntoMap(Builder &b, AffineMap map,
480  ArrayRef<OpFoldResult> operands,
481  SmallVector<Value> &remainingValues);
482 
483 /// Returns a map with the same dimension and symbol count as `map`, but whose
484 /// results are the unique affine expressions of `map`.
485 AffineMap removeDuplicateExprs(AffineMap map);
486 
487 /// Returns a map of codomain to domain dimensions such that the first codomain
488 /// dimension for a particular domain dimension is selected.
489 /// Returns an empty map if the input map is empty.
490 /// Returns null map (not empty map) if `map` is not invertible (i.e. `map` does
491 /// not contain a subset that is a permutation of full domain rank).
492 ///
493 /// Prerequisites:
494 /// 1. `map` has no symbols.
495 ///
496 /// Example 1:
497 ///
498 /// ```mlir
499 /// (d0, d1, d2) -> (d1, d1, d0, d2, d1, d2, d1, d0)
500 /// 0 2 3
501 /// ```
502 ///
503 /// returns:
504 ///
505 /// ```mlir
506 /// (d0, d1, d2, d3, d4, d5, d6, d7) -> (d2, d0, d3)
507 /// ```
508 ///
509 /// Example 2:
510 ///
511 /// ```mlir
512 /// (d0, d1, d2) -> (d1, d0 + d1, d0, d2, d1, d2, d1, d0)
513 /// 0 2 3
514 /// ```
515 ///
516 /// returns:
517 ///
518 /// ```mlir
519 /// (d0, d1, d2, d3, d4, d5, d6, d7) -> (d2, d0, d3)
520 /// ```
521 AffineMap inversePermutation(AffineMap map);
522 
523 /// Return the reverse map of a projected permutation where the projected
524 /// dimensions are transformed into 0s.
525 ///
526 /// Prerequisites: `map` must be a projected permutation.
527 ///
528 /// Example 1:
529 ///
530 /// ```mlir
531 /// affine_map<(d0, d1, d2, d3) -> (d2, d0)>
532 /// ```
533 ///
534 /// returns:
535 ///
536 /// ```mlir
537 /// affine_map<(d0, d1) -> (d1, 0, d0, 0)>
538 /// ```
539 ///
540 /// Example 2:
541 ///
542 /// ```mlir
543 /// affine_map<(d0, d1, d2, d3) -> (d0, d3)>
544 /// ```
545 ///
546 /// returns:
547 ///
548 /// ```mlir
549 /// affine_map<(d0, d1) -> (d0, 0, 0, d1)>
550 /// ```
551 ///
552 /// Example 3:
553 ///
554 /// ```mlir
555 /// affine_map<(d0, d1, d2, d3) -> (d2)>
556 /// ```
557 ///
558 /// returns:
559 ///
560 /// ```mlir
561 /// affine_map<(d0) -> (0, 0, d0, 0)>
562 /// ```
563 /// Example 4:
564 ///
565 /// ```mlir
566 /// affine_map<(d0, d1, d2) -> (d0, 0)>
567 /// ```
568 ///
569 /// returns:
570 ///
571 /// ```mlir
572 /// affine_map<(d0, d1) -> (d0, 0, 0)>
573 /// ```
574 AffineMap inverseAndBroadcastProjectedPermutation(AffineMap map);
575 
576 /// Concatenates a list of `maps` into a single AffineMap, stepping over
577 /// potentially empty maps. Assumes each of the underlying map has 0 symbols.
578 /// The resulting map has a number of dims equal to the max of `maps`' dims and
579 /// the concatenated results as its results.
580 /// Returns an empty map if all input `maps` are empty.
581 ///
582 /// Example:
583 /// When applied to the following list of 3 affine maps,
584 ///
585 /// ```mlir
586 /// {
587 /// (i, j, k) -> (i, k),
588 /// (i, j, k) -> (k, j),
589 /// (i, j, k) -> (i, j)
590 /// }
591 /// ```
592 ///
593 /// Returns the map:
594 ///
595 /// ```mlir
596 /// (i, j, k) -> (i, k, k, j, i, j)
597 /// ```
598 AffineMap concatAffineMaps(ArrayRef<AffineMap> maps);
599 
600 /// Returns the map that results from projecting out the dimensions specified in
601 /// `projectedDimensions`. The projected dimensions are set to 0.
602 ///
603 /// Example:
604 /// 1) map : affine_map<(d0, d1, d2) -> (d0, d1)>
605 /// projected_dimensions : {2}
606 /// result : affine_map<(d0, d1) -> (d0, d1)>
607 ///
608 /// 2) map : affine_map<(d0, d1) -> (d0 + d1)>
609 /// projected_dimensions : {1}
610 /// result : affine_map<(d0) -> (d0)>
611 ///
612 /// 3) map : affine_map<(d0, d1, d2) -> (d0, d1)>
613 /// projected_dimensions : {1}
614 /// result : affine_map<(d0, d1) -> (d0, 0)>
615 ///
616 /// This function also compresses the dims when the boolean flag is true.
617 AffineMap projectDims(AffineMap map,
618  const llvm::SmallBitVector &projectedDimensions,
619  bool compressDimsFlag = false);
620 /// Symbol counterpart of `projectDims`.
621 /// This function also compresses the symbols when the boolean flag is true.
622 AffineMap projectSymbols(AffineMap map,
623  const llvm::SmallBitVector &projectedSymbols,
624  bool compressSymbolsFlag = false);
625 /// Calls `projectDims(map, projectedDimensions, compressDimsFlag)`.
626 /// If `compressSymbolsFlag` is true, additionally call `compressUnusedSymbols`.
627 AffineMap getProjectedMap(AffineMap map,
628  const llvm::SmallBitVector &projectedDimensions,
629  bool compressDimsFlag = true,
630  bool compressSymbolsFlag = true);
631 
632 // Return a bitvector where each bit set indicates a dimension that is not used
633 // by any of the maps in the input array `maps`.
634 llvm::SmallBitVector getUnusedDimsBitVector(ArrayRef<AffineMap> maps);
635 
636 // Return a bitvector where each bit set indicates a symbol that is not used
637 // by any of the maps in the input array `maps`.
638 llvm::SmallBitVector getUnusedSymbolsBitVector(ArrayRef<AffineMap> maps);
639 
640 /// Expand `map` to operate on `rank` dims while projecting out the dims in
641 /// `projectedDimensions`. This amounts to composing `map` with
642 /// `id(rank).dropResults(projectedDimensions)`.
643 AffineMap expandDimsToRank(AffineMap map, int64_t rank,
644  const llvm::SmallBitVector &projectedDimensions);
645 
646 inline raw_ostream &operator<<(raw_ostream &os, AffineMap map) {
647  map.print(os);
648  return os;
649 }
650 
651 //===----------------------------------------------------------------------===//
652 // Templated helper functions.
653 //===----------------------------------------------------------------------===//
654 
655 /// Apply a permutation from `map` to `source` and return the result.
656 template <typename T>
658  assert(map.isProjectedPermutation());
659  assert(map.getNumInputs() == source.size());
660  SmallVector<T> result;
661  result.reserve(map.getNumResults());
662  for (AffineExpr expr : map.getResults()) {
663  if (auto dimExpr = dyn_cast<AffineDimExpr>(expr)) {
664  result.push_back(source[dimExpr.getPosition()]);
665  } else if (auto constExpr = dyn_cast<AffineConstantExpr>(expr)) {
666  assert(constExpr.getValue() == 0 &&
667  "Unexpected constant in projected permutation map");
668  result.push_back(0);
669  } else {
670  llvm_unreachable("Unexpected result in projected permutation map");
671  }
672  }
673  return result;
674 }
675 
676 /// Calculates maximum dimension and symbol positions from the expressions
677 /// in `exprsLists` and stores them in `maxDim` and `maxSym` respectively.
678 template <typename AffineExprContainer>
680  int64_t &maxDim, int64_t &maxSym) {
681  for (const auto &exprs : exprsList) {
682  for (auto expr : exprs) {
683  expr.walk([&maxDim, &maxSym](AffineExpr e) {
684  if (auto d = dyn_cast<AffineDimExpr>(e))
685  maxDim = std::max(maxDim, static_cast<int64_t>(d.getPosition()));
686  if (auto s = dyn_cast<AffineSymbolExpr>(e))
687  maxSym = std::max(maxSym, static_cast<int64_t>(s.getPosition()));
688  });
689  }
690  }
691 }
692 
693 } // namespace mlir
694 
695 namespace llvm {
696 
697 // AffineExpr hash just like pointers
698 template <>
699 struct DenseMapInfo<mlir::AffineMap> {
701  auto *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
702  return mlir::AffineMap(static_cast<mlir::AffineMap::ImplType *>(pointer));
703  }
706  return mlir::AffineMap(static_cast<mlir::AffineMap::ImplType *>(pointer));
707  }
708  static unsigned getHashValue(mlir::AffineMap val) {
709  return mlir::hash_value(val);
710  }
711  static bool isEqual(mlir::AffineMap LHS, mlir::AffineMap RHS) {
712  return LHS == RHS;
713  }
714 };
715 
716 } // namespace llvm
717 
718 #endif // MLIR_IR_AFFINEMAP_H
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
A dimensional identifier appearing in an affine expression.
Definition: AffineExpr.h:236
Base type for affine expression.
Definition: AffineExpr.h:68
AffineExpr shiftDims(unsigned numDims, unsigned shift, unsigned offset=0) const
Replace dims[offset ...
Definition: AffineExpr.cpp:133
AffineExpr shiftSymbols(unsigned numSymbols, unsigned shift, unsigned offset=0) const
Replace symbols[offset ...
Definition: AffineExpr.cpp:145
bool isFunctionOfDim(unsigned position) const
Return true if the affine expression involves AffineDimExpr position.
Definition: AffineExpr.cpp:316
bool isFunctionOfSymbol(unsigned position) const
Return true if the affine expression involves AffineSymbolExpr position.
Definition: AffineExpr.cpp:327
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition: AffineMap.h:46
int64_t getSingleConstantResult() const
Returns the constant result of this map.
Definition: AffineMap.cpp:381
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:135
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:639
AffineMap getMajorSubMap(unsigned numResults) const
Returns the map consisting of the most major numResults results.
Definition: AffineMap.cpp:644
MLIRContext * getContext() const
Definition: AffineMap.cpp:343
friend ::llvm::hash_code hash_value(AffineMap arg)
Definition: AffineMap.h:407
bool isFunctionOfDim(unsigned position) const
Return true if any affine expression involves AffineDimExpr position.
Definition: AffineMap.h:221
bool isMinorIdentity() const
Returns true if this affine map is a minor identity, i.e.
Definition: AffineMap.cpp:155
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:415
bool isConstant() const
Returns true if this affine map has only constant results.
Definition: AffineMap.cpp:377
static AffineMap getMultiDimIdentityMap(unsigned numDims, MLIRContext *context)
Returns an AffineMap with 'numDims' identity result dim exprs.
Definition: AffineMap.cpp:334
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
AffineMap shiftDims(unsigned shift, unsigned offset=0) const
Replace dims[offset ...
Definition: AffineMap.h:267
bool isSingleConstant() const
Returns true if this affine map is a single result constant function.
Definition: AffineMap.cpp:373
AffineMap insertResult(AffineExpr expr, unsigned pos) const
Returns a new AffineMap with the same number of dims and symbols and an extra result inserted at pos.
Definition: AffineMap.h:315
bool isProjectedPermutation(bool allowZeroInResults=false) const
Returns true if the AffineMap represents a subset (i.e.
Definition: AffineMap.cpp:595
AffineMap getMinorSubMap(unsigned numResults) const
Returns the map consisting of the most minor numResults results.
Definition: AffineMap.cpp:652
detail::AffineMapStorage ImplType
Definition: AffineMap.h:48
uint64_t getLargestKnownDivisorOfMapExprs()
Get the largest known divisor of all map expressions.
Definition: AffineMap.cpp:323
constexpr AffineMap()=default
bool isEmpty() const
Returns true if this affine map is an empty map, i.e., () -> ().
Definition: AffineMap.cpp:369
AffineMap dropResult(int64_t pos) const
Returns a new AffineMap with the same number of dims and symbols and one less result at pos,...
Definition: AffineMap.h:293
AffineMap(ImplType *map)
Definition: AffineMap.h:51
std::optional< unsigned > getResultPosition(AffineExpr input) const
Extracts the first result position where input dimension resides.
Definition: AffineMap.cpp:419
bool operator==(AffineMap other) const
Definition: AffineMap.h:133
unsigned getNumSymbols() const
Definition: AffineMap.cpp:398
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:176
unsigned getNumDims() const
Definition: AffineMap.cpp:394
ArrayRef< AffineExpr > getResults() const
Definition: AffineMap.cpp:407
SmallVector< int64_t > getConstantResults() const
Returns the constant results of this map.
Definition: AffineMap.cpp:386
bool isFunctionOfSymbol(unsigned position) const
Return true if any affine expression involves AffineSymbolExpr position.
Definition: AffineMap.h:228
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:216
bool isSymbolIdentity() const
Returns true if this affine map is an identity affine map on the symbol identifiers.
Definition: AffineMap.cpp:357
unsigned getNumResults() const
Definition: AffineMap.cpp:402
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:500
unsigned getNumInputs() const
Definition: AffineMap.cpp:403
AffineMap shiftSymbols(unsigned shift, unsigned offset=0) const
Replace symbols[offset ...
Definition: AffineMap.h:280
static AffineMap getFromOpaquePointer(const void *pointer)
Definition: AffineMap.h:395
const void * getAsOpaquePointer() const
Methods supporting C API.
Definition: AffineMap.h:392
AffineExpr getResult(unsigned idx) const
Definition: AffineMap.cpp:411
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:142
AffineMap replace(AffineExpr expr, AffineExpr replacement, unsigned numResultDims, unsigned numResultSyms) const
Sparse replace method.
Definition: AffineMap.cpp:515
void dump() const
static AffineMap getPermutationMap(ArrayRef< unsigned > permutation, MLIRContext *context)
Returns an AffineMap representing a permutation.
Definition: AffineMap.cpp:264
SmallVector< unsigned > getBroadcastDims() const
Returns the list of broadcast dimensions (i.e.
Definition: AffineMap.cpp:161
bool operator!=(AffineMap other) const
Definition: AffineMap.h:134
void walkExprs(llvm::function_ref< void(AffineExpr)> callback) const
Walk all of the AffineExpr's in this mapping.
Definition: AffineMap.cpp:490
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:453
static AffineMap getConstantMap(int64_t val, MLIRContext *context)
Returns a single constant result affine map.
Definition: AffineMap.cpp:128
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:280
AffineMap getSubMap(ArrayRef< unsigned > resultPos) const
Returns the map consisting of the resultPos subset.
Definition: AffineMap.cpp:631
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:434
void print(raw_ostream &os) const
AffineMap compose(AffineMap map) const
Returns the AffineMap resulting from composing this with map.
Definition: AffineMap.cpp:556
bool isIdentity() const
Returns true if this affine map is an identity affine map.
Definition: AffineMap.cpp:345
bool isPermutation() const
Returns true if the AffineMap represents a symbol-less permutation map.
Definition: AffineMap.cpp:625
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:312
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
Include the generated interface declarations.
Definition: CallGraph.h:229
Include the generated interface declarations.
AffineMap simplifyAffineMap(AffineMap map)
Simplifies an affine map by simplifying its underlying AffineExpr results.
Definition: AffineMap.cpp:750
inline ::llvm::hash_code hash_value(AffineMap arg)
Definition: AffineMap.h:407
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:930
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:760
llvm::SmallBitVector getUnusedSymbolsBitVector(ArrayRef< AffineMap > maps)
Definition: AffineMap.cpp:917
SmallVector< T > applyPermutationMap(AffineMap map, llvm::ArrayRef< T > source)
Apply a permutation from map to source and return the result.
Definition: AffineMap.h:657
AffineMap inverseAndBroadcastProjectedPermutation(AffineMap map)
Return the reverse map of a projected permutation where the projected dimensions are transformed into...
Definition: AffineMap.cpp:792
AffineMap inversePermutation(AffineMap map)
Returns a map of codomain to domain dimensions such that the first codomain dimension for a particula...
Definition: AffineMap.cpp:768
AffineMap concatAffineMaps(ArrayRef< AffineMap > maps)
Concatenates a list of maps into a single AffineMap, stepping over potentially empty maps.
Definition: AffineMap.cpp:813
AffineMap compressSymbols(AffineMap map, const llvm::SmallBitVector &unusedSymbols)
Drop the symbols that are listed in unusedSymbols.
Definition: AffineMap.cpp:708
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:679
AffineMap compressUnusedDims(AffineMap map)
Drop the dims that are not used.
Definition: AffineMap.cpp:699
AffineMap compressDims(AffineMap map, const llvm::SmallBitVector &unusedDims)
Drop the dims that are listed in unusedDims.
Definition: AffineMap.cpp:694
AffineMap getProjectedMap(AffineMap map, const llvm::SmallBitVector &projectedDimensions, bool compressDimsFlag=true, bool compressSymbolsFlag=true)
Calls projectDims(map, projectedDimensions, compressDimsFlag).
Definition: AffineMap.cpp:895
llvm::SmallBitVector getUnusedDimsBitVector(ArrayRef< AffineMap > maps)
Definition: AffineMap.cpp:905
inline ::llvm::hash_code hash_value(AffineExpr arg)
Make AffineExpr hashable.
Definition: AffineExpr.h:260
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:881
AffineMap compressUnusedSymbols(AffineMap map)
Drop the symbols that are not used.
Definition: AffineMap.cpp:713
AffineMap projectSymbols(AffineMap map, const llvm::SmallBitVector &projectedSymbols, bool compressSymbolsFlag=false)
Symbol counterpart of projectDims.
Definition: AffineMap.cpp:888
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:722
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
Definition: AliasAnalysis.h:78
static unsigned getHashValue(mlir::AffineMap val)
Definition: AffineMap.h:708
static mlir::AffineMap getEmptyKey()
Definition: AffineMap.h:700
static bool isEqual(mlir::AffineMap LHS, mlir::AffineMap RHS)
Definition: AffineMap.h:711
static mlir::AffineMap getTombstoneKey()
Definition: AffineMap.h:704
A mutable affine map. Its affine expressions are however unique.
Definition: AffineMap.h:412
void setNumDims(unsigned d)
Definition: AffineMap.h:422
void reset(AffineMap map)
Resets this MutableAffineMap with 'map'.
Definition: AffineMap.cpp:946
void setResult(unsigned idx, AffineExpr result)
Definition: AffineMap.h:419
AffineMap getAffineMap() const
Get the AffineMap corresponding to this MutableAffineMap.
Definition: AffineMap.cpp:968
void setNumSymbols(unsigned d)
Definition: AffineMap.h:424
AffineExpr getResult(unsigned idx) const
Definition: AffineMap.h:418
unsigned getNumSymbols() const
Definition: AffineMap.h:423
ArrayRef< AffineExpr > getResults() const
Definition: AffineMap.h:417
bool isMultipleOf(unsigned idx, int64_t factor) const
Returns true if the idx'th result expression is a multiple of factor.
Definition: AffineMap.cpp:954
MLIRContext * getContext() const
Definition: AffineMap.h:425
unsigned getNumResults() const
Definition: AffineMap.h:420
unsigned getNumDims() const
Definition: AffineMap.h:421
void simplify()
Simplify the (result) expressions in this map using analysis (used by.
Definition: AffineMap.cpp:960