MLIR 24.0.0git
AffineValueMap.cpp
Go to the documentation of this file.
1//===- AffineValueMap.cpp - MLIR Affine Value Map Class -------------------===//
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
11
12using namespace mlir;
13using namespace mlir::affine;
14
16 ValueRange results)
17 : map(map), operands(operands.begin(), operands.end()),
18 results(results.begin(), results.end()) {}
19
21 ValueRange results) {
22 this->map.reset(map);
23 this->operands.assign(operands.begin(), operands.end());
24 this->results.assign(results.begin(), results.end());
25}
26
28 AffineMap sMap = getAffineMap();
29 fullyComposeAffineMapAndOperands(&sMap, &operands);
30 // Full composition also canonicalizes and simplifies before returning. We
31 // need to canonicalize once more to drop unused operands.
32 canonicalizeMapAndOperands(&sMap, &operands);
33 this->map.reset(sMap);
34}
35
37 AffineExpr expr, AffineValueMap *res,
38 bool pairwise) {
39 assert((!pairwise || a.getNumResults() == b.getNumResults()) &&
40 "matching by position requires equal result counts");
41 bool validExpr = true;
42 expr.walk([&](AffineExpr subExpr) {
43 if (auto dim = llvm::dyn_cast<AffineDimExpr>(subExpr))
44 validExpr &= dim.getPosition() < 2;
45 else if (llvm::isa<AffineSymbolExpr>(subExpr))
46 validExpr = false;
47 });
48 assert(validExpr && "combining expression must use only d0 and d1");
49
50 SmallVector<Value, 4> allOperands;
51 allOperands.reserve(a.getNumOperands() + b.getNumOperands());
52 auto aDims = a.getOperands().take_front(a.getNumDims());
53 auto bDims = b.getOperands().take_front(b.getNumDims());
54 auto aSyms = a.getOperands().take_back(a.getNumSymbols());
55 auto bSyms = b.getOperands().take_back(b.getNumSymbols());
56 allOperands.append(aDims.begin(), aDims.end());
57 allOperands.append(bDims.begin(), bDims.end());
58 allOperands.append(aSyms.begin(), aSyms.end());
59 allOperands.append(bSyms.begin(), bSyms.end());
60
61 // Shift dims and symbols of b's map.
62 auto bMap = b.getAffineMap()
63 .shiftDims(a.getNumDims())
64 .shiftSymbols(a.getNumSymbols());
65
66 // Substitute each pair of results into the combining expression.
67 auto aMap = a.getAffineMap();
68 SmallVector<AffineExpr> resultExprs;
69 if (pairwise) {
70 resultExprs.reserve(a.getNumResults());
71 for (auto [aResult, bResult] :
72 llvm::zip_equal(aMap.getResults(), bMap.getResults())) {
73 AffineExpr replacements[] = {aResult, bResult};
74 resultExprs.push_back(expr.replaceDims(replacements));
75 }
76 } else {
77 resultExprs.reserve(a.getNumResults() * b.getNumResults());
78 for (AffineExpr aResult : aMap.getResults())
79 for (AffineExpr bResult : bMap.getResults()) {
80 AffineExpr replacements[] = {aResult, bResult};
81 resultExprs.push_back(expr.replaceDims(replacements));
82 }
83 }
84
85 auto resultMap = AffineMap::get(bMap.getNumDims(), bMap.getNumSymbols(),
86 resultExprs, bMap.getContext());
87 fullyComposeAffineMapAndOperands(&resultMap, &allOperands);
88 canonicalizeMapAndOperands(&resultMap, &allOperands);
89 resultMap = simplifyAffineMap(resultMap);
90 res->reset(resultMap, allOperands);
91}
92
94 const AffineValueMap &b, AffineValueMap *res) {
95 MLIRContext *context = a.getAffineMap().getContext();
96 AffineExpr lhs = getAffineDimExpr(0, context);
97 AffineExpr rhs = getAffineDimExpr(1, context);
98 combine(a, b, lhs - rhs, res);
99}
100
102 const AffineValueMap &b,
103 AffineValueMap *res) {
104 MLIRContext *context = a.getAffineMap().getContext();
105 AffineExpr lhs = getAffineDimExpr(0, context);
106 AffineExpr rhs = getAffineDimExpr(1, context);
107 combine(a, b, lhs - rhs, res, /*pairwise=*/false);
108}
109
110// Returns true and sets 'indexOfMatch' if 'valueToMatch' is found in
111// 'valuesToSearch' beginning at 'indexStart'. Returns false otherwise.
112static bool findIndex(Value valueToMatch, ArrayRef<Value> valuesToSearch,
113 unsigned indexStart, unsigned *indexOfMatch) {
114 unsigned size = valuesToSearch.size();
115 for (unsigned i = indexStart; i < size; ++i) {
116 if (valueToMatch == valuesToSearch[i]) {
117 *indexOfMatch = i;
118 return true;
119 }
120 }
121 return false;
122}
123
124bool AffineValueMap::isMultipleOf(unsigned idx, int64_t factor) const {
125 return map.isMultipleOf(idx, factor);
126}
127
128/// This method uses the invariant that operands are always positionally aligned
129/// with the AffineDimExpr in the underlying AffineMap.
130bool AffineValueMap::isFunctionOf(unsigned idx, Value value) const {
131 unsigned index;
132 if (!findIndex(value, operands, /*indexStart=*/0, &index)) {
133 return false;
134 }
135 auto expr = const_cast<AffineValueMap *>(this)->getAffineMap().getResult(idx);
136 // TODO: this is better implemented on a flattened representation.
137 // At least for now it is conservative.
138 return expr.isFunctionOfDim(index);
139}
140
142 return static_cast<Value>(operands[i]);
143}
144
148
149AffineMap AffineValueMap::getAffineMap() const { return map.getAffineMap(); }
150
152 if (getNumResults() != other.getNumResults())
153 return false;
154 AffineValueMap diff;
155 AffineValueMap::difference(*this, other, &diff);
156 return llvm::all_of(diff.getAffineMap().getResults(), [](AffineExpr e) {
157 return e == getAffineConstantExpr(0, e.getContext());
158 });
159}
160
static bool findIndex(Value valueToMatch, ArrayRef< Value > valuesToSearch, unsigned indexStart, unsigned *indexOfMatch)
b
Return true if permutation is a valid permutation of the outer_dims_perm (case OuterOrInnerPerm::Oute...
Base type for affine expression.
Definition AffineExpr.h:68
RetT walk(FnT &&callback) const
Walk all of the AffineExpr's in this expression in postorder.
Definition AffineExpr.h:119
bool isFunctionOfDim(unsigned position) const
Return true if the affine expression involves AffineDimExpr position.
AffineExpr replaceDims(ArrayRef< AffineExpr > dimReplacements) const
Dim-only version of replaceDimsAndSymbols.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
Definition AffineMap.h:46
MLIRContext * getContext() const
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
ArrayRef< AffineExpr > getResults() const
AffineExpr getResult(unsigned idx) const
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:71
This class provides an abstraction over the different types of ranges over Values.
Definition ValueRange.h:392
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
Value getOperand(unsigned i) const
static void cartesianProductDifference(const AffineValueMap &a, const AffineValueMap &b, AffineValueMap *res)
Subtract results of 'b' from results of 'a' over their Cartesian product.
bool operator==(const AffineValueMap &other) const
Checks if the application of this map to its operands is semantically equal to other's.
bool isMultipleOf(unsigned idx, int64_t factor) const
Return true if the idx^th result can be proved to be a multiple of 'factor', false otherwise.
static void combine(const AffineValueMap &a, const AffineValueMap &b, AffineExpr expr, AffineValueMap *res, bool pairwise=true)
Combine results from 'a' and 'b' using 'expr'.
void composeSimplifyAndCanonicalize()
Composes all incoming affine.apply ops and then simplifies and canonicalizes the map and operands.
ArrayRef< Value > getOperands() const
unsigned getNumOperands() const
bool isFunctionOf(unsigned idx, Value value) const
Return true if the idx^th result depends on 'value', false otherwise.
void reset(AffineMap map, ValueRange operands, ValueRange results={})
static void difference(const AffineValueMap &a, const AffineValueMap &b, AffineValueMap *res)
Subtract each result of 'b' from the result of 'a' at the same index; the result counts must be equal...
void canonicalizeMapAndOperands(AffineMap *map, SmallVectorImpl< Value > *operands)
Modifies both map and operands in-place so as to:
void fullyComposeAffineMapAndOperands(AffineMap *map, SmallVectorImpl< Value > *operands, bool composeAffineMin=false)
Given an affine map map and its input operands, this method composes into map, maps of AffineApplyOps...
Include the generated interface declarations.
AffineMap simplifyAffineMap(AffineMap map)
Simplifies an affine map by simplifying its underlying AffineExpr results.
AffineExpr getAffineDimExpr(unsigned position, MLIRContext *context)
These free functions allow clients of the API to not use classes in detail.