20 #include "llvm/ADT/STLExtras.h"
21 #include "llvm/Support/MathExtras.h"
28 using llvm::divideCeilSigned;
29 using llvm::divideFloorSigned;
30 using llvm::divideSignedWouldOverflow;
40 template <
typename WalkRetTy>
43 struct AffineExprWalker
48 : callback(callback) {}
51 return callback(expr);
54 return callback(expr);
56 WalkRetTy visitDimExpr(
AffineDimExpr expr) {
return callback(expr); }
60 return AffineExprWalker(callback).walkPostOrder(e);
83 llvm_unreachable(
"unknown binary operation on affine expressions");
95 unsigned dimId = llvm::cast<AffineDimExpr>(*this).getPosition();
96 if (dimId >= dimReplacements.size())
98 return dimReplacements[dimId];
101 unsigned symId = llvm::cast<AffineSymbolExpr>(*this).getPosition();
102 if (symId >= symReplacements.size())
104 return symReplacements[symId];
111 auto binOp = llvm::cast<AffineBinaryOpExpr>(*
this);
112 auto lhs = binOp.getLHS(), rhs = binOp.getRHS();
113 auto newLHS = lhs.replaceDimsAndSymbols(dimReplacements, symReplacements);
114 auto newRHS = rhs.replaceDimsAndSymbols(dimReplacements, symReplacements);
115 if (newLHS == lhs && newRHS == rhs)
119 llvm_unreachable(
"Unknown AffineExpr");
123 return replaceDimsAndSymbols(dimReplacements, {});
128 return replaceDimsAndSymbols({}, symReplacements);
134 unsigned offset)
const {
136 for (
unsigned idx = 0; idx < offset; ++idx)
138 for (
unsigned idx = offset; idx < numDims; ++idx)
140 return replaceDimsAndSymbols(dims, {});
146 unsigned offset)
const {
148 for (
unsigned idx = 0; idx < offset; ++idx)
150 for (
unsigned idx = offset; idx < numSymbols; ++idx)
152 return replaceDimsAndSymbols({}, symbols);
158 auto it = map.find(*
this);
169 auto binOp = llvm::cast<AffineBinaryOpExpr>(*
this);
170 auto lhs = binOp.getLHS(), rhs = binOp.getRHS();
171 auto newLHS = lhs.replace(map);
172 auto newRHS = rhs.replace(map);
173 if (newLHS == lhs && newRHS == rhs)
177 llvm_unreachable(
"Unknown AffineExpr");
183 map.insert(std::make_pair(expr, replacement));
202 auto expr = llvm::cast<AffineBinaryOpExpr>(*
this);
203 return expr.getLHS().isSymbolicOrConstant() &&
204 expr.getRHS().isSymbolicOrConstant();
207 llvm_unreachable(
"Unknown AffineExpr");
219 auto op = llvm::cast<AffineBinaryOpExpr>(*
this);
220 return op.getLHS().isPureAffine() && op.getRHS().isPureAffine();
226 auto op = llvm::cast<AffineBinaryOpExpr>(*
this);
227 return op.getLHS().isPureAffine() && op.getRHS().isPureAffine() &&
228 (llvm::isa<AffineConstantExpr>(op.getLHS()) ||
229 llvm::isa<AffineConstantExpr>(op.getRHS()));
234 auto op = llvm::cast<AffineBinaryOpExpr>(*
this);
235 return op.getLHS().isPureAffine() &&
236 llvm::isa<AffineConstantExpr>(op.getRHS());
239 llvm_unreachable(
"Unknown AffineExpr");
255 binExpr = llvm::cast<AffineBinaryOpExpr>(*
this);
256 auto rhs = llvm::dyn_cast<AffineConstantExpr>(binExpr.
getRHS());
258 if (rhs && rhs.getValue() != 0) {
260 if (lhsDiv % rhs.getValue() == 0)
261 return std::abs(lhsDiv / rhs.getValue());
266 return std::abs(llvm::cast<AffineConstantExpr>(*this).getValue());
268 binExpr = llvm::cast<AffineBinaryOpExpr>(*
this);
275 binExpr = llvm::cast<AffineBinaryOpExpr>(*
this);
280 llvm_unreachable(
"Unknown AffineExpr");
290 return factor * factor == 1;
292 return llvm::cast<AffineConstantExpr>(*this).getValue() % factor == 0;
294 binExpr = llvm::cast<AffineBinaryOpExpr>(*
this);
300 (l * u) % factor == 0;
306 binExpr = llvm::cast<AffineBinaryOpExpr>(*
this);
313 llvm_unreachable(
"Unknown AffineExpr");
320 if (
auto expr = llvm::dyn_cast<AffineBinaryOpExpr>(*
this)) {
321 return expr.getLHS().isFunctionOfDim(position) ||
322 expr.getRHS().isFunctionOfDim(position);
331 if (
auto expr = llvm::dyn_cast<AffineBinaryOpExpr>(*
this)) {
332 return expr.getLHS().isFunctionOfSymbol(position) ||
333 expr.getRHS().isFunctionOfSymbol(position);
361 bool fromMul =
false) {
365 "unexpected opKind");
368 return cast<AffineConstantExpr>(expr).getValue() == 0;
372 return (cast<AffineSymbolExpr>(expr).getPosition() == symbolPos);
421 llvm_unreachable(
"Unknown AffineExpr");
432 "unexpected opKind");
435 if (cast<AffineConstantExpr>(expr).getValue() != 0)
461 return binaryExpr.
getLHS() *
476 llvm_unreachable(
"Unknown AffineExpr");
484 auto addExpr = dyn_cast<AffineBinaryOpExpr>(expr);
486 result.push_back(expr);
496 auto mulExpr = dyn_cast<AffineBinaryOpExpr>(candidate);
499 if (
auto lhs = dyn_cast<AffineConstantExpr>(mulExpr.getLHS())) {
500 if (lhs.getValue() == -1) {
501 expr = mulExpr.getRHS();
505 if (
auto rhs = dyn_cast<AffineConstantExpr>(mulExpr.getRHS())) {
506 if (rhs.getValue() == -1) {
507 expr = mulExpr.getLHS();
523 unsigned numDims,
unsigned numSymbols) {
530 for (int64_t i = 0, e = summands.size(); i < e; ++i) {
538 if (innerMod.
getRHS() != rhs)
543 for (int64_t
j = 0;
j < e; ++
j)
545 diff = diff + summands[
j];
546 diff = diff - innerMod.
getLHS();
548 auto constExpr = dyn_cast<AffineConstantExpr>(diff);
549 if (constExpr && constExpr.getValue() == 0)
561 unsigned numSymbols) {
602 return simplifiedQuotient
607 llvm_unreachable(
"Unknown AffineExpr");
613 storage->context = context;
618 assignCtx,
static_cast<unsigned>(
kind), position);
647 storage->context = context;
657 return llvm::to_vector(llvm::map_range(constants, [&](int64_t constant) {
664 auto lhsConst = dyn_cast<AffineConstantExpr>(lhs);
665 auto rhsConst = dyn_cast<AffineConstantExpr>(rhs);
667 if (lhsConst && rhsConst) {
669 if (llvm::AddOverflow(lhsConst.getValue(), rhsConst.getValue(), sum)) {
677 if (isa<AffineConstantExpr>(lhs) ||
686 if (rhsConst.getValue() == 0)
690 auto lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
692 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS()))
693 return lBin.getLHS() + (lrhs.getValue() + rhsConst.getValue());
699 std::optional<int64_t> rLhsConst, rRhsConst;
702 auto lBinOpExpr = dyn_cast<AffineBinaryOpExpr>(lhs);
704 (rLhsConstExpr = dyn_cast<AffineConstantExpr>(lBinOpExpr.getRHS()))) {
705 rLhsConst = rLhsConstExpr.
getValue();
706 firstExpr = lBinOpExpr.getLHS();
712 auto rBinOpExpr = dyn_cast<AffineBinaryOpExpr>(rhs);
715 (rRhsConstExpr = dyn_cast<AffineConstantExpr>(rBinOpExpr.getRHS()))) {
716 rRhsConst = rRhsConstExpr.
getValue();
717 secondExpr = rBinOpExpr.getLHS();
723 if (rLhsConst && rRhsConst && firstExpr == secondExpr)
731 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS())) {
732 return lBin.getLHS() + rhs + lrhs;
745 auto lrhs = rBinOpExpr.getLHS();
746 auto rrhs = rBinOpExpr.getRHS();
752 auto lrhsBinOpExpr = dyn_cast<AffineBinaryOpExpr>(lrhs);
754 auto rrhsConstOpExpr = dyn_cast<AffineConstantExpr>(rrhs);
755 if (rrhsConstOpExpr && rrhsConstOpExpr.getValue() == -1 && lrhsBinOpExpr &&
758 llrhs = lrhsBinOpExpr.getLHS();
760 rlrhs = lrhsBinOpExpr.getRHS();
761 auto llrhsBinOpExpr = dyn_cast<AffineBinaryOpExpr>(llrhs);
764 if (llrhsBinOpExpr.getRHS() == rlrhs && lhs == llrhsBinOpExpr.getLHS())
775 llrhs = lrBinOpExpr.
getLHS();
776 rlrhs = lrBinOpExpr.
getRHS();
777 auto rlrhsConstOpExpr = dyn_cast<AffineConstantExpr>(rlrhs);
779 bool isPositiveRhs = rlrhsConstOpExpr && rlrhsConstOpExpr.getValue() > 0;
781 if (isPositiveRhs && lhs == llrhs && rlrhs == -rrhs) {
801 auto lhsConst = dyn_cast<AffineConstantExpr>(lhs);
802 auto rhsConst = dyn_cast<AffineConstantExpr>(rhs);
804 if (lhsConst && rhsConst) {
806 if (llvm::MulOverflow(lhsConst.getValue(), rhsConst.getValue(),
product)) {
827 if (rhsConst.getValue() == 1)
830 if (rhsConst.getValue() == 0)
835 auto lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
837 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS()))
838 return lBin.getLHS() * (lrhs.getValue() * rhsConst.getValue());
844 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS())) {
845 return (lBin.getLHS() * rhs) * lrhs;
872 return *
this + (-other);
876 auto lhsConst = dyn_cast<AffineConstantExpr>(lhs);
877 auto rhsConst = dyn_cast<AffineConstantExpr>(rhs);
879 if (!rhsConst || rhsConst.getValue() == 0)
883 if (divideSignedWouldOverflow(lhsConst.getValue(), rhsConst.getValue()))
886 divideFloorSigned(lhsConst.getValue(), rhsConst.getValue()),
897 auto lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
899 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS())) {
901 if (lrhs.getValue() % rhsConst.getValue() == 0)
902 return lBin.getLHS() * (lrhs.getValue() / rhsConst.getValue());
909 int64_t llhsDiv = lBin.getLHS().getLargestKnownDivisor();
910 int64_t lrhsDiv = lBin.getRHS().getLargestKnownDivisor();
912 if (llhsDiv % rhsConst.getValue() == 0 ||
913 lrhsDiv % rhsConst.getValue() == 0)
914 return lBin.getLHS().floorDiv(rhsConst.getValue()) +
915 lBin.getRHS().floorDiv(rhsConst.getValue());
935 auto lhsConst = dyn_cast<AffineConstantExpr>(lhs);
936 auto rhsConst = dyn_cast<AffineConstantExpr>(rhs);
938 if (!rhsConst || rhsConst.getValue() == 0)
942 if (divideSignedWouldOverflow(lhsConst.getValue(), rhsConst.getValue()))
945 divideCeilSigned(lhsConst.getValue(), rhsConst.getValue()),
951 if (rhsConst.getValue() == 1)
956 auto lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
958 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS())) {
960 if (lrhs.getValue() % rhsConst.getValue() == 0)
961 return lBin.getLHS() * (lrhs.getValue() / rhsConst.getValue());
982 auto lhsConst = dyn_cast<AffineConstantExpr>(lhs);
983 auto rhsConst = dyn_cast<AffineConstantExpr>(rhs);
986 if (!rhsConst || rhsConst.getValue() < 1)
1003 auto lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
1005 int64_t llhsDiv = lBin.getLHS().getLargestKnownDivisor();
1006 int64_t lrhsDiv = lBin.getRHS().getLargestKnownDivisor();
1008 if (llhsDiv % rhsConst.getValue() == 0)
1009 return lBin.getRHS() % rhsConst.getValue();
1010 if (lrhsDiv % rhsConst.getValue() == 0)
1011 return lBin.getLHS() % rhsConst.getValue();
1016 auto intermediate = dyn_cast<AffineConstantExpr>(lBin.getRHS());
1017 if (intermediate && intermediate.getValue() >= 1 &&
1018 mod(intermediate.getValue(), rhsConst.getValue()) == 0) {
1019 return lBin.getLHS() % rhsConst.getValue();
1054 unsigned numSymbols,
1058 assert(flatExprs.size() - numDims - numSymbols - 1 == localExprs.size() &&
1059 "unexpected number of local expressions");
1063 for (
unsigned j = 0;
j < numDims + numSymbols;
j++) {
1064 if (flatExprs[
j] == 0)
1068 expr = expr +
id * flatExprs[
j];
1072 for (
unsigned j = numDims + numSymbols, e = flatExprs.size() - 1;
j < e;
1074 if (flatExprs[
j] == 0)
1076 auto term = localExprs[
j - numDims - numSymbols] * flatExprs[
j];
1081 int64_t constTerm = flatExprs[flatExprs.size() - 1];
1083 expr = expr + constTerm;
1097 unsigned numSymbols,
1100 assert(!flatExprs.empty() &&
"flatExprs cannot be empty");
1103 assert(flatExprs.size() - numDims - numSymbols - 1 == localExprs.size() &&
1104 "unexpected number of local expressions");
1136 auto addEntry = [&](std::pair<unsigned, signed> index, int64_t coefficient,
1138 assert(!llvm::is_contained(indices, index) &&
1139 "Key is already present in indices vector and overwriting will "
1140 "happen in `indexToExprMap` and `coefficients`!");
1142 indices.push_back(index);
1143 coefficients.insert({index, coefficient});
1144 indexToExprMap.insert({index, expr});
1152 unsigned offsetSym = 0;
1153 signed offsetDim = -1;
1154 for (
unsigned j = numDims;
j < numDims + numSymbols; ++
j) {
1155 if (flatExprs[
j] == 0)
1161 std::pair<unsigned, signed> indexEntry(
1162 j - numDims,
std::max(numDims, numSymbols) + offsetSym++);
1163 addEntry(indexEntry, flatExprs[
j],
1171 unsigned lhsPos, rhsPos;
1178 if (flatExprs[numDims + numSymbols + it.index()] == 0)
1180 AffineExpr lhs = cast<AffineBinaryOpExpr>(expr).getLHS();
1181 AffineExpr rhs = cast<AffineBinaryOpExpr>(expr).getRHS();
1182 if (!((isa<AffineDimExpr>(lhs) || isa<AffineSymbolExpr>(lhs)) &&
1183 (isa<AffineDimExpr>(rhs) || isa<AffineSymbolExpr>(rhs) ||
1184 isa<AffineConstantExpr>(rhs)))) {
1187 if (isa<AffineConstantExpr>(rhs)) {
1192 if (isa<AffineDimExpr>(lhs)) {
1193 lhsPos = cast<AffineDimExpr>(lhs).getPosition();
1194 std::pair<unsigned, signed> indexEntry(lhsPos, offsetDim--);
1195 addEntry(indexEntry, flatExprs[numDims + numSymbols + it.index()],
1198 lhsPos = cast<AffineSymbolExpr>(lhs).getPosition();
1199 std::pair<unsigned, signed> indexEntry(
1200 lhsPos,
std::max(numDims, numSymbols) + offsetSym++);
1201 addEntry(indexEntry, flatExprs[numDims + numSymbols + it.index()],
1204 }
else if (isa<AffineDimExpr>(lhs)) {
1210 lhsPos = cast<AffineDimExpr>(lhs).getPosition();
1211 rhsPos = cast<AffineSymbolExpr>(rhs).getPosition();
1212 std::pair<unsigned, signed> indexEntry(lhsPos, rhsPos);
1213 addEntry(indexEntry, flatExprs[numDims + numSymbols + it.index()], expr);
1219 lhsPos = cast<AffineSymbolExpr>(lhs).getPosition();
1220 rhsPos = cast<AffineSymbolExpr>(rhs).getPosition();
1221 std::pair<unsigned, signed> indexEntry(
1222 lhsPos,
std::max(numDims, numSymbols) + offsetSym++);
1223 addEntry(indexEntry, flatExprs[numDims + numSymbols + it.index()], expr);
1225 addedToMap[it.index()] =
true;
1228 for (
unsigned j = 0;
j < numDims; ++
j) {
1229 if (flatExprs[
j] == 0)
1235 std::pair<unsigned, signed> indexEntry(
j, offsetDim--);
1242 llvm::sort(indices);
1243 for (
const std::pair<unsigned, unsigned> index : indices) {
1244 assert(indexToExprMap.lookup(index) &&
1245 "cannot find key in `indexToExprMap` map");
1246 expr = expr + indexToExprMap.lookup(index) * coefficients.lookup(index);
1250 for (
unsigned j = numDims + numSymbols, e = flatExprs.size() - 1;
j < e;
1254 if (flatExprs[
j] == 0 || addedToMap[
j - numDims - numSymbols])
1256 auto term = localExprs[
j - numDims - numSymbols] * flatExprs[
j];
1261 int64_t constTerm = flatExprs.back();
1263 expr = expr + constTerm;
1268 unsigned numSymbols)
1269 : numDims(numDims), numSymbols(numSymbols), numLocals(0) {
1287 if (!isa<AffineConstantExpr>(expr.
getRHS())) {
1294 return addLocalVariableSemiAffine(mulLhs, rhs, a * b, lhs, lhs.size());
1298 int64_t rhsConst = rhs[getConstantIndex()];
1299 for (int64_t &lhsElt : lhs)
1309 assert(lhs.size() == rhs.size());
1311 for (
unsigned i = 0, e = rhs.size(); i < e; i++) {
1340 if (!isa<AffineConstantExpr>(expr.
getRHS())) {
1346 AffineExpr modExpr = dividendExpr % divisorExpr;
1347 return addLocalVariableSemiAffine(modLhs, rhs, modExpr, lhs, lhs.size());
1350 int64_t rhsConst = rhs[getConstantIndex()];
1356 for (i = 0, e = lhs.size(); i < e; i++)
1357 if (lhs[i] % rhsConst != 0)
1360 if (i == lhs.size()) {
1361 std::fill(lhs.begin(), lhs.end(), 0);
1369 uint64_t gcd = rhsConst;
1370 for (int64_t lhsElt : lhs)
1371 gcd = std::gcd(gcd, (uint64_t)
std::abs(lhsElt));
1374 for (int64_t &floorDividendElt : floorDividend)
1375 floorDividendElt = floorDividendElt /
static_cast<int64_t
>(gcd);
1377 int64_t floorDivisor = rhsConst /
static_cast<int64_t
>(gcd);
1386 if ((loc = findLocalId(floorDivExpr)) == -1) {
1389 lhs[getLocalVarStartIndex() +
numLocals - 1] = -rhsConst;
1392 lhs[getLocalVarStartIndex() + loc] -= rhsConst;
1399 return visitDivExpr(expr,
true);
1403 return visitDivExpr(expr,
false);
1419 eq[getSymbolStartIndex() + expr.
getPosition()] = 1;
1427 eq[getConstantIndex()] = expr.
getValue();
1431 LogicalResult SimpleAffineExprFlattener::addLocalVariableSemiAffine(
1434 assert(result.size() == resultSize &&
1435 "`result` vector passed is not of correct size");
1437 if ((loc = findLocalId(localExpr)) == -1) {
1441 std::fill(result.begin(), result.end(), 0);
1443 result[getLocalVarStartIndex() +
numLocals - 1] = 1;
1445 result[getLocalVarStartIndex() + loc] = 1;
1474 if (!isa<AffineConstantExpr>(expr.
getRHS())) {
1481 return addLocalVariableSemiAffine(divLhs, rhs, divExpr, lhs, lhs.size());
1485 int64_t rhsConst = rhs[getConstantIndex()];
1492 for (int64_t lhsElt : lhs)
1493 gcd = std::gcd(gcd, (uint64_t)
std::abs(lhsElt));
1496 for (int64_t &lhsElt : lhs)
1497 lhsElt = lhsElt /
static_cast<int64_t
>(gcd);
1499 int64_t divisor = rhsConst /
static_cast<int64_t
>(gcd);
1515 if ((loc = findLocalId(divExpr)) == -1) {
1522 dividend.back() += divisor - 1;
1528 std::fill(lhs.begin(), lhs.end(), 0);
1530 lhs[getLocalVarStartIndex() +
numLocals - 1] = 1;
1532 lhs[getLocalVarStartIndex() + loc] = 1;
1544 assert(divisor > 0 &&
"positive constant divisor expected");
1546 subExpr.insert(subExpr.begin() + getLocalVarStartIndex() +
numLocals, 0);
1555 subExpr.insert(subExpr.begin() + getLocalVarStartIndex() +
numLocals, 0);
1562 int SimpleAffineExprFlattener::findLocalId(
AffineExpr localExpr) {
1571 unsigned numSymbols) {
1596 return simplifiedExpr;
1600 AffineExpr expr,
unsigned numDims,
unsigned numSymbols,
1601 ArrayRef<std::optional<int64_t>> constLowerBounds,
1602 ArrayRef<std::optional<int64_t>> constUpperBounds,
bool isUpper) {
1604 if (
auto binOpExpr = dyn_cast<AffineBinaryOpExpr>(expr)) {
1608 auto rhsConst = dyn_cast<AffineConstantExpr>(binOpExpr.getRHS());
1609 if (!rhsConst || rhsConst.getValue() < 1)
1610 return std::nullopt;
1613 constLowerBounds, constUpperBounds, isUpper);
1615 return std::nullopt;
1616 return divideFloorSigned(*bound, rhsConst.getValue());
1619 auto rhsConst = dyn_cast<AffineConstantExpr>(binOpExpr.getRHS());
1620 if (rhsConst && rhsConst.getValue() >= 1) {
1623 constLowerBounds, constUpperBounds, isUpper);
1625 return std::nullopt;
1626 return divideCeilSigned(*bound, rhsConst.getValue());
1628 return std::nullopt;
1634 auto rhsConst = dyn_cast<AffineConstantExpr>(binOpExpr.getRHS());
1635 if (rhsConst && rhsConst.getValue() >= 1) {
1636 int64_t rhsConstVal = rhsConst.getValue();
1638 constLowerBounds, constUpperBounds,
1642 constLowerBounds, constUpperBounds, isUpper);
1644 divideFloorSigned(*lb, rhsConstVal) ==
1645 divideFloorSigned(*ub, rhsConstVal))
1646 return isUpper ? mod(*ub, rhsConstVal) : mod(*lb, rhsConstVal);
1647 return isUpper ? rhsConstVal - 1 : 0;
1655 if (failed(simpleResult))
1656 return std::nullopt;
1661 return std::nullopt;
1665 for (
unsigned i = 0, e = numDims + numSymbols; i < e; ++i) {
1666 if (flattenedExpr[i] > 0) {
1667 auto &constBound = isUpper ? constUpperBounds[i] : constLowerBounds[i];
1669 return std::nullopt;
1670 bound += *constBound * flattenedExpr[i];
1671 }
else if (flattenedExpr[i] < 0) {
1672 auto &constBound = isUpper ? constLowerBounds[i] : constUpperBounds[i];
1674 return std::nullopt;
1675 bound += *constBound * flattenedExpr[i];
1679 bound += flattenedExpr.back();
static int64_t product(ArrayRef< int64_t > vals)
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 bool canSimplifyDivisionBySymbol(AffineExpr expr, unsigned symbolPos, AffineExprKind opKind, bool fromMul=false)
Returns true if the expression is divisible by the given symbol with position symbolPos.
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 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)
union mlir::linalg::@1183::ArityGroupAndKind::Kind kind
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)
virtual LogicalResult addLocalIdSemiAffine(ArrayRef< int64_t > lhs, ArrayRef< int64_t > rhs, AffineExpr localExpr)
Add a local identifier (needed to flatten a mod, floordiv, ceildiv, mul expr) when the rhs is a symbo...
LogicalResult visitModExpr(AffineBinaryOpExpr expr)
LogicalResult visitAddExpr(AffineBinaryOpExpr expr)
LogicalResult visitCeilDivExpr(AffineBinaryOpExpr expr)
LogicalResult visitMulExpr(AffineBinaryOpExpr expr)
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:
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
Fraction abs(const Fraction &f)
Include the generated interface declarations.
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...
@ 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.
AffineExpr getAffineSymbolExpr(unsigned position, MLIRContext *context)
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
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.