18 #include "llvm/ADT/STLExtras.h"
32 template <
typename WalkRetTy>
35 struct AffineExprWalker
40 : callback(callback) {}
43 return callback(expr);
46 return callback(expr);
48 WalkRetTy visitDimExpr(
AffineDimExpr expr) {
return callback(expr); }
52 return AffineExprWalker(callback).walkPostOrder(e);
75 llvm_unreachable(
"unknown binary operation on affine expressions");
87 unsigned dimId = llvm::cast<AffineDimExpr>(*this).getPosition();
88 if (dimId >= dimReplacements.size())
90 return dimReplacements[dimId];
93 unsigned symId = llvm::cast<AffineSymbolExpr>(*this).getPosition();
94 if (symId >= symReplacements.size())
96 return symReplacements[symId];
103 auto binOp = llvm::cast<AffineBinaryOpExpr>(*
this);
104 auto lhs = binOp.getLHS(), rhs = binOp.getRHS();
105 auto newLHS = lhs.replaceDimsAndSymbols(dimReplacements, symReplacements);
106 auto newRHS = rhs.replaceDimsAndSymbols(dimReplacements, symReplacements);
107 if (newLHS == lhs && newRHS == rhs)
111 llvm_unreachable(
"Unknown AffineExpr");
115 return replaceDimsAndSymbols(dimReplacements, {});
120 return replaceDimsAndSymbols({}, symReplacements);
126 unsigned offset)
const {
128 for (
unsigned idx = 0; idx < offset; ++idx)
130 for (
unsigned idx = offset; idx < numDims; ++idx)
132 return replaceDimsAndSymbols(dims, {});
138 unsigned offset)
const {
140 for (
unsigned idx = 0; idx < offset; ++idx)
142 for (
unsigned idx = offset; idx < numSymbols; ++idx)
144 return replaceDimsAndSymbols({}, symbols);
150 auto it = map.find(*
this);
161 auto binOp = llvm::cast<AffineBinaryOpExpr>(*
this);
162 auto lhs = binOp.getLHS(), rhs = binOp.getRHS();
163 auto newLHS = lhs.replace(map);
164 auto newRHS = rhs.replace(map);
165 if (newLHS == lhs && newRHS == rhs)
169 llvm_unreachable(
"Unknown AffineExpr");
175 map.insert(std::make_pair(expr, replacement));
194 auto expr = llvm::cast<AffineBinaryOpExpr>(*
this);
195 return expr.getLHS().isSymbolicOrConstant() &&
196 expr.getRHS().isSymbolicOrConstant();
199 llvm_unreachable(
"Unknown AffineExpr");
211 auto op = llvm::cast<AffineBinaryOpExpr>(*
this);
212 return op.getLHS().isPureAffine() && op.getRHS().isPureAffine();
218 auto op = llvm::cast<AffineBinaryOpExpr>(*
this);
219 return op.getLHS().isPureAffine() && op.getRHS().isPureAffine() &&
220 (llvm::isa<AffineConstantExpr>(op.getLHS()) ||
221 llvm::isa<AffineConstantExpr>(op.getRHS()));
226 auto op = llvm::cast<AffineBinaryOpExpr>(*
this);
227 return op.getLHS().isPureAffine() &&
228 llvm::isa<AffineConstantExpr>(op.getRHS());
231 llvm_unreachable(
"Unknown AffineExpr");
247 binExpr = llvm::cast<AffineBinaryOpExpr>(*
this);
248 auto rhs = llvm::dyn_cast<AffineConstantExpr>(binExpr.
getRHS());
250 if (rhs && rhs.getValue() != 0) {
252 if (lhsDiv % rhs.getValue() == 0)
253 return lhsDiv / rhs.getValue();
258 return std::abs(llvm::cast<AffineConstantExpr>(*this).getValue());
260 binExpr = llvm::cast<AffineBinaryOpExpr>(*
this);
267 binExpr = llvm::cast<AffineBinaryOpExpr>(*
this);
272 llvm_unreachable(
"Unknown AffineExpr");
282 return factor * factor == 1;
284 return llvm::cast<AffineConstantExpr>(*this).getValue() % factor == 0;
286 binExpr = llvm::cast<AffineBinaryOpExpr>(*
this);
292 (l * u) % factor == 0;
298 binExpr = llvm::cast<AffineBinaryOpExpr>(*
this);
305 llvm_unreachable(
"Unknown AffineExpr");
312 if (
auto expr = llvm::dyn_cast<AffineBinaryOpExpr>(*
this)) {
313 return expr.getLHS().isFunctionOfDim(position) ||
314 expr.getRHS().isFunctionOfDim(position);
323 if (
auto expr = llvm::dyn_cast<AffineBinaryOpExpr>(*
this)) {
324 return expr.getLHS().isFunctionOfSymbol(position) ||
325 expr.getRHS().isFunctionOfSymbol(position);
356 "unexpected opKind");
359 return cast<AffineConstantExpr>(expr).getValue() == 0;
363 return (cast<AffineSymbolExpr>(expr).getPosition() == symbolPos);
404 llvm_unreachable(
"Unknown AffineExpr");
415 "unexpected opKind");
418 if (cast<AffineConstantExpr>(expr).getValue() != 0)
444 return binaryExpr.
getLHS() *
459 llvm_unreachable(
"Unknown AffineExpr");
467 auto addExpr = dyn_cast<AffineBinaryOpExpr>(expr);
469 result.push_back(expr);
479 auto mulExpr = dyn_cast<AffineBinaryOpExpr>(candidate);
482 if (
auto lhs = dyn_cast<AffineConstantExpr>(mulExpr.getLHS())) {
483 if (lhs.getValue() == -1) {
484 expr = mulExpr.getRHS();
488 if (
auto rhs = dyn_cast<AffineConstantExpr>(mulExpr.getRHS())) {
489 if (rhs.getValue() == -1) {
490 expr = mulExpr.getLHS();
506 unsigned numDims,
unsigned numSymbols) {
513 for (int64_t i = 0, e = summands.size(); i < e; ++i) {
521 if (innerMod.
getRHS() != rhs)
526 for (int64_t
j = 0;
j < e; ++
j)
528 diff = diff + summands[
j];
529 diff = diff - innerMod.
getLHS();
531 auto constExpr = dyn_cast<AffineConstantExpr>(diff);
532 if (constExpr && constExpr.getValue() == 0)
544 unsigned numSymbols) {
585 llvm_unreachable(
"Unknown AffineExpr");
591 storage->context = context;
596 assignCtx,
static_cast<unsigned>(kind), position);
625 storage->context = context;
635 return llvm::to_vector(llvm::map_range(constants, [&](int64_t constant) {
642 auto lhsConst = dyn_cast<AffineConstantExpr>(lhs);
643 auto rhsConst = dyn_cast<AffineConstantExpr>(rhs);
645 if (lhsConst && rhsConst)
651 if (isa<AffineConstantExpr>(lhs) ||
660 if (rhsConst.getValue() == 0)
664 auto lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
666 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS()))
667 return lBin.getLHS() + (lrhs.getValue() + rhsConst.getValue());
673 std::optional<int64_t> rLhsConst, rRhsConst;
676 auto lBinOpExpr = dyn_cast<AffineBinaryOpExpr>(lhs);
678 (rLhsConstExpr = dyn_cast<AffineConstantExpr>(lBinOpExpr.getRHS()))) {
679 rLhsConst = rLhsConstExpr.
getValue();
680 firstExpr = lBinOpExpr.getLHS();
686 auto rBinOpExpr = dyn_cast<AffineBinaryOpExpr>(rhs);
689 (rRhsConstExpr = dyn_cast<AffineConstantExpr>(rBinOpExpr.getRHS()))) {
690 rRhsConst = rRhsConstExpr.
getValue();
691 secondExpr = rBinOpExpr.getLHS();
697 if (rLhsConst && rRhsConst && firstExpr == secondExpr)
705 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS())) {
706 return lBin.getLHS() + rhs + lrhs;
719 auto lrhs = rBinOpExpr.getLHS();
720 auto rrhs = rBinOpExpr.getRHS();
726 auto lrhsBinOpExpr = dyn_cast<AffineBinaryOpExpr>(lrhs);
728 auto rrhsConstOpExpr = dyn_cast<AffineConstantExpr>(rrhs);
729 if (rrhsConstOpExpr && rrhsConstOpExpr.getValue() == -1 && lrhsBinOpExpr &&
732 llrhs = lrhsBinOpExpr.getLHS();
734 rlrhs = lrhsBinOpExpr.getRHS();
735 auto llrhsBinOpExpr = dyn_cast<AffineBinaryOpExpr>(llrhs);
738 if (llrhsBinOpExpr.getRHS() == rlrhs && lhs == llrhsBinOpExpr.getLHS())
747 llrhs = lrBinOpExpr.
getLHS();
748 rlrhs = lrBinOpExpr.
getRHS();
750 if (lhs == llrhs && rlrhs == -rrhs) {
770 auto lhsConst = dyn_cast<AffineConstantExpr>(lhs);
771 auto rhsConst = dyn_cast<AffineConstantExpr>(rhs);
773 if (lhsConst && rhsConst)
791 if (rhsConst.getValue() == 1)
794 if (rhsConst.getValue() == 0)
799 auto lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
801 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS()))
802 return lBin.getLHS() * (lrhs.getValue() * rhsConst.getValue());
808 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS())) {
809 return (lBin.getLHS() * rhs) * lrhs;
836 return *
this + (-other);
840 auto lhsConst = dyn_cast<AffineConstantExpr>(lhs);
841 auto rhsConst = dyn_cast<AffineConstantExpr>(rhs);
844 if (!rhsConst || rhsConst.getValue() < 1)
858 auto lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
860 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS())) {
862 if (lrhs.getValue() % rhsConst.getValue() == 0)
863 return lBin.getLHS() * (lrhs.getValue() / rhsConst.getValue());
870 int64_t llhsDiv = lBin.getLHS().getLargestKnownDivisor();
871 int64_t lrhsDiv = lBin.getRHS().getLargestKnownDivisor();
873 if (llhsDiv % rhsConst.getValue() == 0 ||
874 lrhsDiv % rhsConst.getValue() == 0)
875 return lBin.getLHS().floorDiv(rhsConst.getValue()) +
876 lBin.getRHS().floorDiv(rhsConst.getValue());
896 auto lhsConst = dyn_cast<AffineConstantExpr>(lhs);
897 auto rhsConst = dyn_cast<AffineConstantExpr>(rhs);
899 if (!rhsConst || rhsConst.getValue() < 1)
908 if (rhsConst.getValue() == 1)
913 auto lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
915 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS())) {
917 if (lrhs.getValue() % rhsConst.getValue() == 0)
918 return lBin.getLHS() * (lrhs.getValue() / rhsConst.getValue());
939 auto lhsConst = dyn_cast<AffineConstantExpr>(lhs);
940 auto rhsConst = dyn_cast<AffineConstantExpr>(rhs);
943 if (!rhsConst || rhsConst.getValue() < 1)
958 auto lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
960 int64_t llhsDiv = lBin.getLHS().getLargestKnownDivisor();
961 int64_t lrhsDiv = lBin.getRHS().getLargestKnownDivisor();
963 if (llhsDiv % rhsConst.getValue() == 0)
964 return lBin.getRHS() % rhsConst.getValue();
965 if (lrhsDiv % rhsConst.getValue() == 0)
966 return lBin.getLHS() % rhsConst.getValue();
971 auto intermediate = dyn_cast<AffineConstantExpr>(lBin.getRHS());
972 if (intermediate && intermediate.getValue() >= 1 &&
973 mod(intermediate.getValue(), rhsConst.getValue()) == 0) {
974 return lBin.getLHS() % rhsConst.getValue();
1010 unsigned numSymbols,
1014 assert(flatExprs.size() - numDims - numSymbols - 1 == localExprs.size() &&
1015 "unexpected number of local expressions");
1019 for (
unsigned j = 0;
j < numDims + numSymbols;
j++) {
1020 if (flatExprs[
j] == 0)
1024 expr = expr +
id * flatExprs[
j];
1028 for (
unsigned j = numDims + numSymbols, e = flatExprs.size() - 1;
j < e;
1030 if (flatExprs[
j] == 0)
1032 auto term = localExprs[
j - numDims - numSymbols] * flatExprs[
j];
1037 int64_t constTerm = flatExprs[flatExprs.size() - 1];
1039 expr = expr + constTerm;
1053 unsigned numSymbols,
1056 assert(!flatExprs.empty() &&
"flatExprs cannot be empty");
1059 assert(flatExprs.size() - numDims - numSymbols - 1 == localExprs.size() &&
1060 "unexpected number of local expressions");
1092 auto addEntry = [&](std::pair<unsigned, signed> index, int64_t coefficient,
1094 assert(!llvm::is_contained(indices, index) &&
1095 "Key is already present in indices vector and overwriting will "
1096 "happen in `indexToExprMap` and `coefficients`!");
1098 indices.push_back(index);
1099 coefficients.insert({index, coefficient});
1100 indexToExprMap.insert({index, expr});
1108 unsigned offsetSym = 0;
1109 signed offsetDim = -1;
1110 for (
unsigned j = numDims;
j < numDims + numSymbols; ++
j) {
1111 if (flatExprs[
j] == 0)
1117 std::pair<unsigned, signed> indexEntry(
1118 j - numDims,
std::max(numDims, numSymbols) + offsetSym++);
1119 addEntry(indexEntry, flatExprs[
j],
1127 unsigned lhsPos, rhsPos;
1134 if (flatExprs[numDims + numSymbols + it.index()] == 0)
1136 AffineExpr lhs = cast<AffineBinaryOpExpr>(expr).getLHS();
1137 AffineExpr rhs = cast<AffineBinaryOpExpr>(expr).getRHS();
1138 if (!((isa<AffineDimExpr>(lhs) || isa<AffineSymbolExpr>(lhs)) &&
1139 (isa<AffineDimExpr>(rhs) || isa<AffineSymbolExpr>(rhs) ||
1140 isa<AffineConstantExpr>(rhs)))) {
1143 if (isa<AffineConstantExpr>(rhs)) {
1148 if (isa<AffineDimExpr>(lhs)) {
1149 lhsPos = cast<AffineDimExpr>(lhs).getPosition();
1150 std::pair<unsigned, signed> indexEntry(lhsPos, offsetDim--);
1151 addEntry(indexEntry, flatExprs[numDims + numSymbols + it.index()],
1154 lhsPos = cast<AffineSymbolExpr>(lhs).getPosition();
1155 std::pair<unsigned, signed> indexEntry(
1156 lhsPos,
std::max(numDims, numSymbols) + offsetSym++);
1157 addEntry(indexEntry, flatExprs[numDims + numSymbols + it.index()],
1160 }
else if (isa<AffineDimExpr>(lhs)) {
1166 lhsPos = cast<AffineDimExpr>(lhs).getPosition();
1167 rhsPos = cast<AffineSymbolExpr>(rhs).getPosition();
1168 std::pair<unsigned, signed> indexEntry(lhsPos, rhsPos);
1169 addEntry(indexEntry, flatExprs[numDims + numSymbols + it.index()], expr);
1175 lhsPos = cast<AffineSymbolExpr>(lhs).getPosition();
1176 rhsPos = cast<AffineSymbolExpr>(rhs).getPosition();
1177 std::pair<unsigned, signed> indexEntry(
1178 lhsPos,
std::max(numDims, numSymbols) + offsetSym++);
1179 addEntry(indexEntry, flatExprs[numDims + numSymbols + it.index()], expr);
1181 addedToMap[it.index()] =
true;
1184 for (
unsigned j = 0;
j < numDims; ++
j) {
1185 if (flatExprs[
j] == 0)
1191 std::pair<unsigned, signed> indexEntry(
j, offsetDim--);
1198 llvm::sort(indices);
1199 for (
const std::pair<unsigned, unsigned> index : indices) {
1200 assert(indexToExprMap.lookup(index) &&
1201 "cannot find key in `indexToExprMap` map");
1202 expr = expr + indexToExprMap.lookup(index) * coefficients.lookup(index);
1206 for (
unsigned j = numDims + numSymbols, e = flatExprs.size() - 1;
j < e;
1210 if (flatExprs[
j] == 0 || addedToMap[
j - numDims - numSymbols])
1212 auto term = localExprs[
j - numDims - numSymbols] * flatExprs[
j];
1217 int64_t constTerm = flatExprs.back();
1219 expr = expr + constTerm;
1224 unsigned numSymbols)
1225 : numDims(numDims), numSymbols(numSymbols), numLocals(0) {
1243 if (!isa<AffineConstantExpr>(expr.
getRHS())) {
1249 addLocalVariableSemiAffine(a * b, lhs, lhs.size());
1254 int64_t rhsConst = rhs[getConstantIndex()];
1255 for (int64_t &lhsElt : lhs)
1265 assert(lhs.size() == rhs.size());
1267 for (
unsigned i = 0, e = rhs.size(); i < e; i++) {
1296 if (!isa<AffineConstantExpr>(expr.
getRHS())) {
1301 AffineExpr modExpr = dividendExpr % divisorExpr;
1302 addLocalVariableSemiAffine(modExpr, lhs, lhs.size());
1306 int64_t rhsConst = rhs[getConstantIndex()];
1312 for (i = 0, e = lhs.size(); i < e; i++)
1313 if (lhs[i] % rhsConst != 0)
1316 if (i == lhs.size()) {
1317 std::fill(lhs.begin(), lhs.end(), 0);
1325 uint64_t
gcd = rhsConst;
1326 for (int64_t lhsElt : lhs)
1330 for (int64_t &floorDividendElt : floorDividend)
1331 floorDividendElt = floorDividendElt /
static_cast<int64_t
>(
gcd);
1333 int64_t floorDivisor = rhsConst /
static_cast<int64_t
>(
gcd);
1342 if ((loc = findLocalId(floorDivExpr)) == -1) {
1345 lhs[getLocalVarStartIndex() +
numLocals - 1] = -rhsConst;
1348 lhs[getLocalVarStartIndex() + loc] = -rhsConst;
1355 return visitDivExpr(expr,
true);
1359 return visitDivExpr(expr,
false);
1375 eq[getSymbolStartIndex() + expr.
getPosition()] = 1;
1383 eq[getConstantIndex()] = expr.
getValue();
1387 void SimpleAffineExprFlattener::addLocalVariableSemiAffine(
1389 unsigned long resultSize) {
1390 assert(result.size() == resultSize &&
1391 "`result` vector passed is not of correct size");
1393 if ((loc = findLocalId(expr)) == -1)
1395 std::fill(result.begin(), result.end(), 0);
1397 result[getLocalVarStartIndex() +
numLocals - 1] = 1;
1399 result[getLocalVarStartIndex() + loc] = 1;
1427 if (!isa<AffineConstantExpr>(expr.
getRHS())) {
1433 addLocalVariableSemiAffine(divExpr, lhs, lhs.size());
1438 int64_t rhsConst = rhs[getConstantIndex()];
1445 for (int64_t lhsElt : lhs)
1449 for (int64_t &lhsElt : lhs)
1450 lhsElt = lhsElt /
static_cast<int64_t
>(
gcd);
1452 int64_t divisor = rhsConst /
static_cast<int64_t
>(
gcd);
1468 if ((loc = findLocalId(divExpr)) == -1) {
1475 dividend.back() += divisor - 1;
1481 std::fill(lhs.begin(), lhs.end(), 0);
1483 lhs[getLocalVarStartIndex() +
numLocals - 1] = 1;
1485 lhs[getLocalVarStartIndex() + loc] = 1;
1497 assert(divisor > 0 &&
"positive constant divisor expected");
1499 subExpr.insert(subExpr.begin() + getLocalVarStartIndex() +
numLocals, 0);
1507 subExpr.insert(subExpr.begin() + getLocalVarStartIndex() +
numLocals, 0);
1512 int SimpleAffineExprFlattener::findLocalId(
AffineExpr localExpr) {
1521 unsigned numSymbols) {
1546 return simplifiedExpr;
1550 AffineExpr expr,
unsigned numDims,
unsigned numSymbols,
1551 ArrayRef<std::optional<int64_t>> constLowerBounds,
1552 ArrayRef<std::optional<int64_t>> constUpperBounds,
bool isUpper) {
1554 if (
auto binOpExpr = dyn_cast<AffineBinaryOpExpr>(expr)) {
1558 auto rhsConst = dyn_cast<AffineConstantExpr>(binOpExpr.getRHS());
1559 if (!rhsConst || rhsConst.getValue() < 1)
1560 return std::nullopt;
1563 constLowerBounds, constUpperBounds, isUpper);
1565 return std::nullopt;
1569 auto rhsConst = dyn_cast<AffineConstantExpr>(binOpExpr.getRHS());
1570 if (rhsConst && rhsConst.getValue() >= 1) {
1573 constLowerBounds, constUpperBounds, isUpper);
1575 return std::nullopt;
1578 return std::nullopt;
1584 auto rhsConst = dyn_cast<AffineConstantExpr>(binOpExpr.getRHS());
1585 if (rhsConst && rhsConst.getValue() >= 1) {
1586 int64_t rhsConstVal = rhsConst.getValue();
1588 constLowerBounds, constUpperBounds,
1592 constLowerBounds, constUpperBounds, isUpper);
1595 return isUpper ?
mod(*ub, rhsConstVal) :
mod(*lb, rhsConstVal);
1596 return isUpper ? rhsConstVal - 1 : 0;
1604 if (
failed(simpleResult))
1605 return std::nullopt;
1610 return std::nullopt;
1614 for (
unsigned i = 0, e = numDims + numSymbols; i < e; ++i) {
1615 if (flattenedExpr[i] > 0) {
1616 auto &constBound = isUpper ? constUpperBounds[i] : constLowerBounds[i];
1618 return std::nullopt;
1619 bound += *constBound * flattenedExpr[i];
1620 }
else if (flattenedExpr[i] < 0) {
1621 auto &constBound = isUpper ? constLowerBounds[i] : constUpperBounds[i];
1623 return std::nullopt;
1624 bound += *constBound * flattenedExpr[i];
1628 bound += flattenedExpr.back();
static AffineExpr symbolicDivide(AffineExpr expr, unsigned symbolPos, AffineExprKind opKind)
Divides the given expression by the given symbol at position symbolPos.
static AffineExpr simplifyMul(AffineExpr lhs, AffineExpr rhs)
Simplify a multiply expression. Return nullptr if it can't be simplified.
static AffineExpr simplifyMod(AffineExpr lhs, AffineExpr rhs)
static AffineExpr simplifyAdd(AffineExpr lhs, AffineExpr rhs)
Simplify add expression. Return nullptr if it can't be simplified.
static AffineExpr getSemiAffineExprFromFlatForm(ArrayRef< int64_t > flatExprs, unsigned numDims, unsigned numSymbols, ArrayRef< AffineExpr > localExprs, MLIRContext *context)
Constructs a semi-affine expression from a flat ArrayRef.
static AffineExpr simplifyCeilDiv(AffineExpr lhs, AffineExpr rhs)
static AffineExpr simplifyFloorDiv(AffineExpr lhs, AffineExpr rhs)
static bool isNegatedAffineExpr(AffineExpr candidate, AffineExpr &expr)
Return "true" if candidate is a negated expression, i.e., Mul(-1, expr).
static AffineExpr getAffineDimOrSymbol(AffineExprKind kind, unsigned position, MLIRContext *context)
static bool isModOfModSubtraction(AffineExpr lhs, AffineExpr rhs, unsigned numDims, unsigned numSymbols)
Return "true" if lhs % rhs is guaranteed to evaluate to zero based on the fact that lhs contains anot...
static void getSummandExprs(AffineExpr expr, SmallVector< AffineExpr > &result)
Populate result with all summand operands of given (potentially nested) addition.
static bool isDivisibleBySymbol(AffineExpr expr, unsigned symbolPos, AffineExprKind opKind)
Returns true if the expression is divisible by the given symbol with position symbolPos.
static AffineExpr simplifySemiAffine(AffineExpr expr, unsigned numDims, unsigned numSymbols)
Simplify a semi-affine expression by handling modulo, floordiv, or ceildiv operations when the second...
static MLIRContext * getContext(OpFoldResult val)
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
Affine binary operation expression.
AffineExpr getLHS() const
AffineBinaryOpExpr(AffineExpr::ImplType *ptr)
AffineExpr getRHS() const
An integer constant appearing in affine expression.
AffineConstantExpr(AffineExpr::ImplType *ptr=nullptr)
A dimensional identifier appearing in an affine expression.
AffineDimExpr(AffineExpr::ImplType *ptr)
unsigned getPosition() const
See documentation for AffineExprVisitorBase.
RetTy walkPostOrder(AffineExpr expr)
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.
AffineExpr shiftDims(unsigned numDims, unsigned shift, unsigned offset=0) const
Replace dims[offset ...
AffineExpr operator+(int64_t v) const
bool isSymbolicOrConstant() const
Returns true if this expression is made out of only symbols and constants, i.e., it does not involve ...
AffineExpr operator*(int64_t v) const
bool operator==(AffineExpr other) const
bool isPureAffine() const
Returns true if this is a pure affine expression, i.e., multiplication, floordiv, ceildiv,...
AffineExpr shiftSymbols(unsigned numSymbols, unsigned shift, unsigned offset=0) const
Replace symbols[offset ...
AffineExpr operator-() const
AffineExpr floorDiv(uint64_t v) const
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.
bool isMultipleOf(int64_t factor) const
Return true if the affine expression is a multiple of 'factor'.
int64_t getLargestKnownDivisor() const
Returns the greatest known integral divisor of this affine expression.
AffineExpr compose(AffineMap map) const
Compose with an AffineMap.
bool isFunctionOfDim(unsigned position) const
Return true if the affine expression involves AffineDimExpr position.
bool isFunctionOfSymbol(unsigned position) const
Return true if the affine expression involves AffineSymbolExpr position.
AffineExpr replaceDims(ArrayRef< AffineExpr > dimReplacements) const
Dim-only version of replaceDimsAndSymbols.
AffineExpr operator%(uint64_t v) const
MLIRContext * getContext() const
AffineExpr replace(AffineExpr expr, AffineExpr replacement) const
Sparse replace method.
AffineExpr replaceSymbols(ArrayRef< AffineExpr > symReplacements) const
Symbol-only version of replaceDimsAndSymbols.
AffineExpr ceilDiv(uint64_t v) const
void print(raw_ostream &os) const
A multi-dimensional affine map Affine map's are immutable like Type's, and they are uniqued.
ArrayRef< AffineExpr > getResults() const
A symbolic identifier appearing in an affine expression.
AffineSymbolExpr(AffineExpr::ImplType *ptr)
unsigned getPosition() const
MLIRContext is the top-level object for a collection of MLIR operations.
StorageUniquer & getAffineUniquer()
Returns the storage uniquer used for creating affine constructs.
virtual void addLocalFloorDivId(ArrayRef< int64_t > dividend, int64_t divisor, AffineExpr localExpr)
LogicalResult visitSymbolExpr(AffineSymbolExpr expr)
std::vector< SmallVector< int64_t, 8 > > operandExprStack
LogicalResult visitDimExpr(AffineDimExpr expr)
LogicalResult visitFloorDivExpr(AffineBinaryOpExpr expr)
LogicalResult visitConstantExpr(AffineConstantExpr expr)
LogicalResult visitModExpr(AffineBinaryOpExpr expr)
LogicalResult visitAddExpr(AffineBinaryOpExpr expr)
LogicalResult visitCeilDivExpr(AffineBinaryOpExpr expr)
LogicalResult visitMulExpr(AffineBinaryOpExpr expr)
virtual void addLocalIdSemiAffine(AffineExpr localExpr)
Add a local identifier (needed to flatten a mod, floordiv, ceildiv, mul expr) when the rhs is a symbo...
SmallVector< AffineExpr, 4 > localExprs
SimpleAffineExprFlattener(unsigned numDims, unsigned numSymbols)
A utility class to get or create instances of "storage classes".
Storage * get(function_ref< void(Storage *)> initFn, TypeID id, Args &&...args)
Gets a uniqued instance of 'Storage'.
A utility result that is used to signal how to proceed with an ongoing walk:
Detect if any of the given parameter types has a sub-element handler.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
LLVM_ATTRIBUTE_ALWAYS_INLINE MPInt gcd(const MPInt &a, const MPInt &b)
Fraction abs(const Fraction &f)
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
std::optional< int64_t > getBoundForAffineExpr(AffineExpr expr, unsigned numDims, unsigned numSymbols, ArrayRef< std::optional< int64_t >> constLowerBounds, ArrayRef< std::optional< int64_t >> constUpperBounds, bool isUpper)
Get a lower or upper (depending on isUpper) bound for expr while using the constant lower and upper b...
int64_t floorDiv(int64_t lhs, int64_t rhs)
Returns the result of MLIR's floordiv operation on constants.
int64_t ceilDiv(int64_t lhs, int64_t rhs)
Returns the result of MLIR's ceildiv operation on constants.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
@ 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.
AffineExpr getAffineBinaryOpExpr(AffineExprKind kind, AffineExpr lhs, AffineExpr rhs)
AffineExpr getAffineExprFromFlatForm(ArrayRef< int64_t > flatExprs, unsigned numDims, unsigned numSymbols, ArrayRef< AffineExpr > localExprs, MLIRContext *context)
Constructs an affine expression from a flat ArrayRef.
AffineExpr getAffineConstantExpr(int64_t constant, MLIRContext *context)
AffineExpr simplifyAffineExpr(AffineExpr expr, unsigned numDims, unsigned numSymbols)
Simplify an affine expression by flattening and some amount of simple analysis.
SmallVector< AffineExpr > getAffineConstantExprs(ArrayRef< int64_t > constants, MLIRContext *context)
AffineExpr getAffineDimExpr(unsigned position, MLIRContext *context)
These free functions allow clients of the API to not use classes in detail.
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
AffineExpr getAffineSymbolExpr(unsigned position, MLIRContext *context)
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
int64_t mod(int64_t lhs, int64_t rhs)
Returns MLIR's mod operation on constants.
This class represents an efficient way to signal success or failure.
A binary operation appearing in an affine expression.
An integer constant appearing in affine expression.
A dimensional or symbolic identifier appearing in an affine expression.
Base storage class appearing in an affine expression.
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.