xref: /llvm-project/mlir/lib/IR/AffineMap.cpp (revision fcb1591b46f12b8908a8cdb252611708820102f8)
18901448fSMLIR Team //===- AffineMap.cpp - MLIR Affine Map Classes ----------------------------===//
28901448fSMLIR Team //
330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68901448fSMLIR Team //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
88901448fSMLIR Team 
98901448fSMLIR Team #include "mlir/IR/AffineMap.h"
101d3e7e26SNicolas Vasilache #include "AffineMapDetail.h"
114dc72d47SNicolas Vasilache #include "mlir/IR/AffineExpr.h"
1226e35b0fSMatthias Springer #include "mlir/IR/Builders.h"
13c7cae0e4SRiver Riddle #include "mlir/IR/BuiltinAttributes.h"
1409f7a55fSRiver Riddle #include "mlir/IR/BuiltinTypes.h"
15255ba1c3SNicolas Vasilache #include "llvm/ADT/STLExtras.h"
165288c25cSthomasraoux #include "llvm/ADT/SmallBitVector.h"
175ca20851SMaheshRavishankar #include "llvm/ADT/SmallSet.h"
184dc72d47SNicolas Vasilache #include "llvm/ADT/SmallVector.h"
198901448fSMLIR Team #include "llvm/ADT/StringRef.h"
200fb216fbSRamkumar Ramachandra #include "llvm/Support/MathExtras.h"
214a1df48fSNicolas Vasilache #include "llvm/Support/raw_ostream.h"
224dc72d47SNicolas Vasilache #include <iterator>
23ddff3766SUday Bondhugula #include <numeric>
24a1fe1f5fSKazu Hirata #include <optional>
25255ba1c3SNicolas Vasilache #include <type_traits>
268901448fSMLIR Team 
278901448fSMLIR Team using namespace mlir;
288901448fSMLIR Team 
290fb216fbSRamkumar Ramachandra using llvm::divideCeilSigned;
300fb216fbSRamkumar Ramachandra using llvm::divideFloorSigned;
310fb216fbSRamkumar Ramachandra using llvm::mod;
320fb216fbSRamkumar Ramachandra 
33d18ae9e2SUday Bondhugula namespace {
34d18ae9e2SUday Bondhugula 
35d18ae9e2SUday Bondhugula // AffineExprConstantFolder evaluates an affine expression using constant
36e472f5b3SRiver Riddle // operands passed in 'operandConsts'. Returns an IntegerAttr attribute
37e472f5b3SRiver Riddle // representing the constant value of the affine expression evaluated on
38e472f5b3SRiver Riddle // constant 'operandConsts', or nullptr if it can't be folded.
39d18ae9e2SUday Bondhugula class AffineExprConstantFolder {
40d18ae9e2SUday Bondhugula public:
41792d1c25SRiver Riddle   AffineExprConstantFolder(unsigned numDims, ArrayRef<Attribute> operandConsts)
42d18ae9e2SUday Bondhugula       : numDims(numDims), operandConsts(operandConsts) {}
43d18ae9e2SUday Bondhugula 
44d18ae9e2SUday Bondhugula   /// Attempt to constant fold the specified affine expr, or return null on
45d18ae9e2SUday Bondhugula   /// failure.
46792d1c25SRiver Riddle   IntegerAttr constantFold(AffineExpr expr) {
47e472f5b3SRiver Riddle     if (auto result = constantFoldImpl(expr))
48e472f5b3SRiver Riddle       return IntegerAttr::get(IndexType::get(expr.getContext()), *result);
49e472f5b3SRiver Riddle     return nullptr;
50e472f5b3SRiver Riddle   }
51e472f5b3SRiver Riddle 
521609f1c2Slong.chen   bool hasPoison() const { return hasPoison_; }
531609f1c2Slong.chen 
54e472f5b3SRiver Riddle private:
550a81ace0SKazu Hirata   std::optional<int64_t> constantFoldImpl(AffineExpr expr) {
568ebb6ff1SNicolas Vasilache     switch (expr.getKind()) {
57ce2edea1SNicolas Vasilache     case AffineExprKind::Add:
58d18ae9e2SUday Bondhugula       return constantFoldBinExpr(
59d18ae9e2SUday Bondhugula           expr, [](int64_t lhs, int64_t rhs) { return lhs + rhs; });
60ce2edea1SNicolas Vasilache     case AffineExprKind::Mul:
61d18ae9e2SUday Bondhugula       return constantFoldBinExpr(
62d18ae9e2SUday Bondhugula           expr, [](int64_t lhs, int64_t rhs) { return lhs * rhs; });
63ce2edea1SNicolas Vasilache     case AffineExprKind::Mod:
64d18ae9e2SUday Bondhugula       return constantFoldBinExpr(
65d9c5e8a2SBenjamin Kramer           expr, [this](int64_t lhs, int64_t rhs) -> std::optional<int64_t> {
66dc4786b4Slong.chen             if (rhs < 1) {
67dc4786b4Slong.chen               hasPoison_ = true;
68dc4786b4Slong.chen               return std::nullopt;
69dc4786b4Slong.chen             }
70dc4786b4Slong.chen             return mod(lhs, rhs);
71dc4786b4Slong.chen           });
72ce2edea1SNicolas Vasilache     case AffineExprKind::FloorDiv:
73d18ae9e2SUday Bondhugula       return constantFoldBinExpr(
74d9c5e8a2SBenjamin Kramer           expr, [this](int64_t lhs, int64_t rhs) -> std::optional<int64_t> {
75dc4786b4Slong.chen             if (rhs == 0) {
76dc4786b4Slong.chen               hasPoison_ = true;
77dc4786b4Slong.chen               return std::nullopt;
78dc4786b4Slong.chen             }
790fb216fbSRamkumar Ramachandra             return divideFloorSigned(lhs, rhs);
80dc4786b4Slong.chen           });
81ce2edea1SNicolas Vasilache     case AffineExprKind::CeilDiv:
82d18ae9e2SUday Bondhugula       return constantFoldBinExpr(
83d9c5e8a2SBenjamin Kramer           expr, [this](int64_t lhs, int64_t rhs) -> std::optional<int64_t> {
84dc4786b4Slong.chen             if (rhs == 0) {
85dc4786b4Slong.chen               hasPoison_ = true;
86dc4786b4Slong.chen               return std::nullopt;
87dc4786b4Slong.chen             }
880fb216fbSRamkumar Ramachandra             return divideCeilSigned(lhs, rhs);
89dc4786b4Slong.chen           });
90ce2edea1SNicolas Vasilache     case AffineExprKind::Constant:
911609f1c2Slong.chen       return cast<AffineConstantExpr>(expr).getValue();
92ce2edea1SNicolas Vasilache     case AffineExprKind::DimId:
93c1fa60b4STres Popp       if (auto attr = llvm::dyn_cast_or_null<IntegerAttr>(
941609f1c2Slong.chen               operandConsts[cast<AffineDimExpr>(expr).getPosition()]))
95e472f5b3SRiver Riddle         return attr.getInt();
961a36588eSKazu Hirata       return std::nullopt;
97ce2edea1SNicolas Vasilache     case AffineExprKind::SymbolId:
98c1fa60b4STres Popp       if (auto attr = llvm::dyn_cast_or_null<IntegerAttr>(
99c1fa60b4STres Popp               operandConsts[numDims +
1001609f1c2Slong.chen                             cast<AffineSymbolExpr>(expr).getPosition()]))
101e472f5b3SRiver Riddle         return attr.getInt();
1021a36588eSKazu Hirata       return std::nullopt;
103d18ae9e2SUday Bondhugula     }
104ff5d021cSMehdi Amini     llvm_unreachable("Unknown AffineExpr");
105d18ae9e2SUday Bondhugula   }
106d18ae9e2SUday Bondhugula 
10725e6b541SJacques Pienaar   // TODO: Change these to operate on APInts too.
1081609f1c2Slong.chen   std::optional<int64_t> constantFoldBinExpr(
1091609f1c2Slong.chen       AffineExpr expr,
1101609f1c2Slong.chen       llvm::function_ref<std::optional<int64_t>(int64_t, int64_t)> op) {
1111609f1c2Slong.chen     auto binOpExpr = cast<AffineBinaryOpExpr>(expr);
112e472f5b3SRiver Riddle     if (auto lhs = constantFoldImpl(binOpExpr.getLHS()))
113e472f5b3SRiver Riddle       if (auto rhs = constantFoldImpl(binOpExpr.getRHS()))
114e472f5b3SRiver Riddle         return op(*lhs, *rhs);
1151a36588eSKazu Hirata     return std::nullopt;
116d18ae9e2SUday Bondhugula   }
117d18ae9e2SUday Bondhugula 
118d18ae9e2SUday Bondhugula   // The number of dimension operands in AffineMap containing this expression.
119d18ae9e2SUday Bondhugula   unsigned numDims;
120d18ae9e2SUday Bondhugula   // The constant valued operands used to evaluate this AffineExpr.
121792d1c25SRiver Riddle   ArrayRef<Attribute> operandConsts;
1221609f1c2Slong.chen   bool hasPoison_{false};
123d18ae9e2SUday Bondhugula };
124d18ae9e2SUday Bondhugula 
125be0a7e9fSMehdi Amini } // namespace
126d18ae9e2SUday Bondhugula 
1271d3e7e26SNicolas Vasilache /// Returns a single constant result affine map.
1281d3e7e26SNicolas Vasilache AffineMap AffineMap::getConstantMap(int64_t val, MLIRContext *context) {
1291d3e7e26SNicolas Vasilache   return get(/*dimCount=*/0, /*symbolCount=*/0,
1305a91b989SMLIR Team              {getAffineConstantExpr(val, context)});
1311d3e7e26SNicolas Vasilache }
132fc46bcf5SUday Bondhugula 
1337a801390SNicolas Vasilache /// Returns an identity affine map (d0, ..., dn) -> (dp, ..., dn) on the most
1347a801390SNicolas Vasilache /// minor dimensions.
1357a801390SNicolas Vasilache AffineMap AffineMap::getMinorIdentityMap(unsigned dims, unsigned results,
1367a801390SNicolas Vasilache                                          MLIRContext *context) {
1377a801390SNicolas Vasilache   assert(dims >= results && "Dimension mismatch");
1387a801390SNicolas Vasilache   auto id = AffineMap::getMultiDimIdentityMap(dims, context);
1397a801390SNicolas Vasilache   return AffineMap::get(dims, 0, id.getResults().take_back(results), context);
1407a801390SNicolas Vasilache }
1417a801390SNicolas Vasilache 
14213f15e8fSDiego Caballero AffineMap AffineMap::getFilteredIdentityMap(
14313f15e8fSDiego Caballero     MLIRContext *ctx, unsigned numDims,
14413f15e8fSDiego Caballero     llvm::function_ref<bool(AffineDimExpr)> keepDimFilter) {
14513f15e8fSDiego Caballero   auto identityMap = getMultiDimIdentityMap(numDims, ctx);
14613f15e8fSDiego Caballero 
14713f15e8fSDiego Caballero   // Apply filter to results.
14813f15e8fSDiego Caballero   llvm::SmallBitVector dropDimResults(numDims);
14913f15e8fSDiego Caballero   for (auto [idx, resultExpr] : llvm::enumerate(identityMap.getResults()))
1501609f1c2Slong.chen     dropDimResults[idx] = !keepDimFilter(cast<AffineDimExpr>(resultExpr));
15113f15e8fSDiego Caballero 
15213f15e8fSDiego Caballero   return identityMap.dropResults(dropDimResults);
15313f15e8fSDiego Caballero }
15413f15e8fSDiego Caballero 
155ec2f2cecSNicolas Vasilache bool AffineMap::isMinorIdentity() const {
15616947650Sthomasraoux   return getNumDims() >= getNumResults() &&
15716947650Sthomasraoux          *this ==
158ec2f2cecSNicolas Vasilache              getMinorIdentityMap(getNumDims(), getNumResults(), getContext());
159051452bdSMehdi Amini }
1607a801390SNicolas Vasilache 
1612ee5586aSAndrzej Warzyński SmallVector<unsigned> AffineMap::getBroadcastDims() const {
1622ee5586aSAndrzej Warzyński   SmallVector<unsigned> broadcastedDims;
1632ee5586aSAndrzej Warzyński   for (const auto &[resIdx, expr] : llvm::enumerate(getResults())) {
1642ee5586aSAndrzej Warzyński     if (auto constExpr = dyn_cast<AffineConstantExpr>(expr)) {
1652ee5586aSAndrzej Warzyński       if (constExpr.getValue() != 0)
1662ee5586aSAndrzej Warzyński         continue;
1672ee5586aSAndrzej Warzyński       broadcastedDims.push_back(resIdx);
1682ee5586aSAndrzej Warzyński     }
1692ee5586aSAndrzej Warzyński   }
1702ee5586aSAndrzej Warzyński 
1712ee5586aSAndrzej Warzyński   return broadcastedDims;
1722ee5586aSAndrzej Warzyński }
1732ee5586aSAndrzej Warzyński 
174fd2b0896SSergei Grechanik /// Returns true if this affine map is a minor identity up to broadcasted
175fd2b0896SSergei Grechanik /// dimensions which are indicated by value 0 in the result.
176fd2b0896SSergei Grechanik bool AffineMap::isMinorIdentityWithBroadcasting(
177fd2b0896SSergei Grechanik     SmallVectorImpl<unsigned> *broadcastedDims) const {
178fd2b0896SSergei Grechanik   if (broadcastedDims)
179fd2b0896SSergei Grechanik     broadcastedDims->clear();
180fd2b0896SSergei Grechanik   if (getNumDims() < getNumResults())
181fd2b0896SSergei Grechanik     return false;
182fd2b0896SSergei Grechanik   unsigned suffixStart = getNumDims() - getNumResults();
183e4853be2SMehdi Amini   for (const auto &idxAndExpr : llvm::enumerate(getResults())) {
184fd2b0896SSergei Grechanik     unsigned resIdx = idxAndExpr.index();
185fd2b0896SSergei Grechanik     AffineExpr expr = idxAndExpr.value();
1861609f1c2Slong.chen     if (auto constExpr = dyn_cast<AffineConstantExpr>(expr)) {
187fd2b0896SSergei Grechanik       // Each result may be either a constant 0 (broadcasted dimension).
188fd2b0896SSergei Grechanik       if (constExpr.getValue() != 0)
189fd2b0896SSergei Grechanik         return false;
190fd2b0896SSergei Grechanik       if (broadcastedDims)
191fd2b0896SSergei Grechanik         broadcastedDims->push_back(resIdx);
1921609f1c2Slong.chen     } else if (auto dimExpr = dyn_cast<AffineDimExpr>(expr)) {
193fd2b0896SSergei Grechanik       // Or it may be the input dimension corresponding to this result position.
194fd2b0896SSergei Grechanik       if (dimExpr.getPosition() != suffixStart + resIdx)
195fd2b0896SSergei Grechanik         return false;
196fd2b0896SSergei Grechanik     } else {
197fd2b0896SSergei Grechanik       return false;
198fd2b0896SSergei Grechanik     }
199fd2b0896SSergei Grechanik   }
200fd2b0896SSergei Grechanik   return true;
201fd2b0896SSergei Grechanik }
202fd2b0896SSergei Grechanik 
2035288c25cSthomasraoux /// Return true if this affine map can be converted to a minor identity with
2045288c25cSthomasraoux /// broadcast by doing a permute. Return a permutation (there may be
2055288c25cSthomasraoux /// several) to apply to get to a minor identity with broadcasts.
2065288c25cSthomasraoux /// Ex:
2075288c25cSthomasraoux ///  * (d0, d1, d2) -> (0, d1) maps to minor identity (d1, 0 = d2) with
2085288c25cSthomasraoux ///  perm = [1, 0] and broadcast d2
2095288c25cSthomasraoux ///  * (d0, d1, d2) -> (d0, 0) cannot be mapped to a minor identity by
2105288c25cSthomasraoux ///  permutation + broadcast
2115288c25cSthomasraoux ///  * (d0, d1, d2, d3) -> (0, d1, d3) maps to minor identity (d1, 0 = d2, d3)
2125288c25cSthomasraoux ///  with perm = [1, 0, 2] and broadcast d2
2135288c25cSthomasraoux ///  * (d0, d1) -> (d1, 0, 0, d0) maps to minor identity (d0, d1) with extra
2145288c25cSthomasraoux ///  leading broadcat dimensions. The map returned would be (0, 0, d0, d1) with
2155288c25cSthomasraoux ///  perm = [3, 0, 1, 2]
2165288c25cSthomasraoux bool AffineMap::isPermutationOfMinorIdentityWithBroadcasting(
2175288c25cSthomasraoux     SmallVectorImpl<unsigned> &permutedDims) const {
2185288c25cSthomasraoux   unsigned projectionStart =
2195288c25cSthomasraoux       getNumResults() < getNumInputs() ? getNumInputs() - getNumResults() : 0;
2205288c25cSthomasraoux   permutedDims.clear();
2215288c25cSthomasraoux   SmallVector<unsigned> broadcastDims;
2225288c25cSthomasraoux   permutedDims.resize(getNumResults(), 0);
2235288c25cSthomasraoux   // If there are more results than input dimensions we want the new map to
2245288c25cSthomasraoux   // start with broadcast dimensions in order to be a minor identity with
2255288c25cSthomasraoux   // broadcasting.
2265288c25cSthomasraoux   unsigned leadingBroadcast =
2275288c25cSthomasraoux       getNumResults() > getNumInputs() ? getNumResults() - getNumInputs() : 0;
2285288c25cSthomasraoux   llvm::SmallBitVector dimFound(std::max(getNumInputs(), getNumResults()),
2295288c25cSthomasraoux                                 false);
230e4853be2SMehdi Amini   for (const auto &idxAndExpr : llvm::enumerate(getResults())) {
2315288c25cSthomasraoux     unsigned resIdx = idxAndExpr.index();
2325288c25cSthomasraoux     AffineExpr expr = idxAndExpr.value();
2335288c25cSthomasraoux     // Each result may be either a constant 0 (broadcast dimension) or a
2345288c25cSthomasraoux     // dimension.
2351609f1c2Slong.chen     if (auto constExpr = dyn_cast<AffineConstantExpr>(expr)) {
2365288c25cSthomasraoux       if (constExpr.getValue() != 0)
2375288c25cSthomasraoux         return false;
2385288c25cSthomasraoux       broadcastDims.push_back(resIdx);
2391609f1c2Slong.chen     } else if (auto dimExpr = dyn_cast<AffineDimExpr>(expr)) {
2405288c25cSthomasraoux       if (dimExpr.getPosition() < projectionStart)
2415288c25cSthomasraoux         return false;
2425288c25cSthomasraoux       unsigned newPosition =
2435288c25cSthomasraoux           dimExpr.getPosition() - projectionStart + leadingBroadcast;
2445288c25cSthomasraoux       permutedDims[resIdx] = newPosition;
2455288c25cSthomasraoux       dimFound[newPosition] = true;
2465288c25cSthomasraoux     } else {
2475288c25cSthomasraoux       return false;
2485288c25cSthomasraoux     }
2495288c25cSthomasraoux   }
2505288c25cSthomasraoux   // Find a permuation for the broadcast dimension. Since they are broadcasted
2515288c25cSthomasraoux   // any valid permutation is acceptable. We just permute the dim into a slot
2525288c25cSthomasraoux   // without an existing dimension.
2535288c25cSthomasraoux   unsigned pos = 0;
2545288c25cSthomasraoux   for (auto dim : broadcastDims) {
2555288c25cSthomasraoux     while (pos < dimFound.size() && dimFound[pos]) {
2565288c25cSthomasraoux       pos++;
2575288c25cSthomasraoux     }
2585288c25cSthomasraoux     permutedDims[dim] = pos++;
2595288c25cSthomasraoux   }
2605288c25cSthomasraoux   return true;
2615288c25cSthomasraoux }
2625288c25cSthomasraoux 
263f60bbb6cSJose Ignacio Gomez /// Returns an AffineMap representing a permutation.
264f60bbb6cSJose Ignacio Gomez AffineMap AffineMap::getPermutationMap(ArrayRef<unsigned> permutation,
265f60bbb6cSJose Ignacio Gomez                                        MLIRContext *context) {
266f60bbb6cSJose Ignacio Gomez   assert(!permutation.empty() &&
267f60bbb6cSJose Ignacio Gomez          "Cannot create permutation map from empty permutation vector");
268fab2bb8bSJustin Lebar   const auto *m = llvm::max_element(permutation);
269b0d5b4d2SChengji Yao   auto permutationMap = getMultiDimMapWithTargets(*m + 1, permutation, context);
270f60bbb6cSJose Ignacio Gomez   assert(permutationMap.isPermutation() && "Invalid permutation vector");
271f60bbb6cSJose Ignacio Gomez   return permutationMap;
272f60bbb6cSJose Ignacio Gomez }
27332c3decbSMatthias Springer AffineMap AffineMap::getPermutationMap(ArrayRef<int64_t> permutation,
27432c3decbSMatthias Springer                                        MLIRContext *context) {
27532c3decbSMatthias Springer   SmallVector<unsigned> perm = llvm::map_to_vector(
27632c3decbSMatthias Springer       permutation, [](int64_t i) { return static_cast<unsigned>(i); });
27732c3decbSMatthias Springer   return AffineMap::getPermutationMap(perm, context);
27832c3decbSMatthias Springer }
279f60bbb6cSJose Ignacio Gomez 
280b0d5b4d2SChengji Yao AffineMap AffineMap::getMultiDimMapWithTargets(unsigned numDims,
281b0d5b4d2SChengji Yao                                                ArrayRef<unsigned> targets,
282b0d5b4d2SChengji Yao                                                MLIRContext *context) {
283b0d5b4d2SChengji Yao   SmallVector<AffineExpr, 4> affExprs;
284b0d5b4d2SChengji Yao   for (unsigned t : targets)
285b0d5b4d2SChengji Yao     affExprs.push_back(getAffineDimExpr(t, context));
286b0d5b4d2SChengji Yao   AffineMap result = AffineMap::get(/*dimCount=*/numDims, /*symbolCount=*/0,
287b0d5b4d2SChengji Yao                                     affExprs, context);
288b0d5b4d2SChengji Yao   return result;
289b0d5b4d2SChengji Yao }
290b0d5b4d2SChengji Yao 
291fe8a62c4SUday Bondhugula /// Creates an affine map each for each list of AffineExpr's in `exprsList`
292fe8a62c4SUday Bondhugula /// while inferring the right number of dimensional and symbolic inputs needed
293fe8a62c4SUday Bondhugula /// based on the maximum dimensional and symbolic identifier appearing in the
294fe8a62c4SUday Bondhugula /// expressions.
2958513ff05SNicolas Vasilache template <typename AffineExprContainer>
296564a9de2SBenjamin Kramer static SmallVector<AffineMap, 4>
297fe8a62c4SUday Bondhugula inferFromExprList(ArrayRef<AffineExprContainer> exprsList,
298fe8a62c4SUday Bondhugula                   MLIRContext *context) {
299fe8a62c4SUday Bondhugula   if (exprsList.empty())
300fe8a62c4SUday Bondhugula     return {};
3018513ff05SNicolas Vasilache   int64_t maxDim = -1, maxSym = -1;
3028513ff05SNicolas Vasilache   getMaxDimAndSymbol(exprsList, maxDim, maxSym);
3038513ff05SNicolas Vasilache   SmallVector<AffineMap, 4> maps;
3048513ff05SNicolas Vasilache   maps.reserve(exprsList.size());
3058513ff05SNicolas Vasilache   for (const auto &exprs : exprsList)
3068513ff05SNicolas Vasilache     maps.push_back(AffineMap::get(/*dimCount=*/maxDim + 1,
3079f3ab92eSJeremy Bruestle                                   /*symbolCount=*/maxSym + 1, exprs, context));
3088513ff05SNicolas Vasilache   return maps;
3098513ff05SNicolas Vasilache }
3108513ff05SNicolas Vasilache 
3118513ff05SNicolas Vasilache SmallVector<AffineMap, 4>
312fe8a62c4SUday Bondhugula AffineMap::inferFromExprList(ArrayRef<ArrayRef<AffineExpr>> exprsList,
313fe8a62c4SUday Bondhugula                              MLIRContext *context) {
314fe8a62c4SUday Bondhugula   return ::inferFromExprList(exprsList, context);
3158513ff05SNicolas Vasilache }
3168513ff05SNicolas Vasilache 
3178513ff05SNicolas Vasilache SmallVector<AffineMap, 4>
318fe8a62c4SUday Bondhugula AffineMap::inferFromExprList(ArrayRef<SmallVector<AffineExpr, 4>> exprsList,
319fe8a62c4SUday Bondhugula                              MLIRContext *context) {
320fe8a62c4SUday Bondhugula   return ::inferFromExprList(exprsList, context);
3218513ff05SNicolas Vasilache }
3228513ff05SNicolas Vasilache 
323ddff3766SUday Bondhugula uint64_t AffineMap::getLargestKnownDivisorOfMapExprs() {
324ddff3766SUday Bondhugula   uint64_t gcd = 0;
325ddff3766SUday Bondhugula   for (AffineExpr resultExpr : getResults()) {
326ddff3766SUday Bondhugula     uint64_t thisGcd = resultExpr.getLargestKnownDivisor();
327ddff3766SUday Bondhugula     gcd = std::gcd(gcd, thisGcd);
328ddff3766SUday Bondhugula   }
329ddff3766SUday Bondhugula   if (gcd == 0)
330ddff3766SUday Bondhugula     gcd = std::numeric_limits<uint64_t>::max();
331ddff3766SUday Bondhugula   return gcd;
332ddff3766SUday Bondhugula }
333ddff3766SUday Bondhugula 
334f28e4df6SMLIR Team AffineMap AffineMap::getMultiDimIdentityMap(unsigned numDims,
335f28e4df6SMLIR Team                                             MLIRContext *context) {
336f28e4df6SMLIR Team   SmallVector<AffineExpr, 4> dimExprs;
337f28e4df6SMLIR Team   dimExprs.reserve(numDims);
338f28e4df6SMLIR Team   for (unsigned i = 0; i < numDims; ++i)
339f28e4df6SMLIR Team     dimExprs.push_back(mlir::getAffineDimExpr(i, context));
3409f3ab92eSJeremy Bruestle   return get(/*dimCount=*/numDims, /*symbolCount=*/0, dimExprs, context);
341f28e4df6SMLIR Team }
342f28e4df6SMLIR Team 
3439e6cf0d0SDiego Caballero MLIRContext *AffineMap::getContext() const { return map->context; }
34450cc57e2SChris Lattner 
3451d3e7e26SNicolas Vasilache bool AffineMap::isIdentity() const {
3466b614091SMLIR Team   if (getNumDims() != getNumResults())
3476b614091SMLIR Team     return false;
3486707c7beSNicolas Vasilache   ArrayRef<AffineExpr> results = getResults();
3492487f2dcSMLIR Team   for (unsigned i = 0, numDims = getNumDims(); i < numDims; ++i) {
3501609f1c2Slong.chen     auto expr = dyn_cast<AffineDimExpr>(results[i]);
3518ebb6ff1SNicolas Vasilache     if (!expr || expr.getPosition() != i)
3526b614091SMLIR Team       return false;
3536b614091SMLIR Team   }
3546b614091SMLIR Team   return true;
3556b614091SMLIR Team }
3566b614091SMLIR Team 
3575b779a3dSKai Sasaki bool AffineMap::isSymbolIdentity() const {
3585b779a3dSKai Sasaki   if (getNumSymbols() != getNumResults())
3595b779a3dSKai Sasaki     return false;
3605b779a3dSKai Sasaki   ArrayRef<AffineExpr> results = getResults();
3615b779a3dSKai Sasaki   for (unsigned i = 0, numSymbols = getNumSymbols(); i < numSymbols; ++i) {
3621609f1c2Slong.chen     auto expr = dyn_cast<AffineDimExpr>(results[i]);
3635b779a3dSKai Sasaki     if (!expr || expr.getPosition() != i)
3645b779a3dSKai Sasaki       return false;
3655b779a3dSKai Sasaki   }
3665b779a3dSKai Sasaki   return true;
3675b779a3dSKai Sasaki }
3685b779a3dSKai Sasaki 
3699e6cf0d0SDiego Caballero bool AffineMap::isEmpty() const {
3709e6cf0d0SDiego Caballero   return getNumDims() == 0 && getNumSymbols() == 0 && getNumResults() == 0;
3719e6cf0d0SDiego Caballero }
3729e6cf0d0SDiego Caballero 
3731d3e7e26SNicolas Vasilache bool AffineMap::isSingleConstant() const {
3741609f1c2Slong.chen   return getNumResults() == 1 && isa<AffineConstantExpr>(getResult(0));
375d32a28c5STatiana Shpeisman }
376d32a28c5STatiana Shpeisman 
377884a6291SStephan Herhut bool AffineMap::isConstant() const {
378971b8525SJakub Kuderski   return llvm::all_of(getResults(), llvm::IsaPred<AffineConstantExpr>);
379884a6291SStephan Herhut }
380884a6291SStephan Herhut 
3811d3e7e26SNicolas Vasilache int64_t AffineMap::getSingleConstantResult() const {
382d32a28c5STatiana Shpeisman   assert(isSingleConstant() && "map must have a single constant result");
3831609f1c2Slong.chen   return cast<AffineConstantExpr>(getResult(0)).getValue();
384d32a28c5STatiana Shpeisman }
385d32a28c5STatiana Shpeisman 
386884a6291SStephan Herhut SmallVector<int64_t> AffineMap::getConstantResults() const {
387884a6291SStephan Herhut   assert(isConstant() && "map must have only constant results");
388884a6291SStephan Herhut   SmallVector<int64_t> result;
389884a6291SStephan Herhut   for (auto expr : getResults())
3901609f1c2Slong.chen     result.emplace_back(cast<AffineConstantExpr>(expr).getValue());
391884a6291SStephan Herhut   return result;
392884a6291SStephan Herhut }
393884a6291SStephan Herhut 
394362557e1SNicolas Vasilache unsigned AffineMap::getNumDims() const {
395362557e1SNicolas Vasilache   assert(map && "uninitialized map storage");
396362557e1SNicolas Vasilache   return map->numDims;
397362557e1SNicolas Vasilache }
398362557e1SNicolas Vasilache unsigned AffineMap::getNumSymbols() const {
399362557e1SNicolas Vasilache   assert(map && "uninitialized map storage");
400362557e1SNicolas Vasilache   return map->numSymbols;
401362557e1SNicolas Vasilache }
402935a5f67SBenjamin Kramer unsigned AffineMap::getNumResults() const { return getResults().size(); }
4031d3e7e26SNicolas Vasilache unsigned AffineMap::getNumInputs() const {
404362557e1SNicolas Vasilache   assert(map && "uninitialized map storage");
4051d3e7e26SNicolas Vasilache   return map->numDims + map->numSymbols;
4061d3e7e26SNicolas Vasilache }
407362557e1SNicolas Vasilache ArrayRef<AffineExpr> AffineMap::getResults() const {
408362557e1SNicolas Vasilache   assert(map && "uninitialized map storage");
409935a5f67SBenjamin Kramer   return map->results();
410362557e1SNicolas Vasilache }
4111d3e7e26SNicolas Vasilache AffineExpr AffineMap::getResult(unsigned idx) const {
412935a5f67SBenjamin Kramer   return getResults()[idx];
4131d3e7e26SNicolas Vasilache }
414b55b4076SNicolas Vasilache 
4159ddb464dSAart Bik unsigned AffineMap::getDimPosition(unsigned idx) const {
4161609f1c2Slong.chen   return cast<AffineDimExpr>(getResult(idx)).getPosition();
4179ddb464dSAart Bik }
4189ddb464dSAart Bik 
4190a81ace0SKazu Hirata std::optional<unsigned> AffineMap::getResultPosition(AffineExpr input) const {
4201609f1c2Slong.chen   if (!isa<AffineDimExpr>(input))
4211a36588eSKazu Hirata     return std::nullopt;
422bf3f7016SDiego Caballero 
423bf3f7016SDiego Caballero   for (unsigned i = 0, numResults = getNumResults(); i < numResults; i++) {
424bf3f7016SDiego Caballero     if (getResult(i) == input)
425a643bd31SAart Bik       return i;
426bf3f7016SDiego Caballero   }
427bf3f7016SDiego Caballero 
4281a36588eSKazu Hirata   return std::nullopt;
429a643bd31SAart Bik }
430a643bd31SAart Bik 
431d18ae9e2SUday Bondhugula /// Folds the results of the application of an affine map on the provided
432d18ae9e2SUday Bondhugula /// operands to a constant if possible. Returns false if the folding happens,
433d18ae9e2SUday Bondhugula /// true otherwise.
434dc4786b4Slong.chen LogicalResult AffineMap::constantFold(ArrayRef<Attribute> operandConstants,
435dc4786b4Slong.chen                                       SmallVectorImpl<Attribute> &results,
436dc4786b4Slong.chen                                       bool *hasPoison) const {
437a87db48eSAlex Zinenko   // Attempt partial folding.
438a87db48eSAlex Zinenko   SmallVector<int64_t, 2> integers;
439dc4786b4Slong.chen   partialConstantFold(operandConstants, &integers, hasPoison);
440a87db48eSAlex Zinenko 
441a87db48eSAlex Zinenko   // If all expressions folded to a constant, populate results with attributes
442a87db48eSAlex Zinenko   // containing those constants.
443a87db48eSAlex Zinenko   if (integers.empty())
444a87db48eSAlex Zinenko     return failure();
445a87db48eSAlex Zinenko 
446a87db48eSAlex Zinenko   auto range = llvm::map_range(integers, [this](int64_t i) {
447a87db48eSAlex Zinenko     return IntegerAttr::get(IndexType::get(getContext()), i);
448a87db48eSAlex Zinenko   });
449a87db48eSAlex Zinenko   results.append(range.begin(), range.end());
450a87db48eSAlex Zinenko   return success();
451a87db48eSAlex Zinenko }
452a87db48eSAlex Zinenko 
453dc4786b4Slong.chen AffineMap AffineMap::partialConstantFold(ArrayRef<Attribute> operandConstants,
454dc4786b4Slong.chen                                          SmallVectorImpl<int64_t> *results,
455dc4786b4Slong.chen                                          bool *hasPoison) const {
456d18ae9e2SUday Bondhugula   assert(getNumInputs() == operandConstants.size());
457d18ae9e2SUday Bondhugula 
458d18ae9e2SUday Bondhugula   // Fold each of the result expressions.
459d18ae9e2SUday Bondhugula   AffineExprConstantFolder exprFolder(getNumDims(), operandConstants);
460a87db48eSAlex Zinenko   SmallVector<AffineExpr, 4> exprs;
461a87db48eSAlex Zinenko   exprs.reserve(getNumResults());
462a87db48eSAlex Zinenko 
463d18ae9e2SUday Bondhugula   for (auto expr : getResults()) {
464792d1c25SRiver Riddle     auto folded = exprFolder.constantFold(expr);
465dc4786b4Slong.chen     if (exprFolder.hasPoison() && hasPoison) {
466dc4786b4Slong.chen       *hasPoison = true;
467dc4786b4Slong.chen       return {};
468dc4786b4Slong.chen     }
469a87db48eSAlex Zinenko     // If did not fold to a constant, keep the original expression, and clear
470a87db48eSAlex Zinenko     // the integer results vector.
471a87db48eSAlex Zinenko     if (folded) {
472a87db48eSAlex Zinenko       exprs.push_back(
473a87db48eSAlex Zinenko           getAffineConstantExpr(folded.getInt(), folded.getContext()));
474a87db48eSAlex Zinenko       if (results)
475a87db48eSAlex Zinenko         results->push_back(folded.getInt());
476a87db48eSAlex Zinenko     } else {
477a87db48eSAlex Zinenko       exprs.push_back(expr);
478a87db48eSAlex Zinenko       if (results) {
479a87db48eSAlex Zinenko         results->clear();
480a87db48eSAlex Zinenko         results = nullptr;
481d18ae9e2SUday Bondhugula       }
482a87db48eSAlex Zinenko     }
483a87db48eSAlex Zinenko   }
484a87db48eSAlex Zinenko 
485a87db48eSAlex Zinenko   return get(getNumDims(), getNumSymbols(), exprs, getContext());
486d18ae9e2SUday Bondhugula }
4877983bbc2SChris Lattner 
4885a91b989SMLIR Team /// Walk all of the AffineExpr's in this mapping. Each node in an expression
4897983bbc2SChris Lattner /// tree is visited in postorder.
4901fc096afSMehdi Amini void AffineMap::walkExprs(llvm::function_ref<void(AffineExpr)> callback) const {
4917983bbc2SChris Lattner   for (auto expr : getResults())
4927983bbc2SChris Lattner     expr.walk(callback);
4937983bbc2SChris Lattner }
4947983bbc2SChris Lattner 
4957983bbc2SChris Lattner /// This method substitutes any uses of dimensions and symbols (e.g.
4967983bbc2SChris Lattner /// dim#0 with dimReplacements[0]) in subexpressions and returns the modified
4977983bbc2SChris Lattner /// expression mapping.  Because this can be used to eliminate dims and
4987983bbc2SChris Lattner /// symbols, the client needs to specify the number of dims and symbols in
4997983bbc2SChris Lattner /// the result.  The returned map always has the same number of results.
5007983bbc2SChris Lattner AffineMap AffineMap::replaceDimsAndSymbols(ArrayRef<AffineExpr> dimReplacements,
5017983bbc2SChris Lattner                                            ArrayRef<AffineExpr> symReplacements,
5027983bbc2SChris Lattner                                            unsigned numResultDims,
50378453e37SChintan Kaur                                            unsigned numResultSyms) const {
5047983bbc2SChris Lattner   SmallVector<AffineExpr, 8> results;
5057983bbc2SChris Lattner   results.reserve(getNumResults());
5067983bbc2SChris Lattner   for (auto expr : getResults())
5077983bbc2SChris Lattner     results.push_back(
5087983bbc2SChris Lattner         expr.replaceDimsAndSymbols(dimReplacements, symReplacements));
5099f3ab92eSJeremy Bruestle   return get(numResultDims, numResultSyms, results, getContext());
5107983bbc2SChris Lattner }
511c6f798a9SNicolas Vasilache 
51293a873dfSNicolas Vasilache /// Sparse replace method. Apply AffineExpr::replace(`expr`, `replacement`) to
51393a873dfSNicolas Vasilache /// each of the results and return a new AffineMap with the new results and
51493a873dfSNicolas Vasilache /// with the specified number of dims and symbols.
51593a873dfSNicolas Vasilache AffineMap AffineMap::replace(AffineExpr expr, AffineExpr replacement,
51693a873dfSNicolas Vasilache                              unsigned numResultDims,
51793a873dfSNicolas Vasilache                              unsigned numResultSyms) const {
51893a873dfSNicolas Vasilache   SmallVector<AffineExpr, 4> newResults;
51993a873dfSNicolas Vasilache   newResults.reserve(getNumResults());
52093a873dfSNicolas Vasilache   for (AffineExpr e : getResults())
52193a873dfSNicolas Vasilache     newResults.push_back(e.replace(expr, replacement));
52293a873dfSNicolas Vasilache   return AffineMap::get(numResultDims, numResultSyms, newResults, getContext());
52393a873dfSNicolas Vasilache }
52493a873dfSNicolas Vasilache 
52593a873dfSNicolas Vasilache /// Sparse replace method. Apply AffineExpr::replace(`map`) to each of the
52693a873dfSNicolas Vasilache /// results and return a new AffineMap with the new results and with the
52793a873dfSNicolas Vasilache /// specified number of dims and symbols.
52893a873dfSNicolas Vasilache AffineMap AffineMap::replace(const DenseMap<AffineExpr, AffineExpr> &map,
52993a873dfSNicolas Vasilache                              unsigned numResultDims,
53093a873dfSNicolas Vasilache                              unsigned numResultSyms) const {
53193a873dfSNicolas Vasilache   SmallVector<AffineExpr, 4> newResults;
53293a873dfSNicolas Vasilache   newResults.reserve(getNumResults());
53393a873dfSNicolas Vasilache   for (AffineExpr e : getResults())
53493a873dfSNicolas Vasilache     newResults.push_back(e.replace(map));
53593a873dfSNicolas Vasilache   return AffineMap::get(numResultDims, numResultSyms, newResults, getContext());
53693a873dfSNicolas Vasilache }
53793a873dfSNicolas Vasilache 
5387b47de77SNicolas Vasilache AffineMap
5397b47de77SNicolas Vasilache AffineMap::replace(const DenseMap<AffineExpr, AffineExpr> &map) const {
5407b47de77SNicolas Vasilache   SmallVector<AffineExpr, 4> newResults;
5417b47de77SNicolas Vasilache   newResults.reserve(getNumResults());
5427b47de77SNicolas Vasilache   for (AffineExpr e : getResults())
5437b47de77SNicolas Vasilache     newResults.push_back(e.replace(map));
544fe8a62c4SUday Bondhugula   return AffineMap::inferFromExprList(newResults, getContext()).front();
5457b47de77SNicolas Vasilache }
5467b47de77SNicolas Vasilache 
5474dc72d47SNicolas Vasilache AffineMap AffineMap::dropResults(const llvm::SmallBitVector &positions) const {
5484dc72d47SNicolas Vasilache   auto exprs = llvm::to_vector<4>(getResults());
5494dc72d47SNicolas Vasilache   // TODO: this is a pretty terrible API .. is there anything better?
5504dc72d47SNicolas Vasilache   for (auto pos = positions.find_last(); pos != -1;
5514dc72d47SNicolas Vasilache        pos = positions.find_prev(pos))
5524dc72d47SNicolas Vasilache     exprs.erase(exprs.begin() + pos);
5534dc72d47SNicolas Vasilache   return AffineMap::get(getNumDims(), getNumSymbols(), exprs, getContext());
5544dc72d47SNicolas Vasilache }
5554dc72d47SNicolas Vasilache 
556f349abc2SVladislav Vinogradov AffineMap AffineMap::compose(AffineMap map) const {
557c6f798a9SNicolas Vasilache   assert(getNumDims() == map.getNumResults() && "Number of results mismatch");
558c6f798a9SNicolas Vasilache   // Prepare `map` by concatenating the symbols and rewriting its exprs.
559c6f798a9SNicolas Vasilache   unsigned numDims = map.getNumDims();
560c6f798a9SNicolas Vasilache   unsigned numSymbolsThisMap = getNumSymbols();
561c6f798a9SNicolas Vasilache   unsigned numSymbols = numSymbolsThisMap + map.getNumSymbols();
562c6f798a9SNicolas Vasilache   SmallVector<AffineExpr, 8> newDims(numDims);
563c6f798a9SNicolas Vasilache   for (unsigned idx = 0; idx < numDims; ++idx) {
564c6f798a9SNicolas Vasilache     newDims[idx] = getAffineDimExpr(idx, getContext());
565c6f798a9SNicolas Vasilache   }
5663bcca6b1SChengji Yao   SmallVector<AffineExpr, 8> newSymbols(numSymbols - numSymbolsThisMap);
567c6f798a9SNicolas Vasilache   for (unsigned idx = numSymbolsThisMap; idx < numSymbols; ++idx) {
568c6f798a9SNicolas Vasilache     newSymbols[idx - numSymbolsThisMap] =
569c6f798a9SNicolas Vasilache         getAffineSymbolExpr(idx, getContext());
570c6f798a9SNicolas Vasilache   }
571c6f798a9SNicolas Vasilache   auto newMap =
572c6f798a9SNicolas Vasilache       map.replaceDimsAndSymbols(newDims, newSymbols, numDims, numSymbols);
573c6f798a9SNicolas Vasilache   SmallVector<AffineExpr, 8> exprs;
574c6f798a9SNicolas Vasilache   exprs.reserve(getResults().size());
575c6f798a9SNicolas Vasilache   for (auto expr : getResults())
576c6f798a9SNicolas Vasilache     exprs.push_back(expr.compose(newMap));
5779f3ab92eSJeremy Bruestle   return AffineMap::get(numDims, numSymbols, exprs, map.getContext());
578c6f798a9SNicolas Vasilache }
57910237de8SRiver Riddle 
580f349abc2SVladislav Vinogradov SmallVector<int64_t, 4> AffineMap::compose(ArrayRef<int64_t> values) const {
581a490d387SNicolas Vasilache   assert(getNumSymbols() == 0 && "Expected symbol-less map");
582a490d387SNicolas Vasilache   SmallVector<AffineExpr, 4> exprs;
583a490d387SNicolas Vasilache   exprs.reserve(values.size());
584a490d387SNicolas Vasilache   MLIRContext *ctx = getContext();
585a490d387SNicolas Vasilache   for (auto v : values)
586a490d387SNicolas Vasilache     exprs.push_back(getAffineConstantExpr(v, ctx));
587a490d387SNicolas Vasilache   auto resMap = compose(AffineMap::get(0, 0, exprs, ctx));
588a490d387SNicolas Vasilache   SmallVector<int64_t, 4> res;
589a490d387SNicolas Vasilache   res.reserve(resMap.getNumResults());
590a490d387SNicolas Vasilache   for (auto e : resMap.getResults())
5911609f1c2Slong.chen     res.push_back(cast<AffineConstantExpr>(e).getValue());
592a490d387SNicolas Vasilache   return res;
593a490d387SNicolas Vasilache }
594a490d387SNicolas Vasilache 
5956d114944SAndrzej Warzyński size_t AffineMap::getNumOfZeroResults() const {
5966d114944SAndrzej Warzyński   size_t res = 0;
5976d114944SAndrzej Warzyński   for (auto expr : getResults()) {
5986d114944SAndrzej Warzyński     auto constExpr = dyn_cast<AffineConstantExpr>(expr);
5996d114944SAndrzej Warzyński     if (constExpr && constExpr.getValue() == 0)
6006d114944SAndrzej Warzyński       res++;
6016d114944SAndrzej Warzyński   }
6026d114944SAndrzej Warzyński 
6036d114944SAndrzej Warzyński   return res;
6046d114944SAndrzej Warzyński }
6056d114944SAndrzej Warzyński 
6066d114944SAndrzej Warzyński AffineMap AffineMap::dropZeroResults() {
6076d114944SAndrzej Warzyński   auto exprs = llvm::to_vector(getResults());
6086d114944SAndrzej Warzyński   SmallVector<AffineExpr> newExprs;
6096d114944SAndrzej Warzyński 
6106d114944SAndrzej Warzyński   for (auto expr : getResults()) {
6116d114944SAndrzej Warzyński     auto constExpr = dyn_cast<AffineConstantExpr>(expr);
6126d114944SAndrzej Warzyński     if (!constExpr || constExpr.getValue() != 0)
6136d114944SAndrzej Warzyński       newExprs.push_back(expr);
6146d114944SAndrzej Warzyński   }
6156d114944SAndrzej Warzyński   return AffineMap::get(getNumDims(), getNumSymbols(), newExprs, getContext());
6166d114944SAndrzej Warzyński }
6176d114944SAndrzej Warzyński 
6185c1d356cSDiego Caballero bool AffineMap::isProjectedPermutation(bool allowZeroInResults) const {
619e7e03ceeSNicolas Vasilache   if (getNumSymbols() > 0)
620e7e03ceeSNicolas Vasilache     return false;
6215c1d356cSDiego Caballero 
6225c1d356cSDiego Caballero   // Having more results than inputs means that results have duplicated dims or
6235c1d356cSDiego Caballero   // zeros that can't be mapped to input dims.
6245c1d356cSDiego Caballero   if (getNumResults() > getNumInputs())
6255c1d356cSDiego Caballero     return false;
6265c1d356cSDiego Caballero 
627e7e03ceeSNicolas Vasilache   SmallVector<bool, 8> seen(getNumInputs(), false);
6285c1d356cSDiego Caballero   // A projected permutation can have, at most, only one instance of each input
6295c1d356cSDiego Caballero   // dimension in the result expressions. Zeros are allowed as long as the
6305c1d356cSDiego Caballero   // number of result expressions is lower or equal than the number of input
6315c1d356cSDiego Caballero   // expressions.
632e7e03ceeSNicolas Vasilache   for (auto expr : getResults()) {
6331609f1c2Slong.chen     if (auto dim = dyn_cast<AffineDimExpr>(expr)) {
634e7e03ceeSNicolas Vasilache       if (seen[dim.getPosition()])
635e7e03ceeSNicolas Vasilache         return false;
636e7e03ceeSNicolas Vasilache       seen[dim.getPosition()] = true;
6375c1d356cSDiego Caballero     } else {
6381609f1c2Slong.chen       auto constExpr = dyn_cast<AffineConstantExpr>(expr);
6395c1d356cSDiego Caballero       if (!allowZeroInResults || !constExpr || constExpr.getValue() != 0)
640e7e03ceeSNicolas Vasilache         return false;
641e7e03ceeSNicolas Vasilache     }
6425c1d356cSDiego Caballero   }
6435c1d356cSDiego Caballero 
6445c1d356cSDiego Caballero   // Results are either dims or zeros and zeros can be mapped to input dims.
645e7e03ceeSNicolas Vasilache   return true;
646e7e03ceeSNicolas Vasilache }
647e7e03ceeSNicolas Vasilache 
648f349abc2SVladislav Vinogradov bool AffineMap::isPermutation() const {
649e7e03ceeSNicolas Vasilache   if (getNumDims() != getNumResults())
650e7e03ceeSNicolas Vasilache     return false;
651e7e03ceeSNicolas Vasilache   return isProjectedPermutation();
652e7e03ceeSNicolas Vasilache }
653e7e03ceeSNicolas Vasilache 
654f349abc2SVladislav Vinogradov AffineMap AffineMap::getSubMap(ArrayRef<unsigned> resultPos) const {
65528fb7437SNicolas Vasilache   SmallVector<AffineExpr, 4> exprs;
65628fb7437SNicolas Vasilache   exprs.reserve(resultPos.size());
65724ed3a94SNicolas Vasilache   for (auto idx : resultPos)
65828fb7437SNicolas Vasilache     exprs.push_back(getResult(idx));
6599f3ab92eSJeremy Bruestle   return AffineMap::get(getNumDims(), getNumSymbols(), exprs, getContext());
66028fb7437SNicolas Vasilache }
66128fb7437SNicolas Vasilache 
6626841e6afSAlex Zinenko AffineMap AffineMap::getSliceMap(unsigned start, unsigned length) const {
6636841e6afSAlex Zinenko   return AffineMap::get(getNumDims(), getNumSymbols(),
6646841e6afSAlex Zinenko                         getResults().slice(start, length), getContext());
6656841e6afSAlex Zinenko }
6666841e6afSAlex Zinenko 
667f349abc2SVladislav Vinogradov AffineMap AffineMap::getMajorSubMap(unsigned numResults) const {
668a490d387SNicolas Vasilache   if (numResults == 0)
669a490d387SNicolas Vasilache     return AffineMap();
670a490d387SNicolas Vasilache   if (numResults > getNumResults())
671a490d387SNicolas Vasilache     return *this;
672a9dcbcfeSBenjamin Kramer   return getSliceMap(0, numResults);
673a490d387SNicolas Vasilache }
674a490d387SNicolas Vasilache 
675f349abc2SVladislav Vinogradov AffineMap AffineMap::getMinorSubMap(unsigned numResults) const {
67624ed3a94SNicolas Vasilache   if (numResults == 0)
67724ed3a94SNicolas Vasilache     return AffineMap();
67824ed3a94SNicolas Vasilache   if (numResults > getNumResults())
67924ed3a94SNicolas Vasilache     return *this;
680a9dcbcfeSBenjamin Kramer   return getSliceMap(getNumResults() - numResults, numResults);
68124ed3a94SNicolas Vasilache }
68224ed3a94SNicolas Vasilache 
683255ba1c3SNicolas Vasilache /// Implementation detail to compress multiple affine maps with a compressionFun
684255ba1c3SNicolas Vasilache /// that is expected to be either compressUnusedDims or compressUnusedSymbols.
685255ba1c3SNicolas Vasilache /// The implementation keeps track of num dims and symbols across the different
686255ba1c3SNicolas Vasilache /// affine maps.
687255ba1c3SNicolas Vasilache static SmallVector<AffineMap> compressUnusedListImpl(
688255ba1c3SNicolas Vasilache     ArrayRef<AffineMap> maps,
689335d2df5SNicolas Vasilache     llvm::function_ref<AffineMap(AffineMap)> compressionFun) {
690335d2df5SNicolas Vasilache   if (maps.empty())
691335d2df5SNicolas Vasilache     return SmallVector<AffineMap>();
692335d2df5SNicolas Vasilache   SmallVector<AffineExpr> allExprs;
693335d2df5SNicolas Vasilache   allExprs.reserve(maps.size() * maps.front().getNumResults());
694335d2df5SNicolas Vasilache   unsigned numDims = maps.front().getNumDims(),
695335d2df5SNicolas Vasilache            numSymbols = maps.front().getNumSymbols();
696335d2df5SNicolas Vasilache   for (auto m : maps) {
697335d2df5SNicolas Vasilache     assert(numDims == m.getNumDims() && numSymbols == m.getNumSymbols() &&
698335d2df5SNicolas Vasilache            "expected maps with same num dims and symbols");
699335d2df5SNicolas Vasilache     llvm::append_range(allExprs, m.getResults());
700335d2df5SNicolas Vasilache   }
701335d2df5SNicolas Vasilache   AffineMap unifiedMap = compressionFun(
702335d2df5SNicolas Vasilache       AffineMap::get(numDims, numSymbols, allExprs, maps.front().getContext()));
703335d2df5SNicolas Vasilache   unsigned unifiedNumDims = unifiedMap.getNumDims(),
704335d2df5SNicolas Vasilache            unifiedNumSymbols = unifiedMap.getNumSymbols();
705335d2df5SNicolas Vasilache   ArrayRef<AffineExpr> unifiedResults = unifiedMap.getResults();
706335d2df5SNicolas Vasilache   SmallVector<AffineMap> res;
707335d2df5SNicolas Vasilache   res.reserve(maps.size());
708335d2df5SNicolas Vasilache   for (auto m : maps) {
709335d2df5SNicolas Vasilache     res.push_back(AffineMap::get(unifiedNumDims, unifiedNumSymbols,
710335d2df5SNicolas Vasilache                                  unifiedResults.take_front(m.getNumResults()),
711335d2df5SNicolas Vasilache                                  m.getContext()));
712335d2df5SNicolas Vasilache     unifiedResults = unifiedResults.drop_front(m.getNumResults());
713335d2df5SNicolas Vasilache   }
714335d2df5SNicolas Vasilache   return res;
715335d2df5SNicolas Vasilache }
716335d2df5SNicolas Vasilache 
717255ba1c3SNicolas Vasilache AffineMap mlir::compressDims(AffineMap map,
718255ba1c3SNicolas Vasilache                              const llvm::SmallBitVector &unusedDims) {
719255ba1c3SNicolas Vasilache   return projectDims(map, unusedDims, /*compressDimsFlag=*/true);
720255ba1c3SNicolas Vasilache }
721255ba1c3SNicolas Vasilache 
722255ba1c3SNicolas Vasilache AffineMap mlir::compressUnusedDims(AffineMap map) {
723255ba1c3SNicolas Vasilache   return compressDims(map, getUnusedDimsBitVector({map}));
724255ba1c3SNicolas Vasilache }
725255ba1c3SNicolas Vasilache 
726335d2df5SNicolas Vasilache SmallVector<AffineMap> mlir::compressUnusedDims(ArrayRef<AffineMap> maps) {
727255ba1c3SNicolas Vasilache   return compressUnusedListImpl(
728255ba1c3SNicolas Vasilache       maps, [](AffineMap m) { return compressUnusedDims(m); });
729335d2df5SNicolas Vasilache }
730335d2df5SNicolas Vasilache 
7316635c12aSBenjamin Kramer AffineMap mlir::compressSymbols(AffineMap map,
7326635c12aSBenjamin Kramer                                 const llvm::SmallBitVector &unusedSymbols) {
733255ba1c3SNicolas Vasilache   return projectSymbols(map, unusedSymbols, /*compressSymbolsFlag=*/true);
7345bc4f884SNicolas Vasilache }
7355bc4f884SNicolas Vasilache 
7365bc4f884SNicolas Vasilache AffineMap mlir::compressUnusedSymbols(AffineMap map) {
737255ba1c3SNicolas Vasilache   return compressSymbols(map, getUnusedSymbolsBitVector({map}));
7385bc4f884SNicolas Vasilache }
7395bc4f884SNicolas Vasilache 
740335d2df5SNicolas Vasilache SmallVector<AffineMap> mlir::compressUnusedSymbols(ArrayRef<AffineMap> maps) {
741255ba1c3SNicolas Vasilache   return compressUnusedListImpl(
742335d2df5SNicolas Vasilache       maps, [](AffineMap m) { return compressUnusedSymbols(m); });
743335d2df5SNicolas Vasilache }
744335d2df5SNicolas Vasilache 
74526e35b0fSMatthias Springer AffineMap mlir::foldAttributesIntoMap(Builder &b, AffineMap map,
74626e35b0fSMatthias Springer                                       ArrayRef<OpFoldResult> operands,
74726e35b0fSMatthias Springer                                       SmallVector<Value> &remainingValues) {
74826e35b0fSMatthias Springer   SmallVector<AffineExpr> dimReplacements, symReplacements;
74926e35b0fSMatthias Springer   int64_t numDims = 0;
75026e35b0fSMatthias Springer   for (int64_t i = 0; i < map.getNumDims(); ++i) {
75126e35b0fSMatthias Springer     if (auto attr = operands[i].dyn_cast<Attribute>()) {
75226e35b0fSMatthias Springer       dimReplacements.push_back(
753a5757c5bSChristian Sigg           b.getAffineConstantExpr(cast<IntegerAttr>(attr).getInt()));
75426e35b0fSMatthias Springer     } else {
75526e35b0fSMatthias Springer       dimReplacements.push_back(b.getAffineDimExpr(numDims++));
756*fcb1591bSKazu Hirata       remainingValues.push_back(cast<Value>(operands[i]));
75726e35b0fSMatthias Springer     }
75826e35b0fSMatthias Springer   }
75926e35b0fSMatthias Springer   int64_t numSymbols = 0;
76026e35b0fSMatthias Springer   for (int64_t i = 0; i < map.getNumSymbols(); ++i) {
76126e35b0fSMatthias Springer     if (auto attr = operands[i + map.getNumDims()].dyn_cast<Attribute>()) {
76226e35b0fSMatthias Springer       symReplacements.push_back(
763a5757c5bSChristian Sigg           b.getAffineConstantExpr(cast<IntegerAttr>(attr).getInt()));
76426e35b0fSMatthias Springer     } else {
76526e35b0fSMatthias Springer       symReplacements.push_back(b.getAffineSymbolExpr(numSymbols++));
766*fcb1591bSKazu Hirata       remainingValues.push_back(cast<Value>(operands[i + map.getNumDims()]));
76726e35b0fSMatthias Springer     }
76826e35b0fSMatthias Springer   }
76926e35b0fSMatthias Springer   return map.replaceDimsAndSymbols(dimReplacements, symReplacements, numDims,
77026e35b0fSMatthias Springer                                    numSymbols);
77126e35b0fSMatthias Springer }
77226e35b0fSMatthias Springer 
77310237de8SRiver Riddle AffineMap mlir::simplifyAffineMap(AffineMap map) {
7745a91b989SMLIR Team   SmallVector<AffineExpr, 8> exprs;
77510237de8SRiver Riddle   for (auto e : map.getResults()) {
77610237de8SRiver Riddle     exprs.push_back(
77710237de8SRiver Riddle         simplifyAffineExpr(e, map.getNumDims(), map.getNumSymbols()));
77810237de8SRiver Riddle   }
7799f3ab92eSJeremy Bruestle   return AffineMap::get(map.getNumDims(), map.getNumSymbols(), exprs,
7809f3ab92eSJeremy Bruestle                         map.getContext());
78110237de8SRiver Riddle }
78221d9dc4fSNicolas Vasilache 
7835e809313SUday Bondhugula AffineMap mlir::removeDuplicateExprs(AffineMap map) {
7845e809313SUday Bondhugula   auto results = map.getResults();
7855262865aSKazu Hirata   SmallVector<AffineExpr, 4> uniqueExprs(results);
786b7b337fbSKazu Hirata   uniqueExprs.erase(llvm::unique(uniqueExprs), uniqueExprs.end());
7875e809313SUday Bondhugula   return AffineMap::get(map.getNumDims(), map.getNumSymbols(), uniqueExprs,
7885e809313SUday Bondhugula                         map.getContext());
7895e809313SUday Bondhugula }
7905e809313SUday Bondhugula 
79121d9dc4fSNicolas Vasilache AffineMap mlir::inversePermutation(AffineMap map) {
79247ec8702SNicolas Vasilache   if (map.isEmpty())
793235e2fe0SNicolas Vasilache     return map;
79421d9dc4fSNicolas Vasilache   assert(map.getNumSymbols() == 0 && "expected map without symbols");
79521d9dc4fSNicolas Vasilache   SmallVector<AffineExpr, 4> exprs(map.getNumDims());
796e4853be2SMehdi Amini   for (const auto &en : llvm::enumerate(map.getResults())) {
79721d9dc4fSNicolas Vasilache     auto expr = en.value();
7984a1df48fSNicolas Vasilache     // Skip non-permutations.
7991609f1c2Slong.chen     if (auto d = dyn_cast<AffineDimExpr>(expr)) {
80021d9dc4fSNicolas Vasilache       if (exprs[d.getPosition()])
80121d9dc4fSNicolas Vasilache         continue;
80221d9dc4fSNicolas Vasilache       exprs[d.getPosition()] = getAffineDimExpr(en.index(), d.getContext());
80321d9dc4fSNicolas Vasilache     }
8044a1df48fSNicolas Vasilache   }
80521d9dc4fSNicolas Vasilache   SmallVector<AffineExpr, 4> seenExprs;
80621d9dc4fSNicolas Vasilache   seenExprs.reserve(map.getNumDims());
80721d9dc4fSNicolas Vasilache   for (auto expr : exprs)
80821d9dc4fSNicolas Vasilache     if (expr)
80921d9dc4fSNicolas Vasilache       seenExprs.push_back(expr);
810600c47e7SNicolas Vasilache   if (seenExprs.size() != map.getNumInputs())
811600c47e7SNicolas Vasilache     return AffineMap();
8129f3ab92eSJeremy Bruestle   return AffineMap::get(map.getNumResults(), 0, seenExprs, map.getContext());
81321d9dc4fSNicolas Vasilache }
81421d9dc4fSNicolas Vasilache 
81565bdeddbSOkwan Kwon AffineMap mlir::inverseAndBroadcastProjectedPermutation(AffineMap map) {
8165c1d356cSDiego Caballero   assert(map.isProjectedPermutation(/*allowZeroInResults=*/true));
8179621c1efSthomasraoux   MLIRContext *context = map.getContext();
8189621c1efSthomasraoux   AffineExpr zero = mlir::getAffineConstantExpr(0, context);
8199621c1efSthomasraoux   // Start with all the results as 0.
8209621c1efSthomasraoux   SmallVector<AffineExpr, 4> exprs(map.getNumInputs(), zero);
8219621c1efSthomasraoux   for (unsigned i : llvm::seq(unsigned(0), map.getNumResults())) {
8225c1d356cSDiego Caballero     // Skip zeros from input map. 'exprs' is already initialized to zero.
8231609f1c2Slong.chen     if (auto constExpr = dyn_cast<AffineConstantExpr>(map.getResult(i))) {
8245c1d356cSDiego Caballero       assert(constExpr.getValue() == 0 &&
8255c1d356cSDiego Caballero              "Unexpected constant in projected permutation");
8265c1d356cSDiego Caballero       (void)constExpr;
8275c1d356cSDiego Caballero       continue;
8285c1d356cSDiego Caballero     }
8295c1d356cSDiego Caballero 
8305c1d356cSDiego Caballero     // Reverse each dimension existing in the original map result.
8319621c1efSthomasraoux     exprs[map.getDimPosition(i)] = getAffineDimExpr(i, context);
8329621c1efSthomasraoux   }
8339621c1efSthomasraoux   return AffineMap::get(map.getNumResults(), /*symbolCount=*/0, exprs, context);
8349621c1efSthomasraoux }
8359621c1efSthomasraoux 
83606514c55SIan Wood AffineMap mlir::concatAffineMaps(ArrayRef<AffineMap> maps,
83706514c55SIan Wood                                  MLIRContext *context) {
83806514c55SIan Wood   if (maps.empty())
83906514c55SIan Wood     return AffineMap::get(context);
840f9c8febcSJakub Lichman   unsigned numResults = 0, numDims = 0, numSymbols = 0;
84121d9dc4fSNicolas Vasilache   for (auto m : maps)
84247ec8702SNicolas Vasilache     numResults += m.getNumResults();
8434562e389SRiver Riddle   SmallVector<AffineExpr, 8> results;
84421d9dc4fSNicolas Vasilache   results.reserve(numResults);
84521d9dc4fSNicolas Vasilache   for (auto m : maps) {
846f9c8febcSJakub Lichman     for (auto res : m.getResults())
847f9c8febcSJakub Lichman       results.push_back(res.shiftSymbols(m.getNumSymbols(), numSymbols));
848f9c8febcSJakub Lichman 
849f9c8febcSJakub Lichman     numSymbols += m.getNumSymbols();
85021d9dc4fSNicolas Vasilache     numDims = std::max(m.getNumDims(), numDims);
85121d9dc4fSNicolas Vasilache   }
85206514c55SIan Wood   return AffineMap::get(numDims, numSymbols, results, context);
85321d9dc4fSNicolas Vasilache }
854a248fa90SFrank Laub 
855255ba1c3SNicolas Vasilache /// Common implementation to project out dimensions or symbols from an affine
856255ba1c3SNicolas Vasilache /// map based on the template type.
857255ba1c3SNicolas Vasilache /// Additionally, if 'compress' is true, the projected out dimensions or symbols
858255ba1c3SNicolas Vasilache /// are also dropped from the resulting map.
859255ba1c3SNicolas Vasilache template <typename AffineDimOrSymExpr>
860255ba1c3SNicolas Vasilache static AffineMap projectCommonImpl(AffineMap map,
861255ba1c3SNicolas Vasilache                                    const llvm::SmallBitVector &toProject,
862255ba1c3SNicolas Vasilache                                    bool compress) {
863255ba1c3SNicolas Vasilache   static_assert(llvm::is_one_of<AffineDimOrSymExpr, AffineDimExpr,
864255ba1c3SNicolas Vasilache                                 AffineSymbolExpr>::value,
865255ba1c3SNicolas Vasilache                 "expected AffineDimExpr or AffineSymbolExpr");
866255ba1c3SNicolas Vasilache 
867255ba1c3SNicolas Vasilache   constexpr bool isDim = std::is_same<AffineDimOrSymExpr, AffineDimExpr>::value;
868255ba1c3SNicolas Vasilache   int64_t numDimOrSym = (isDim) ? map.getNumDims() : map.getNumSymbols();
869255ba1c3SNicolas Vasilache   SmallVector<AffineExpr> replacements;
870255ba1c3SNicolas Vasilache   replacements.reserve(numDimOrSym);
871255ba1c3SNicolas Vasilache 
872255ba1c3SNicolas Vasilache   auto createNewDimOrSym = (isDim) ? getAffineDimExpr : getAffineSymbolExpr;
87324657a95SRahul Joshi 
87424657a95SRahul Joshi   using replace_fn_ty =
87524657a95SRahul Joshi       std::function<AffineExpr(AffineExpr, ArrayRef<AffineExpr>)>;
87624657a95SRahul Joshi   replace_fn_ty replaceDims = [](AffineExpr e,
87724657a95SRahul Joshi                                  ArrayRef<AffineExpr> replacements) {
878255ba1c3SNicolas Vasilache     return e.replaceDims(replacements);
879255ba1c3SNicolas Vasilache   };
88024657a95SRahul Joshi   replace_fn_ty replaceSymbols = [](AffineExpr e,
88124657a95SRahul Joshi                                     ArrayRef<AffineExpr> replacements) {
882255ba1c3SNicolas Vasilache     return e.replaceSymbols(replacements);
883255ba1c3SNicolas Vasilache   };
88424657a95SRahul Joshi   replace_fn_ty replaceNewDimOrSym = (isDim) ? replaceDims : replaceSymbols;
885255ba1c3SNicolas Vasilache 
886255ba1c3SNicolas Vasilache   MLIRContext *context = map.getContext();
887255ba1c3SNicolas Vasilache   int64_t newNumDimOrSym = 0;
888255ba1c3SNicolas Vasilache   for (unsigned dimOrSym = 0; dimOrSym < numDimOrSym; ++dimOrSym) {
889255ba1c3SNicolas Vasilache     if (toProject.test(dimOrSym)) {
890255ba1c3SNicolas Vasilache       replacements.push_back(getAffineConstantExpr(0, context));
891255ba1c3SNicolas Vasilache       continue;
892255ba1c3SNicolas Vasilache     }
893255ba1c3SNicolas Vasilache     int64_t newPos = compress ? newNumDimOrSym++ : dimOrSym;
894255ba1c3SNicolas Vasilache     replacements.push_back(createNewDimOrSym(newPos, context));
895255ba1c3SNicolas Vasilache   }
896255ba1c3SNicolas Vasilache   SmallVector<AffineExpr> resultExprs;
897255ba1c3SNicolas Vasilache   resultExprs.reserve(map.getNumResults());
898255ba1c3SNicolas Vasilache   for (auto e : map.getResults())
899255ba1c3SNicolas Vasilache     resultExprs.push_back(replaceNewDimOrSym(e, replacements));
900255ba1c3SNicolas Vasilache 
901255ba1c3SNicolas Vasilache   int64_t numDims = (compress && isDim) ? newNumDimOrSym : map.getNumDims();
902255ba1c3SNicolas Vasilache   int64_t numSyms = (compress && !isDim) ? newNumDimOrSym : map.getNumSymbols();
903255ba1c3SNicolas Vasilache   return AffineMap::get(numDims, numSyms, resultExprs, context);
904255ba1c3SNicolas Vasilache }
905255ba1c3SNicolas Vasilache 
906255ba1c3SNicolas Vasilache AffineMap mlir::projectDims(AffineMap map,
907255ba1c3SNicolas Vasilache                             const llvm::SmallBitVector &projectedDimensions,
908255ba1c3SNicolas Vasilache                             bool compressDimsFlag) {
909255ba1c3SNicolas Vasilache   return projectCommonImpl<AffineDimExpr>(map, projectedDimensions,
910255ba1c3SNicolas Vasilache                                           compressDimsFlag);
911255ba1c3SNicolas Vasilache }
912255ba1c3SNicolas Vasilache 
913255ba1c3SNicolas Vasilache AffineMap mlir::projectSymbols(AffineMap map,
914255ba1c3SNicolas Vasilache                                const llvm::SmallBitVector &projectedSymbols,
915255ba1c3SNicolas Vasilache                                bool compressSymbolsFlag) {
916255ba1c3SNicolas Vasilache   return projectCommonImpl<AffineSymbolExpr>(map, projectedSymbols,
917255ba1c3SNicolas Vasilache                                              compressSymbolsFlag);
918255ba1c3SNicolas Vasilache }
919255ba1c3SNicolas Vasilache 
9206635c12aSBenjamin Kramer AffineMap mlir::getProjectedMap(AffineMap map,
921255ba1c3SNicolas Vasilache                                 const llvm::SmallBitVector &projectedDimensions,
922255ba1c3SNicolas Vasilache                                 bool compressDimsFlag,
923255ba1c3SNicolas Vasilache                                 bool compressSymbolsFlag) {
924255ba1c3SNicolas Vasilache   map = projectDims(map, projectedDimensions, compressDimsFlag);
925255ba1c3SNicolas Vasilache   if (compressSymbolsFlag)
926255ba1c3SNicolas Vasilache     map = compressUnusedSymbols(map);
927255ba1c3SNicolas Vasilache   return map;
9285ca20851SMaheshRavishankar }
9295ca20851SMaheshRavishankar 
930c3839c0bSBenoit Jacob llvm::SmallBitVector mlir::getUnusedDimsBitVector(ArrayRef<AffineMap> maps) {
931c3839c0bSBenoit Jacob   unsigned numDims = maps[0].getNumDims();
932c3839c0bSBenoit Jacob   llvm::SmallBitVector numDimsBitVector(numDims, true);
933255ba1c3SNicolas Vasilache   for (AffineMap m : maps) {
934c3839c0bSBenoit Jacob     for (unsigned i = 0; i < numDims; ++i) {
935c3839c0bSBenoit Jacob       if (m.isFunctionOfDim(i))
936c3839c0bSBenoit Jacob         numDimsBitVector.reset(i);
937c3839c0bSBenoit Jacob     }
938c3839c0bSBenoit Jacob   }
939c3839c0bSBenoit Jacob   return numDimsBitVector;
940c3839c0bSBenoit Jacob }
941c3839c0bSBenoit Jacob 
942255ba1c3SNicolas Vasilache llvm::SmallBitVector mlir::getUnusedSymbolsBitVector(ArrayRef<AffineMap> maps) {
943255ba1c3SNicolas Vasilache   unsigned numSymbols = maps[0].getNumSymbols();
944255ba1c3SNicolas Vasilache   llvm::SmallBitVector numSymbolsBitVector(numSymbols, true);
945255ba1c3SNicolas Vasilache   for (AffineMap m : maps) {
946255ba1c3SNicolas Vasilache     for (unsigned i = 0; i < numSymbols; ++i) {
947255ba1c3SNicolas Vasilache       if (m.isFunctionOfSymbol(i))
948255ba1c3SNicolas Vasilache         numSymbolsBitVector.reset(i);
949255ba1c3SNicolas Vasilache     }
950255ba1c3SNicolas Vasilache   }
951255ba1c3SNicolas Vasilache   return numSymbolsBitVector;
952255ba1c3SNicolas Vasilache }
953255ba1c3SNicolas Vasilache 
9544dc72d47SNicolas Vasilache AffineMap
9554dc72d47SNicolas Vasilache mlir::expandDimsToRank(AffineMap map, int64_t rank,
9564dc72d47SNicolas Vasilache                        const llvm::SmallBitVector &projectedDimensions) {
9574dc72d47SNicolas Vasilache   auto id = AffineMap::getMultiDimIdentityMap(rank, map.getContext());
9584dc72d47SNicolas Vasilache   AffineMap proj = id.dropResults(projectedDimensions);
9594dc72d47SNicolas Vasilache   return map.compose(proj);
9604dc72d47SNicolas Vasilache }
9614dc72d47SNicolas Vasilache 
962a248fa90SFrank Laub //===----------------------------------------------------------------------===//
963a248fa90SFrank Laub // MutableAffineMap.
964a248fa90SFrank Laub //===----------------------------------------------------------------------===//
965a248fa90SFrank Laub 
966a248fa90SFrank Laub MutableAffineMap::MutableAffineMap(AffineMap map)
9675262865aSKazu Hirata     : results(map.getResults()), numDims(map.getNumDims()),
9685262865aSKazu Hirata       numSymbols(map.getNumSymbols()), context(map.getContext()) {}
969a248fa90SFrank Laub 
970a248fa90SFrank Laub void MutableAffineMap::reset(AffineMap map) {
971a248fa90SFrank Laub   results.clear();
972a248fa90SFrank Laub   numDims = map.getNumDims();
973a248fa90SFrank Laub   numSymbols = map.getNumSymbols();
9749f3ab92eSJeremy Bruestle   context = map.getContext();
97589d8035eSBenjamin Kramer   llvm::append_range(results, map.getResults());
976a248fa90SFrank Laub }
977a248fa90SFrank Laub 
978a248fa90SFrank Laub bool MutableAffineMap::isMultipleOf(unsigned idx, int64_t factor) const {
979d1ceb740SUday Bondhugula   return results[idx].isMultipleOf(factor);
980a248fa90SFrank Laub }
981a248fa90SFrank Laub 
982255ba1c3SNicolas Vasilache // Simplifies the result affine expressions of this map. The expressions
983255ba1c3SNicolas Vasilache // have to be pure for the simplification implemented.
984a248fa90SFrank Laub void MutableAffineMap::simplify() {
985a248fa90SFrank Laub   // Simplify each of the results if possible.
9869db53a18SRiver Riddle   // TODO: functional-style map
987a248fa90SFrank Laub   for (unsigned i = 0, e = getNumResults(); i < e; i++) {
988a248fa90SFrank Laub     results[i] = simplifyAffineExpr(getResult(i), numDims, numSymbols);
989a248fa90SFrank Laub   }
990a248fa90SFrank Laub }
991a248fa90SFrank Laub 
992a248fa90SFrank Laub AffineMap MutableAffineMap::getAffineMap() const {
9939f3ab92eSJeremy Bruestle   return AffineMap::get(numDims, numSymbols, results, context);
994a248fa90SFrank Laub }
995