MLIR 24.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
26namespace llvm {
27class SmallBitVector;
28} // namespace llvm
29
30namespace mlir {
31
32namespace detail {
33struct AffineMapStorage;
34} // namespace detail
35
36class Attribute;
37class Builder;
38class OpFoldResult;
39class 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.
46class AffineMap {
47public:
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,
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);
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.
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#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
202 LLVM_DUMP_METHOD void dump() const;
203#endif
204
205 unsigned getNumDims() const;
206 unsigned getNumSymbols() const;
207 unsigned getNumResults() const;
208 unsigned getNumInputs() const;
209
211 AffineExpr getResult(unsigned idx) const;
212
213 /// Extracts the position of the dimensional expression at the given result,
214 /// when the caller knows it is safe to do so.
215 unsigned getDimPosition(unsigned idx) const;
216
217 /// Extracts the first result position where `input` dimension resides.
218 /// Returns `std::nullopt` if `input` is not a dimension expression or cannot
219 /// be found in results.
220 std::optional<unsigned> getResultPosition(AffineExpr input) const;
221
222 /// Return true if any affine expression involves AffineDimExpr `position`.
223 bool isFunctionOfDim(unsigned position) const {
224 return llvm::any_of(getResults(), [&](AffineExpr e) {
225 return e.isFunctionOfDim(position);
226 });
227 }
228
229 /// Return true if any affine expression involves AffineSymbolExpr `position`.
230 bool isFunctionOfSymbol(unsigned position) const {
231 return llvm::any_of(getResults(), [&](AffineExpr e) {
232 return e.isFunctionOfSymbol(position);
233 });
234 }
235
236 /// Walk all of the AffineExpr's in this mapping. Each node in an expression
237 /// tree is visited in postorder.
238 void walkExprs(llvm::function_ref<void(AffineExpr)> callback) const;
239
240 /// This method substitutes any uses of dimensions and symbols (e.g.
241 /// dim#0 with dimReplacements[0]) in subexpressions and returns the modified
242 /// expression mapping. Because this can be used to eliminate dims and
243 /// symbols, the client needs to specify the number of dims and symbols in
244 /// the result. The returned map always has the same number of results.
246 ArrayRef<AffineExpr> symReplacements,
247 unsigned numResultDims,
248 unsigned numResultSyms) const;
249
250 /// Sparse replace method. Apply AffineExpr::replace(`expr`, `replacement`) to
251 /// each of the results and return a new AffineMap with the new results and
252 /// with the specified number of dims and symbols.
254 unsigned numResultDims, unsigned numResultSyms) const;
255
256 /// Sparse replace method. Apply AffineExpr::replace(`map`) to each of the
257 /// results and return a new AffineMap with the new results and with inferred
258 /// number of dims and symbols.
260
261 /// Sparse replace method. Apply AffineExpr::replace(`map`) to each of the
262 /// results and return a new AffineMap with the new results and with the
263 /// specified number of dims and symbols.
265 unsigned numResultDims, unsigned numResultSyms) const;
266
267 /// Replace dims[offset ... numDims)
268 /// by dims[offset + shift ... shift + numDims).
269 AffineMap shiftDims(unsigned shift, unsigned offset = 0) const {
270 assert(offset <= getNumDims());
271 return AffineMap::get(getNumDims() + shift, getNumSymbols(),
272 llvm::map_to_vector<4>(
273 getResults(),
274 [&](AffineExpr e) {
275 return e.shiftDims(getNumDims(), shift, offset);
276 }),
277 getContext());
278 }
279
280 /// Replace symbols[offset ... numSymbols)
281 /// by symbols[offset + shift ... shift + numSymbols).
282 AffineMap shiftSymbols(unsigned shift, unsigned offset = 0) const {
283 return AffineMap::get(getNumDims(), getNumSymbols() + shift,
284 llvm::map_to_vector<4>(getResults(),
285 [&](AffineExpr e) {
286 return e.shiftSymbols(
287 getNumSymbols(), shift,
288 offset);
289 }),
290 getContext());
291 }
292
293 /// Returns a new AffineMap with the same number of dims and symbols and one
294 /// less result at `pos`, dropped.
296 return dropResults(ArrayRef({pos}));
297 }
298
299 // Returns a new AffineMap with the same number of dims and symbols, but all
300 // results in `positions` dropped.
302 SmallVector<int64_t> reverse_sorted_positions = llvm::to_vector(positions);
303 llvm::sort(reverse_sorted_positions, std::greater<int64_t>());
304
305 auto exprs = llvm::to_vector<4>(getResults());
306 for (int64_t pos : reverse_sorted_positions)
307 exprs.erase(exprs.begin() + pos);
308 return AffineMap::get(getNumDims(), getNumSymbols(), exprs, getContext());
309 }
310
311 // Returns a new AffineMap with the same number of dims and symbols, but all
312 // results in `positions` dropped.
313 AffineMap dropResults(const llvm::SmallBitVector &positions) const;
314
315 /// Returns a new AffineMap with the same number of dims and symbols and an
316 /// extra result inserted at `pos`.
317 AffineMap insertResult(AffineExpr expr, unsigned pos) const {
318 auto exprs = llvm::to_vector<4>(getResults());
319 exprs.insert(exprs.begin() + pos, expr);
320 return AffineMap::get(getNumDims(), getNumSymbols(), exprs, getContext());
321 }
322
323 /// Folds the results of the application of an affine map on the provided
324 /// operands to a constant if possible.
325 LogicalResult constantFold(ArrayRef<Attribute> operandConstants,
327 bool *hasPoison = nullptr) const;
328
329 /// Propagates the constant operands into this affine map. Operands are
330 /// allowed to be null, at which point they are treated as non-constant. This
331 /// does not change the number of symbols and dimensions. Returns a new map,
332 /// which may be equal to the old map if no folding happened. If `results` is
333 /// provided and if all expressions in the map were folded to constants,
334 /// `results` will contain the values of these constants.
336 SmallVectorImpl<int64_t> *results = nullptr,
337 bool *hasPoison = nullptr) const;
338
339 /// Returns the AffineMap resulting from composing `this` with `map`.
340 /// The resulting AffineMap has as many AffineDimExpr as `map` and as many
341 /// AffineSymbolExpr as the concatenation of `this` and `map` (in which case
342 /// the symbols of `this` map come first).
343 ///
344 /// Prerequisites:
345 /// The maps are composable, i.e. that the number of AffineDimExpr of `this`
346 /// matches the number of results of `map`.
347 ///
348 /// Example:
349 /// map1: `(d0, d1)[s0, s1] -> (d0 + 1 + s1, d1 - 1 - s0)`
350 /// map2: `(d0)[s0] -> (d0 + s0, d0 - s0)`
351 /// map1.compose(map2):
352 /// `(d0)[s0, s1, s2] -> (d0 + s1 + s2 + 1, d0 - s0 - s2 - 1)`
353 AffineMap compose(AffineMap map) const;
354
355 /// Applies composition by the dims of `this` to the integer `values` and
356 /// returns the resulting values. `this` must be symbol-less.
358
359 /// Returns the number of "zero" results (constant values == 0) in this map.
360 ///
361 /// Example:
362 /// * For `(d0, d1) -> (d0, d1, 0)` returns 1
363 /// * For `(d0, d1, d2) -> (d0, d1)` returns 0
364 /// * For `(d0, d1, d2) -> (d0, 0, d1, 0, d2)` returns 2
365 size_t getNumOfZeroResults() const;
366
367 /// Returns the AffineMap resulting from removing "zero" results (constant
368 /// values == 0) from this map.
369 ///
370 /// Example:
371 /// * For `(d0, d1) -> (d0, d1, 0)` returns `(d0, d1) -> (d0, d1)`
372 /// * For `(d0, d1, d2) -> (d0, d1)` returns `(d0, d1, d2) -> (d0, d1)`
373 /// * For `(d0, d1, d2) -> (d0, 0, d1, 0, d2)` returns
374 /// `(d0, d1, d2) -> (d0, d1, d2)`
376
377 /// Returns true if the AffineMap represents a subset (i.e. a projection) of a
378 /// symbol-less permutation map. `allowZeroInResults` allows projected
379 /// permutation maps with constant zero result expressions.
380 /// TODO: Remove `allowZeroInResults` when constant zero result expressions
381 /// are broadly supported.
382 bool isProjectedPermutation(bool allowZeroInResults = false) const;
383
384 /// Returns true if the AffineMap represents a symbol-less permutation map.
385 bool isPermutation() const;
386
387 /// Returns the map consisting of the `resultPos` subset.
388 AffineMap getSubMap(ArrayRef<unsigned> resultPos) const;
389
390 /// Returns the map consisting of `length` expressions starting from `start`.
391 AffineMap getSliceMap(unsigned start, unsigned length) const;
392
393 /// Returns the map consisting of the most major `numResults` results.
394 /// Returns the null AffineMap if `numResults` == 0.
395 /// Returns `*this` if `numResults` >= `this->getNumResults()`.
396 AffineMap getMajorSubMap(unsigned numResults) const;
397
398 /// Returns the map consisting of the most minor `numResults` results.
399 /// Returns the null AffineMap if `numResults` == 0.
400 /// Returns `*this` if `numResults` >= `this->getNumResults()`.
401 AffineMap getMinorSubMap(unsigned numResults) const;
402
403 /// Get the largest known divisor of all map expressions.
404 /// For eg: for (d0, d1) -> (8*d0 + 4, 4*d1 + 2), the result is 2.
405 /// In the case of maps with no expressions or all zero constant expressions,
406 /// the largest known divisor is trivially the max uint64_t value.
408
409 friend ::llvm::hash_code hash_value(AffineMap arg);
410
411 /// Methods supporting C API.
412 const void *getAsOpaquePointer() const {
413 return static_cast<const void *>(map);
414 }
415 static AffineMap getFromOpaquePointer(const void *pointer) {
416 return AffineMap(reinterpret_cast<ImplType *>(const_cast<void *>(pointer)));
417 }
418
419private:
420 ImplType *map{nullptr};
421
422 static AffineMap getImpl(unsigned dimCount, unsigned symbolCount,
423 ArrayRef<AffineExpr> results, MLIRContext *context);
424};
425
426// Make AffineExpr hashable.
427inline ::llvm::hash_code hash_value(AffineMap arg) {
428 return ::llvm::hash_value(arg.map);
429}
430
431/// A mutable affine map. Its affine expressions are however unique.
433public:
434 MutableAffineMap() = default;
436
437 ArrayRef<AffineExpr> getResults() const { return results; }
438 AffineExpr getResult(unsigned idx) const { return results[idx]; }
439 void setResult(unsigned idx, AffineExpr result) { results[idx] = result; }
440 unsigned getNumResults() const { return results.size(); }
441 unsigned getNumDims() const { return numDims; }
442 void setNumDims(unsigned d) { numDims = d; }
443 unsigned getNumSymbols() const { return numSymbols; }
444 void setNumSymbols(unsigned d) { numSymbols = d; }
445 MLIRContext *getContext() const { return context; }
446
447 /// Returns true if the idx'th result expression is a multiple of factor.
448 bool isMultipleOf(unsigned idx, int64_t factor) const;
449
450 /// Resets this MutableAffineMap with 'map'.
451 void reset(AffineMap map);
452
453 /// Simplify the (result) expressions in this map using analysis (used by
454 //-simplify-affine-expr pass).
455 void simplify();
456 /// Get the AffineMap corresponding to this MutableAffineMap. Note that an
457 /// AffineMap will be uniqued and stored in context, while a mutable one
458 /// isn't.
459 AffineMap getAffineMap() const;
460
461private:
462 // Same meaning as AffineMap's fields.
464 unsigned numDims = 0;
465 unsigned numSymbols = 0;
466 /// A pointer to the IR's context to store all newly created
467 /// AffineExprStorage's.
468 MLIRContext *context = nullptr;
469};
470
471/// Simplifies an affine map by simplifying its underlying AffineExpr results.
472AffineMap simplifyAffineMap(AffineMap map);
473
474/// Drop the dims that are listed in `unusedDims`.
475AffineMap compressDims(AffineMap map, const llvm::SmallBitVector &unusedDims);
476
477/// Drop the dims that are not used.
478AffineMap compressUnusedDims(AffineMap map);
479
480/// Drop the dims that are not used by any of the individual maps in `maps`.
481/// Asserts that all maps in `maps` are normalized to the same number of
482/// dims and symbols.
483SmallVector<AffineMap> compressUnusedDims(ArrayRef<AffineMap> maps);
484
485/// Drop the symbols that are listed in `unusedSymbols`.
486AffineMap compressSymbols(AffineMap map,
487 const llvm::SmallBitVector &unusedSymbols);
488
489/// Drop the symbols that are not used.
490AffineMap compressUnusedSymbols(AffineMap map);
491
492/// Drop the symbols that are not used by any of the individual maps in `maps`.
493/// Asserts that all maps in `maps` are normalized to the same number of
494/// dims and symbols.
495SmallVector<AffineMap> compressUnusedSymbols(ArrayRef<AffineMap> maps);
496
497/// Fold all attributes among the given operands into the affine map. Return the
498/// folded affine map. Return all remaining values via `remainingValues`.
499AffineMap foldAttributesIntoMap(Builder &b, AffineMap map,
500 ArrayRef<OpFoldResult> operands,
501 SmallVector<Value> &remainingValues);
502
503/// Returns a map with the same dimension and symbol count as `map`, but whose
504/// results are the unique affine expressions of `map`.
505AffineMap removeDuplicateExprs(AffineMap map);
506
507/// Returns a map of codomain to domain dimensions such that the first codomain
508/// dimension for a particular domain dimension is selected.
509/// Returns an empty map if the input map is empty.
510/// Returns null map (not empty map) if `map` is not invertible (i.e. `map` does
511/// not contain a subset that is a permutation of full domain rank).
512///
513/// Prerequisites:
514/// 1. `map` has no symbols.
515///
516/// Example 1:
517///
518/// ```mlir
519/// (d0, d1, d2) -> (d1, d1, d0, d2, d1, d2, d1, d0)
520/// 0 2 3
521/// ```
522///
523/// returns:
524///
525/// ```mlir
526/// (d0, d1, d2, d3, d4, d5, d6, d7) -> (d2, d0, d3)
527/// ```
528///
529/// Example 2:
530///
531/// ```mlir
532/// (d0, d1, d2) -> (d1, d0 + d1, d0, d2, d1, d2, d1, d0)
533/// 0 2 3
534/// ```
535///
536/// returns:
537///
538/// ```mlir
539/// (d0, d1, d2, d3, d4, d5, d6, d7) -> (d2, d0, d3)
540/// ```
541AffineMap inversePermutation(AffineMap map);
542
543/// Return the reverse map of a projected permutation where the projected
544/// dimensions are transformed into 0s.
545///
546/// Prerequisites: `map` must be a projected permutation.
547///
548/// Example 1:
549///
550/// ```mlir
551/// affine_map<(d0, d1, d2, d3) -> (d2, d0)>
552/// ```
553///
554/// returns:
555///
556/// ```mlir
557/// affine_map<(d0, d1) -> (d1, 0, d0, 0)>
558/// ```
559///
560/// Example 2:
561///
562/// ```mlir
563/// affine_map<(d0, d1, d2, d3) -> (d0, d3)>
564/// ```
565///
566/// returns:
567///
568/// ```mlir
569/// affine_map<(d0, d1) -> (d0, 0, 0, d1)>
570/// ```
571///
572/// Example 3:
573///
574/// ```mlir
575/// affine_map<(d0, d1, d2, d3) -> (d2)>
576/// ```
577///
578/// returns:
579///
580/// ```mlir
581/// affine_map<(d0) -> (0, 0, d0, 0)>
582/// ```
583/// Example 4:
584///
585/// ```mlir
586/// affine_map<(d0, d1, d2) -> (d0, 0)>
587/// ```
588///
589/// returns:
590///
591/// ```mlir
592/// affine_map<(d0, d1) -> (d0, 0, 0)>
593/// ```
594AffineMap inverseAndBroadcastProjectedPermutation(AffineMap map);
595
596/// Concatenates a list of `maps` into a single AffineMap, stepping over
597/// potentially empty maps. Assumes each of the underlying map has 0 symbols.
598/// The resulting map has a number of dims equal to the max of `maps`' dims and
599/// the concatenated results as its results.
600/// Returns an empty map if all input `maps` are empty.
601///
602/// Example:
603/// When applied to the following list of 3 affine maps,
604///
605/// ```mlir
606/// {
607/// (i, j, k) -> (i, k),
608/// (i, j, k) -> (k, j),
609/// (i, j, k) -> (i, j)
610/// }
611/// ```
612///
613/// Returns the map:
614///
615/// ```mlir
616/// (i, j, k) -> (i, k, k, j, i, j)
617/// ```
618AffineMap concatAffineMaps(ArrayRef<AffineMap> maps, MLIRContext *context);
619
620/// Returns the map that results from projecting out the dimensions specified in
621/// `projectedDimensions`. The projected dimensions are set to 0.
622///
623/// Example:
624/// 1) map : affine_map<(d0, d1, d2) -> (d0, d1)>
625/// projected_dimensions : {2}
626/// result : affine_map<(d0, d1) -> (d0, d1)>
627///
628/// 2) map : affine_map<(d0, d1) -> (d0 + d1)>
629/// projected_dimensions : {1}
630/// result : affine_map<(d0) -> (d0)>
631///
632/// 3) map : affine_map<(d0, d1, d2) -> (d0, d1)>
633/// projected_dimensions : {1}
634/// result : affine_map<(d0, d1) -> (d0, 0)>
635///
636/// This function also compresses the dims when the boolean flag is true.
637AffineMap projectDims(AffineMap map,
638 const llvm::SmallBitVector &projectedDimensions,
639 bool compressDimsFlag = false);
640/// Symbol counterpart of `projectDims`.
641/// This function also compresses the symbols when the boolean flag is true.
642AffineMap projectSymbols(AffineMap map,
643 const llvm::SmallBitVector &projectedSymbols,
644 bool compressSymbolsFlag = false);
645/// Calls `projectDims(map, projectedDimensions, compressDimsFlag)`.
646/// If `compressSymbolsFlag` is true, additionally call `compressUnusedSymbols`.
647AffineMap getProjectedMap(AffineMap map,
648 const llvm::SmallBitVector &projectedDimensions,
649 bool compressDimsFlag = true,
650 bool compressSymbolsFlag = true);
651
652// Return a bitvector where each bit set indicates a dimension that is not used
653// by any of the maps in the input array `maps`.
654llvm::SmallBitVector getUnusedDimsBitVector(ArrayRef<AffineMap> maps);
655
656// Return a bitvector where each bit set indicates a symbol that is not used
657// by any of the maps in the input array `maps`.
658llvm::SmallBitVector getUnusedSymbolsBitVector(ArrayRef<AffineMap> maps);
659
660/// Expand `map` to operate on `rank` dims while projecting out the dims in
661/// `projectedDimensions`. This amounts to composing `map` with
662/// `id(rank).dropResults(projectedDimensions)`.
663AffineMap expandDimsToRank(AffineMap map, int64_t rank,
664 const llvm::SmallBitVector &projectedDimensions);
665
667 map.print(os);
668 return os;
669}
670
671//===----------------------------------------------------------------------===//
672// Templated helper functions.
673//===----------------------------------------------------------------------===//
674
675/// Apply a permutation from `map` to `source` and return the result.
676template <typename T>
678 assert(map.isProjectedPermutation());
679 assert(map.getNumInputs() == source.size());
681 result.reserve(map.getNumResults());
682 for (AffineExpr expr : map.getResults()) {
683 if (auto dimExpr = dyn_cast<AffineDimExpr>(expr)) {
684 result.push_back(source[dimExpr.getPosition()]);
685 } else if (auto constExpr = dyn_cast<AffineConstantExpr>(expr)) {
686 assert(constExpr.getValue() == 0 &&
687 "Unexpected constant in projected permutation map");
688 result.push_back(0);
689 } else {
690 llvm_unreachable("Unexpected result in projected permutation map");
691 }
692 }
693 return result;
694}
695
696/// Calculates maximum dimension and symbol positions from the expressions
697/// in `exprsLists` and stores them in `maxDim` and `maxSym` respectively.
698template <typename AffineExprContainer>
700 int64_t &maxDim, int64_t &maxSym) {
701 for (const auto &exprs : exprsList) {
702 for (auto expr : exprs) {
703 expr.walk([&maxDim, &maxSym](AffineExpr e) {
704 if (auto d = dyn_cast<AffineDimExpr>(e))
705 maxDim = std::max(maxDim, static_cast<int64_t>(d.getPosition()));
706 if (auto s = dyn_cast<AffineSymbolExpr>(e))
707 maxSym = std::max(maxSym, static_cast<int64_t>(s.getPosition()));
708 });
709 }
710 }
711}
712
713} // namespace mlir
714
715namespace llvm {
716
717// AffineExpr hash just like pointers
718template <>
719struct DenseMapInfo<mlir::AffineMap> {
720 static unsigned getHashValue(mlir::AffineMap val) {
721 return mlir::hash_value(val);
722 }
724 return LHS == RHS;
725 }
726};
727
728} // namespace llvm
729
730#endif // MLIR_IR_AFFINEMAP_H
b
Return true if permutation is a valid permutation of the outer_dims_perm (case OuterOrInnerPerm::Oute...
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be the output argument nBegin is set to its * replacement(set to `begin` if no invalidation happens). Since outgoing *copies could have been inserted at `end`
A dimensional identifier appearing in an affine expression.
Definition AffineExpr.h:225
Base type for affine expression.
Definition AffineExpr.h:68
AffineExpr shiftDims(unsigned numDims, unsigned shift, unsigned offset=0) const
Replace dims[offset ... numDims) by dims[offset + shift ... shift + numDims).
AffineExpr shiftSymbols(unsigned numSymbols, unsigned shift, unsigned offset=0) const
Replace symbols[offset ... numSymbols) by symbols[offset + shift ... shift + numSymbols).
bool isFunctionOfDim(unsigned position) const
Return true if the affine expression involves AffineDimExpr position.
bool isFunctionOfSymbol(unsigned position) const
Return true if the affine expression involves AffineSymbolExpr position.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition AffineMap.h:46
int64_t getSingleConstantResult() const
Returns the constant result of this map.
static AffineMap getMinorIdentityMap(unsigned dims, unsigned results, MLIRContext *context)
Returns an identity affine map (d0, ..., dn) -> (dp, ..., dn) on the most minor dimensions.
AffineMap dropResults(ArrayRef< int64_t > positions) const
Definition AffineMap.h:301
AffineMap getSliceMap(unsigned start, unsigned length) const
Returns the map consisting of length expressions starting from start.
AffineMap getMajorSubMap(unsigned numResults) const
Returns the map consisting of the most major numResults results.
MLIRContext * getContext() const
bool isFunctionOfDim(unsigned position) const
Return true if any affine expression involves AffineDimExpr position.
Definition AffineMap.h:223
bool isMinorIdentity() const
Returns true if this affine map is a minor identity, i.e.
unsigned getDimPosition(unsigned idx) const
Extracts the position of the dimensional expression at the given result, when the caller knows it is ...
bool isConstant() const
Returns true if this affine map has only constant results.
static AffineMap getMultiDimIdentityMap(unsigned numDims, MLIRContext *context)
Returns an AffineMap with 'numDims' identity result dim exprs.
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 ... numDims) by dims[offset + shift ... shift + numDims).
Definition AffineMap.h:269
bool isSingleConstant() const
Returns true if this affine map is a single result constant function.
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:317
const void * getAsOpaquePointer() const
Methods supporting C API.
Definition AffineMap.h:412
bool isProjectedPermutation(bool allowZeroInResults=false) const
Returns true if the AffineMap represents a subset (i.e.
AffineMap getMinorSubMap(unsigned numResults) const
Returns the map consisting of the most minor numResults results.
detail::AffineMapStorage ImplType
Definition AffineMap.h:48
uint64_t getLargestKnownDivisorOfMapExprs()
Get the largest known divisor of all map expressions.
constexpr AffineMap()=default
bool isEmpty() const
Returns true if this affine map is an empty map, i.e., () -> ().
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:295
AffineMap(ImplType *map)
Definition AffineMap.h:51
std::optional< unsigned > getResultPosition(AffineExpr input) const
Extracts the first result position where input dimension resides.
bool operator==(AffineMap other) const
Definition AffineMap.h:133
unsigned getNumSymbols() const
bool isMinorIdentityWithBroadcasting(SmallVectorImpl< unsigned > *broadcastedDims=nullptr) const
Returns true if this affine map is a minor identity up to broadcasted dimensions which are indicated ...
unsigned getNumDims() const
ArrayRef< AffineExpr > getResults() const
SmallVector< int64_t > getConstantResults() const
Returns the constant results of this map.
bool isFunctionOfSymbol(unsigned position) const
Return true if any affine expression involves AffineSymbolExpr position.
Definition AffineMap.h:230
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...
size_t getNumOfZeroResults() const
Returns the number of "zero" results (constant values == 0) in this map.
bool isSymbolIdentity() const
Returns true if this affine map is an identity affine map on the symbol identifiers.
unsigned getNumResults() const
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...
AffineMap replaceDimsAndSymbols(ArrayRef< AffineExpr > dimReplacements, ArrayRef< AffineExpr > symReplacements, unsigned numResultDims, unsigned numResultSyms) const
This method substitutes any uses of dimensions and symbols (e.g.
unsigned getNumInputs() const
AffineMap shiftSymbols(unsigned shift, unsigned offset=0) const
Replace symbols[offset ... numSymbols) by symbols[offset + shift ... shift + numSymbols).
Definition AffineMap.h:282
static AffineMap getFromOpaquePointer(const void *pointer)
Definition AffineMap.h:415
AffineExpr getResult(unsigned idx) const
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...
AffineMap replace(AffineExpr expr, AffineExpr replacement, unsigned numResultDims, unsigned numResultSyms) const
Sparse replace method.
AffineMap dropZeroResults()
Returns the AffineMap resulting from removing "zero" results (constant values == 0) from this map.
LLVM_DUMP_METHOD void dump() const
static AffineMap getPermutationMap(ArrayRef< unsigned > permutation, MLIRContext *context)
Returns an AffineMap representing a permutation.
friend::llvm::hash_code hash_value(AffineMap arg)
SmallVector< unsigned > getBroadcastDims() const
Returns the list of broadcast dimensions (i.e.
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.
AffineMap partialConstantFold(ArrayRef< Attribute > operandConstants, SmallVectorImpl< int64_t > *results=nullptr, bool *hasPoison=nullptr) const
Propagates the constant operands into this affine map.
static AffineMap getConstantMap(int64_t val, MLIRContext *context)
Returns a single constant result affine map.
static AffineMap getMultiDimMapWithTargets(unsigned numDims, ArrayRef< unsigned > targets, MLIRContext *context)
Returns an affine map with numDims input dimensions and results specified by targets.
AffineMap getSubMap(ArrayRef< unsigned > resultPos) const
Returns the map consisting of the resultPos subset.
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...
void print(raw_ostream &os) const
AffineMap compose(AffineMap map) const
Returns the AffineMap resulting from composing this with map.
bool isIdentity() const
Returns true if this affine map is an identity affine map.
bool isPermutation() const
Returns true if the AffineMap represents a symbol-less permutation map.
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:51
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:71
This class represents a single result from folding an operation.
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Definition CallGraph.h:229
AttrTypeReplacer.
Include the generated interface declarations.
AffineMap simplifyAffineMap(AffineMap map)
Simplifies an affine map by simplifying its underlying AffineExpr results.
AffineMap concatAffineMaps(ArrayRef< AffineMap > maps, MLIRContext *context)
Concatenates a list of maps into a single AffineMap, stepping over potentially empty maps.
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.
AffineMap removeDuplicateExprs(AffineMap map)
Returns a map with the same dimension and symbol count as map, but whose results are the unique affin...
llvm::SmallBitVector getUnusedSymbolsBitVector(ArrayRef< AffineMap > maps)
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
AffineMap inverseAndBroadcastProjectedPermutation(AffineMap map)
Return the reverse map of a projected permutation where the projected dimensions are transformed into...
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:699
AffineMap inversePermutation(AffineMap map)
Returns a map of codomain to domain dimensions such that the first codomain dimension for a particula...
AffineMap compressSymbols(AffineMap map, const llvm::SmallBitVector &unusedSymbols)
Drop the symbols that are listed in unusedSymbols.
AffineMap compressUnusedDims(AffineMap map)
Drop the dims that are not used.
AffineMap compressDims(AffineMap map, const llvm::SmallBitVector &unusedDims)
Drop the dims that are listed in unusedDims.
AffineMap getProjectedMap(AffineMap map, const llvm::SmallBitVector &projectedDimensions, bool compressDimsFlag=true, bool compressSymbolsFlag=true)
Calls projectDims(map, projectedDimensions, compressDimsFlag).
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
Definition LLVM.h:123
SmallVector< T > applyPermutationMap(AffineMap map, llvm::ArrayRef< T > source)
Apply a permutation from map to source and return the result.
Definition AffineMap.h:677
llvm::SmallBitVector getUnusedDimsBitVector(ArrayRef< AffineMap > maps)
inline ::llvm::hash_code hash_value(AffineExpr arg)
Make AffineExpr hashable.
Definition AffineExpr.h:249
AffineMap projectDims(AffineMap map, const llvm::SmallBitVector &projectedDimensions, bool compressDimsFlag=false)
Returns the map that results from projecting out the dimensions specified in projectedDimensions.
AffineMap compressUnusedSymbols(AffineMap map)
Drop the symbols that are not used.
AffineMap projectSymbols(AffineMap map, const llvm::SmallBitVector &projectedSymbols, bool compressSymbolsFlag=false)
Symbol counterpart of projectDims.
AffineMap foldAttributesIntoMap(Builder &b, AffineMap map, ArrayRef< OpFoldResult > operands, SmallVector< Value > &remainingValues)
Fold all attributes among the given operands into the affine map.
static unsigned getHashValue(mlir::AffineMap val)
Definition AffineMap.h:720
static bool isEqual(mlir::AffineMap LHS, mlir::AffineMap RHS)
Definition AffineMap.h:723
void setNumDims(unsigned d)
Definition AffineMap.h:442
void reset(AffineMap map)
Resets this MutableAffineMap with 'map'.
MLIRContext * getContext() const
Definition AffineMap.h:445
void setResult(unsigned idx, AffineExpr result)
Definition AffineMap.h:439
AffineMap getAffineMap() const
Get the AffineMap corresponding to this MutableAffineMap.
void setNumSymbols(unsigned d)
Definition AffineMap.h:444
AffineExpr getResult(unsigned idx) const
Definition AffineMap.h:438
unsigned getNumSymbols() const
Definition AffineMap.h:443
bool isMultipleOf(unsigned idx, int64_t factor) const
Returns true if the idx'th result expression is a multiple of factor.
ArrayRef< AffineExpr > getResults() const
Definition AffineMap.h:437
unsigned getNumResults() const
Definition AffineMap.h:440
unsigned getNumDims() const
Definition AffineMap.h:441
void simplify()
Simplify the (result) expressions in this map using analysis (used by.