Coverage Report

Created: 2020-06-26 05:44

/home/arjun/llvm-project/mlir/include/mlir/IR/AffineMap.h
Line
Count
Source (jump to first uncovered line)
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_AFFINE_MAP_H
15
#define MLIR_IR_AFFINE_MAP_H
16
17
#include "mlir/IR/AffineExpr.h"
18
#include "mlir/Support/LLVM.h"
19
#include "llvm/ADT/ArrayRef.h"
20
#include "llvm/ADT/DenseMapInfo.h"
21
22
namespace mlir {
23
24
namespace detail {
25
struct AffineMapStorage;
26
} // end namespace detail
27
28
class Attribute;
29
struct LogicalResult;
30
class MLIRContext;
31
32
/// A multi-dimensional affine map
33
/// Affine map's are immutable like Type's, and they are uniqued.
34
/// Eg: (d0, d1) -> (d0/128, d0 mod 128, d1)
35
/// The names used (d0, d1) don't matter - it's the mathematical function that
36
/// is unique to this affine map.
37
class AffineMap {
38
public:
39
  using ImplType = detail::AffineMapStorage;
40
41
0
  constexpr AffineMap() : map(nullptr) {}
42
0
  explicit AffineMap(ImplType *map) : map(map) {}
43
44
  /// Returns a zero result affine map with no dimensions or symbols: () -> ().
45
  static AffineMap get(MLIRContext *context);
46
47
  /// Returns a zero result affine map with `dimCount` dimensions and
48
  /// `symbolCount` symbols, e.g.: `(...) -> ()`.
49
  static AffineMap get(unsigned dimCount, unsigned symbolCount,
50
                       MLIRContext *context);
51
52
  /// Returns an affine map with `dimCount` dimensions and `symbolCount` mapping
53
  /// to a single output dimension
54
  static AffineMap get(unsigned dimCount, unsigned symbolCount,
55
                       AffineExpr result);
56
57
  /// Returns an affine map with `dimCount` dimensions and `symbolCount` mapping
58
  /// to the given results.
59
  static AffineMap get(unsigned dimCount, unsigned symbolCount,
60
                       ArrayRef<AffineExpr> results, MLIRContext *context);
61
62
  /// Returns a single constant result affine map.
63
  static AffineMap getConstantMap(int64_t val, MLIRContext *context);
64
65
  /// Returns an AffineMap with 'numDims' identity result dim exprs.
66
  static AffineMap getMultiDimIdentityMap(unsigned numDims,
67
                                          MLIRContext *context);
68
69
  /// Returns an identity affine map (d0, ..., dn) -> (dp, ..., dn) on the most
70
  /// minor dimensions.
71
  static AffineMap getMinorIdentityMap(unsigned dims, unsigned results,
72
                                       MLIRContext *context);
73
74
  /// Returns an AffineMap representing a permutation.
75
  /// The permutation is expressed as a non-empty vector of integers.
76
  /// E.g. the permutation `(i,j,k) -> (j,k,i)` will be expressed with
77
  /// `permutation = [1,2,0]`. All values in `permutation` must be
78
  /// integers, in the range 0..`permutation.size()-1` without duplications
79
  /// (i.e. `[1,1,2]` is an invalid permutation).
80
  static AffineMap getPermutationMap(ArrayRef<unsigned> permutation,
81
                                     MLIRContext *context);
82
83
  /// Returns a vector of AffineMaps; each with as many results as
84
  /// `exprs.size()`, as many dims as the largest dim in `exprs` and as many
85
  /// symbols as the largest symbol in `exprs`.
86
  static SmallVector<AffineMap, 4>
87
  inferFromExprList(ArrayRef<ArrayRef<AffineExpr>> exprsList);
88
  static SmallVector<AffineMap, 4>
89
  inferFromExprList(ArrayRef<SmallVector<AffineExpr, 4>> exprsList);
90
91
  MLIRContext *getContext() const;
92
93
0
  explicit operator bool() { return map != nullptr; }
94
0
  bool operator==(AffineMap other) const { return other.map == map; }
95
0
  bool operator!=(AffineMap other) const { return !(other.map == map); }
96
97
  /// Returns true if this affine map is an identity affine map.
98
  /// An identity affine map corresponds to an identity affine function on the
99
  /// dimensional identifiers.
100
  bool isIdentity() const;
101
102
  /// Returns true if the map is a minor identity map, i.e. an identity affine
103
  /// map (d0, ..., dn) -> (dp, ..., dn) on the most minor dimensions.
104
  static bool isMinorIdentity(AffineMap map);
105
106
  /// Returns true if this affine map is an empty map, i.e., () -> ().
107
  bool isEmpty() const;
108
109
  /// Returns true if this affine map is a single result constant function.
110
  bool isSingleConstant() const;
111
112
  /// Returns the constant result of this map. This methods asserts that the map
113
  /// has a single constant result.
114
  int64_t getSingleConstantResult() const;
115
116
  // Prints affine map to 'os'.
117
  void print(raw_ostream &os) const;
118
  void dump() const;
119
120
  unsigned getNumDims() const;
121
  unsigned getNumSymbols() const;
122
  unsigned getNumResults() const;
123
  unsigned getNumInputs() const;
124
125
  ArrayRef<AffineExpr> getResults() const;
126
  AffineExpr getResult(unsigned idx) const;
127
128
  /// Walk all of the AffineExpr's in this mapping. Each node in an expression
129
  /// tree is visited in postorder.
130
  void walkExprs(std::function<void(AffineExpr)> callback) const;
131
132
  /// This method substitutes any uses of dimensions and symbols (e.g.
133
  /// dim#0 with dimReplacements[0]) in subexpressions and returns the modified
134
  /// expression mapping.  Because this can be used to eliminate dims and
135
  /// symbols, the client needs to specify the number of dims and symbols in
136
  /// the result.  The returned map always has the same number of results.
137
  AffineMap replaceDimsAndSymbols(ArrayRef<AffineExpr> dimReplacements,
138
                                  ArrayRef<AffineExpr> symReplacements,
139
                                  unsigned numResultDims,
140
                                  unsigned numResultSyms) const;
141
142
  /// Folds the results of the application of an affine map on the provided
143
  /// operands to a constant if possible.
144
  LogicalResult constantFold(ArrayRef<Attribute> operandConstants,
145
                             SmallVectorImpl<Attribute> &results) const;
146
147
  /// Propagates the constant operands into this affine map. Operands are
148
  /// allowed to be null, at which point they are treated as non-constant. This
149
  /// does not change the number of symbols and dimensions. Returns a new map,
150
  /// which may be equal to the old map if no folding happened. If `results` is
151
  /// provided and if all expressions in the map were folded to constants,
152
  /// `results` will contain the values of these constants.
153
  AffineMap
154
  partialConstantFold(ArrayRef<Attribute> operandConstants,
155
                      SmallVectorImpl<int64_t> *results = nullptr) const;
156
157
  /// Returns the AffineMap resulting from composing `this` with `map`.
158
  /// The resulting AffineMap has as many AffineDimExpr as `map` and as many
159
  /// AffineSymbolExpr as the concatenation of `this` and `map` (in which case
160
  /// the symbols of `this` map come first).
161
  ///
162
  /// Prerequisites:
163
  /// The maps are composable, i.e. that the number of AffineDimExpr of `this`
164
  /// matches the number of results of `map`.
165
  ///
166
  /// Example:
167
  ///   map1: `(d0, d1)[s0, s1] -> (d0 + 1 + s1, d1 - 1 - s0)`
168
  ///   map2: `(d0)[s0] -> (d0 + s0, d0 - s0)`
169
  ///   map1.compose(map2):
170
  ///     `(d0)[s0, s1, s2] -> (d0 + s1 + s2 + 1, d0 - s0 - s2 - 1)`
171
  AffineMap compose(AffineMap map);
172
173
  /// Returns true if the AffineMap represents a subset (i.e. a projection) of a
174
  /// symbol-less permutation map.
175
  bool isProjectedPermutation();
176
177
  /// Returns true if the AffineMap represents a symbol-less permutation map.
178
  bool isPermutation();
179
180
  /// Returns the map consisting of the `resultPos` subset.
181
  AffineMap getSubMap(ArrayRef<unsigned> resultPos);
182
183
  friend ::llvm::hash_code hash_value(AffineMap arg);
184
185
private:
186
  ImplType *map;
187
188
  static AffineMap getImpl(unsigned dimCount, unsigned symbolCount,
189
                           ArrayRef<AffineExpr> results, MLIRContext *context);
190
};
191
192
// Make AffineExpr hashable.
193
0
inline ::llvm::hash_code hash_value(AffineMap arg) {
194
0
  return ::llvm::hash_value(arg.map);
195
0
}
196
197
/// A mutable affine map. Its affine expressions are however unique.
198
struct MutableAffineMap {
199
public:
200
0
  MutableAffineMap() {}
201
  MutableAffineMap(AffineMap map);
202
203
0
  ArrayRef<AffineExpr> getResults() const { return results; }
204
0
  AffineExpr getResult(unsigned idx) const { return results[idx]; }
205
0
  void setResult(unsigned idx, AffineExpr result) { results[idx] = result; }
206
0
  unsigned getNumResults() const { return results.size(); }
207
0
  unsigned getNumDims() const { return numDims; }
208
0
  void setNumDims(unsigned d) { numDims = d; }
209
0
  unsigned getNumSymbols() const { return numSymbols; }
210
0
  void setNumSymbols(unsigned d) { numSymbols = d; }
211
0
  MLIRContext *getContext() const { return context; }
212
213
  /// Returns true if the idx'th result expression is a multiple of factor.
214
  bool isMultipleOf(unsigned idx, int64_t factor) const;
215
216
  /// Resets this MutableAffineMap with 'map'.
217
  void reset(AffineMap map);
218
219
  /// Simplify the (result) expressions in this map using analysis (used by
220
  //-simplify-affine-expr pass).
221
  void simplify();
222
  /// Get the AffineMap corresponding to this MutableAffineMap. Note that an
223
  /// AffineMap will be uniqued and stored in context, while a mutable one
224
  /// isn't.
225
  AffineMap getAffineMap() const;
226
227
private:
228
  // Same meaning as AffineMap's fields.
229
  SmallVector<AffineExpr, 8> results;
230
  unsigned numDims;
231
  unsigned numSymbols;
232
  /// A pointer to the IR's context to store all newly created
233
  /// AffineExprStorage's.
234
  MLIRContext *context;
235
};
236
237
/// Simplifies an affine map by simplifying its underlying AffineExpr results.
238
AffineMap simplifyAffineMap(AffineMap map);
239
240
/// Returns a map with the same dimension and symbol count as `map`, but whose
241
/// results are the unique affine expressions of `map`.
242
AffineMap removeDuplicateExprs(AffineMap map);
243
244
/// Returns a map of codomain to domain dimensions such that the first codomain
245
/// dimension for a particular domain dimension is selected.
246
/// Returns an empty map if the input map is empty.
247
/// Returns null map (not empty map) if `map` is not invertible (i.e. `map` does
248
/// not contain a subset that is a permutation of full domain rank).
249
///
250
/// Prerequisites:
251
///   1. `map` has no symbols.
252
///
253
/// Example 1:
254
///
255
/// ```mlir
256
///    (d0, d1, d2) -> (d1, d1, d0, d2, d1, d2, d1, d0)
257
///                      0       2   3
258
/// ```
259
///
260
/// returns:
261
///
262
/// ```mlir
263
///    (d0, d1, d2, d3, d4, d5, d6, d7) -> (d2, d0, d3)
264
/// ```
265
///
266
/// Example 2:
267
///
268
/// ```mlir
269
///    (d0, d1, d2) -> (d1, d0 + d1, d0, d2, d1, d2, d1, d0)
270
///                      0            2   3
271
/// ```
272
///
273
/// returns:
274
///
275
/// ```mlir
276
///    (d0, d1, d2, d3, d4, d5, d6, d7) -> (d2, d0, d3)
277
/// ```
278
AffineMap inversePermutation(AffineMap map);
279
280
/// Concatenates a list of `maps` into a single AffineMap, stepping over
281
/// potentially empty maps. Assumes each of the underlying map has 0 symbols.
282
/// The resulting map has a number of dims equal to the max of `maps`' dims and
283
/// the concatenated results as its results.
284
/// Returns an empty map if all input `maps` are empty.
285
///
286
/// Example:
287
/// When applied to the following list of 3 affine maps,
288
///
289
/// ```mlir
290
///    {
291
///      (i, j, k) -> (i, k),
292
///      (i, j, k) -> (k, j),
293
///      (i, j, k) -> (i, j)
294
///    }
295
/// ```
296
///
297
/// Returns the map:
298
///
299
/// ```mlir
300
///     (i, j, k) -> (i, k, k, j, i, j)
301
/// ```
302
AffineMap concatAffineMaps(ArrayRef<AffineMap> maps);
303
304
0
inline raw_ostream &operator<<(raw_ostream &os, AffineMap map) {
305
0
  map.print(os);
306
0
  return os;
307
0
}
308
} // end namespace mlir
309
310
namespace llvm {
311
312
// AffineExpr hash just like pointers
313
template <> struct DenseMapInfo<mlir::AffineMap> {
314
0
  static mlir::AffineMap getEmptyKey() {
315
0
    auto pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
316
0
    return mlir::AffineMap(static_cast<mlir::AffineMap::ImplType *>(pointer));
317
0
  }
318
0
  static mlir::AffineMap getTombstoneKey() {
319
0
    auto pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
320
0
    return mlir::AffineMap(static_cast<mlir::AffineMap::ImplType *>(pointer));
321
0
  }
322
0
  static unsigned getHashValue(mlir::AffineMap val) {
323
0
    return mlir::hash_value(val);
324
0
  }
325
0
  static bool isEqual(mlir::AffineMap LHS, mlir::AffineMap RHS) {
326
0
    return LHS == RHS;
327
0
  }
328
};
329
330
} // namespace llvm
331
332
#endif // MLIR_IR_AFFINE_MAP_H