/home/arjun/llvm-project/mlir/lib/IR/AffineMap.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- AffineMap.cpp - MLIR Affine Map Classes ----------------------------===// |
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/IR/AffineMap.h" |
10 | | #include "AffineMapDetail.h" |
11 | | #include "mlir/IR/Attributes.h" |
12 | | #include "mlir/IR/StandardTypes.h" |
13 | | #include "mlir/Support/LogicalResult.h" |
14 | | #include "mlir/Support/MathExtras.h" |
15 | | #include "llvm/ADT/StringRef.h" |
16 | | #include "llvm/Support/raw_ostream.h" |
17 | | |
18 | | using namespace mlir; |
19 | | |
20 | | namespace { |
21 | | |
22 | | // AffineExprConstantFolder evaluates an affine expression using constant |
23 | | // operands passed in 'operandConsts'. Returns an IntegerAttr attribute |
24 | | // representing the constant value of the affine expression evaluated on |
25 | | // constant 'operandConsts', or nullptr if it can't be folded. |
26 | | class AffineExprConstantFolder { |
27 | | public: |
28 | | AffineExprConstantFolder(unsigned numDims, ArrayRef<Attribute> operandConsts) |
29 | 0 | : numDims(numDims), operandConsts(operandConsts) {} |
30 | | |
31 | | /// Attempt to constant fold the specified affine expr, or return null on |
32 | | /// failure. |
33 | 0 | IntegerAttr constantFold(AffineExpr expr) { |
34 | 0 | if (auto result = constantFoldImpl(expr)) |
35 | 0 | return IntegerAttr::get(IndexType::get(expr.getContext()), *result); |
36 | 0 | return nullptr; |
37 | 0 | } |
38 | | |
39 | | private: |
40 | 0 | Optional<int64_t> constantFoldImpl(AffineExpr expr) { |
41 | 0 | switch (expr.getKind()) { |
42 | 0 | case AffineExprKind::Add: |
43 | 0 | return constantFoldBinExpr( |
44 | 0 | expr, [](int64_t lhs, int64_t rhs) { return lhs + rhs; }); |
45 | 0 | case AffineExprKind::Mul: |
46 | 0 | return constantFoldBinExpr( |
47 | 0 | expr, [](int64_t lhs, int64_t rhs) { return lhs * rhs; }); |
48 | 0 | case AffineExprKind::Mod: |
49 | 0 | return constantFoldBinExpr( |
50 | 0 | expr, [](int64_t lhs, int64_t rhs) { return mod(lhs, rhs); }); |
51 | 0 | case AffineExprKind::FloorDiv: |
52 | 0 | return constantFoldBinExpr( |
53 | 0 | expr, [](int64_t lhs, int64_t rhs) { return floorDiv(lhs, rhs); }); |
54 | 0 | case AffineExprKind::CeilDiv: |
55 | 0 | return constantFoldBinExpr( |
56 | 0 | expr, [](int64_t lhs, int64_t rhs) { return ceilDiv(lhs, rhs); }); |
57 | 0 | case AffineExprKind::Constant: |
58 | 0 | return expr.cast<AffineConstantExpr>().getValue(); |
59 | 0 | case AffineExprKind::DimId: |
60 | 0 | if (auto attr = operandConsts[expr.cast<AffineDimExpr>().getPosition()] |
61 | 0 | .dyn_cast_or_null<IntegerAttr>()) |
62 | 0 | return attr.getInt(); |
63 | 0 | return llvm::None; |
64 | 0 | case AffineExprKind::SymbolId: |
65 | 0 | if (auto attr = operandConsts[numDims + |
66 | 0 | expr.cast<AffineSymbolExpr>().getPosition()] |
67 | 0 | .dyn_cast_or_null<IntegerAttr>()) |
68 | 0 | return attr.getInt(); |
69 | 0 | return llvm::None; |
70 | 0 | } |
71 | 0 | llvm_unreachable("Unknown AffineExpr"); |
72 | 0 | } |
73 | | |
74 | | // TODO: Change these to operate on APInts too. |
75 | | Optional<int64_t> constantFoldBinExpr(AffineExpr expr, |
76 | 0 | int64_t (*op)(int64_t, int64_t)) { |
77 | 0 | auto binOpExpr = expr.cast<AffineBinaryOpExpr>(); |
78 | 0 | if (auto lhs = constantFoldImpl(binOpExpr.getLHS())) |
79 | 0 | if (auto rhs = constantFoldImpl(binOpExpr.getRHS())) |
80 | 0 | return op(*lhs, *rhs); |
81 | 0 | return llvm::None; |
82 | 0 | } |
83 | | |
84 | | // The number of dimension operands in AffineMap containing this expression. |
85 | | unsigned numDims; |
86 | | // The constant valued operands used to evaluate this AffineExpr. |
87 | | ArrayRef<Attribute> operandConsts; |
88 | | }; |
89 | | |
90 | | } // end anonymous namespace |
91 | | |
92 | | /// Returns a single constant result affine map. |
93 | 0 | AffineMap AffineMap::getConstantMap(int64_t val, MLIRContext *context) { |
94 | 0 | return get(/*dimCount=*/0, /*symbolCount=*/0, |
95 | 0 | {getAffineConstantExpr(val, context)}); |
96 | 0 | } |
97 | | |
98 | | /// Returns an identity affine map (d0, ..., dn) -> (dp, ..., dn) on the most |
99 | | /// minor dimensions. |
100 | | AffineMap AffineMap::getMinorIdentityMap(unsigned dims, unsigned results, |
101 | 0 | MLIRContext *context) { |
102 | 0 | assert(dims >= results && "Dimension mismatch"); |
103 | 0 | auto id = AffineMap::getMultiDimIdentityMap(dims, context); |
104 | 0 | return AffineMap::get(dims, 0, id.getResults().take_back(results), context); |
105 | 0 | } |
106 | | |
107 | 0 | bool AffineMap::isMinorIdentity(AffineMap map) { |
108 | 0 | if (!map) |
109 | 0 | return false; |
110 | 0 | return map == getMinorIdentityMap(map.getNumDims(), map.getNumResults(), |
111 | 0 | map.getContext()); |
112 | 0 | } |
113 | | |
114 | | /// Returns an AffineMap representing a permutation. |
115 | | AffineMap AffineMap::getPermutationMap(ArrayRef<unsigned> permutation, |
116 | | MLIRContext *context) { |
117 | | assert(!permutation.empty() && |
118 | | "Cannot create permutation map from empty permutation vector"); |
119 | | SmallVector<AffineExpr, 4> affExprs; |
120 | | for (auto index : permutation) |
121 | | affExprs.push_back(getAffineDimExpr(index, context)); |
122 | | auto m = std::max_element(permutation.begin(), permutation.end()); |
123 | | auto permutationMap = AffineMap::get(*m + 1, 0, affExprs, context); |
124 | | assert(permutationMap.isPermutation() && "Invalid permutation vector"); |
125 | | return permutationMap; |
126 | | } |
127 | | |
128 | | template <typename AffineExprContainer> |
129 | | static void getMaxDimAndSymbol(ArrayRef<AffineExprContainer> exprsList, |
130 | 0 | int64_t &maxDim, int64_t &maxSym) { |
131 | 0 | for (const auto &exprs : exprsList) { |
132 | 0 | for (auto expr : exprs) { |
133 | 0 | expr.walk([&maxDim, &maxSym](AffineExpr e) { |
134 | 0 | if (auto d = e.dyn_cast<AffineDimExpr>()) |
135 | 0 | maxDim = std::max(maxDim, static_cast<int64_t>(d.getPosition())); |
136 | 0 | if (auto s = e.dyn_cast<AffineSymbolExpr>()) |
137 | 0 | maxSym = std::max(maxSym, static_cast<int64_t>(s.getPosition())); |
138 | 0 | }); Unexecuted instantiation: AffineMap.cpp:_ZZL18getMaxDimAndSymbolIN4llvm8ArrayRefIN4mlir10AffineExprEEEEvNS1_IT_EERlS7_ENKUlS3_E_clES3_ Unexecuted instantiation: AffineMap.cpp:_ZZL18getMaxDimAndSymbolIN4llvm11SmallVectorIN4mlir10AffineExprELj4EEEEvNS0_8ArrayRefIT_EERlS8_ENKUlS3_E_clES3_ |
139 | 0 | } |
140 | 0 | } |
141 | 0 | } Unexecuted instantiation: AffineMap.cpp:_ZL18getMaxDimAndSymbolIN4llvm8ArrayRefIN4mlir10AffineExprEEEEvNS1_IT_EERlS7_ Unexecuted instantiation: AffineMap.cpp:_ZL18getMaxDimAndSymbolIN4llvm11SmallVectorIN4mlir10AffineExprELj4EEEEvNS0_8ArrayRefIT_EERlS8_ |
142 | | |
143 | | template <typename AffineExprContainer> |
144 | | static SmallVector<AffineMap, 4> |
145 | | inferFromExprList(ArrayRef<AffineExprContainer> exprsList) { |
146 | | assert(!exprsList.empty()); |
147 | | assert(!exprsList[0].empty()); |
148 | | auto context = exprsList[0][0].getContext(); |
149 | | int64_t maxDim = -1, maxSym = -1; |
150 | | getMaxDimAndSymbol(exprsList, maxDim, maxSym); |
151 | | SmallVector<AffineMap, 4> maps; |
152 | | maps.reserve(exprsList.size()); |
153 | | for (const auto &exprs : exprsList) |
154 | | maps.push_back(AffineMap::get(/*dimCount=*/maxDim + 1, |
155 | | /*symbolCount=*/maxSym + 1, exprs, context)); |
156 | | return maps; |
157 | | } |
158 | | |
159 | | SmallVector<AffineMap, 4> |
160 | 0 | AffineMap::inferFromExprList(ArrayRef<ArrayRef<AffineExpr>> exprsList) { |
161 | 0 | return ::inferFromExprList(exprsList); |
162 | 0 | } |
163 | | |
164 | | SmallVector<AffineMap, 4> |
165 | 0 | AffineMap::inferFromExprList(ArrayRef<SmallVector<AffineExpr, 4>> exprsList) { |
166 | 0 | return ::inferFromExprList(exprsList); |
167 | 0 | } |
168 | | |
169 | | AffineMap AffineMap::getMultiDimIdentityMap(unsigned numDims, |
170 | 0 | MLIRContext *context) { |
171 | 0 | SmallVector<AffineExpr, 4> dimExprs; |
172 | 0 | dimExprs.reserve(numDims); |
173 | 0 | for (unsigned i = 0; i < numDims; ++i) |
174 | 0 | dimExprs.push_back(mlir::getAffineDimExpr(i, context)); |
175 | 0 | return get(/*dimCount=*/numDims, /*symbolCount=*/0, dimExprs, context); |
176 | 0 | } |
177 | | |
178 | 0 | MLIRContext *AffineMap::getContext() const { return map->context; } |
179 | | |
180 | 0 | bool AffineMap::isIdentity() const { |
181 | 0 | if (getNumDims() != getNumResults()) |
182 | 0 | return false; |
183 | 0 | ArrayRef<AffineExpr> results = getResults(); |
184 | 0 | for (unsigned i = 0, numDims = getNumDims(); i < numDims; ++i) { |
185 | 0 | auto expr = results[i].dyn_cast<AffineDimExpr>(); |
186 | 0 | if (!expr || expr.getPosition() != i) |
187 | 0 | return false; |
188 | 0 | } |
189 | 0 | return true; |
190 | 0 | } |
191 | | |
192 | 0 | bool AffineMap::isEmpty() const { |
193 | 0 | return getNumDims() == 0 && getNumSymbols() == 0 && getNumResults() == 0; |
194 | 0 | } |
195 | | |
196 | 0 | bool AffineMap::isSingleConstant() const { |
197 | 0 | return getNumResults() == 1 && getResult(0).isa<AffineConstantExpr>(); |
198 | 0 | } |
199 | | |
200 | 0 | int64_t AffineMap::getSingleConstantResult() const { |
201 | 0 | assert(isSingleConstant() && "map must have a single constant result"); |
202 | 0 | return getResult(0).cast<AffineConstantExpr>().getValue(); |
203 | 0 | } |
204 | | |
205 | 0 | unsigned AffineMap::getNumDims() const { |
206 | 0 | assert(map && "uninitialized map storage"); |
207 | 0 | return map->numDims; |
208 | 0 | } |
209 | 0 | unsigned AffineMap::getNumSymbols() const { |
210 | 0 | assert(map && "uninitialized map storage"); |
211 | 0 | return map->numSymbols; |
212 | 0 | } |
213 | 0 | unsigned AffineMap::getNumResults() const { |
214 | 0 | assert(map && "uninitialized map storage"); |
215 | 0 | return map->results.size(); |
216 | 0 | } |
217 | 0 | unsigned AffineMap::getNumInputs() const { |
218 | 0 | assert(map && "uninitialized map storage"); |
219 | 0 | return map->numDims + map->numSymbols; |
220 | 0 | } |
221 | | |
222 | 0 | ArrayRef<AffineExpr> AffineMap::getResults() const { |
223 | 0 | assert(map && "uninitialized map storage"); |
224 | 0 | return map->results; |
225 | 0 | } |
226 | 0 | AffineExpr AffineMap::getResult(unsigned idx) const { |
227 | 0 | assert(map && "uninitialized map storage"); |
228 | 0 | return map->results[idx]; |
229 | 0 | } |
230 | | |
231 | | /// Folds the results of the application of an affine map on the provided |
232 | | /// operands to a constant if possible. Returns false if the folding happens, |
233 | | /// true otherwise. |
234 | | LogicalResult |
235 | | AffineMap::constantFold(ArrayRef<Attribute> operandConstants, |
236 | 0 | SmallVectorImpl<Attribute> &results) const { |
237 | 0 | // Attempt partial folding. |
238 | 0 | SmallVector<int64_t, 2> integers; |
239 | 0 | partialConstantFold(operandConstants, &integers); |
240 | 0 |
|
241 | 0 | // If all expressions folded to a constant, populate results with attributes |
242 | 0 | // containing those constants. |
243 | 0 | if (integers.empty()) |
244 | 0 | return failure(); |
245 | 0 | |
246 | 0 | auto range = llvm::map_range(integers, [this](int64_t i) { |
247 | 0 | return IntegerAttr::get(IndexType::get(getContext()), i); |
248 | 0 | }); |
249 | 0 | results.append(range.begin(), range.end()); |
250 | 0 | return success(); |
251 | 0 | } |
252 | | |
253 | | AffineMap |
254 | | AffineMap::partialConstantFold(ArrayRef<Attribute> operandConstants, |
255 | 0 | SmallVectorImpl<int64_t> *results) const { |
256 | 0 | assert(getNumInputs() == operandConstants.size()); |
257 | 0 |
|
258 | 0 | // Fold each of the result expressions. |
259 | 0 | AffineExprConstantFolder exprFolder(getNumDims(), operandConstants); |
260 | 0 | SmallVector<AffineExpr, 4> exprs; |
261 | 0 | exprs.reserve(getNumResults()); |
262 | 0 |
|
263 | 0 | for (auto expr : getResults()) { |
264 | 0 | auto folded = exprFolder.constantFold(expr); |
265 | 0 | // If did not fold to a constant, keep the original expression, and clear |
266 | 0 | // the integer results vector. |
267 | 0 | if (folded) { |
268 | 0 | exprs.push_back( |
269 | 0 | getAffineConstantExpr(folded.getInt(), folded.getContext())); |
270 | 0 | if (results) |
271 | 0 | results->push_back(folded.getInt()); |
272 | 0 | } else { |
273 | 0 | exprs.push_back(expr); |
274 | 0 | if (results) { |
275 | 0 | results->clear(); |
276 | 0 | results = nullptr; |
277 | 0 | } |
278 | 0 | } |
279 | 0 | } |
280 | 0 |
|
281 | 0 | return get(getNumDims(), getNumSymbols(), exprs, getContext()); |
282 | 0 | } |
283 | | |
284 | | /// Walk all of the AffineExpr's in this mapping. Each node in an expression |
285 | | /// tree is visited in postorder. |
286 | 0 | void AffineMap::walkExprs(std::function<void(AffineExpr)> callback) const { |
287 | 0 | for (auto expr : getResults()) |
288 | 0 | expr.walk(callback); |
289 | 0 | } |
290 | | |
291 | | /// This method substitutes any uses of dimensions and symbols (e.g. |
292 | | /// dim#0 with dimReplacements[0]) in subexpressions and returns the modified |
293 | | /// expression mapping. Because this can be used to eliminate dims and |
294 | | /// symbols, the client needs to specify the number of dims and symbols in |
295 | | /// the result. The returned map always has the same number of results. |
296 | | AffineMap AffineMap::replaceDimsAndSymbols(ArrayRef<AffineExpr> dimReplacements, |
297 | | ArrayRef<AffineExpr> symReplacements, |
298 | | unsigned numResultDims, |
299 | 0 | unsigned numResultSyms) const { |
300 | 0 | SmallVector<AffineExpr, 8> results; |
301 | 0 | results.reserve(getNumResults()); |
302 | 0 | for (auto expr : getResults()) |
303 | 0 | results.push_back( |
304 | 0 | expr.replaceDimsAndSymbols(dimReplacements, symReplacements)); |
305 | 0 |
|
306 | 0 | return get(numResultDims, numResultSyms, results, getContext()); |
307 | 0 | } |
308 | | |
309 | 0 | AffineMap AffineMap::compose(AffineMap map) { |
310 | 0 | assert(getNumDims() == map.getNumResults() && "Number of results mismatch"); |
311 | 0 | // Prepare `map` by concatenating the symbols and rewriting its exprs. |
312 | 0 | unsigned numDims = map.getNumDims(); |
313 | 0 | unsigned numSymbolsThisMap = getNumSymbols(); |
314 | 0 | unsigned numSymbols = numSymbolsThisMap + map.getNumSymbols(); |
315 | 0 | SmallVector<AffineExpr, 8> newDims(numDims); |
316 | 0 | for (unsigned idx = 0; idx < numDims; ++idx) { |
317 | 0 | newDims[idx] = getAffineDimExpr(idx, getContext()); |
318 | 0 | } |
319 | 0 | SmallVector<AffineExpr, 8> newSymbols(numSymbols); |
320 | 0 | for (unsigned idx = numSymbolsThisMap; idx < numSymbols; ++idx) { |
321 | 0 | newSymbols[idx - numSymbolsThisMap] = |
322 | 0 | getAffineSymbolExpr(idx, getContext()); |
323 | 0 | } |
324 | 0 | auto newMap = |
325 | 0 | map.replaceDimsAndSymbols(newDims, newSymbols, numDims, numSymbols); |
326 | 0 | SmallVector<AffineExpr, 8> exprs; |
327 | 0 | exprs.reserve(getResults().size()); |
328 | 0 | for (auto expr : getResults()) |
329 | 0 | exprs.push_back(expr.compose(newMap)); |
330 | 0 | return AffineMap::get(numDims, numSymbols, exprs, map.getContext()); |
331 | 0 | } |
332 | | |
333 | 0 | bool AffineMap::isProjectedPermutation() { |
334 | 0 | if (getNumSymbols() > 0) |
335 | 0 | return false; |
336 | 0 | SmallVector<bool, 8> seen(getNumInputs(), false); |
337 | 0 | for (auto expr : getResults()) { |
338 | 0 | if (auto dim = expr.dyn_cast<AffineDimExpr>()) { |
339 | 0 | if (seen[dim.getPosition()]) |
340 | 0 | return false; |
341 | 0 | seen[dim.getPosition()] = true; |
342 | 0 | continue; |
343 | 0 | } |
344 | 0 | return false; |
345 | 0 | } |
346 | 0 | return true; |
347 | 0 | } |
348 | | |
349 | 0 | bool AffineMap::isPermutation() { |
350 | 0 | if (getNumDims() != getNumResults()) |
351 | 0 | return false; |
352 | 0 | return isProjectedPermutation(); |
353 | 0 | } |
354 | | |
355 | 0 | AffineMap AffineMap::getSubMap(ArrayRef<unsigned> resultPos) { |
356 | 0 | SmallVector<AffineExpr, 4> exprs; |
357 | 0 | exprs.reserve(resultPos.size()); |
358 | 0 | for (auto idx : resultPos) { |
359 | 0 | exprs.push_back(getResult(idx)); |
360 | 0 | } |
361 | 0 | return AffineMap::get(getNumDims(), getNumSymbols(), exprs, getContext()); |
362 | 0 | } |
363 | | |
364 | 0 | AffineMap mlir::simplifyAffineMap(AffineMap map) { |
365 | 0 | SmallVector<AffineExpr, 8> exprs; |
366 | 0 | for (auto e : map.getResults()) { |
367 | 0 | exprs.push_back( |
368 | 0 | simplifyAffineExpr(e, map.getNumDims(), map.getNumSymbols())); |
369 | 0 | } |
370 | 0 | return AffineMap::get(map.getNumDims(), map.getNumSymbols(), exprs, |
371 | 0 | map.getContext()); |
372 | 0 | } |
373 | | |
374 | 0 | AffineMap mlir::removeDuplicateExprs(AffineMap map) { |
375 | 0 | auto results = map.getResults(); |
376 | 0 | SmallVector<AffineExpr, 4> uniqueExprs(results.begin(), results.end()); |
377 | 0 | uniqueExprs.erase(std::unique(uniqueExprs.begin(), uniqueExprs.end()), |
378 | 0 | uniqueExprs.end()); |
379 | 0 | return AffineMap::get(map.getNumDims(), map.getNumSymbols(), uniqueExprs, |
380 | 0 | map.getContext()); |
381 | 0 | } |
382 | | |
383 | 0 | AffineMap mlir::inversePermutation(AffineMap map) { |
384 | 0 | if (map.isEmpty()) |
385 | 0 | return map; |
386 | 0 | assert(map.getNumSymbols() == 0 && "expected map without symbols"); |
387 | 0 | SmallVector<AffineExpr, 4> exprs(map.getNumDims()); |
388 | 0 | for (auto en : llvm::enumerate(map.getResults())) { |
389 | 0 | auto expr = en.value(); |
390 | 0 | // Skip non-permutations. |
391 | 0 | if (auto d = expr.dyn_cast<AffineDimExpr>()) { |
392 | 0 | if (exprs[d.getPosition()]) |
393 | 0 | continue; |
394 | 0 | exprs[d.getPosition()] = getAffineDimExpr(en.index(), d.getContext()); |
395 | 0 | } |
396 | 0 | } |
397 | 0 | SmallVector<AffineExpr, 4> seenExprs; |
398 | 0 | seenExprs.reserve(map.getNumDims()); |
399 | 0 | for (auto expr : exprs) |
400 | 0 | if (expr) |
401 | 0 | seenExprs.push_back(expr); |
402 | 0 | if (seenExprs.size() != map.getNumInputs()) |
403 | 0 | return AffineMap(); |
404 | 0 | return AffineMap::get(map.getNumResults(), 0, seenExprs, map.getContext()); |
405 | 0 | } |
406 | | |
407 | 0 | AffineMap mlir::concatAffineMaps(ArrayRef<AffineMap> maps) { |
408 | 0 | unsigned numResults = 0; |
409 | 0 | for (auto m : maps) |
410 | 0 | numResults += m.getNumResults(); |
411 | 0 | unsigned numDims = 0; |
412 | 0 | SmallVector<AffineExpr, 8> results; |
413 | 0 | results.reserve(numResults); |
414 | 0 | for (auto m : maps) { |
415 | 0 | assert(m.getNumSymbols() == 0 && "expected map without symbols"); |
416 | 0 | results.append(m.getResults().begin(), m.getResults().end()); |
417 | 0 | numDims = std::max(m.getNumDims(), numDims); |
418 | 0 | } |
419 | 0 | return AffineMap::get(numDims, /*numSymbols=*/0, results, |
420 | 0 | maps.front().getContext()); |
421 | 0 | } |
422 | | |
423 | | //===----------------------------------------------------------------------===// |
424 | | // MutableAffineMap. |
425 | | //===----------------------------------------------------------------------===// |
426 | | |
427 | | MutableAffineMap::MutableAffineMap(AffineMap map) |
428 | | : numDims(map.getNumDims()), numSymbols(map.getNumSymbols()), |
429 | 0 | context(map.getContext()) { |
430 | 0 | for (auto result : map.getResults()) |
431 | 0 | results.push_back(result); |
432 | 0 | } |
433 | | |
434 | 0 | void MutableAffineMap::reset(AffineMap map) { |
435 | 0 | results.clear(); |
436 | 0 | numDims = map.getNumDims(); |
437 | 0 | numSymbols = map.getNumSymbols(); |
438 | 0 | context = map.getContext(); |
439 | 0 | for (auto result : map.getResults()) |
440 | 0 | results.push_back(result); |
441 | 0 | } |
442 | | |
443 | 0 | bool MutableAffineMap::isMultipleOf(unsigned idx, int64_t factor) const { |
444 | 0 | if (results[idx].isMultipleOf(factor)) |
445 | 0 | return true; |
446 | 0 | |
447 | 0 | // TODO(bondhugula): use simplifyAffineExpr and FlatAffineConstraints to |
448 | 0 | // complete this (for a more powerful analysis). |
449 | 0 | return false; |
450 | 0 | } |
451 | | |
452 | | // Simplifies the result affine expressions of this map. The expressions have to |
453 | | // be pure for the simplification implemented. |
454 | 0 | void MutableAffineMap::simplify() { |
455 | 0 | // Simplify each of the results if possible. |
456 | 0 | // TODO(ntv): functional-style map |
457 | 0 | for (unsigned i = 0, e = getNumResults(); i < e; i++) { |
458 | 0 | results[i] = simplifyAffineExpr(getResult(i), numDims, numSymbols); |
459 | 0 | } |
460 | 0 | } |
461 | | |
462 | 0 | AffineMap MutableAffineMap::getAffineMap() const { |
463 | 0 | return AffineMap::get(numDims, numSymbols, results, context); |
464 | 0 | } |