MLIR 23.0.0git
ReifyValueBounds.cpp
Go to the documentation of this file.
1//===- ReifyValueBounds.cpp --- Reify value bounds with arith ops -------*-===//
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#include <utility>
10
12
17
18using namespace mlir;
19using namespace mlir::arith;
20
21[[maybe_unused]] static bool isIndexLikeType(Type type,
23 return type.isIndex() || (options.allowIntegerType && type.isInteger());
24}
25
27 if (value.getType().isIndex())
28 return value;
29 assert(value.getType().isSignlessInteger() &&
30 "expected index or signless integer type");
31 return IndexCastOp::create(b, loc, b.getIndexType(), value);
32}
33
34/// Build Arith IR for the given affine map and its operands.
36 ValueRange operands) {
37 assert(map.getNumResults() == 1 && "multiple results not supported yet");
38 std::function<Value(AffineExpr)> buildExpr = [&](AffineExpr e) -> Value {
39 switch (e.getKind()) {
41 return ConstantIndexOp::create(b, loc,
42 cast<AffineConstantExpr>(e).getValue());
44 return castToIndexValue(b, loc,
45 operands[cast<AffineDimExpr>(e).getPosition()]);
47 return castToIndexValue(
48 b, loc,
49 operands[cast<AffineSymbolExpr>(e).getPosition() + map.getNumDims()]);
51 auto binaryExpr = cast<AffineBinaryOpExpr>(e);
52 return AddIOp::create(b, loc, buildExpr(binaryExpr.getLHS()),
53 buildExpr(binaryExpr.getRHS()));
54 }
56 auto binaryExpr = cast<AffineBinaryOpExpr>(e);
57 return MulIOp::create(b, loc, buildExpr(binaryExpr.getLHS()),
58 buildExpr(binaryExpr.getRHS()));
59 }
61 auto binaryExpr = cast<AffineBinaryOpExpr>(e);
62 return DivSIOp::create(b, loc, buildExpr(binaryExpr.getLHS()),
63 buildExpr(binaryExpr.getRHS()));
64 }
66 auto binaryExpr = cast<AffineBinaryOpExpr>(e);
67 return CeilDivSIOp::create(b, loc, buildExpr(binaryExpr.getLHS()),
68 buildExpr(binaryExpr.getRHS()));
69 }
71 auto binaryExpr = cast<AffineBinaryOpExpr>(e);
72 return RemSIOp::create(b, loc, buildExpr(binaryExpr.getLHS()),
73 buildExpr(binaryExpr.getRHS()));
74 }
75 }
76 llvm_unreachable("unsupported AffineExpr kind");
77 };
78 return buildExpr(map.getResult(0));
79}
80
81FailureOr<OpFoldResult> mlir::arith::reifyValueBound(
86 // Compute bound.
87 AffineMap boundMap;
88 ValueDimList mapOperands;
90 boundMap, mapOperands, type, var, std::move(stopCondition), options)))
91 return failure();
92
93 // Materialize tensor.dim/memref.dim ops.
94 SmallVector<Value> operands;
95 for (auto valueDim : mapOperands) {
96 Value value = valueDim.first;
97 std::optional<int64_t> dim = valueDim.second;
98
99 if (!dim.has_value()) {
100 // This is an index-typed/integer-typed value.
101 assert(isIndexLikeType(value.getType(), options) &&
102 "expected index or integer type");
103 operands.push_back(value);
104 continue;
105 }
106
107 assert(cast<ShapedType>(value.getType()).isDynamicDim(*dim) &&
108 "expected dynamic dim");
109 if (isa<RankedTensorType>(value.getType())) {
110 // A tensor dimension is used: generate a tensor.dim.
111 operands.push_back(tensor::DimOp::create(b, loc, value, *dim));
112 } else if (isa<MemRefType>(value.getType())) {
113 // A memref dimension is used: generate a memref.dim.
114 operands.push_back(memref::DimOp::create(b, loc, value, *dim));
115 } else {
116 llvm_unreachable("cannot generate DimOp for unsupported shaped type");
117 }
118 }
119
120 // Check for special cases where no arith ops are needed.
121 if (boundMap.isSingleConstant()) {
122 // Bound is a constant: return an IntegerAttr.
123 return static_cast<OpFoldResult>(
124 b.getIndexAttr(boundMap.getSingleConstantResult()));
125 }
126 // No arith ops are needed if the bound is a single SSA value.
127 if (auto expr = dyn_cast<AffineDimExpr>(boundMap.getResult(0)))
128 return static_cast<OpFoldResult>(
129 castToIndexValue(b, loc, operands[expr.getPosition()]));
130 if (auto expr = dyn_cast<AffineSymbolExpr>(boundMap.getResult(0)))
131 return static_cast<OpFoldResult>(castToIndexValue(
132 b, loc, operands[expr.getPosition() + boundMap.getNumDims()]));
133 // General case: build Arith ops.
134 return static_cast<OpFoldResult>(buildArithValue(b, loc, boundMap, operands));
135}
136
139 int64_t dim, const ValueBoundsConstraintSet::StopConditionFn &stopCondition,
141 auto reifyToOperands = [&](Value v, std::optional<int64_t> d,
143 // We are trying to reify a bound for `value` in terms of the owning op's
144 // operands. Construct a stop condition that evaluates to "true" for any SSA
145 // value expect for `value`. I.e., the bound will be computed in terms of
146 // any SSA values expect for `value`. The first such values are operands of
147 // the owner of `value`.
148 return v != value;
149 };
150 return reifyValueBound(b, loc, type, {value, dim},
151 stopCondition ? stopCondition : reifyToOperands,
152 options);
153}
154
155FailureOr<OpFoldResult> mlir::arith::reifyIndexValueBound(
159 auto reifyToOperands = [&](Value v, std::optional<int64_t> d,
161 return v != value;
162 };
163 return reifyValueBound(b, loc, type, value,
164 stopCondition ? stopCondition : reifyToOperands,
165 options);
166}
static Value castToIndexValue(OpBuilder &b, Location loc, Value value)
static Value buildArithValue(OpBuilder &b, Location loc, AffineMap map, ValueRange operands)
Build Arith IR for the given affine map and its operands.
static bool isIndexLikeType(Type type, ValueBoundsOptions options)
b
Return true if permutation is a valid permutation of the outer_dims_perm (case OuterOrInnerPerm::Oute...
static llvm::ManagedStatic< PassManagerOptions > options
Base type for affine expression.
Definition AffineExpr.h:68
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.
bool isSingleConstant() const
Returns true if this affine map is a single result constant function.
unsigned getNumDims() const
unsigned getNumResults() const
AffineExpr getResult(unsigned idx) const
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition Location.h:76
This class helps build Operations.
Definition Builders.h:209
This class represents a single result from folding an operation.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
bool isSignlessInteger() const
Return true if this is a signless integer type (with the specified width).
Definition Types.cpp:66
bool isIndex() const
Definition Types.cpp:56
bool isInteger() const
Return true if this is an integer type (with the specified width).
Definition Types.cpp:58
A variable that can be added to the constraint set as a "column".
A helper class to be used with ValueBoundsOpInterface.
static LogicalResult computeBound(AffineMap &resultMap, ValueDimList &mapOperands, presburger::BoundType type, const Variable &var, StopConditionFn stopCondition, ValueBoundsOptions options={})
Compute a bound for the given variable.
std::function< bool( Value, std::optional< int64_t >, ValueBoundsConstraintSet &cstr)> StopConditionFn
The stop condition when traversing the backward slice of a shaped value/ index-type value.
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:389
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
Type getType() const
Return the type of this value.
Definition Value.h:105
static ConstantIndexOp create(OpBuilder &builder, Location location, int64_t value)
Definition ArithOps.cpp:369
FailureOr< OpFoldResult > reifyShapedValueDimBound(OpBuilder &b, Location loc, presburger::BoundType type, Value value, int64_t dim, const ValueBoundsConstraintSet::StopConditionFn &stopCondition=nullptr, ValueBoundsOptions options={})
Reify a bound for the specified dimension of the given shaped value in terms of SSA values for which ...
FailureOr< OpFoldResult > reifyIndexValueBound(OpBuilder &b, Location loc, presburger::BoundType type, Value value, const ValueBoundsConstraintSet::StopConditionFn &stopCondition=nullptr, ValueBoundsOptions options={})
Reify a bound for the given index-typed value in terms of SSA values for which stopCondition is met.
FailureOr< OpFoldResult > reifyValueBound(OpBuilder &b, Location loc, presburger::BoundType type, const ValueBoundsConstraintSet::Variable &var, ValueBoundsConstraintSet::StopConditionFn stopCondition, ValueBoundsOptions options={})
Reify a bound for the given variable in terms of SSA values for which stopCondition is met.
BoundType
The type of bound: equal, lower bound or upper bound.
Include the generated interface declarations.
@ CeilDiv
RHS of ceildiv is always a constant or a symbolic expression.
Definition AffineExpr.h:50
@ 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
SmallVector< std::pair< Value, std::optional< int64_t > >, 2 > ValueDimList
Options that control value bound computation.