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