MLIR  18.0.0git
ValueBoundsOpInterfaceImpl.cpp
Go to the documentation of this file.
1 //===- ValueBoundsOpInterfaceImpl.cpp - Impl. of ValueBoundsOpInterface ---===//
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 
10 
13 
14 using namespace mlir;
15 using namespace mlir::affine;
16 
17 namespace mlir {
18 namespace {
19 
20 struct AffineApplyOpInterface
21  : public ValueBoundsOpInterface::ExternalModel<AffineApplyOpInterface,
22  AffineApplyOp> {
23  void populateBoundsForIndexValue(Operation *op, Value value,
24  ValueBoundsConstraintSet &cstr) const {
25  auto applyOp = cast<AffineApplyOp>(op);
26  assert(value == applyOp.getResult() && "invalid value");
27  assert(applyOp.getAffineMap().getNumResults() == 1 &&
28  "expected single result");
29 
30  // Fully compose this affine.apply with other ops because the folding logic
31  // can see opportunities for simplifying the affine map that
32  // `FlatLinearConstraints` can currently not see.
33  AffineMap map = applyOp.getAffineMap();
34  SmallVector<Value> operands = llvm::to_vector(applyOp.getOperands());
35  fullyComposeAffineMapAndOperands(&map, &operands);
36 
37  // Align affine map result with dims/symbols in the constraint set.
38  AffineExpr expr = map.getResult(0);
39  SmallVector<AffineExpr> dimReplacements, symReplacements;
40  for (int64_t i = 0, e = map.getNumDims(); i < e; ++i)
41  dimReplacements.push_back(cstr.getExpr(operands[i]));
42  for (int64_t i = map.getNumDims(),
43  e = map.getNumDims() + map.getNumSymbols();
44  i < e; ++i)
45  symReplacements.push_back(cstr.getExpr(operands[i]));
46  AffineExpr bound =
47  expr.replaceDimsAndSymbols(dimReplacements, symReplacements);
48  cstr.bound(value) == bound;
49  }
50 };
51 
52 struct AffineMinOpInterface
53  : public ValueBoundsOpInterface::ExternalModel<AffineMinOpInterface,
54  AffineMinOp> {
55  void populateBoundsForIndexValue(Operation *op, Value value,
56  ValueBoundsConstraintSet &cstr) const {
57  auto minOp = cast<AffineMinOp>(op);
58  assert(value == minOp.getResult() && "invalid value");
59 
60  // Align affine map results with dims/symbols in the constraint set.
61  for (AffineExpr expr : minOp.getAffineMap().getResults()) {
62  SmallVector<AffineExpr> dimReplacements = llvm::to_vector(llvm::map_range(
63  minOp.getDimOperands(), [&](Value v) { return cstr.getExpr(v); }));
64  SmallVector<AffineExpr> symReplacements = llvm::to_vector(llvm::map_range(
65  minOp.getSymbolOperands(), [&](Value v) { return cstr.getExpr(v); }));
66  AffineExpr bound =
67  expr.replaceDimsAndSymbols(dimReplacements, symReplacements);
68  cstr.bound(value) <= bound;
69  }
70  };
71 };
72 
73 struct AffineMaxOpInterface
74  : public ValueBoundsOpInterface::ExternalModel<AffineMaxOpInterface,
75  AffineMaxOp> {
76  void populateBoundsForIndexValue(Operation *op, Value value,
77  ValueBoundsConstraintSet &cstr) const {
78  auto maxOp = cast<AffineMaxOp>(op);
79  assert(value == maxOp.getResult() && "invalid value");
80 
81  // Align affine map results with dims/symbols in the constraint set.
82  for (AffineExpr expr : maxOp.getAffineMap().getResults()) {
83  SmallVector<AffineExpr> dimReplacements = llvm::to_vector(llvm::map_range(
84  maxOp.getDimOperands(), [&](Value v) { return cstr.getExpr(v); }));
85  SmallVector<AffineExpr> symReplacements = llvm::to_vector(llvm::map_range(
86  maxOp.getSymbolOperands(), [&](Value v) { return cstr.getExpr(v); }));
87  AffineExpr bound =
88  expr.replaceDimsAndSymbols(dimReplacements, symReplacements);
89  cstr.bound(value) >= bound;
90  }
91  };
92 };
93 
94 } // namespace
95 } // namespace mlir
96 
98  DialectRegistry &registry) {
99  registry.addExtension(+[](MLIRContext *ctx, AffineDialect *dialect) {
100  AffineApplyOp::attachInterface<AffineApplyOpInterface>(*ctx);
101  AffineMaxOp::attachInterface<AffineMaxOpInterface>(*ctx);
102  AffineMinOp::attachInterface<AffineMinOpInterface>(*ctx);
103  });
104 }
105 
108  assert(value1.getType().isIndex() && "expected index type");
109  assert(value2.getType().isIndex() && "expected index type");
110 
111  // Subtract the two values/dimensions from each other. If the result is 0,
112  // both are equal.
113  Builder b(value1.getContext());
114  AffineMap map = AffineMap::get(/*dimCount=*/2, /*symbolCount=*/0,
115  b.getAffineDimExpr(0) - b.getAffineDimExpr(1));
116  // Fully compose the affine map with other ops because the folding logic
117  // can see opportunities for simplifying the affine map that
118  // `FlatLinearConstraints` can currently not see.
119  SmallVector<Value> mapOperands;
120  mapOperands.push_back(value1);
121  mapOperands.push_back(value2);
122  affine::fullyComposeAffineMapAndOperands(&map, &mapOperands);
123  ValueDimList valueDims;
124  for (Value v : mapOperands)
125  valueDims.push_back({v, std::nullopt});
127  presburger::BoundType::EQ, map, valueDims);
128 }
Base type for affine expression.
Definition: AffineExpr.h:68
AffineExpr replaceDimsAndSymbols(ArrayRef< AffineExpr > dimReplacements, ArrayRef< AffineExpr > symReplacements) const
This method substitutes any uses of dimensions and symbols (e.g.
Definition: AffineExpr.cpp:66
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition: AffineMap.h:47
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
unsigned getNumSymbols() const
Definition: AffineMap.cpp:378
unsigned getNumDims() const
Definition: AffineMap.cpp:374
AffineExpr getResult(unsigned idx) const
Definition: AffineMap.cpp:391
This class is a general helper class for creating context-global objects like types,...
Definition: Builders.h:50
AffineExpr getAffineDimExpr(unsigned position)
Definition: Builders.cpp:353
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
void addExtension(std::unique_ptr< DialectExtensionBase > extension)
Add the given extension to the registry.
This class provides support for representing a failure result, or a valid value of type T.
Definition: LogicalResult.h:78
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
bool isIndex() const
Definition: Types.cpp:56
A helper class to be used with ValueBoundsOpInterface.
AffineExpr getExpr(Value value, std::optional< int64_t > dim=std::nullopt)
Return an expression that represents the given index-typed value or shaped value dimension.
BoundBuilder bound(Value value)
Add a bound for the given index-typed value or shaped value.
static FailureOr< int64_t > computeConstantBound(presburger::BoundType type, Value value, std::optional< int64_t > dim=std::nullopt, StopConditionFn stopCondition=nullptr, bool closedUB=false)
Compute a constant bound for the given affine map, where dims and symbols are bound to the given oper...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
MLIRContext * getContext() const
Utility to get the associated MLIRContext that this value is defined in.
Definition: Value.h:128
Type getType() const
Return the type of this value.
Definition: Value.h:125
void fullyComposeAffineMapAndOperands(AffineMap *map, SmallVectorImpl< Value > *operands)
Given an affine map map and its input operands, this method composes into map, maps of AffineApplyOps...
Definition: AffineOps.cpp:1114
void registerValueBoundsOpInterfaceExternalModels(DialectRegistry &registry)
FailureOr< int64_t > fullyComposeAndComputeConstantDelta(Value value1, Value value2)
Compute a constant delta of the given two values.
Include the generated interface declarations.