MLIR 22.0.0git
AffineExpr.h
Go to the documentation of this file.
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_AFFINEEXPR_H
15#define MLIR_IR_AFFINEEXPR_H
16
17#include "mlir/IR/Visitors.h"
18#include "mlir/Support/LLVM.h"
19#include "llvm/ADT/DenseMapInfo.h"
20#include "llvm/ADT/Hashing.h"
21#include "llvm/ADT/SmallVector.h"
22#include "llvm/Support/Casting.h"
23#include <type_traits>
24
25namespace mlir {
26
27class MLIRContext;
28class AffineMap;
29class IntegerSet;
30
31namespace detail {
32
37
38} // namespace detail
39
40enum class AffineExprKind {
42 /// RHS of mul is always a constant or a symbolic expression.
44 /// RHS of mod is always a constant or a symbolic expression with a positive
45 /// value.
47 /// RHS of floordiv is always a constant or a symbolic expression.
49 /// RHS of ceildiv is always a constant or a symbolic expression.
51
52 /// This is a marker for the last affine binary op. The range of binary
53 /// op's is expected to be this element and earlier.
55
56 /// Constant integer.
58 /// Dimensional identifier.
60 /// Symbolic identifier.
62};
63
64/// Base type for affine expression.
65/// AffineExpr's are immutable value types with intuitive operators to
66/// operate on chainable, lightweight compositions.
67/// An AffineExpr is an interface to the underlying storage type pointer.
69public:
71
72 constexpr AffineExpr() {}
73 /* implicit */ AffineExpr(const ImplType *expr)
74 : expr(const_cast<ImplType *>(expr)) {}
75
76 bool operator==(AffineExpr other) const { return expr == other.expr; }
77 bool operator!=(AffineExpr other) const { return !(*this == other); }
78 bool operator==(int64_t v) const;
79 bool operator!=(int64_t v) const { return !(*this == v); }
80 explicit operator bool() const { return expr; }
81
82 bool operator!() const { return expr == nullptr; }
83
84 MLIRContext *getContext() const;
85
86 /// Return the classification for this type.
87 AffineExprKind getKind() const;
88
89 void print(raw_ostream &os) const;
90 void dump() const;
91
92 /// Returns true if this expression is made out of only symbols and
93 /// constants, i.e., it does not involve dimensional identifiers.
94 bool isSymbolicOrConstant() const;
95
96 /// Returns true if this is a pure affine expression, i.e., multiplication,
97 /// floordiv, ceildiv, and mod is only allowed w.r.t constants.
98 bool isPureAffine() const;
99
100 /// Returns the greatest known integral divisor of this affine expression. The
101 /// result is always positive.
103
104 /// Return true if the affine expression is a multiple of 'factor'.
105 bool isMultipleOf(int64_t factor) const;
106
107 /// Return true if the affine expression involves AffineDimExpr `position`.
108 bool isFunctionOfDim(unsigned position) const;
109
110 /// Return true if the affine expression involves AffineSymbolExpr `position`.
111 bool isFunctionOfSymbol(unsigned position) const;
112
113 /// Walk all of the AffineExpr's in this expression in postorder. This allows
114 /// a lambda walk function that can either return `void` or a WalkResult. With
115 /// a WalkResult, interrupting is supported.
116 template <typename FnT, typename RetT = detail::walkResultType<FnT>>
117 RetT walk(FnT &&callback) const {
118 return walk<RetT>(*this, callback);
119 }
120
121 /// This method substitutes any uses of dimensions and symbols (e.g.
122 /// dim#0 with dimReplacements[0]) and returns the modified expression tree.
123 /// This is a dense replacement method: a replacement must be specified for
124 /// every single dim and symbol.
126 ArrayRef<AffineExpr> symReplacements) const;
127
128 /// Dim-only version of replaceDimsAndSymbols.
129 AffineExpr replaceDims(ArrayRef<AffineExpr> dimReplacements) const;
130
131 /// Symbol-only version of replaceDimsAndSymbols.
132 AffineExpr replaceSymbols(ArrayRef<AffineExpr> symReplacements) const;
133
134 /// Sparse replace method. Replace `expr` by `replacement` and return the
135 /// modified expression tree.
137
138 /// Sparse replace method. If `*this` appears in `map` replaces it by
139 /// `map[*this]` and return the modified expression tree. Otherwise traverse
140 /// `*this` and apply replace with `map` on its subexpressions.
142
143 /// Replace dims[offset ... numDims)
144 /// by dims[offset + shift ... shift + numDims).
145 AffineExpr shiftDims(unsigned numDims, unsigned shift,
146 unsigned offset = 0) const;
147
148 /// Replace symbols[offset ... numSymbols)
149 /// by symbols[offset + shift ... shift + numSymbols).
150 AffineExpr shiftSymbols(unsigned numSymbols, unsigned shift,
151 unsigned offset = 0) const;
152
155 AffineExpr operator-() const;
157 AffineExpr operator-(AffineExpr other) const;
159 AffineExpr operator*(AffineExpr other) const;
160 AffineExpr floorDiv(uint64_t v) const;
161 AffineExpr floorDiv(AffineExpr other) const;
162 AffineExpr ceilDiv(uint64_t v) const;
163 AffineExpr ceilDiv(AffineExpr other) const;
164 AffineExpr operator%(uint64_t v) const;
165 AffineExpr operator%(AffineExpr other) const;
166
167 /// Compose with an AffineMap.
168 /// Returns the composition of this AffineExpr with `map`.
169 ///
170 /// Prerequisites:
171 /// `this` and `map` are composable, i.e. that the number of AffineDimExpr of
172 /// `this` is smaller than the number of results of `map`. If a result of a
173 /// map does not have a corresponding AffineDimExpr, that result simply does
174 /// not appear in the produced AffineExpr.
175 ///
176 /// Example:
177 /// expr: `d0 + d2`
178 /// map: `(d0, d1, d2)[s0, s1] -> (d0 + s1, d1 + s0, d0 + d1 + d2)`
179 /// returned expr: `d0 * 2 + d1 + d2 + s1`
180 AffineExpr compose(AffineMap map) const;
181
182 friend ::llvm::hash_code hash_value(AffineExpr arg);
183
184 /// Methods supporting C API.
185 const void *getAsOpaquePointer() const {
186 return static_cast<const void *>(expr);
187 }
188 static AffineExpr getFromOpaquePointer(const void *pointer) {
189 return AffineExpr(
190 reinterpret_cast<ImplType *>(const_cast<void *>(pointer)));
191 }
192
193 ImplType *getImpl() const { return expr; }
194
195protected:
196 ImplType *expr{nullptr};
197
198private:
199 /// A trampoline for the templated non-static AffineExpr::walk method to
200 /// dispatch lambda `callback`'s of either a void result type or a
201 /// WalkResult type. Walk all of the AffineExprs in `e` in postorder. Users
202 /// should use the regular (non-static) `walk` method.
203 template <typename WalkRetTy>
204 static WalkRetTy walk(AffineExpr e,
205 function_ref<WalkRetTy(AffineExpr)> callback);
206};
207
208/// Affine binary operation expression. An affine binary operation could be an
209/// add, mul, floordiv, ceildiv, or a modulo operation. (Subtraction is
210/// represented through a multiply by -1 and add.) These expressions are always
211/// constructed in a simplified form. For eg., the LHS and RHS operands can't
212/// both be constants. There are additional canonicalizing rules depending on
213/// the op type: see checks in the constructor.
215public:
218 AffineExpr getLHS() const;
219 AffineExpr getRHS() const;
220};
221
222/// A dimensional identifier appearing in an affine expression.
223class AffineDimExpr : public AffineExpr {
224public:
226 /* implicit */ AffineDimExpr(AffineExpr::ImplType *ptr);
227 unsigned getPosition() const;
228};
229
230/// A symbolic identifier appearing in an affine expression.
232public:
235 unsigned getPosition() const;
236};
237
238/// An integer constant appearing in affine expression.
245
246/// Make AffineExpr hashable.
247inline ::llvm::hash_code hash_value(AffineExpr arg) {
248 return ::llvm::hash_value(arg.expr);
249}
250
251inline AffineExpr operator+(int64_t val, AffineExpr expr) { return expr + val; }
252inline AffineExpr operator*(int64_t val, AffineExpr expr) { return expr * val; }
254 return expr * (-1) + val;
255}
256
257/// These free functions allow clients of the API to not use classes in detail.
258AffineExpr getAffineDimExpr(unsigned position, MLIRContext *context);
259AffineExpr getAffineSymbolExpr(unsigned position, MLIRContext *context);
262 MLIRContext *context);
265
266/// Constructs an affine expression from a flat ArrayRef. If there are local
267/// identifiers (neither dimensional nor symbolic) that appear in the sum of
268/// products expression, 'localExprs' is expected to have the AffineExpr
269/// for it, and is substituted into. The ArrayRef 'eq' is expected to be in the
270/// format [dims, symbols, locals, constant term].
272 unsigned numDims, unsigned numSymbols,
273 ArrayRef<AffineExpr> localExprs,
274 MLIRContext *context);
275
277
278/// Simplify an affine expression by flattening and some amount of simple
279/// analysis. This has complexity linear in the number of nodes in 'expr'.
280/// Returns the simplified expression, which is the same as the input expression
281/// if it can't be simplified. When `expr` is semi-affine, a simplified
282/// semi-affine expression is constructed in the sorted order of dimension and
283/// symbol positions.
284AffineExpr simplifyAffineExpr(AffineExpr expr, unsigned numDims,
285 unsigned numSymbols);
286
287namespace detail {
288template <int N>
290
291template <int N, typename AffineExprTy, typename... AffineExprTy2>
292void bindDims(MLIRContext *ctx, AffineExprTy &e, AffineExprTy2 &...exprs) {
293 e = getAffineDimExpr(N, ctx);
294 bindDims<N + 1, AffineExprTy2 &...>(ctx, exprs...);
295}
296
297template <int N>
299
300template <int N, typename AffineExprTy, typename... AffineExprTy2>
301void bindSymbols(MLIRContext *ctx, AffineExprTy &e, AffineExprTy2 &...exprs) {
302 e = getAffineSymbolExpr(N, ctx);
303 bindSymbols<N + 1, AffineExprTy2 &...>(ctx, exprs...);
304}
305
306} // namespace detail
307
308/// Bind a list of AffineExpr references to DimExpr at positions:
309/// [0 .. sizeof...(exprs)]
310template <typename... AffineExprTy>
311void bindDims(MLIRContext *ctx, AffineExprTy &...exprs) {
312 detail::bindDims<0>(ctx, exprs...);
313}
314
315template <typename AffineExprTy>
317 int idx = 0;
318 for (AffineExprTy &e : exprs)
319 e = getAffineDimExpr(idx++, ctx);
320}
321
322/// Bind a list of AffineExpr references to SymbolExpr at positions:
323/// [0 .. sizeof...(exprs)]
324template <typename... AffineExprTy>
325void bindSymbols(MLIRContext *ctx, AffineExprTy &...exprs) {
326 detail::bindSymbols<0>(ctx, exprs...);
327}
328
329template <typename AffineExprTy>
331 int idx = 0;
332 for (AffineExprTy &e : exprs)
333 e = getAffineSymbolExpr(idx++, ctx);
334}
335
336/// Get a lower or upper (depending on `isUpper`) bound for `expr` while using
337/// the constant lower and upper bounds for its inputs provided in
338/// `constLowerBounds` and `constUpperBounds`. Return std::nullopt if such a
339/// bound can't be computed. This method only handles simple sum of product
340/// expressions (w.r.t constant coefficients) so as to not depend on anything
341/// heavyweight in `Analysis`. Expressions of the form: c0*d0 + c1*d1 + c2*s0 +
342/// ... + c_n are handled. Expressions involving floordiv, ceildiv, mod or
343/// semi-affine ones will lead a none being returned.
344std::optional<int64_t>
345getBoundForAffineExpr(AffineExpr expr, unsigned numDims, unsigned numSymbols,
346 ArrayRef<std::optional<int64_t>> constLowerBounds,
347 ArrayRef<std::optional<int64_t>> constUpperBounds,
348 bool isUpper);
349
350} // namespace mlir
351
352namespace llvm {
353
354// AffineExpr hash just like pointers
355template <>
356struct DenseMapInfo<mlir::AffineExpr> {
359 return mlir::AffineExpr(static_cast<mlir::AffineExpr::ImplType *>(pointer));
360 }
363 return mlir::AffineExpr(static_cast<mlir::AffineExpr::ImplType *>(pointer));
364 }
365 static unsigned getHashValue(mlir::AffineExpr val) {
366 return mlir::hash_value(val);
367 }
369 return LHS == RHS;
370 }
371};
372
373/// Add support for llvm style casts. We provide a cast between To and From if
374/// From is mlir::AffineExpr or derives from it.
375template <typename To, typename From>
376struct CastInfo<To, From,
377 std::enable_if_t<std::is_same_v<mlir::AffineExpr,
378 std::remove_const_t<From>> ||
379 std::is_base_of_v<mlir::AffineExpr, From>>>
381 DefaultDoCastIfPossible<To, From, CastInfo<To, From>> {
382
383 static inline bool isPossible(mlir::AffineExpr expr) {
384 /// Return a constant true instead of a dynamic true when casting to self or
385 /// up the hierarchy.
386 if constexpr (std::is_base_of_v<To, From>) {
387 return true;
388 } else {
389 if constexpr (std::is_same_v<To, ::mlir::AffineBinaryOpExpr>)
391 if constexpr (std::is_same_v<To, ::mlir::AffineDimExpr>)
392 return expr.getKind() == ::mlir::AffineExprKind::DimId;
393 if constexpr (std::is_same_v<To, ::mlir::AffineSymbolExpr>)
395 if constexpr (std::is_same_v<To, ::mlir::AffineConstantExpr>)
397 }
398 }
399 static inline To doCast(mlir::AffineExpr expr) { return To(expr.getImpl()); }
400};
401
402} // namespace llvm
403
404#endif // MLIR_IR_AFFINEEXPR_H
lhs
*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`
AffineExpr getLHS() const
AffineBinaryOpExpr(AffineExpr::ImplType *ptr)
detail::AffineBinaryOpExprStorage ImplType
Definition AffineExpr.h:216
AffineExpr getRHS() const
AffineConstantExpr(AffineExpr::ImplType *ptr=nullptr)
detail::AffineConstantExprStorage ImplType
Definition AffineExpr.h:241
int64_t getValue() const
AffineDimExpr(AffineExpr::ImplType *ptr)
detail::AffineDimExprStorage ImplType
Definition AffineExpr.h:225
unsigned getPosition() const
Base type for affine expression.
Definition AffineExpr.h:68
static AffineExpr getFromOpaquePointer(const void *pointer)
Definition AffineExpr.h:188
AffineExpr replaceDimsAndSymbols(ArrayRef< AffineExpr > dimReplacements, ArrayRef< AffineExpr > symReplacements) const
This method substitutes any uses of dimensions and symbols (e.g.
const void * getAsOpaquePointer() const
Methods supporting C API.
Definition AffineExpr.h:185
AffineExpr shiftDims(unsigned numDims, unsigned shift, unsigned offset=0) const
Replace dims[offset ... numDims) by dims[offset + shift ... shift + numDims).
bool operator==(int64_t v) const
ImplType * getImpl() const
Definition AffineExpr.h:193
bool isSymbolicOrConstant() const
Returns true if this expression is made out of only symbols and constants, i.e., it does not involve ...
AffineExpr operator+(int64_t v) const
AffineExpr operator*(int64_t v) const
constexpr AffineExpr()
Definition AffineExpr.h:72
bool operator==(AffineExpr other) const
Definition AffineExpr.h:76
bool isPureAffine() const
Returns true if this is a pure affine expression, i.e., multiplication, floordiv, ceildiv,...
AffineExpr shiftSymbols(unsigned numSymbols, unsigned shift, unsigned offset=0) const
Replace symbols[offset ... numSymbols) by symbols[offset + shift ... shift + numSymbols).
AffineExpr operator-() const
AffineExpr floorDiv(uint64_t v) const
ImplType * expr
Definition AffineExpr.h:196
RetT walk(FnT &&callback) const
Walk all of the AffineExpr's in this expression in postorder.
Definition AffineExpr.h:117
bool operator!=(int64_t v) const
Definition AffineExpr.h:79
friend::llvm::hash_code hash_value(AffineExpr arg)
AffineExprKind getKind() const
Return the classification for this type.
bool isMultipleOf(int64_t factor) const
Return true if the affine expression is a multiple of 'factor'.
bool operator!() const
Definition AffineExpr.h:82
int64_t getLargestKnownDivisor() const
Returns the greatest known integral divisor of this affine expression.
AffineExpr compose(AffineMap map) const
Compose with an AffineMap.
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.
AffineExpr replaceDims(ArrayRef< AffineExpr > dimReplacements) const
Dim-only version of replaceDimsAndSymbols.
bool operator!=(AffineExpr other) const
Definition AffineExpr.h:77
AffineExpr operator%(uint64_t v) const
MLIRContext * getContext() const
AffineExpr replace(AffineExpr expr, AffineExpr replacement) const
Sparse replace method.
AffineExpr replaceSymbols(ArrayRef< AffineExpr > symReplacements) const
Symbol-only version of replaceDimsAndSymbols.
detail::AffineExprStorage ImplType
Definition AffineExpr.h:70
AffineExpr operator+(AffineExpr other) const
AffineExpr(const ImplType *expr)
Definition AffineExpr.h:73
void dump() const
AffineExpr ceilDiv(uint64_t v) const
void print(raw_ostream &os) const
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition AffineMap.h:46
unsigned getPosition() const
detail::AffineDimExprStorage ImplType
Definition AffineExpr.h:233
AffineSymbolExpr(AffineExpr::ImplType *ptr)
An integer set representing a conjunction of one or more affine equalities and inequalities.
Definition IntegerSet.h:44
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Definition CallGraph.h:229
AttrTypeReplacer.
void bindDims(MLIRContext *ctx)
Definition AffineExpr.h:289
void bindSymbols(MLIRContext *ctx)
Definition AffineExpr.h:298
Include the generated interface declarations.
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
void bindDimsList(MLIRContext *ctx, MutableArrayRef< AffineExprTy > exprs)
Definition AffineExpr.h:316
void bindDims(MLIRContext *ctx, AffineExprTy &...exprs)
Bind a list of AffineExpr references to DimExpr at positions: [0 .
Definition AffineExpr.h:311
std::optional< int64_t > getBoundForAffineExpr(AffineExpr expr, unsigned numDims, unsigned numSymbols, ArrayRef< std::optional< int64_t > > constLowerBounds, ArrayRef< std::optional< int64_t > > constUpperBounds, bool isUpper)
Get a lower or upper (depending on isUpper) bound for expr while using the constant lower and upper b...
AffineExprKind
Definition AffineExpr.h:40
@ CeilDiv
RHS of ceildiv is always a constant or a symbolic expression.
Definition AffineExpr.h:50
@ LAST_AFFINE_BINARY_OP
This is a marker for the last affine binary op.
Definition AffineExpr.h:54
@ Mul
RHS of mul is always a constant or a symbolic expression.
Definition AffineExpr.h:43
@ Mod
RHS of mod is always a constant or a symbolic expression with a positive value.
Definition AffineExpr.h:46
@ DimId
Dimensional identifier.
Definition AffineExpr.h:59
@ FloorDiv
RHS of floordiv is always a constant or a symbolic expression.
Definition AffineExpr.h:48
@ Constant
Constant integer.
Definition AffineExpr.h:57
@ SymbolId
Symbolic identifier.
Definition AffineExpr.h:61
AffineExpr getAffineBinaryOpExpr(AffineExprKind kind, AffineExpr lhs, AffineExpr rhs)
AffineExpr operator-(int64_t val, AffineExpr expr)
Definition AffineExpr.h:253
AffineExpr getAffineExprFromFlatForm(ArrayRef< int64_t > flatExprs, unsigned numDims, unsigned numSymbols, ArrayRef< AffineExpr > localExprs, MLIRContext *context)
Constructs an affine expression from a flat ArrayRef.
void bindSymbols(MLIRContext *ctx, AffineExprTy &...exprs)
Bind a list of AffineExpr references to SymbolExpr at positions: [0 .
Definition AffineExpr.h:325
AffineExpr operator+(int64_t val, AffineExpr expr)
Definition AffineExpr.h:251
AffineExpr operator*(int64_t val, AffineExpr expr)
Definition AffineExpr.h:252
AffineExpr getAffineConstantExpr(int64_t constant, MLIRContext *context)
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
Definition LLVM.h:126
AffineExpr simplifyAffineExpr(AffineExpr expr, unsigned numDims, unsigned numSymbols)
Simplify an affine expression by flattening and some amount of simple analysis.
SmallVector< AffineExpr > getAffineConstantExprs(ArrayRef< int64_t > constants, MLIRContext *context)
inline ::llvm::hash_code hash_value(AffineExpr arg)
Make AffineExpr hashable.
Definition AffineExpr.h:247
AffineExpr getAffineDimExpr(unsigned position, MLIRContext *context)
These free functions allow clients of the API to not use classes in detail.
llvm::function_ref< Fn > function_ref
Definition LLVM.h:152
AffineExpr getAffineSymbolExpr(unsigned position, MLIRContext *context)
void bindSymbolsList(MLIRContext *ctx, MutableArrayRef< AffineExprTy > exprs)
Definition AffineExpr.h:330
static unsigned getHashValue(mlir::AffineExpr val)
Definition AffineExpr.h:365
static mlir::AffineExpr getEmptyKey()
Definition AffineExpr.h:357
static mlir::AffineExpr getTombstoneKey()
Definition AffineExpr.h:361
static bool isEqual(mlir::AffineExpr LHS, mlir::AffineExpr RHS)
Definition AffineExpr.h:368
A binary operation appearing in an affine expression.
An integer constant appearing in affine expression.
A dimensional or symbolic identifier appearing in an affine expression.
Base storage class appearing in an affine expression.