xref: /llvm-project/mlir/lib/Dialect/Affine/IR/AffineValueMap.cpp (revision 1e9bfcd9a423765a86b2fc807c3bc3a097823deb)
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 
9 #include "mlir/Dialect/Affine/IR/AffineValueMap.h"
10 #include "mlir/Dialect/Affine/IR/AffineOps.h"
11 
12 using namespace mlir;
13 using namespace mlir::affine;
14 
AffineValueMap(AffineMap map,ValueRange operands,ValueRange results)15 AffineValueMap::AffineValueMap(AffineMap map, ValueRange operands,
16                                ValueRange results)
17     : map(map), operands(operands.begin(), operands.end()),
18       results(results.begin(), results.end()) {}
19 
reset(AffineMap map,ValueRange operands,ValueRange results)20 void AffineValueMap::reset(AffineMap map, ValueRange operands,
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 
composeSimplifyAndCanonicalize()27 void AffineValueMap::composeSimplifyAndCanonicalize() {
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 
difference(const AffineValueMap & a,const AffineValueMap & b,AffineValueMap * res)36 void AffineValueMap::difference(const AffineValueMap &a,
37                                 const AffineValueMap &b, AffineValueMap *res) {
38   assert(a.getNumResults() == b.getNumResults() && "invalid inputs");
39 
40   SmallVector<Value, 4> allOperands;
41   allOperands.reserve(a.getNumOperands() + b.getNumOperands());
42   auto aDims = a.getOperands().take_front(a.getNumDims());
43   auto bDims = b.getOperands().take_front(b.getNumDims());
44   auto aSyms = a.getOperands().take_back(a.getNumSymbols());
45   auto bSyms = b.getOperands().take_back(b.getNumSymbols());
46   allOperands.append(aDims.begin(), aDims.end());
47   allOperands.append(bDims.begin(), bDims.end());
48   allOperands.append(aSyms.begin(), aSyms.end());
49   allOperands.append(bSyms.begin(), bSyms.end());
50 
51   // Shift dims and symbols of b's map.
52   auto bMap = b.getAffineMap()
53                   .shiftDims(a.getNumDims())
54                   .shiftSymbols(a.getNumSymbols());
55 
56   // Construct the difference expressions.
57   auto aMap = a.getAffineMap();
58   SmallVector<AffineExpr, 4> diffExprs;
59   diffExprs.reserve(a.getNumResults());
60   for (unsigned i = 0, e = bMap.getNumResults(); i < e; ++i)
61     diffExprs.push_back(aMap.getResult(i) - bMap.getResult(i));
62 
63   auto diffMap = AffineMap::get(bMap.getNumDims(), bMap.getNumSymbols(),
64                                 diffExprs, bMap.getContext());
65   fullyComposeAffineMapAndOperands(&diffMap, &allOperands);
66   canonicalizeMapAndOperands(&diffMap, &allOperands);
67   diffMap = simplifyAffineMap(diffMap);
68   res->reset(diffMap, allOperands);
69 }
70 
71 // Returns true and sets 'indexOfMatch' if 'valueToMatch' is found in
72 // 'valuesToSearch' beginning at 'indexStart'. Returns false otherwise.
findIndex(Value valueToMatch,ArrayRef<Value> valuesToSearch,unsigned indexStart,unsigned * indexOfMatch)73 static bool findIndex(Value valueToMatch, ArrayRef<Value> valuesToSearch,
74                       unsigned indexStart, unsigned *indexOfMatch) {
75   unsigned size = valuesToSearch.size();
76   for (unsigned i = indexStart; i < size; ++i) {
77     if (valueToMatch == valuesToSearch[i]) {
78       *indexOfMatch = i;
79       return true;
80     }
81   }
82   return false;
83 }
84 
isMultipleOf(unsigned idx,int64_t factor) const85 bool AffineValueMap::isMultipleOf(unsigned idx, int64_t factor) const {
86   return map.isMultipleOf(idx, factor);
87 }
88 
89 /// This method uses the invariant that operands are always positionally aligned
90 /// with the AffineDimExpr in the underlying AffineMap.
isFunctionOf(unsigned idx,Value value) const91 bool AffineValueMap::isFunctionOf(unsigned idx, Value value) const {
92   unsigned index;
93   if (!findIndex(value, operands, /*indexStart=*/0, &index)) {
94     return false;
95   }
96   auto expr = const_cast<AffineValueMap *>(this)->getAffineMap().getResult(idx);
97   // TODO: this is better implemented on a flattened representation.
98   // At least for now it is conservative.
99   return expr.isFunctionOfDim(index);
100 }
101 
getOperand(unsigned i) const102 Value AffineValueMap::getOperand(unsigned i) const {
103   return static_cast<Value>(operands[i]);
104 }
105 
getOperands() const106 ArrayRef<Value> AffineValueMap::getOperands() const {
107   return ArrayRef<Value>(operands);
108 }
109 
getAffineMap() const110 AffineMap AffineValueMap::getAffineMap() const { return map.getAffineMap(); }
111 
112 AffineValueMap::~AffineValueMap() = default;
113