MLIR 22.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 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.
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.
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 the number of "zero" results (constant values == 0) in this map.
358 ///
359 /// Example:
360 /// * For `(d0, d1) -> (d0, d1, 0)` returns 1
361 /// * For `(d0, d1, d2) -> (d0, d1)` returns 0
362 /// * For `(d0, d1, d2) -> (d0, 0, d1, 0, d2)` returns 2
363 size_t getNumOfZeroResults() const;
364
365 /// Returns the AffineMap resulting from removing "zero" results (constant
366 /// values == 0) from this map.
367 ///
368 /// Example:
369 /// * For `(d0, d1) -> (d0, d1, 0)` returns `(d0, d1) -> (d0, d1)`
370 /// * For `(d0, d1, d2) -> (d0, d1)` returns `(d0, d1, d2) -> (d0, d1)`
371 /// * For `(d0, d1, d2) -> (d0, 0, d1, 0, d2)` returns
372 /// `(d0, d1, d2) -> (d0, d1, d2)`
374
375 /// Returns true if the AffineMap represents a subset (i.e. a projection) of a
376 /// symbol-less permutation map. `allowZeroInResults` allows projected
377 /// permutation maps with constant zero result expressions.
378 /// TODO: Remove `allowZeroInResults` when constant zero result expressions
379 /// are broadly supported.
380 bool isProjectedPermutation(bool allowZeroInResults = false) const;
381
382 /// Returns true if the AffineMap represents a symbol-less permutation map.
383 bool isPermutation() const;
384
385 /// Returns the map consisting of the `resultPos` subset.
386 AffineMap getSubMap(ArrayRef<unsigned> resultPos) const;
387
388 /// Returns the map consisting of `length` expressions starting from `start`.
389 AffineMap getSliceMap(unsigned start, unsigned length) const;
390
391 /// Returns the map consisting of the most major `numResults` results.
392 /// Returns the null AffineMap if `numResults` == 0.
393 /// Returns `*this` if `numResults` >= `this->getNumResults()`.
394 AffineMap getMajorSubMap(unsigned numResults) const;
395
396 /// Returns the map consisting of the most minor `numResults` results.
397 /// Returns the null AffineMap if `numResults` == 0.
398 /// Returns `*this` if `numResults` >= `this->getNumResults()`.
399 AffineMap getMinorSubMap(unsigned numResults) const;
400
401 /// Get the largest known divisor of all map expressions.
402 /// For eg: for (d0, d1) -> (8*d0 + 4, 4*d1 + 2), the result is 2.
403 /// In the case of maps with no expressions or all zero constant expressions,
404 /// the largest known divisor is trivially the max uint64_t value.
406
407 friend ::llvm::hash_code hash_value(AffineMap arg);
408
409 /// Methods supporting C API.
410 const void *getAsOpaquePointer() const {
411 return static_cast<const void *>(map);
412 }
413 static AffineMap getFromOpaquePointer(const void *pointer) {
414 return AffineMap(reinterpret_cast<ImplType *>(const_cast<void *>(pointer)));
415 }
416
417private:
418 ImplType *map{nullptr};
419
420 static AffineMap getImpl(unsigned dimCount, unsigned symbolCount,
421 ArrayRef<AffineExpr> results, MLIRContext *context);
422};
423
424// Make AffineExpr hashable.
425inline ::llvm::hash_code hash_value(AffineMap arg) {
426 return ::llvm::hash_value(arg.map);
427}
428
429/// A mutable affine map. Its affine expressions are however unique.
431public:
432 MutableAffineMap() = default;
434
435 ArrayRef<AffineExpr> getResults() const { return results; }
436 AffineExpr getResult(unsigned idx) const { return results[idx]; }
437 void setResult(unsigned idx, AffineExpr result) { results[idx] = result; }
438 unsigned getNumResults() const { return results.size(); }
439 unsigned getNumDims() const { return numDims; }
440 void setNumDims(unsigned d) { numDims = d; }
441 unsigned getNumSymbols() const { return numSymbols; }
442 void setNumSymbols(unsigned d) { numSymbols = d; }
443 MLIRContext *getContext() const { return context; }
444
445 /// Returns true if the idx'th result expression is a multiple of factor.
446 bool isMultipleOf(unsigned idx, int64_t factor) const;
447
448 /// Resets this MutableAffineMap with 'map'.
449 void reset(AffineMap map);
450
451 /// Simplify the (result) expressions in this map using analysis (used by
452 //-simplify-affine-expr pass).
453 void simplify();
454 /// Get the AffineMap corresponding to this MutableAffineMap. Note that an
455 /// AffineMap will be uniqued and stored in context, while a mutable one
456 /// isn't.
457 AffineMap getAffineMap() const;
458
459private:
460 // Same meaning as AffineMap's fields.
462 unsigned numDims = 0;
463 unsigned numSymbols = 0;
464 /// A pointer to the IR's context to store all newly created
465 /// AffineExprStorage's.
466 MLIRContext *context = nullptr;
467};
468
469/// Simplifies an affine map by simplifying its underlying AffineExpr results.
470AffineMap simplifyAffineMap(AffineMap map);
471
472/// Drop the dims that are listed in `unusedDims`.
473AffineMap compressDims(AffineMap map, const llvm::SmallBitVector &unusedDims);
474
475/// Drop the dims that are not used.
476AffineMap compressUnusedDims(AffineMap map);
477
478/// Drop the dims that are not used by any of the individual maps in `maps`.
479/// Asserts that all maps in `maps` are normalized to the same number of
480/// dims and symbols.
481SmallVector<AffineMap> compressUnusedDims(ArrayRef<AffineMap> maps);
482
483/// Drop the symbols that are listed in `unusedSymbols`.
484AffineMap compressSymbols(AffineMap map,
485 const llvm::SmallBitVector &unusedSymbols);
486
487/// Drop the symbols that are not used.
488AffineMap compressUnusedSymbols(AffineMap map);
489
490/// Drop the symbols that are not used by any of the individual maps in `maps`.
491/// Asserts that all maps in `maps` are normalized to the same number of
492/// dims and symbols.
493SmallVector<AffineMap> compressUnusedSymbols(ArrayRef<AffineMap> maps);
494
495/// Fold all attributes among the given operands into the affine map. Return the
496/// folded affine map. Return all remaining values via `remainingValues`.
497AffineMap foldAttributesIntoMap(Builder &b, AffineMap map,
498 ArrayRef<OpFoldResult> operands,
499 SmallVector<Value> &remainingValues);
500
501/// Returns a map with the same dimension and symbol count as `map`, but whose
502/// results are the unique affine expressions of `map`.
503AffineMap removeDuplicateExprs(AffineMap map);
504
505/// Returns a map of codomain to domain dimensions such that the first codomain
506/// dimension for a particular domain dimension is selected.
507/// Returns an empty map if the input map is empty.
508/// Returns null map (not empty map) if `map` is not invertible (i.e. `map` does
509/// not contain a subset that is a permutation of full domain rank).
510///
511/// Prerequisites:
512/// 1. `map` has no symbols.
513///
514/// Example 1:
515///
516/// ```mlir
517/// (d0, d1, d2) -> (d1, d1, d0, d2, d1, d2, d1, d0)
518/// 0 2 3
519/// ```
520///
521/// returns:
522///
523/// ```mlir
524/// (d0, d1, d2, d3, d4, d5, d6, d7) -> (d2, d0, d3)
525/// ```
526///
527/// Example 2:
528///
529/// ```mlir
530/// (d0, d1, d2) -> (d1, d0 + d1, d0, d2, d1, d2, d1, d0)
531/// 0 2 3
532/// ```
533///
534/// returns:
535///
536/// ```mlir
537/// (d0, d1, d2, d3, d4, d5, d6, d7) -> (d2, d0, d3)
538/// ```
539AffineMap inversePermutation(AffineMap map);
540
541/// Return the reverse map of a projected permutation where the projected
542/// dimensions are transformed into 0s.
543///
544/// Prerequisites: `map` must be a projected permutation.
545///
546/// Example 1:
547///
548/// ```mlir
549/// affine_map<(d0, d1, d2, d3) -> (d2, d0)>
550/// ```
551///
552/// returns:
553///
554/// ```mlir
555/// affine_map<(d0, d1) -> (d1, 0, d0, 0)>
556/// ```
557///
558/// Example 2:
559///
560/// ```mlir
561/// affine_map<(d0, d1, d2, d3) -> (d0, d3)>
562/// ```
563///
564/// returns:
565///
566/// ```mlir
567/// affine_map<(d0, d1) -> (d0, 0, 0, d1)>
568/// ```
569///
570/// Example 3:
571///
572/// ```mlir
573/// affine_map<(d0, d1, d2, d3) -> (d2)>
574/// ```
575///
576/// returns:
577///
578/// ```mlir
579/// affine_map<(d0) -> (0, 0, d0, 0)>
580/// ```
581/// Example 4:
582///
583/// ```mlir
584/// affine_map<(d0, d1, d2) -> (d0, 0)>
585/// ```
586///
587/// returns:
588///
589/// ```mlir
590/// affine_map<(d0, d1) -> (d0, 0, 0)>
591/// ```
592AffineMap inverseAndBroadcastProjectedPermutation(AffineMap map);
593
594/// Concatenates a list of `maps` into a single AffineMap, stepping over
595/// potentially empty maps. Assumes each of the underlying map has 0 symbols.
596/// The resulting map has a number of dims equal to the max of `maps`' dims and
597/// the concatenated results as its results.
598/// Returns an empty map if all input `maps` are empty.
599///
600/// Example:
601/// When applied to the following list of 3 affine maps,
602///
603/// ```mlir
604/// {
605/// (i, j, k) -> (i, k),
606/// (i, j, k) -> (k, j),
607/// (i, j, k) -> (i, j)
608/// }
609/// ```
610///
611/// Returns the map:
612///
613/// ```mlir
614/// (i, j, k) -> (i, k, k, j, i, j)
615/// ```
616AffineMap concatAffineMaps(ArrayRef<AffineMap> maps, MLIRContext *context);
617
618/// Returns the map that results from projecting out the dimensions specified in
619/// `projectedDimensions`. The projected dimensions are set to 0.
620///
621/// Example:
622/// 1) map : affine_map<(d0, d1, d2) -> (d0, d1)>
623/// projected_dimensions : {2}
624/// result : affine_map<(d0, d1) -> (d0, d1)>
625///
626/// 2) map : affine_map<(d0, d1) -> (d0 + d1)>
627/// projected_dimensions : {1}
628/// result : affine_map<(d0) -> (d0)>
629///
630/// 3) map : affine_map<(d0, d1, d2) -> (d0, d1)>
631/// projected_dimensions : {1}
632/// result : affine_map<(d0, d1) -> (d0, 0)>
633///
634/// This function also compresses the dims when the boolean flag is true.
635AffineMap projectDims(AffineMap map,
636 const llvm::SmallBitVector &projectedDimensions,
637 bool compressDimsFlag = false);
638/// Symbol counterpart of `projectDims`.
639/// This function also compresses the symbols when the boolean flag is true.
640AffineMap projectSymbols(AffineMap map,
641 const llvm::SmallBitVector &projectedSymbols,
642 bool compressSymbolsFlag = false);
643/// Calls `projectDims(map, projectedDimensions, compressDimsFlag)`.
644/// If `compressSymbolsFlag` is true, additionally call `compressUnusedSymbols`.
645AffineMap getProjectedMap(AffineMap map,
646 const llvm::SmallBitVector &projectedDimensions,
647 bool compressDimsFlag = true,
648 bool compressSymbolsFlag = true);
649
650// Return a bitvector where each bit set indicates a dimension that is not used
651// by any of the maps in the input array `maps`.
652llvm::SmallBitVector getUnusedDimsBitVector(ArrayRef<AffineMap> maps);
653
654// Return a bitvector where each bit set indicates a symbol that is not used
655// by any of the maps in the input array `maps`.
656llvm::SmallBitVector getUnusedSymbolsBitVector(ArrayRef<AffineMap> maps);
657
658/// Expand `map` to operate on `rank` dims while projecting out the dims in
659/// `projectedDimensions`. This amounts to composing `map` with
660/// `id(rank).dropResults(projectedDimensions)`.
661AffineMap expandDimsToRank(AffineMap map, int64_t rank,
662 const llvm::SmallBitVector &projectedDimensions);
663
665 map.print(os);
666 return os;
667}
668
669//===----------------------------------------------------------------------===//
670// Templated helper functions.
671//===----------------------------------------------------------------------===//
672
673/// Apply a permutation from `map` to `source` and return the result.
674template <typename T>
676 assert(map.isProjectedPermutation());
677 assert(map.getNumInputs() == source.size());
679 result.reserve(map.getNumResults());
680 for (AffineExpr expr : map.getResults()) {
681 if (auto dimExpr = dyn_cast<AffineDimExpr>(expr)) {
682 result.push_back(source[dimExpr.getPosition()]);
683 } else if (auto constExpr = dyn_cast<AffineConstantExpr>(expr)) {
684 assert(constExpr.getValue() == 0 &&
685 "Unexpected constant in projected permutation map");
686 result.push_back(0);
687 } else {
688 llvm_unreachable("Unexpected result in projected permutation map");
689 }
690 }
691 return result;
692}
693
694/// Calculates maximum dimension and symbol positions from the expressions
695/// in `exprsLists` and stores them in `maxDim` and `maxSym` respectively.
696template <typename AffineExprContainer>
698 int64_t &maxDim, int64_t &maxSym) {
699 for (const auto &exprs : exprsList) {
700 for (auto expr : exprs) {
701 expr.walk([&maxDim, &maxSym](AffineExpr e) {
702 if (auto d = dyn_cast<AffineDimExpr>(e))
703 maxDim = std::max(maxDim, static_cast<int64_t>(d.getPosition()));
704 if (auto s = dyn_cast<AffineSymbolExpr>(e))
705 maxSym = std::max(maxSym, static_cast<int64_t>(s.getPosition()));
706 });
707 }
708 }
709}
710
711} // namespace mlir
712
713namespace llvm {
714
715// AffineExpr hash just like pointers
716template <>
717struct DenseMapInfo<mlir::AffineMap> {
720 return mlir::AffineMap(static_cast<mlir::AffineMap::ImplType *>(pointer));
721 }
724 return mlir::AffineMap(static_cast<mlir::AffineMap::ImplType *>(pointer));
725 }
726 static unsigned getHashValue(mlir::AffineMap val) {
727 return mlir::hash_value(val);
728 }
730 return LHS == RHS;
731 }
732};
733
734} // namespace llvm
735
736#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:223
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:299
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:221
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:267
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:315
const void * getAsOpaquePointer() const
Methods supporting C API.
Definition AffineMap.h:410
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:293
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: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...
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:280
static AffineMap getFromOpaquePointer(const void *pointer)
Definition AffineMap.h:413
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.
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:63
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...
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.
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.
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:126
SmallVector< T > applyPermutationMap(AffineMap map, llvm::ArrayRef< T > source)
Apply a permutation from map to source and return the result.
Definition AffineMap.h:675
llvm::SmallBitVector getUnusedDimsBitVector(ArrayRef< AffineMap > maps)
inline ::llvm::hash_code hash_value(AffineExpr arg)
Make AffineExpr hashable.
Definition AffineExpr.h:247
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:726
static mlir::AffineMap getEmptyKey()
Definition AffineMap.h:718
static bool isEqual(mlir::AffineMap LHS, mlir::AffineMap RHS)
Definition AffineMap.h:729
static mlir::AffineMap getTombstoneKey()
Definition AffineMap.h:722
void setNumDims(unsigned d)
Definition AffineMap.h:440
void reset(AffineMap map)
Resets this MutableAffineMap with 'map'.
MLIRContext * getContext() const
Definition AffineMap.h:443
void setResult(unsigned idx, AffineExpr result)
Definition AffineMap.h:437
AffineMap getAffineMap() const
Get the AffineMap corresponding to this MutableAffineMap.
void setNumSymbols(unsigned d)
Definition AffineMap.h:442
AffineExpr getResult(unsigned idx) const
Definition AffineMap.h:436
unsigned getNumSymbols() const
Definition AffineMap.h:441
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:435
unsigned getNumResults() const
Definition AffineMap.h:438
unsigned getNumDims() const
Definition AffineMap.h:439
void simplify()
Simplify the (result) expressions in this map using analysis (used by.