MLIR 24.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#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
91 LLVM_DUMP_METHOD void dump() const;
92#endif
93
94 /// Returns true if this expression is made out of only symbols and
95 /// constants, i.e., it does not involve dimensional identifiers.
96 bool isSymbolicOrConstant() const;
97
98 /// Returns true if this is a pure affine expression, i.e., multiplication,
99 /// floordiv, ceildiv, and mod is only allowed w.r.t constants.
100 bool isPureAffine() const;
101
102 /// Returns the greatest known integral divisor of this affine expression. The
103 /// result is always positive.
105
106 /// Return true if the affine expression is a multiple of 'factor'.
107 bool isMultipleOf(int64_t factor) const;
108
109 /// Return true if the affine expression involves AffineDimExpr `position`.
110 bool isFunctionOfDim(unsigned position) const;
111
112 /// Return true if the affine expression involves AffineSymbolExpr `position`.
113 bool isFunctionOfSymbol(unsigned position) const;
114
115 /// Walk all of the AffineExpr's in this expression in postorder. This allows
116 /// a lambda walk function that can either return `void` or a WalkResult. With
117 /// a WalkResult, interrupting is supported.
118 template <typename FnT, typename RetT = detail::walkResultType<FnT>>
119 RetT walk(FnT &&callback) const {
120 return walk<RetT>(*this, callback);
121 }
122
123 /// This method substitutes any uses of dimensions and symbols (e.g.
124 /// dim#0 with dimReplacements[0]) and returns the modified expression tree.
125 /// This is a dense replacement method: a replacement must be specified for
126 /// every single dim and symbol.
128 ArrayRef<AffineExpr> symReplacements) const;
129
130 /// Dim-only version of replaceDimsAndSymbols.
131 AffineExpr replaceDims(ArrayRef<AffineExpr> dimReplacements) const;
132
133 /// Symbol-only version of replaceDimsAndSymbols.
134 AffineExpr replaceSymbols(ArrayRef<AffineExpr> symReplacements) const;
135
136 /// Sparse replace method. Replace `expr` by `replacement` and return the
137 /// modified expression tree.
139
140 /// Sparse replace method. If `*this` appears in `map` replaces it by
141 /// `map[*this]` and return the modified expression tree. Otherwise traverse
142 /// `*this` and apply replace with `map` on its subexpressions.
144
145 /// Replace dims[offset ... numDims)
146 /// by dims[offset + shift ... shift + numDims).
147 AffineExpr shiftDims(unsigned numDims, unsigned shift,
148 unsigned offset = 0) const;
149
150 /// Replace symbols[offset ... numSymbols)
151 /// by symbols[offset + shift ... shift + numSymbols).
152 AffineExpr shiftSymbols(unsigned numSymbols, unsigned shift,
153 unsigned offset = 0) const;
154
157 AffineExpr operator-() const;
159 AffineExpr operator-(AffineExpr other) const;
161 AffineExpr operator*(AffineExpr other) const;
162 AffineExpr floorDiv(uint64_t v) const;
163 AffineExpr floorDiv(AffineExpr other) const;
164 AffineExpr ceilDiv(uint64_t v) const;
165 AffineExpr ceilDiv(AffineExpr other) const;
166 AffineExpr operator%(uint64_t v) const;
167 AffineExpr operator%(AffineExpr other) const;
168
169 /// Compose with an AffineMap.
170 /// Returns the composition of this AffineExpr with `map`.
171 ///
172 /// Prerequisites:
173 /// `this` and `map` are composable, i.e. that the number of AffineDimExpr of
174 /// `this` is smaller than the number of results of `map`. If a result of a
175 /// map does not have a corresponding AffineDimExpr, that result simply does
176 /// not appear in the produced AffineExpr.
177 ///
178 /// Example:
179 /// expr: `d0 + d2`
180 /// map: `(d0, d1, d2)[s0, s1] -> (d0 + s1, d1 + s0, d0 + d1 + d2)`
181 /// returned expr: `d0 * 2 + d1 + d2 + s1`
182 AffineExpr compose(AffineMap map) const;
183
184 friend ::llvm::hash_code hash_value(AffineExpr arg);
185
186 /// Methods supporting C API.
187 const void *getAsOpaquePointer() const {
188 return static_cast<const void *>(expr);
189 }
190 static AffineExpr getFromOpaquePointer(const void *pointer) {
191 return AffineExpr(
192 reinterpret_cast<ImplType *>(const_cast<void *>(pointer)));
193 }
194
195 ImplType *getImpl() const { return expr; }
196
197protected:
198 ImplType *expr{nullptr};
199
200private:
201 /// A trampoline for the templated non-static AffineExpr::walk method to
202 /// dispatch lambda `callback`'s of either a void result type or a
203 /// WalkResult type. Walk all of the AffineExprs in `e` in postorder. Users
204 /// should use the regular (non-static) `walk` method.
205 template <typename WalkRetTy>
206 static WalkRetTy walk(AffineExpr e,
207 function_ref<WalkRetTy(AffineExpr)> callback);
208};
209
210/// Affine binary operation expression. An affine binary operation could be an
211/// add, mul, floordiv, ceildiv, or a modulo operation. (Subtraction is
212/// represented through a multiply by -1 and add.) These expressions are always
213/// constructed in a simplified form. For eg., the LHS and RHS operands can't
214/// both be constants. There are additional canonicalizing rules depending on
215/// the op type: see checks in the constructor.
217public:
220 AffineExpr getLHS() const;
221 AffineExpr getRHS() const;
222};
223
224/// A dimensional identifier appearing in an affine expression.
225class AffineDimExpr : public AffineExpr {
226public:
228 /* implicit */ AffineDimExpr(AffineExpr::ImplType *ptr);
229 unsigned getPosition() const;
230};
231
232/// A symbolic identifier appearing in an affine expression.
234public:
237 unsigned getPosition() const;
238};
239
240/// An integer constant appearing in affine expression.
247
248/// Make AffineExpr hashable.
249inline ::llvm::hash_code hash_value(AffineExpr arg) {
250 return ::llvm::hash_value(arg.expr);
251}
252
253inline AffineExpr operator+(int64_t val, AffineExpr expr) { return expr + val; }
254inline AffineExpr operator*(int64_t val, AffineExpr expr) { return expr * val; }
256 return expr * (-1) + val;
257}
258
259/// These free functions allow clients of the API to not use classes in detail.
260AffineExpr getAffineDimExpr(unsigned position, MLIRContext *context);
261AffineExpr getAffineSymbolExpr(unsigned position, MLIRContext *context);
264 MLIRContext *context);
266 AffineExpr rhs);
267
268/// Constructs an affine expression from a flat ArrayRef. If there are local
269/// identifiers (neither dimensional nor symbolic) that appear in the sum of
270/// products expression, 'localExprs' is expected to have the AffineExpr
271/// for it, and is substituted into. The ArrayRef 'eq' is expected to be in the
272/// format [dims, symbols, locals, constant term].
274 unsigned numDims, unsigned numSymbols,
275 ArrayRef<AffineExpr> localExprs,
276 MLIRContext *context);
277
279
280/// Simplify an affine expression by flattening and some amount of simple
281/// analysis. This has complexity linear in the number of nodes in 'expr'.
282/// Returns the simplified expression, which is the same as the input expression
283/// if it can't be simplified. When `expr` is semi-affine, a simplified
284/// semi-affine expression is constructed in the sorted order of dimension and
285/// symbol positions.
286AffineExpr simplifyAffineExpr(AffineExpr expr, unsigned numDims,
287 unsigned numSymbols);
288
289namespace detail {
290template <int N>
292
293template <int N, typename AffineExprTy, typename... AffineExprTy2>
294void bindDims(MLIRContext *ctx, AffineExprTy &e, AffineExprTy2 &...exprs) {
295 e = getAffineDimExpr(N, ctx);
296 bindDims<N + 1, AffineExprTy2 &...>(ctx, exprs...);
297}
298
299template <int N>
301
302template <int N, typename AffineExprTy, typename... AffineExprTy2>
303void bindSymbols(MLIRContext *ctx, AffineExprTy &e, AffineExprTy2 &...exprs) {
304 e = getAffineSymbolExpr(N, ctx);
305 bindSymbols<N + 1, AffineExprTy2 &...>(ctx, exprs...);
306}
307
308} // namespace detail
309
310/// Bind a list of AffineExpr references to DimExpr at positions:
311/// [0 .. sizeof...(exprs)]
312template <typename... AffineExprTy>
313void bindDims(MLIRContext *ctx, AffineExprTy &...exprs) {
314 detail::bindDims<0>(ctx, exprs...);
315}
316
317template <typename AffineExprTy>
319 int idx = 0;
320 for (AffineExprTy &e : exprs)
321 e = getAffineDimExpr(idx++, ctx);
322}
323
324/// Bind a list of AffineExpr references to SymbolExpr at positions:
325/// [0 .. sizeof...(exprs)]
326template <typename... AffineExprTy>
327void bindSymbols(MLIRContext *ctx, AffineExprTy &...exprs) {
328 detail::bindSymbols<0>(ctx, exprs...);
329}
330
331template <typename AffineExprTy>
333 int idx = 0;
334 for (AffineExprTy &e : exprs)
335 e = getAffineSymbolExpr(idx++, ctx);
336}
337
338/// Get a lower or upper (depending on `isUpper`) bound for `expr` while using
339/// the constant lower and upper bounds for its inputs provided in
340/// `constLowerBounds` and `constUpperBounds`. Return std::nullopt if such a
341/// bound can't be computed. This method only handles simple sum of product
342/// expressions (w.r.t constant coefficients) so as to not depend on anything
343/// heavyweight in `Analysis`. Expressions of the form: c0*d0 + c1*d1 + c2*s0 +
344/// ... + c_n are handled. Expressions involving floordiv, ceildiv, mod or
345/// semi-affine ones will lead a none being returned.
346std::optional<int64_t>
347getBoundForAffineExpr(AffineExpr expr, unsigned numDims, unsigned numSymbols,
348 ArrayRef<std::optional<int64_t>> constLowerBounds,
349 ArrayRef<std::optional<int64_t>> constUpperBounds,
350 bool isUpper);
351
352} // namespace mlir
353
354namespace llvm {
355
356// AffineExpr hash just like pointers
357template <>
358struct DenseMapInfo<mlir::AffineExpr> {
359 static unsigned getHashValue(mlir::AffineExpr val) {
360 return mlir::hash_value(val);
361 }
363 return LHS == RHS;
364 }
365};
366
367/// Add support for llvm style casts. We provide a cast between To and From if
368/// From is mlir::AffineExpr or derives from it.
369template <typename To, typename From>
370struct CastInfo<To, From,
371 std::enable_if_t<std::is_same_v<mlir::AffineExpr,
372 std::remove_const_t<From>> ||
373 std::is_base_of_v<mlir::AffineExpr, From>>>
375 DefaultDoCastIfPossible<To, From, CastInfo<To, From>> {
376
377 static inline bool isPossible(mlir::AffineExpr expr) {
378 /// Return a constant true instead of a dynamic true when casting to self or
379 /// up the hierarchy.
380 if constexpr (std::is_base_of_v<To, From>) {
381 return true;
382 } else {
383 if constexpr (std::is_same_v<To, ::mlir::AffineBinaryOpExpr>)
385 if constexpr (std::is_same_v<To, ::mlir::AffineDimExpr>)
386 return expr.getKind() == ::mlir::AffineExprKind::DimId;
387 if constexpr (std::is_same_v<To, ::mlir::AffineSymbolExpr>)
389 if constexpr (std::is_same_v<To, ::mlir::AffineConstantExpr>)
391 }
392 }
393 static inline To doCast(mlir::AffineExpr expr) { return To(expr.getImpl()); }
394};
395
396} // namespace llvm
397
398#endif // MLIR_IR_AFFINEEXPR_H
*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:218
AffineExpr getRHS() const
AffineConstantExpr(AffineExpr::ImplType *ptr=nullptr)
detail::AffineConstantExprStorage ImplType
Definition AffineExpr.h:243
int64_t getValue() const
AffineDimExpr(AffineExpr::ImplType *ptr)
detail::AffineDimExprStorage ImplType
Definition AffineExpr.h:227
unsigned getPosition() const
Base type for affine expression.
Definition AffineExpr.h:68
static AffineExpr getFromOpaquePointer(const void *pointer)
Definition AffineExpr.h:190
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:187
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:195
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:198
RetT walk(FnT &&callback) const
Walk all of the AffineExpr's in this expression in postorder.
Definition AffineExpr.h:119
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
LLVM_DUMP_METHOD 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:235
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:71
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Definition CallGraph.h:229
AttrTypeReplacer.
void bindDims(MLIRContext *ctx)
Definition AffineExpr.h:291
void bindSymbols(MLIRContext *ctx)
Definition AffineExpr.h:300
Include the generated interface declarations.
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
void bindDimsList(MLIRContext *ctx, MutableArrayRef< AffineExprTy > exprs)
Definition AffineExpr.h:318
void bindDims(MLIRContext *ctx, AffineExprTy &...exprs)
Bind a list of AffineExpr references to DimExpr at positions: [0 .
Definition AffineExpr.h:313
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:255
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:327
AffineExpr operator+(int64_t val, AffineExpr expr)
Definition AffineExpr.h:253
AffineExpr operator*(int64_t val, AffineExpr expr)
Definition AffineExpr.h:254
AffineExpr getAffineConstantExpr(int64_t constant, MLIRContext *context)
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
Definition LLVM.h:123
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:249
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:155
AffineExpr getAffineSymbolExpr(unsigned position, MLIRContext *context)
void bindSymbolsList(MLIRContext *ctx, MutableArrayRef< AffineExprTy > exprs)
Definition AffineExpr.h:332
static unsigned getHashValue(mlir::AffineExpr val)
Definition AffineExpr.h:359
static bool isEqual(mlir::AffineExpr LHS, mlir::AffineExpr RHS)
Definition AffineExpr.h:362
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.