Coverage Report

Created: 2020-06-26 05:44

/home/arjun/llvm-project/mlir/include/mlir/IR/AffineExpr.h
Line
Count
Source (jump to first uncovered line)
1
//===- AffineExpr.h - MLIR Affine Expr 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
// An affine expression is an affine combination of dimension identifiers and
10
// symbols, including ceildiv/floordiv/mod by a constant integer.
11
//
12
//===----------------------------------------------------------------------===//
13
14
#ifndef MLIR_IR_AFFINE_EXPR_H
15
#define MLIR_IR_AFFINE_EXPR_H
16
17
#include "mlir/Support/LLVM.h"
18
#include "llvm/ADT/DenseMapInfo.h"
19
#include "llvm/Support/Casting.h"
20
#include <type_traits>
21
22
namespace mlir {
23
24
class MLIRContext;
25
class AffineMap;
26
class IntegerSet;
27
28
namespace detail {
29
30
struct AffineExprStorage;
31
struct AffineBinaryOpExprStorage;
32
struct AffineDimExprStorage;
33
struct AffineSymbolExprStorage;
34
struct AffineConstantExprStorage;
35
36
} // namespace detail
37
38
enum class AffineExprKind {
39
  Add,
40
  /// RHS of mul is always a constant or a symbolic expression.
41
  Mul,
42
  /// RHS of mod is always a constant or a symbolic expression with a positive
43
  /// value.
44
  Mod,
45
  /// RHS of floordiv is always a constant or a symbolic expression.
46
  FloorDiv,
47
  /// RHS of ceildiv is always a constant or a symbolic expression.
48
  CeilDiv,
49
50
  /// This is a marker for the last affine binary op. The range of binary
51
  /// op's is expected to be this element and earlier.
52
  LAST_AFFINE_BINARY_OP = CeilDiv,
53
54
  /// Constant integer.
55
  Constant,
56
  /// Dimensional identifier.
57
  DimId,
58
  /// Symbolic identifier.
59
  SymbolId,
60
};
61
62
/// Base type for affine expression.
63
/// AffineExpr's are immutable value types with intuitive operators to
64
/// operate on chainable, lightweight compositions.
65
/// An AffineExpr is an interface to the underlying storage type pointer.
66
class AffineExpr {
67
public:
68
  using ImplType = detail::AffineExprStorage;
69
70
0
  constexpr AffineExpr() : expr(nullptr) {}
71
  /* implicit */ AffineExpr(const ImplType *expr)
72
0
      : expr(const_cast<ImplType *>(expr)) {}
73
74
0
  bool operator==(AffineExpr other) const { return expr == other.expr; }
75
0
  bool operator!=(AffineExpr other) const { return !(*this == other); }
76
  bool operator==(int64_t v) const;
77
0
  bool operator!=(int64_t v) const { return !(*this == v); }
78
0
  explicit operator bool() const { return expr; }
79
80
0
  bool operator!() const { return expr == nullptr; }
81
82
  template <typename U> bool isa() const;
83
  template <typename U> U dyn_cast() const;
84
  template <typename U> U dyn_cast_or_null() const;
85
  template <typename U> U cast() const;
86
87
  MLIRContext *getContext() const;
88
89
  /// Return the classification for this type.
90
  AffineExprKind getKind() const;
91
92
  void print(raw_ostream &os) const;
93
  void dump() const;
94
95
  /// Returns true if this expression is made out of only symbols and
96
  /// constants, i.e., it does not involve dimensional identifiers.
97
  bool isSymbolicOrConstant() const;
98
99
  /// Returns true if this is a pure affine expression, i.e., multiplication,
100
  /// floordiv, ceildiv, and mod is only allowed w.r.t constants.
101
  bool isPureAffine() const;
102
103
  /// Returns the greatest known integral divisor of this affine expression. The
104
  /// result is always positive.
105
  int64_t getLargestKnownDivisor() const;
106
107
  /// Return true if the affine expression is a multiple of 'factor'.
108
  bool isMultipleOf(int64_t factor) const;
109
110
  /// Return true if the affine expression involves AffineDimExpr `position`.
111
  bool isFunctionOfDim(unsigned position) const;
112
113
  /// Walk all of the AffineExpr's in this expression in postorder.
114
  void walk(std::function<void(AffineExpr)> callback) const;
115
116
  /// This method substitutes any uses of dimensions and symbols (e.g.
117
  /// dim#0 with dimReplacements[0]) and returns the modified expression tree.
118
  AffineExpr replaceDimsAndSymbols(ArrayRef<AffineExpr> dimReplacements,
119
                                   ArrayRef<AffineExpr> symReplacements) const;
120
121
  AffineExpr operator+(int64_t v) const;
122
  AffineExpr operator+(AffineExpr other) const;
123
  AffineExpr operator-() const;
124
  AffineExpr operator-(int64_t v) const;
125
  AffineExpr operator-(AffineExpr other) const;
126
  AffineExpr operator*(int64_t v) const;
127
  AffineExpr operator*(AffineExpr other) const;
128
  AffineExpr floorDiv(uint64_t v) const;
129
  AffineExpr floorDiv(AffineExpr other) const;
130
  AffineExpr ceilDiv(uint64_t v) const;
131
  AffineExpr ceilDiv(AffineExpr other) const;
132
  AffineExpr operator%(uint64_t v) const;
133
  AffineExpr operator%(AffineExpr other) const;
134
135
  /// Compose with an AffineMap.
136
  /// Returns the composition of this AffineExpr with `map`.
137
  ///
138
  /// Prerequisites:
139
  /// `this` and `map` are composable, i.e. that the number of AffineDimExpr of
140
  /// `this` is smaller than the number of results of `map`. If a result of a
141
  /// map does not have a corresponding AffineDimExpr, that result simply does
142
  /// not appear in the produced AffineExpr.
143
  ///
144
  /// Example:
145
  ///   expr: `d0 + d2`
146
  ///   map:  `(d0, d1, d2)[s0, s1] -> (d0 + s1, d1 + s0, d0 + d1 + d2)`
147
  ///   returned expr: `d0 * 2 + d1 + d2 + s1`
148
  AffineExpr compose(AffineMap map) const;
149
150
  friend ::llvm::hash_code hash_value(AffineExpr arg);
151
152
protected:
153
  ImplType *expr;
154
};
155
156
/// Affine binary operation expression. An affine binary operation could be an
157
/// add, mul, floordiv, ceildiv, or a modulo operation. (Subtraction is
158
/// represented through a multiply by -1 and add.) These expressions are always
159
/// constructed in a simplified form. For eg., the LHS and RHS operands can't
160
/// both be constants. There are additional canonicalizing rules depending on
161
/// the op type: see checks in the constructor.
162
class AffineBinaryOpExpr : public AffineExpr {
163
public:
164
  using ImplType = detail::AffineBinaryOpExprStorage;
165
  /* implicit */ AffineBinaryOpExpr(AffineExpr::ImplType *ptr);
166
  AffineExpr getLHS() const;
167
  AffineExpr getRHS() const;
168
};
169
170
/// A dimensional identifier appearing in an affine expression.
171
class AffineDimExpr : public AffineExpr {
172
public:
173
  using ImplType = detail::AffineDimExprStorage;
174
  /* implicit */ AffineDimExpr(AffineExpr::ImplType *ptr);
175
  unsigned getPosition() const;
176
};
177
178
/// A symbolic identifier appearing in an affine expression.
179
class AffineSymbolExpr : public AffineExpr {
180
public:
181
  using ImplType = detail::AffineDimExprStorage;
182
  /* implicit */ AffineSymbolExpr(AffineExpr::ImplType *ptr);
183
  unsigned getPosition() const;
184
};
185
186
/// An integer constant appearing in affine expression.
187
class AffineConstantExpr : public AffineExpr {
188
public:
189
  using ImplType = detail::AffineConstantExprStorage;
190
  /* implicit */ AffineConstantExpr(AffineExpr::ImplType *ptr = nullptr);
191
  int64_t getValue() const;
192
};
193
194
/// Make AffineExpr hashable.
195
0
inline ::llvm::hash_code hash_value(AffineExpr arg) {
196
0
  return ::llvm::hash_value(arg.expr);
197
0
}
198
199
0
inline AffineExpr operator+(int64_t val, AffineExpr expr) { return expr + val; }
200
0
inline AffineExpr operator*(int64_t val, AffineExpr expr) { return expr * val; }
201
0
inline AffineExpr operator-(int64_t val, AffineExpr expr) {
202
0
  return expr * (-1) + val;
203
0
}
204
205
/// These free functions allow clients of the API to not use classes in detail.
206
AffineExpr getAffineDimExpr(unsigned position, MLIRContext *context);
207
AffineExpr getAffineSymbolExpr(unsigned position, MLIRContext *context);
208
AffineExpr getAffineConstantExpr(int64_t constant, MLIRContext *context);
209
AffineExpr getAffineBinaryOpExpr(AffineExprKind kind, AffineExpr lhs,
210
                                 AffineExpr rhs);
211
212
/// Constructs an affine expression from a flat ArrayRef. If there are local
213
/// identifiers (neither dimensional nor symbolic) that appear in the sum of
214
/// products expression, 'localExprs' is expected to have the AffineExpr
215
/// for it, and is substituted into. The ArrayRef 'eq' is expected to be in the
216
/// format [dims, symbols, locals, constant term].
217
AffineExpr getAffineExprFromFlatForm(ArrayRef<int64_t> flatExprs,
218
                                     unsigned numDims, unsigned numSymbols,
219
                                     ArrayRef<AffineExpr> localExprs,
220
                                     MLIRContext *context);
221
222
raw_ostream &operator<<(raw_ostream &os, AffineExpr expr);
223
224
0
template <typename U> bool AffineExpr::isa() const {
225
0
  if (std::is_same<U, AffineBinaryOpExpr>::value)
226
0
    return getKind() <= AffineExprKind::LAST_AFFINE_BINARY_OP;
227
0
  if (std::is_same<U, AffineDimExpr>::value)
228
0
    return getKind() == AffineExprKind::DimId;
229
0
  if (std::is_same<U, AffineSymbolExpr>::value)
230
0
    return getKind() == AffineExprKind::SymbolId;
231
0
  if (std::is_same<U, AffineConstantExpr>::value)
232
0
    return getKind() == AffineExprKind::Constant;
233
0
}
Unexecuted instantiation: _ZNK4mlir10AffineExpr3isaINS_18AffineBinaryOpExprEEEbv
Unexecuted instantiation: _ZNK4mlir10AffineExpr3isaINS_18AffineConstantExprEEEbv
Unexecuted instantiation: _ZNK4mlir10AffineExpr3isaINS_13AffineDimExprEEEbv
Unexecuted instantiation: _ZNK4mlir10AffineExpr3isaINS_16AffineSymbolExprEEEbv
234
0
template <typename U> U AffineExpr::dyn_cast() const {
235
0
  if (isa<U>())
236
0
    return U(expr);
237
0
  return U(nullptr);
238
0
}
Unexecuted instantiation: _ZNK4mlir10AffineExpr8dyn_castINS_13AffineDimExprEEET_v
Unexecuted instantiation: _ZNK4mlir10AffineExpr8dyn_castINS_16AffineSymbolExprEEET_v
Unexecuted instantiation: _ZNK4mlir10AffineExpr8dyn_castINS_18AffineConstantExprEEET_v
Unexecuted instantiation: _ZNK4mlir10AffineExpr8dyn_castINS_18AffineBinaryOpExprEEET_v
239
template <typename U> U AffineExpr::dyn_cast_or_null() const {
240
  return (!*this || !isa<U>()) ? U(nullptr) : U(expr);
241
}
242
0
template <typename U> U AffineExpr::cast() const {
243
0
  assert(isa<U>());
244
0
  return U(expr);
245
0
}
Unexecuted instantiation: _ZNK4mlir10AffineExpr4castINS_18AffineBinaryOpExprEEET_v
Unexecuted instantiation: _ZNK4mlir10AffineExpr4castINS_18AffineConstantExprEEET_v
Unexecuted instantiation: _ZNK4mlir10AffineExpr4castINS_13AffineDimExprEEET_v
Unexecuted instantiation: _ZNK4mlir10AffineExpr4castINS_16AffineSymbolExprEEET_v
246
247
/// Simplify an affine expression by flattening and some amount of
248
/// simple analysis. This has complexity linear in the number of nodes in
249
/// 'expr'. Returns the simplified expression, which is the same as the input
250
///  expression if it can't be simplified.
251
AffineExpr simplifyAffineExpr(AffineExpr expr, unsigned numDims,
252
                              unsigned numSymbols);
253
254
namespace detail {
255
template <int N> void bindDims(MLIRContext *ctx) {}
256
257
template <int N, typename AffineExprTy, typename... AffineExprTy2>
258
void bindDims(MLIRContext *ctx, AffineExprTy &e, AffineExprTy2 &... exprs) {
259
  e = getAffineDimExpr(N, ctx);
260
  bindDims<N + 1, AffineExprTy2 &...>(ctx, exprs...);
261
}
262
} // namespace detail
263
264
/// Bind a list of AffineExpr references to DimExpr at positions:
265
///   [0 .. sizeof...(exprs)]
266
template <typename... AffineExprTy>
267
void bindDims(MLIRContext *ctx, AffineExprTy &... exprs) {
268
  detail::bindDims<0>(ctx, exprs...);
269
}
270
271
} // namespace mlir
272
273
namespace llvm {
274
275
// AffineExpr hash just like pointers
276
template <> struct DenseMapInfo<mlir::AffineExpr> {
277
0
  static mlir::AffineExpr getEmptyKey() {
278
0
    auto pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
279
0
    return mlir::AffineExpr(static_cast<mlir::AffineExpr::ImplType *>(pointer));
280
0
  }
281
0
  static mlir::AffineExpr getTombstoneKey() {
282
0
    auto pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
283
0
    return mlir::AffineExpr(static_cast<mlir::AffineExpr::ImplType *>(pointer));
284
0
  }
285
0
  static unsigned getHashValue(mlir::AffineExpr val) {
286
0
    return mlir::hash_value(val);
287
0
  }
288
0
  static bool isEqual(mlir::AffineExpr LHS, mlir::AffineExpr RHS) {
289
0
    return LHS == RHS;
290
0
  }
291
};
292
293
} // namespace llvm
294
295
#endif // MLIR_IR_AFFINE_EXPR_H