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)
792 if (rhsConst.getValue() == 1)
795 if (rhsConst.getValue() == 0)
800 auto lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
802 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS()))
803 return lBin.getLHS() * (lrhs.getValue() * rhsConst.getValue());
809 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS())) {
810 return (lBin.getLHS() * rhs) * lrhs;
837 return *
this + (-other);
841 auto lhsConst = dyn_cast<AffineConstantExpr>(lhs);
842 auto rhsConst = dyn_cast<AffineConstantExpr>(rhs);
845 if (!rhsConst || rhsConst.getValue() < 1)
859 auto lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
861 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS())) {
863 if (lrhs.getValue() % rhsConst.getValue() == 0)
864 return lBin.getLHS() * (lrhs.getValue() / rhsConst.getValue());
871 int64_t llhsDiv = lBin.getLHS().getLargestKnownDivisor();
872 int64_t lrhsDiv = lBin.getRHS().getLargestKnownDivisor();
874 if (llhsDiv % rhsConst.getValue() == 0 ||
875 lrhsDiv % rhsConst.getValue() == 0)
876 return lBin.getLHS().floorDiv(rhsConst.getValue()) +
877 lBin.getRHS().floorDiv(rhsConst.getValue());
897 auto lhsConst = dyn_cast<AffineConstantExpr>(lhs);
898 auto rhsConst = dyn_cast<AffineConstantExpr>(rhs);
900 if (!rhsConst || rhsConst.getValue() < 1)
909 if (rhsConst.getValue() == 1)
914 auto lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
916 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS())) {
918 if (lrhs.getValue() % rhsConst.getValue() == 0)
919 return lBin.getLHS() * (lrhs.getValue() / rhsConst.getValue());
940 auto lhsConst = dyn_cast<AffineConstantExpr>(lhs);
941 auto rhsConst = dyn_cast<AffineConstantExpr>(rhs);
944 if (!rhsConst || rhsConst.getValue() < 1)
959 auto lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
961 int64_t llhsDiv = lBin.getLHS().getLargestKnownDivisor();
962 int64_t lrhsDiv = lBin.getRHS().getLargestKnownDivisor();
964 if (llhsDiv % rhsConst.getValue() == 0)
965 return lBin.getRHS() % rhsConst.getValue();
966 if (lrhsDiv % rhsConst.getValue() == 0)
967 return lBin.getLHS() % rhsConst.getValue();
972 auto intermediate = dyn_cast<AffineConstantExpr>(lBin.getRHS());
973 if (intermediate && intermediate.getValue() >= 1 &&
974 mod(intermediate.getValue(), rhsConst.getValue()) == 0) {
975 return lBin.getLHS() % rhsConst.getValue();
1011 unsigned numSymbols,
1015 assert(flatExprs.size() - numDims - numSymbols - 1 == localExprs.size() &&
1016 "unexpected number of local expressions");
1020 for (
unsigned j = 0;
j < numDims + numSymbols;
j++) {
1021 if (flatExprs[
j] == 0)
1025 expr = expr +
id * flatExprs[
j];
1029 for (
unsigned j = numDims + numSymbols, e = flatExprs.size() - 1;
j < e;
1031 if (flatExprs[
j] == 0)
1033 auto term = localExprs[
j - numDims - numSymbols] * flatExprs[
j];
1038 int64_t constTerm = flatExprs[flatExprs.size() - 1];
1040 expr = expr + constTerm;
1054 unsigned numSymbols,
1057 assert(!flatExprs.empty() &&
"flatExprs cannot be empty");
1060 assert(flatExprs.size() - numDims - numSymbols - 1 == localExprs.size() &&
1061 "unexpected number of local expressions");
1093 auto addEntry = [&](std::pair<unsigned, signed> index, int64_t coefficient,
1095 assert(!llvm::is_contained(indices, index) &&
1096 "Key is already present in indices vector and overwriting will "
1097 "happen in `indexToExprMap` and `coefficients`!");
1099 indices.push_back(index);
1100 coefficients.insert({index, coefficient});
1101 indexToExprMap.insert({index, expr});
1109 unsigned offsetSym = 0;
1110 signed offsetDim = -1;
1111 for (
unsigned j = numDims;
j < numDims + numSymbols; ++
j) {
1112 if (flatExprs[
j] == 0)
1118 std::pair<unsigned, signed> indexEntry(
1119 j - numDims,
std::max(numDims, numSymbols) + offsetSym++);
1120 addEntry(indexEntry, flatExprs[
j],
1128 unsigned lhsPos, rhsPos;
1135 if (flatExprs[numDims + numSymbols + it.index()] == 0)
1137 AffineExpr lhs = cast<AffineBinaryOpExpr>(expr).getLHS();
1138 AffineExpr rhs = cast<AffineBinaryOpExpr>(expr).getRHS();
1139 if (!((isa<AffineDimExpr>(lhs) || isa<AffineSymbolExpr>(lhs)) &&
1140 (isa<AffineDimExpr>(rhs) || isa<AffineSymbolExpr>(rhs) ||
1141 isa<AffineConstantExpr>(rhs)))) {
1144 if (isa<AffineConstantExpr>(rhs)) {
1149 if (isa<AffineDimExpr>(lhs)) {
1150 lhsPos = cast<AffineDimExpr>(lhs).getPosition();
1151 std::pair<unsigned, signed> indexEntry(lhsPos, offsetDim--);
1152 addEntry(indexEntry, flatExprs[numDims + numSymbols + it.index()],
1155 lhsPos = cast<AffineSymbolExpr>(lhs).getPosition();
1156 std::pair<unsigned, signed> indexEntry(
1157 lhsPos,
std::max(numDims, numSymbols) + offsetSym++);
1158 addEntry(indexEntry, flatExprs[numDims + numSymbols + it.index()],
1161 }
else if (isa<AffineDimExpr>(lhs)) {
1167 lhsPos = cast<AffineDimExpr>(lhs).getPosition();
1168 rhsPos = cast<AffineSymbolExpr>(rhs).getPosition();
1169 std::pair<unsigned, signed> indexEntry(lhsPos, rhsPos);
1170 addEntry(indexEntry, flatExprs[numDims + numSymbols + it.index()], expr);
1176 lhsPos = cast<AffineSymbolExpr>(lhs).getPosition();
1177 rhsPos = cast<AffineSymbolExpr>(rhs).getPosition();
1178 std::pair<unsigned, signed> indexEntry(
1179 lhsPos,
std::max(numDims, numSymbols) + offsetSym++);
1180 addEntry(indexEntry, flatExprs[numDims + numSymbols + it.index()], expr);
1182 addedToMap[it.index()] =
true;
1185 for (
unsigned j = 0;
j < numDims; ++
j) {
1186 if (flatExprs[
j] == 0)
1192 std::pair<unsigned, signed> indexEntry(
j, offsetDim--);
1199 llvm::sort(indices);
1200 for (
const std::pair<unsigned, unsigned> index : indices) {
1201 assert(indexToExprMap.lookup(index) &&
1202 "cannot find key in `indexToExprMap` map");
1203 expr = expr + indexToExprMap.lookup(index) * coefficients.lookup(index);
1207 for (
unsigned j = numDims + numSymbols, e = flatExprs.size() - 1;
j < e;
1211 if (flatExprs[
j] == 0 || addedToMap[
j - numDims - numSymbols])
1213 auto term = localExprs[
j - numDims - numSymbols] * flatExprs[
j];
1218 int64_t constTerm = flatExprs.back();
1220 expr = expr + constTerm;
1225 unsigned numSymbols)
1226 : numDims(numDims), numSymbols(numSymbols), numLocals(0) {
1244 if (!isa<AffineConstantExpr>(expr.
getRHS())) {
1250 addLocalVariableSemiAffine(a * b, lhs, lhs.size());
1255 int64_t rhsConst = rhs[getConstantIndex()];
1256 for (int64_t &lhsElt : lhs)
1266 assert(lhs.size() == rhs.size());
1268 for (
unsigned i = 0, e = rhs.size(); i < e; i++) {
1297 if (!isa<AffineConstantExpr>(expr.
getRHS())) {
1302 AffineExpr modExpr = dividendExpr % divisorExpr;
1303 addLocalVariableSemiAffine(modExpr, lhs, lhs.size());
1307 int64_t rhsConst = rhs[getConstantIndex()];
1313 for (i = 0, e = lhs.size(); i < e; i++)
1314 if (lhs[i] % rhsConst != 0)
1317 if (i == lhs.size()) {
1318 std::fill(lhs.begin(), lhs.end(), 0);
1326 uint64_t
gcd = rhsConst;
1327 for (int64_t lhsElt : lhs)
1331 for (int64_t &floorDividendElt : floorDividend)
1332 floorDividendElt = floorDividendElt /
static_cast<int64_t
>(
gcd);
1334 int64_t floorDivisor = rhsConst /
static_cast<int64_t
>(
gcd);
1343 if ((loc = findLocalId(floorDivExpr)) == -1) {
1346 lhs[getLocalVarStartIndex() +
numLocals - 1] = -rhsConst;
1349 lhs[getLocalVarStartIndex() + loc] = -rhsConst;
1356 return visitDivExpr(expr,
true);
1360 return visitDivExpr(expr,
false);
1376 eq[getSymbolStartIndex() + expr.
getPosition()] = 1;
1384 eq[getConstantIndex()] = expr.
getValue();
1388 void SimpleAffineExprFlattener::addLocalVariableSemiAffine(
1390 unsigned long resultSize) {
1391 assert(result.size() == resultSize &&
1392 "`result` vector passed is not of correct size");
1394 if ((loc = findLocalId(expr)) == -1)
1396 std::fill(result.begin(), result.end(), 0);
1398 result[getLocalVarStartIndex() +
numLocals - 1] = 1;
1400 result[getLocalVarStartIndex() + loc] = 1;
1428 if (!isa<AffineConstantExpr>(expr.
getRHS())) {
1434 addLocalVariableSemiAffine(divExpr, lhs, lhs.size());
1439 int64_t rhsConst = rhs[getConstantIndex()];
1446 for (int64_t lhsElt : lhs)
1450 for (int64_t &lhsElt : lhs)
1451 lhsElt = lhsElt /
static_cast<int64_t
>(
gcd);
1453 int64_t divisor = rhsConst /
static_cast<int64_t
>(
gcd);
1469 if ((loc = findLocalId(divExpr)) == -1) {
1476 dividend.back() += divisor - 1;
1482 std::fill(lhs.begin(), lhs.end(), 0);
1484 lhs[getLocalVarStartIndex() +
numLocals - 1] = 1;
1486 lhs[getLocalVarStartIndex() + loc] = 1;
1498 assert(divisor > 0 &&
"positive constant divisor expected");
1500 subExpr.insert(subExpr.begin() + getLocalVarStartIndex() +
numLocals, 0);
1508 subExpr.insert(subExpr.begin() + getLocalVarStartIndex() +
numLocals, 0);
1513 int SimpleAffineExprFlattener::findLocalId(
AffineExpr localExpr) {
1522 unsigned numSymbols) {
1547 return simplifiedExpr;
1551 AffineExpr expr,
unsigned numDims,
unsigned numSymbols,
1552 ArrayRef<std::optional<int64_t>> constLowerBounds,
1553 ArrayRef<std::optional<int64_t>> constUpperBounds,
bool isUpper) {
1555 if (
auto binOpExpr = dyn_cast<AffineBinaryOpExpr>(expr)) {
1559 auto rhsConst = dyn_cast<AffineConstantExpr>(binOpExpr.getRHS());
1560 if (!rhsConst || rhsConst.getValue() < 1)
1561 return std::nullopt;
1564 constLowerBounds, constUpperBounds, isUpper);
1566 return std::nullopt;
1570 auto rhsConst = dyn_cast<AffineConstantExpr>(binOpExpr.getRHS());
1571 if (rhsConst && rhsConst.getValue() >= 1) {
1574 constLowerBounds, constUpperBounds, isUpper);
1576 return std::nullopt;
1579 return std::nullopt;
1585 auto rhsConst = dyn_cast<AffineConstantExpr>(binOpExpr.getRHS());
1586 if (rhsConst && rhsConst.getValue() >= 1) {
1587 int64_t rhsConstVal = rhsConst.getValue();
1589 constLowerBounds, constUpperBounds,
1593 constLowerBounds, constUpperBounds, isUpper);
1596 return isUpper ?
mod(*ub, rhsConstVal) :
mod(*lb, rhsConstVal);
1597 return isUpper ? rhsConstVal - 1 : 0;
1605 if (
failed(simpleResult))
1606 return std::nullopt;
1611 return std::nullopt;
1615 for (
unsigned i = 0, e = numDims + numSymbols; i < e; ++i) {
1616 if (flattenedExpr[i] > 0) {
1617 auto &constBound = isUpper ? constUpperBounds[i] : constLowerBounds[i];
1619 return std::nullopt;
1620 bound += *constBound * flattenedExpr[i];
1621 }
else if (flattenedExpr[i] < 0) {
1622 auto &constBound = isUpper ? constLowerBounds[i] : constUpperBounds[i];
1624 return std::nullopt;
1625 bound += *constBound * flattenedExpr[i];
1629 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.