15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/ADT/SmallBitVector.h"
17 #include "llvm/ADT/SmallSet.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/Support/MathExtras.h"
21 #include "llvm/Support/raw_ostream.h"
25 #include <type_traits>
29 using llvm::divideCeilSigned;
30 using llvm::divideFloorSigned;
39 class AffineExprConstantFolder {
42 : numDims(numDims), operandConsts(operandConsts) {}
47 if (
auto result = constantFoldImpl(expr))
52 bool hasPoison()
const {
return hasPoison_; }
55 std::optional<int64_t> constantFoldImpl(
AffineExpr expr) {
58 return constantFoldBinExpr(
59 expr, [](int64_t lhs, int64_t rhs) {
return lhs + rhs; });
61 return constantFoldBinExpr(
62 expr, [](int64_t lhs, int64_t rhs) {
return lhs * rhs; });
64 return constantFoldBinExpr(
65 expr, [
this](int64_t lhs, int64_t rhs) -> std::optional<int64_t> {
73 return constantFoldBinExpr(
74 expr, [
this](int64_t lhs, int64_t rhs) -> std::optional<int64_t> {
79 return divideFloorSigned(lhs, rhs);
82 return constantFoldBinExpr(
83 expr, [
this](int64_t lhs, int64_t rhs) -> std::optional<int64_t> {
88 return divideCeilSigned(lhs, rhs);
91 return cast<AffineConstantExpr>(expr).getValue();
93 if (
auto attr = llvm::dyn_cast_or_null<IntegerAttr>(
94 operandConsts[cast<AffineDimExpr>(expr).getPosition()]))
98 if (
auto attr = llvm::dyn_cast_or_null<IntegerAttr>(
99 operandConsts[numDims +
100 cast<AffineSymbolExpr>(expr).getPosition()]))
101 return attr.getInt();
104 llvm_unreachable(
"Unknown AffineExpr");
108 std::optional<int64_t> constantFoldBinExpr(
111 auto binOpExpr = cast<AffineBinaryOpExpr>(expr);
112 if (
auto lhs = constantFoldImpl(binOpExpr.getLHS()))
113 if (
auto rhs = constantFoldImpl(binOpExpr.getRHS()))
114 return op(*lhs, *rhs);
122 bool hasPoison_{
false};
137 assert(dims >= results &&
"Dimension mismatch");
148 llvm::SmallBitVector dropDimResults(numDims);
149 for (
auto [idx, resultExpr] :
llvm::enumerate(identityMap.getResults()))
150 dropDimResults[idx] = !keepDimFilter(cast<AffineDimExpr>(resultExpr));
152 return identityMap.dropResults(dropDimResults);
164 if (
auto constExpr = dyn_cast<AffineConstantExpr>(expr)) {
165 if (constExpr.getValue() != 0)
167 broadcastedDims.push_back(resIdx);
171 return broadcastedDims;
179 broadcastedDims->clear();
184 unsigned resIdx = idxAndExpr.index();
186 if (
auto constExpr = dyn_cast<AffineConstantExpr>(expr)) {
188 if (constExpr.getValue() != 0)
191 broadcastedDims->push_back(resIdx);
192 }
else if (
auto dimExpr = dyn_cast<AffineDimExpr>(expr)) {
194 if (dimExpr.getPosition() != suffixStart + resIdx)
218 unsigned projectionStart =
220 permutedDims.clear();
226 unsigned leadingBroadcast =
231 unsigned resIdx = idxAndExpr.index();
235 if (
auto constExpr = dyn_cast<AffineConstantExpr>(expr)) {
236 if (constExpr.getValue() != 0)
238 broadcastDims.push_back(resIdx);
239 }
else if (
auto dimExpr = dyn_cast<AffineDimExpr>(expr)) {
240 if (dimExpr.getPosition() < projectionStart)
242 unsigned newPosition =
243 dimExpr.getPosition() - projectionStart + leadingBroadcast;
244 permutedDims[resIdx] = newPosition;
245 dimFound[newPosition] =
true;
254 for (
auto dim : broadcastDims) {
255 while (pos < dimFound.size() && dimFound[pos]) {
258 permutedDims[dim] = pos++;
266 assert(!permutation.empty() &&
267 "Cannot create permutation map from empty permutation vector");
268 const auto *m = llvm::max_element(permutation);
270 assert(permutationMap.isPermutation() &&
"Invalid permutation vector");
271 return permutationMap;
276 permutation, [](int64_t i) {
return static_cast<unsigned>(i); });
284 for (
unsigned t : targets)
295 template <
typename AffineExprContainer>
299 if (exprsList.empty())
301 int64_t maxDim = -1, maxSym = -1;
304 maps.reserve(exprsList.size());
305 for (
const auto &exprs : exprsList)
307 maxSym + 1, exprs, context));
326 uint64_t thisGcd = resultExpr.getLargestKnownDivisor();
327 gcd = std::gcd(gcd, thisGcd);
337 dimExprs.reserve(numDims);
338 for (
unsigned i = 0; i < numDims; ++i)
340 return get(numDims, 0, dimExprs, context);
349 for (
unsigned i = 0, numDims =
getNumDims(); i < numDims; ++i) {
350 auto expr = dyn_cast<AffineDimExpr>(results[i]);
351 if (!expr || expr.getPosition() != i)
361 for (
unsigned i = 0, numSymbols =
getNumSymbols(); i < numSymbols; ++i) {
362 auto expr = dyn_cast<AffineDimExpr>(results[i]);
363 if (!expr || expr.getPosition() != i)
378 return llvm::all_of(
getResults(), llvm::IsaPred<AffineConstantExpr>);
383 return cast<AffineConstantExpr>(
getResult(0)).getValue();
387 assert(
isConstant() &&
"map must have only constant results");
390 result.emplace_back(cast<AffineConstantExpr>(expr).getValue());
395 assert(map &&
"uninitialized map storage");
399 assert(map &&
"uninitialized map storage");
404 assert(map &&
"uninitialized map storage");
408 assert(map &&
"uninitialized map storage");
416 return cast<AffineDimExpr>(
getResult(idx)).getPosition();
420 if (!isa<AffineDimExpr>(input))
423 for (
unsigned i = 0, numResults =
getNumResults(); i < numResults; i++) {
436 bool *hasPoison)
const {
443 if (integers.empty())
446 auto range = llvm::map_range(integers, [
this](int64_t i) {
449 results.append(range.begin(), range.end());
455 bool *hasPoison)
const {
459 AffineExprConstantFolder exprFolder(
getNumDims(), operandConstants);
464 auto folded = exprFolder.constantFold(expr);
465 if (exprFolder.hasPoison() && hasPoison) {
475 results->push_back(folded.getInt());
477 exprs.push_back(expr);
502 unsigned numResultDims,
503 unsigned numResultSyms)
const {
509 return get(numResultDims, numResultSyms, results,
getContext());
516 unsigned numResultDims,
517 unsigned numResultSyms)
const {
521 newResults.push_back(e.replace(expr, replacement));
529 unsigned numResultDims,
530 unsigned numResultSyms)
const {
534 newResults.push_back(e.replace(map));
543 newResults.push_back(e.replace(map));
548 auto exprs = llvm::to_vector<4>(
getResults());
550 for (
auto pos = positions.find_last(); pos != -1;
551 pos = positions.find_prev(pos))
552 exprs.erase(exprs.begin() + pos);
561 unsigned numSymbols = numSymbolsThisMap + map.
getNumSymbols();
563 for (
unsigned idx = 0; idx < numDims; ++idx) {
567 for (
unsigned idx = numSymbolsThisMap; idx < numSymbols; ++idx) {
568 newSymbols[idx - numSymbolsThisMap] =
576 exprs.push_back(expr.
compose(newMap));
583 exprs.reserve(values.size());
585 for (
auto v : values)
589 res.reserve(resMap.getNumResults());
590 for (
auto e : resMap.getResults())
591 res.push_back(cast<AffineConstantExpr>(e).getValue());
598 auto constExpr = dyn_cast<AffineConstantExpr>(expr);
599 if (constExpr && constExpr.getValue() == 0)
611 auto constExpr = dyn_cast<AffineConstantExpr>(expr);
612 if (!constExpr || constExpr.getValue() != 0)
613 newExprs.push_back(expr);
633 if (
auto dim = dyn_cast<AffineDimExpr>(expr)) {
634 if (seen[dim.getPosition()])
636 seen[dim.getPosition()] =
true;
638 auto constExpr = dyn_cast<AffineConstantExpr>(expr);
639 if (!allowZeroInResults || !constExpr || constExpr.getValue() != 0)
656 exprs.reserve(resultPos.size());
657 for (
auto idx : resultPos)
693 allExprs.reserve(maps.size() * maps.front().getNumResults());
694 unsigned numDims = maps.front().getNumDims(),
695 numSymbols = maps.front().getNumSymbols();
696 for (
auto m : maps) {
697 assert(numDims == m.getNumDims() && numSymbols == m.getNumSymbols() &&
698 "expected maps with same num dims and symbols");
699 llvm::append_range(allExprs, m.getResults());
702 AffineMap::get(numDims, numSymbols, allExprs, maps.front().getContext()));
703 unsigned unifiedNumDims = unifiedMap.
getNumDims(),
707 res.reserve(maps.size());
708 for (
auto m : maps) {
710 unifiedResults.take_front(m.getNumResults()),
712 unifiedResults = unifiedResults.drop_front(m.getNumResults());
718 const llvm::SmallBitVector &unusedDims) {
732 const llvm::SmallBitVector &unusedSymbols) {
750 for (int64_t i = 0; i < map.
getNumDims(); ++i) {
751 if (
auto attr = operands[i].dyn_cast<Attribute>()) {
752 dimReplacements.push_back(
756 remainingValues.push_back(cast<Value>(operands[i]));
759 int64_t numSymbols = 0;
762 symReplacements.push_back(
766 remainingValues.push_back(cast<Value>(operands[i + map.
getNumDims()]));
786 uniqueExprs.erase(llvm::unique(uniqueExprs), uniqueExprs.end());
794 assert(map.
getNumSymbols() == 0 &&
"expected map without symbols");
797 auto expr = en.value();
799 if (
auto d = dyn_cast<AffineDimExpr>(expr)) {
800 if (exprs[d.getPosition()])
807 for (
auto expr : exprs)
809 seenExprs.push_back(expr);
821 for (
unsigned i : llvm::seq(
unsigned(0), map.
getNumResults())) {
823 if (
auto constExpr = dyn_cast<AffineConstantExpr>(map.
getResult(i))) {
824 assert(constExpr.getValue() == 0 &&
825 "Unexpected constant in projected permutation");
840 unsigned numResults = 0, numDims = 0, numSymbols = 0;
842 numResults += m.getNumResults();
844 results.reserve(numResults);
845 for (
auto m : maps) {
846 for (
auto res : m.getResults())
847 results.push_back(res.shiftSymbols(m.getNumSymbols(), numSymbols));
849 numSymbols += m.getNumSymbols();
850 numDims =
std::max(m.getNumDims(), numDims);
859 template <
typename AffineDimOrSymExpr>
861 const llvm::SmallBitVector &toProject,
863 static_assert(llvm::is_one_of<AffineDimOrSymExpr,
AffineDimExpr,
865 "expected AffineDimExpr or AffineSymbolExpr");
867 constexpr
bool isDim = std::is_same<AffineDimOrSymExpr, AffineDimExpr>::value;
870 replacements.reserve(numDimOrSym);
874 using replace_fn_ty =
880 replace_fn_ty replaceSymbols = [](
AffineExpr e,
884 replace_fn_ty replaceNewDimOrSym = (isDim) ? replaceDims : replaceSymbols;
887 int64_t newNumDimOrSym = 0;
888 for (
unsigned dimOrSym = 0; dimOrSym < numDimOrSym; ++dimOrSym) {
889 if (toProject.test(dimOrSym)) {
893 int64_t newPos = compress ? newNumDimOrSym++ : dimOrSym;
894 replacements.push_back(createNewDimOrSym(newPos, context));
899 resultExprs.push_back(replaceNewDimOrSym(e, replacements));
901 int64_t numDims = (compress && isDim) ? newNumDimOrSym : map.
getNumDims();
902 int64_t numSyms = (compress && !isDim) ? newNumDimOrSym : map.
getNumSymbols();
907 const llvm::SmallBitVector &projectedDimensions,
908 bool compressDimsFlag) {
909 return projectCommonImpl<AffineDimExpr>(map, projectedDimensions,
914 const llvm::SmallBitVector &projectedSymbols,
915 bool compressSymbolsFlag) {
916 return projectCommonImpl<AffineSymbolExpr>(map, projectedSymbols,
917 compressSymbolsFlag);
921 const llvm::SmallBitVector &projectedDimensions,
922 bool compressDimsFlag,
923 bool compressSymbolsFlag) {
924 map =
projectDims(map, projectedDimensions, compressDimsFlag);
925 if (compressSymbolsFlag)
931 unsigned numDims = maps[0].getNumDims();
932 llvm::SmallBitVector numDimsBitVector(numDims,
true);
934 for (
unsigned i = 0; i < numDims; ++i) {
935 if (m.isFunctionOfDim(i))
936 numDimsBitVector.reset(i);
939 return numDimsBitVector;
943 unsigned numSymbols = maps[0].getNumSymbols();
944 llvm::SmallBitVector numSymbolsBitVector(numSymbols,
true);
946 for (
unsigned i = 0; i < numSymbols; ++i) {
947 if (m.isFunctionOfSymbol(i))
948 numSymbolsBitVector.reset(i);
951 return numSymbolsBitVector;
956 const llvm::SmallBitVector &projectedDimensions) {
967 : results(map.getResults()), numDims(map.getNumDims()),
968 numSymbols(map.getNumSymbols()), context(map.
getContext()) {}
975 llvm::append_range(results, map.
getResults());
979 return results[idx].isMultipleOf(factor);
static SmallVector< AffineMap > compressUnusedListImpl(ArrayRef< AffineMap > maps, llvm::function_ref< AffineMap(AffineMap)> compressionFun)
Implementation detail to compress multiple affine maps with a compressionFun that is expected to be e...
static SmallVector< AffineMap, 4 > inferFromExprList(ArrayRef< AffineExprContainer > exprsList, MLIRContext *context)
Creates an affine map each for each list of AffineExpr's in exprsList while inferring the right numbe...
static AffineMap projectCommonImpl(AffineMap map, const llvm::SmallBitVector &toProject, bool compress)
Common implementation to project out dimensions or symbols from an affine map based on the template t...
static MLIRContext * getContext(OpFoldResult val)
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
A dimensional identifier appearing in an affine expression.
Base type for affine expression.
AffineExpr replaceDimsAndSymbols(ArrayRef< AffineExpr > dimReplacements, ArrayRef< AffineExpr > symReplacements) const
This method substitutes any uses of dimensions and symbols (e.g.
RetT walk(FnT &&callback) const
Walk all of the AffineExpr's in this expression in postorder.
AffineExprKind getKind() const
Return the classification for this type.
AffineExpr compose(AffineMap map) const
Compose with an AffineMap.
AffineExpr replaceDims(ArrayRef< AffineExpr > dimReplacements) const
Dim-only version of replaceDimsAndSymbols.
MLIRContext * getContext() const
AffineExpr replaceSymbols(ArrayRef< AffineExpr > symReplacements) const
Symbol-only version of replaceDimsAndSymbols.
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
int64_t getSingleConstantResult() const
Returns the constant result of this map.
static AffineMap getMinorIdentityMap(unsigned dims, unsigned results, MLIRContext *context)
Returns an identity affine map (d0, ..., dn) -> (dp, ..., dn) on the most minor dimensions.
AffineMap dropResults(ArrayRef< int64_t > positions) const
AffineMap getSliceMap(unsigned start, unsigned length) const
Returns the map consisting of length expressions starting from start.
AffineMap getMajorSubMap(unsigned numResults) const
Returns the map consisting of the most major numResults results.
MLIRContext * getContext() const
bool isMinorIdentity() const
Returns true if this affine map is a minor identity, i.e.
unsigned getDimPosition(unsigned idx) const
Extracts the position of the dimensional expression at the given result, when the caller knows it is ...
bool isConstant() const
Returns true if this affine map has only constant results.
static AffineMap getMultiDimIdentityMap(unsigned numDims, MLIRContext *context)
Returns an AffineMap with 'numDims' identity result dim exprs.
static AffineMap get(MLIRContext *context)
Returns a zero result affine map with no dimensions or symbols: () -> ().
bool isSingleConstant() const
Returns true if this affine map is a single result constant function.
bool isProjectedPermutation(bool allowZeroInResults=false) const
Returns true if the AffineMap represents a subset (i.e.
AffineMap getMinorSubMap(unsigned numResults) const
Returns the map consisting of the most minor numResults results.
uint64_t getLargestKnownDivisorOfMapExprs()
Get the largest known divisor of all map expressions.
constexpr AffineMap()=default
bool isEmpty() const
Returns true if this affine map is an empty map, i.e., () -> ().
std::optional< unsigned > getResultPosition(AffineExpr input) const
Extracts the first result position where input dimension resides.
unsigned getNumSymbols() const
bool isMinorIdentityWithBroadcasting(SmallVectorImpl< unsigned > *broadcastedDims=nullptr) const
Returns true if this affine map is a minor identity up to broadcasted dimensions which are indicated ...
unsigned getNumDims() const
ArrayRef< AffineExpr > getResults() const
SmallVector< int64_t > getConstantResults() const
Returns the constant results of this map.
bool isPermutationOfMinorIdentityWithBroadcasting(SmallVectorImpl< unsigned > &permutedDims) const
Return true if this affine map can be converted to a minor identity with broadcast by doing a permute...
size_t getNumOfZeroResults() const
Returns the number of "zero" results (constant values == 0) in this map.
bool isSymbolIdentity() const
Returns true if this affine map is an identity affine map on the symbol identifiers.
unsigned getNumResults() const
AffineMap replaceDimsAndSymbols(ArrayRef< AffineExpr > dimReplacements, ArrayRef< AffineExpr > symReplacements, unsigned numResultDims, unsigned numResultSyms) const
This method substitutes any uses of dimensions and symbols (e.g.
unsigned getNumInputs() const
AffineExpr getResult(unsigned idx) const
static AffineMap getFilteredIdentityMap(MLIRContext *ctx, unsigned numDims, llvm::function_ref< bool(AffineDimExpr)> keepDimFilter)
Returns an identity affine map with numDims input dimensions and filtered results using keepDimFilter...
AffineMap replace(AffineExpr expr, AffineExpr replacement, unsigned numResultDims, unsigned numResultSyms) const
Sparse replace method.
AffineMap dropZeroResults()
Returns the AffineMap resulting from removing "zero" results (constant values == 0) from this map.
static AffineMap getPermutationMap(ArrayRef< unsigned > permutation, MLIRContext *context)
Returns an AffineMap representing a permutation.
SmallVector< unsigned > getBroadcastDims() const
Returns the list of broadcast dimensions (i.e.
void walkExprs(llvm::function_ref< void(AffineExpr)> callback) const
Walk all of the AffineExpr's in this mapping.
AffineMap partialConstantFold(ArrayRef< Attribute > operandConstants, SmallVectorImpl< int64_t > *results=nullptr, bool *hasPoison=nullptr) const
Propagates the constant operands into this affine map.
static AffineMap getConstantMap(int64_t val, MLIRContext *context)
Returns a single constant result affine map.
static AffineMap getMultiDimMapWithTargets(unsigned numDims, ArrayRef< unsigned > targets, MLIRContext *context)
Returns an affine map with numDims input dimensions and results specified by targets.
AffineMap getSubMap(ArrayRef< unsigned > resultPos) const
Returns the map consisting of the resultPos subset.
LogicalResult constantFold(ArrayRef< Attribute > operandConstants, SmallVectorImpl< Attribute > &results, bool *hasPoison=nullptr) const
Folds the results of the application of an affine map on the provided operands to a constant if possi...
AffineMap compose(AffineMap map) const
Returns the AffineMap resulting from composing this with map.
bool isIdentity() const
Returns true if this affine map is an identity affine map.
bool isPermutation() const
Returns true if the AffineMap represents a symbol-less permutation map.
static SmallVector< AffineMap, 4 > inferFromExprList(ArrayRef< ArrayRef< AffineExpr >> exprsList, MLIRContext *context)
Returns a vector of AffineMaps; each with as many results as exprs.size(), as many dims as the larges...
A symbolic identifier appearing in an affine expression.
Attributes are known-constant values of operations.
This class is a general helper class for creating context-global objects like types,...
AffineExpr getAffineSymbolExpr(unsigned position)
AffineExpr getAffineConstantExpr(int64_t constant)
AffineExpr getAffineDimExpr(unsigned position)
MLIRContext is the top-level object for a collection of MLIR operations.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Include the generated interface declarations.
AffineMap simplifyAffineMap(AffineMap map)
Simplifies an affine map by simplifying its underlying AffineExpr results.
AffineMap concatAffineMaps(ArrayRef< AffineMap > maps, MLIRContext *context)
Concatenates a list of maps into a single AffineMap, stepping over potentially empty maps.
AffineMap expandDimsToRank(AffineMap map, int64_t rank, const llvm::SmallBitVector &projectedDimensions)
Expand map to operate on rank dims while projecting out the dims in projectedDimensions.
AffineMap removeDuplicateExprs(AffineMap map)
Returns a map with the same dimension and symbol count as map, but whose results are the unique affin...
llvm::SmallBitVector getUnusedSymbolsBitVector(ArrayRef< AffineMap > maps)
AffineMap inverseAndBroadcastProjectedPermutation(AffineMap map)
Return the reverse map of a projected permutation where the projected dimensions are transformed into...
AffineMap inversePermutation(AffineMap map)
Returns a map of codomain to domain dimensions such that the first codomain dimension for a particula...
@ CeilDiv
RHS of ceildiv is always a constant or a symbolic expression.
@ Mul
RHS of mul is always a constant or a symbolic expression.
@ Mod
RHS of mod is always a constant or a symbolic expression with a positive value.
@ DimId
Dimensional identifier.
@ FloorDiv
RHS of floordiv is always a constant or a symbolic expression.
@ Constant
Constant integer.
@ SymbolId
Symbolic identifier.
AffineMap compressSymbols(AffineMap map, const llvm::SmallBitVector &unusedSymbols)
Drop the symbols that are listed in unusedSymbols.
static void getMaxDimAndSymbol(ArrayRef< AffineExprContainer > exprsList, int64_t &maxDim, int64_t &maxSym)
Calculates maximum dimension and symbol positions from the expressions in exprsLists and stores them ...
AffineMap compressUnusedDims(AffineMap map)
Drop the dims that are not used.
AffineMap compressDims(AffineMap map, const llvm::SmallBitVector &unusedDims)
Drop the dims that are listed in unusedDims.
AffineExpr getAffineConstantExpr(int64_t constant, MLIRContext *context)
AffineMap getProjectedMap(AffineMap map, const llvm::SmallBitVector &projectedDimensions, bool compressDimsFlag=true, bool compressSymbolsFlag=true)
Calls projectDims(map, projectedDimensions, compressDimsFlag).
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
llvm::SmallBitVector getUnusedDimsBitVector(ArrayRef< AffineMap > maps)
AffineExpr simplifyAffineExpr(AffineExpr expr, unsigned numDims, unsigned numSymbols)
Simplify an affine expression by flattening and some amount of simple analysis.
AffineExpr getAffineDimExpr(unsigned position, MLIRContext *context)
These free functions allow clients of the API to not use classes in detail.
AffineMap projectDims(AffineMap map, const llvm::SmallBitVector &projectedDimensions, bool compressDimsFlag=false)
Returns the map that results from projecting out the dimensions specified in projectedDimensions.
AffineMap compressUnusedSymbols(AffineMap map)
Drop the symbols that are not used.
AffineMap projectSymbols(AffineMap map, const llvm::SmallBitVector &projectedSymbols, bool compressSymbolsFlag=false)
Symbol counterpart of projectDims.
AffineMap foldAttributesIntoMap(Builder &b, AffineMap map, ArrayRef< OpFoldResult > operands, SmallVector< Value > &remainingValues)
Fold all attributes among the given operands into the affine map.
AffineExpr getAffineSymbolExpr(unsigned position, MLIRContext *context)
void reset(AffineMap map)
Resets this MutableAffineMap with 'map'.
MutableAffineMap()=default
AffineMap getAffineMap() const
Get the AffineMap corresponding to this MutableAffineMap.
AffineExpr getResult(unsigned idx) const
bool isMultipleOf(unsigned idx, int64_t factor) const
Returns true if the idx'th result expression is a multiple of factor.
unsigned getNumResults() const
void simplify()
Simplify the (result) expressions in this map using analysis (used by.
ArrayRef< AffineExpr > results() const
The affine expressions for this (multi-dimensional) map.