15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/ADT/SmallBitVector.h"
17 #include "llvm/ADT/SmallVector.h"
18 #include "llvm/Support/MathExtras.h"
21 #include <type_traits>
25 using llvm::divideCeilSigned;
26 using llvm::divideFloorSigned;
35 class AffineExprConstantFolder {
38 : numDims(numDims), operandConsts(operandConsts) {}
43 if (
auto result = constantFoldImpl(expr))
48 bool hasPoison()
const {
return hasPoison_; }
51 std::optional<int64_t> constantFoldImpl(
AffineExpr expr) {
54 return constantFoldBinExpr(
55 expr, [](int64_t lhs, int64_t rhs) {
return lhs + rhs; });
57 return constantFoldBinExpr(
58 expr, [](int64_t lhs, int64_t rhs) {
return lhs * rhs; });
60 return constantFoldBinExpr(
61 expr, [
this](int64_t lhs, int64_t rhs) -> std::optional<int64_t> {
69 return constantFoldBinExpr(
70 expr, [
this](int64_t lhs, int64_t rhs) -> std::optional<int64_t> {
75 return divideFloorSigned(lhs, rhs);
78 return constantFoldBinExpr(
79 expr, [
this](int64_t lhs, int64_t rhs) -> std::optional<int64_t> {
84 return divideCeilSigned(lhs, rhs);
87 return cast<AffineConstantExpr>(expr).getValue();
89 if (
auto attr = llvm::dyn_cast_or_null<IntegerAttr>(
90 operandConsts[cast<AffineDimExpr>(expr).getPosition()]))
94 if (
auto attr = llvm::dyn_cast_or_null<IntegerAttr>(
95 operandConsts[numDims +
96 cast<AffineSymbolExpr>(expr).getPosition()]))
100 llvm_unreachable(
"Unknown AffineExpr");
104 std::optional<int64_t> constantFoldBinExpr(
107 auto binOpExpr = cast<AffineBinaryOpExpr>(expr);
108 if (
auto lhs = constantFoldImpl(binOpExpr.getLHS()))
109 if (
auto rhs = constantFoldImpl(binOpExpr.getRHS()))
110 return op(*lhs, *rhs);
118 bool hasPoison_{
false};
133 assert(dims >= results &&
"Dimension mismatch");
144 llvm::SmallBitVector dropDimResults(numDims);
145 for (
auto [idx, resultExpr] :
llvm::enumerate(identityMap.getResults()))
146 dropDimResults[idx] = !keepDimFilter(cast<AffineDimExpr>(resultExpr));
148 return identityMap.dropResults(dropDimResults);
160 if (
auto constExpr = dyn_cast<AffineConstantExpr>(expr)) {
161 if (constExpr.getValue() != 0)
163 broadcastedDims.push_back(resIdx);
167 return broadcastedDims;
175 broadcastedDims->clear();
180 unsigned resIdx = idxAndExpr.index();
182 if (
auto constExpr = dyn_cast<AffineConstantExpr>(expr)) {
184 if (constExpr.getValue() != 0)
187 broadcastedDims->push_back(resIdx);
188 }
else if (
auto dimExpr = dyn_cast<AffineDimExpr>(expr)) {
190 if (dimExpr.getPosition() != suffixStart + resIdx)
214 unsigned projectionStart =
216 permutedDims.clear();
222 unsigned leadingBroadcast =
227 unsigned resIdx = idxAndExpr.index();
231 if (
auto constExpr = dyn_cast<AffineConstantExpr>(expr)) {
232 if (constExpr.getValue() != 0)
234 broadcastDims.push_back(resIdx);
235 }
else if (
auto dimExpr = dyn_cast<AffineDimExpr>(expr)) {
236 if (dimExpr.getPosition() < projectionStart)
238 unsigned newPosition =
239 dimExpr.getPosition() - projectionStart + leadingBroadcast;
240 permutedDims[resIdx] = newPosition;
241 dimFound[newPosition] =
true;
250 for (
auto dim : broadcastDims) {
251 while (pos < dimFound.size() && dimFound[pos]) {
254 permutedDims[dim] = pos++;
262 assert(!permutation.empty() &&
263 "Cannot create permutation map from empty permutation vector");
264 const auto *m = llvm::max_element(permutation);
266 assert(permutationMap.isPermutation() &&
"Invalid permutation vector");
267 return permutationMap;
272 permutation, [](int64_t i) {
return static_cast<unsigned>(i); });
280 for (
unsigned t : targets)
291 template <
typename AffineExprContainer>
295 if (exprsList.empty())
297 int64_t maxDim = -1, maxSym = -1;
300 maps.reserve(exprsList.size());
301 for (
const auto &exprs : exprsList)
303 maxSym + 1, exprs, context));
322 uint64_t thisGcd = resultExpr.getLargestKnownDivisor();
323 gcd = std::gcd(gcd, thisGcd);
333 dimExprs.reserve(numDims);
334 for (
unsigned i = 0; i < numDims; ++i)
336 return get(numDims, 0, dimExprs, context);
345 for (
unsigned i = 0, numDims =
getNumDims(); i < numDims; ++i) {
346 auto expr = dyn_cast<AffineDimExpr>(results[i]);
347 if (!expr || expr.getPosition() != i)
357 for (
unsigned i = 0, numSymbols =
getNumSymbols(); i < numSymbols; ++i) {
358 auto expr = dyn_cast<AffineDimExpr>(results[i]);
359 if (!expr || expr.getPosition() != i)
374 return llvm::all_of(
getResults(), llvm::IsaPred<AffineConstantExpr>);
379 return cast<AffineConstantExpr>(
getResult(0)).getValue();
383 assert(
isConstant() &&
"map must have only constant results");
386 result.emplace_back(cast<AffineConstantExpr>(expr).getValue());
391 assert(map &&
"uninitialized map storage");
395 assert(map &&
"uninitialized map storage");
400 assert(map &&
"uninitialized map storage");
404 assert(map &&
"uninitialized map storage");
412 return cast<AffineDimExpr>(
getResult(idx)).getPosition();
416 if (!isa<AffineDimExpr>(input))
419 for (
unsigned i = 0, numResults =
getNumResults(); i < numResults; i++) {
432 bool *hasPoison)
const {
439 if (integers.empty())
442 auto range = llvm::map_range(integers, [
this](int64_t i) {
445 results.append(range.begin(), range.end());
451 bool *hasPoison)
const {
455 AffineExprConstantFolder exprFolder(
getNumDims(), operandConstants);
460 auto folded = exprFolder.constantFold(expr);
461 if (exprFolder.hasPoison() && hasPoison) {
471 results->push_back(folded.getInt());
473 exprs.push_back(expr);
498 unsigned numResultDims,
499 unsigned numResultSyms)
const {
505 return get(numResultDims, numResultSyms, results,
getContext());
512 unsigned numResultDims,
513 unsigned numResultSyms)
const {
517 newResults.push_back(e.replace(expr, replacement));
525 unsigned numResultDims,
526 unsigned numResultSyms)
const {
530 newResults.push_back(e.replace(map));
539 newResults.push_back(e.replace(map));
544 auto exprs = llvm::to_vector<4>(
getResults());
546 for (
auto pos = positions.find_last(); pos != -1;
547 pos = positions.find_prev(pos))
548 exprs.erase(exprs.begin() + pos);
557 unsigned numSymbols = numSymbolsThisMap + map.
getNumSymbols();
559 for (
unsigned idx = 0; idx < numDims; ++idx) {
563 for (
unsigned idx = numSymbolsThisMap; idx < numSymbols; ++idx) {
564 newSymbols[idx - numSymbolsThisMap] =
572 exprs.push_back(expr.
compose(newMap));
580 for (int64_t value : values)
585 res.push_back(cast<AffineConstantExpr>(e.replaceDims(exprs)).getValue());
592 auto constExpr = dyn_cast<AffineConstantExpr>(expr);
593 if (constExpr && constExpr.getValue() == 0)
604 auto constExpr = dyn_cast<AffineConstantExpr>(expr);
605 if (!constExpr || constExpr.getValue() != 0)
606 newExprs.push_back(expr);
626 if (
auto dim = dyn_cast<AffineDimExpr>(expr)) {
627 if (seen[dim.getPosition()])
629 seen[dim.getPosition()] =
true;
631 auto constExpr = dyn_cast<AffineConstantExpr>(expr);
632 if (!allowZeroInResults || !constExpr || constExpr.getValue() != 0)
649 exprs.reserve(resultPos.size());
650 for (
auto idx : resultPos)
686 allExprs.reserve(maps.size() * maps.front().getNumResults());
687 unsigned numDims = maps.front().getNumDims(),
688 numSymbols = maps.front().getNumSymbols();
689 for (
auto m : maps) {
690 assert(numDims == m.getNumDims() && numSymbols == m.getNumSymbols() &&
691 "expected maps with same num dims and symbols");
692 llvm::append_range(allExprs, m.getResults());
695 AffineMap::get(numDims, numSymbols, allExprs, maps.front().getContext()));
696 unsigned unifiedNumDims = unifiedMap.
getNumDims(),
700 res.reserve(maps.size());
701 for (
auto m : maps) {
703 unifiedResults.take_front(m.getNumResults()),
705 unifiedResults = unifiedResults.drop_front(m.getNumResults());
711 const llvm::SmallBitVector &unusedDims) {
725 const llvm::SmallBitVector &unusedSymbols) {
743 for (int64_t i = 0; i < map.
getNumDims(); ++i) {
744 if (
auto attr = dyn_cast<Attribute>(operands[i])) {
745 dimReplacements.push_back(
749 remainingValues.push_back(cast<Value>(operands[i]));
752 int64_t numSymbols = 0;
754 if (
auto attr = dyn_cast<Attribute>(operands[i + map.
getNumDims()])) {
755 symReplacements.push_back(
759 remainingValues.push_back(cast<Value>(operands[i + map.
getNumDims()]));
779 uniqueExprs.erase(llvm::unique(uniqueExprs), uniqueExprs.end());
787 assert(map.
getNumSymbols() == 0 &&
"expected map without symbols");
790 auto expr = en.value();
792 if (
auto d = dyn_cast<AffineDimExpr>(expr)) {
793 if (exprs[d.getPosition()])
800 for (
auto expr : exprs)
802 seenExprs.push_back(expr);
814 for (
unsigned i : llvm::seq(
unsigned(0), map.
getNumResults())) {
816 if (
auto constExpr = dyn_cast<AffineConstantExpr>(map.
getResult(i))) {
817 assert(constExpr.getValue() == 0 &&
818 "Unexpected constant in projected permutation");
833 unsigned numResults = 0, numDims = 0, numSymbols = 0;
835 numResults += m.getNumResults();
837 results.reserve(numResults);
838 for (
auto m : maps) {
839 for (
auto res : m.getResults())
840 results.push_back(res.shiftSymbols(m.getNumSymbols(), numSymbols));
842 numSymbols += m.getNumSymbols();
843 numDims =
std::max(m.getNumDims(), numDims);
852 template <
typename AffineDimOrSymExpr>
854 const llvm::SmallBitVector &toProject,
856 static_assert(llvm::is_one_of<AffineDimOrSymExpr,
AffineDimExpr,
858 "expected AffineDimExpr or AffineSymbolExpr");
860 constexpr
bool isDim = std::is_same<AffineDimOrSymExpr, AffineDimExpr>::value;
863 replacements.reserve(numDimOrSym);
867 using replace_fn_ty =
873 replace_fn_ty replaceSymbols = [](
AffineExpr e,
877 replace_fn_ty replaceNewDimOrSym = (isDim) ? replaceDims : replaceSymbols;
880 int64_t newNumDimOrSym = 0;
881 for (
unsigned dimOrSym = 0; dimOrSym < numDimOrSym; ++dimOrSym) {
882 if (toProject.test(dimOrSym)) {
886 int64_t newPos = compress ? newNumDimOrSym++ : dimOrSym;
887 replacements.push_back(createNewDimOrSym(newPos, context));
892 resultExprs.push_back(replaceNewDimOrSym(e, replacements));
894 int64_t numDims = (compress && isDim) ? newNumDimOrSym : map.
getNumDims();
895 int64_t numSyms = (compress && !isDim) ? newNumDimOrSym : map.
getNumSymbols();
900 const llvm::SmallBitVector &projectedDimensions,
901 bool compressDimsFlag) {
902 return projectCommonImpl<AffineDimExpr>(map, projectedDimensions,
907 const llvm::SmallBitVector &projectedSymbols,
908 bool compressSymbolsFlag) {
909 return projectCommonImpl<AffineSymbolExpr>(map, projectedSymbols,
910 compressSymbolsFlag);
914 const llvm::SmallBitVector &projectedDimensions,
915 bool compressDimsFlag,
916 bool compressSymbolsFlag) {
917 map =
projectDims(map, projectedDimensions, compressDimsFlag);
918 if (compressSymbolsFlag)
924 unsigned numDims = maps[0].getNumDims();
925 llvm::SmallBitVector numDimsBitVector(numDims,
true);
927 for (
unsigned i = 0; i < numDims; ++i) {
928 if (m.isFunctionOfDim(i))
929 numDimsBitVector.reset(i);
932 return numDimsBitVector;
936 unsigned numSymbols = maps[0].getNumSymbols();
937 llvm::SmallBitVector numSymbolsBitVector(numSymbols,
true);
939 for (
unsigned i = 0; i < numSymbols; ++i) {
940 if (m.isFunctionOfSymbol(i))
941 numSymbolsBitVector.reset(i);
944 return numSymbolsBitVector;
949 const llvm::SmallBitVector &projectedDimensions) {
960 : results(map.getResults()), numDims(map.getNumDims()),
961 numSymbols(map.getNumSymbols()), context(map.
getContext()) {}
968 llvm::append_range(results, map.
getResults());
972 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.
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.