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) {
603 llvm_unreachable(
"Unknown AffineExpr");
609 storage->context = context;
614 assignCtx,
static_cast<unsigned>(kind), position);
643 storage->context = context;
653 return llvm::to_vector(llvm::map_range(constants, [&](int64_t constant) {
660 auto lhsConst = dyn_cast<AffineConstantExpr>(lhs);
661 auto rhsConst = dyn_cast<AffineConstantExpr>(rhs);
663 if (lhsConst && rhsConst) {
665 if (llvm::AddOverflow(lhsConst.getValue(), rhsConst.getValue(), sum)) {
673 if (isa<AffineConstantExpr>(lhs) ||
682 if (rhsConst.getValue() == 0)
686 auto lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
688 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS()))
689 return lBin.getLHS() + (lrhs.getValue() + rhsConst.getValue());
695 std::optional<int64_t> rLhsConst, rRhsConst;
698 auto lBinOpExpr = dyn_cast<AffineBinaryOpExpr>(lhs);
700 (rLhsConstExpr = dyn_cast<AffineConstantExpr>(lBinOpExpr.getRHS()))) {
701 rLhsConst = rLhsConstExpr.
getValue();
702 firstExpr = lBinOpExpr.getLHS();
708 auto rBinOpExpr = dyn_cast<AffineBinaryOpExpr>(rhs);
711 (rRhsConstExpr = dyn_cast<AffineConstantExpr>(rBinOpExpr.getRHS()))) {
712 rRhsConst = rRhsConstExpr.
getValue();
713 secondExpr = rBinOpExpr.getLHS();
719 if (rLhsConst && rRhsConst && firstExpr == secondExpr)
727 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS())) {
728 return lBin.getLHS() + rhs + lrhs;
741 auto lrhs = rBinOpExpr.getLHS();
742 auto rrhs = rBinOpExpr.getRHS();
748 auto lrhsBinOpExpr = dyn_cast<AffineBinaryOpExpr>(lrhs);
750 auto rrhsConstOpExpr = dyn_cast<AffineConstantExpr>(rrhs);
751 if (rrhsConstOpExpr && rrhsConstOpExpr.getValue() == -1 && lrhsBinOpExpr &&
754 llrhs = lrhsBinOpExpr.getLHS();
756 rlrhs = lrhsBinOpExpr.getRHS();
757 auto llrhsBinOpExpr = dyn_cast<AffineBinaryOpExpr>(llrhs);
760 if (llrhsBinOpExpr.getRHS() == rlrhs && lhs == llrhsBinOpExpr.getLHS())
771 llrhs = lrBinOpExpr.
getLHS();
772 rlrhs = lrBinOpExpr.
getRHS();
773 auto rlrhsConstOpExpr = dyn_cast<AffineConstantExpr>(rlrhs);
775 bool isPositiveRhs = rlrhsConstOpExpr && rlrhsConstOpExpr.getValue() > 0;
777 if (isPositiveRhs && lhs == llrhs && rlrhs == -rrhs) {
797 auto lhsConst = dyn_cast<AffineConstantExpr>(lhs);
798 auto rhsConst = dyn_cast<AffineConstantExpr>(rhs);
800 if (lhsConst && rhsConst) {
802 if (llvm::MulOverflow(lhsConst.getValue(), rhsConst.getValue(),
product)) {
823 if (rhsConst.getValue() == 1)
826 if (rhsConst.getValue() == 0)
831 auto lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
833 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS()))
834 return lBin.getLHS() * (lrhs.getValue() * rhsConst.getValue());
840 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS())) {
841 return (lBin.getLHS() * rhs) * lrhs;
868 return *
this + (-other);
872 auto lhsConst = dyn_cast<AffineConstantExpr>(lhs);
873 auto rhsConst = dyn_cast<AffineConstantExpr>(rhs);
875 if (!rhsConst || rhsConst.getValue() == 0)
879 if (divideSignedWouldOverflow(lhsConst.getValue(), rhsConst.getValue()))
882 divideFloorSigned(lhsConst.getValue(), rhsConst.getValue()),
893 auto lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
895 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS())) {
897 if (lrhs.getValue() % rhsConst.getValue() == 0)
898 return lBin.getLHS() * (lrhs.getValue() / rhsConst.getValue());
905 int64_t llhsDiv = lBin.getLHS().getLargestKnownDivisor();
906 int64_t lrhsDiv = lBin.getRHS().getLargestKnownDivisor();
908 if (llhsDiv % rhsConst.getValue() == 0 ||
909 lrhsDiv % rhsConst.getValue() == 0)
910 return lBin.getLHS().floorDiv(rhsConst.getValue()) +
911 lBin.getRHS().floorDiv(rhsConst.getValue());
931 auto lhsConst = dyn_cast<AffineConstantExpr>(lhs);
932 auto rhsConst = dyn_cast<AffineConstantExpr>(rhs);
934 if (!rhsConst || rhsConst.getValue() == 0)
938 if (divideSignedWouldOverflow(lhsConst.getValue(), rhsConst.getValue()))
941 divideCeilSigned(lhsConst.getValue(), rhsConst.getValue()),
947 if (rhsConst.getValue() == 1)
952 auto lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
954 if (
auto lrhs = dyn_cast<AffineConstantExpr>(lBin.getRHS())) {
956 if (lrhs.getValue() % rhsConst.getValue() == 0)
957 return lBin.getLHS() * (lrhs.getValue() / rhsConst.getValue());
978 auto lhsConst = dyn_cast<AffineConstantExpr>(lhs);
979 auto rhsConst = dyn_cast<AffineConstantExpr>(rhs);
982 if (!rhsConst || rhsConst.getValue() < 1)
999 auto lBin = dyn_cast<AffineBinaryOpExpr>(lhs);
1001 int64_t llhsDiv = lBin.getLHS().getLargestKnownDivisor();
1002 int64_t lrhsDiv = lBin.getRHS().getLargestKnownDivisor();
1004 if (llhsDiv % rhsConst.getValue() == 0)
1005 return lBin.getRHS() % rhsConst.getValue();
1006 if (lrhsDiv % rhsConst.getValue() == 0)
1007 return lBin.getLHS() % rhsConst.getValue();
1012 auto intermediate = dyn_cast<AffineConstantExpr>(lBin.getRHS());
1013 if (intermediate && intermediate.getValue() >= 1 &&
1014 mod(intermediate.getValue(), rhsConst.getValue()) == 0) {
1015 return lBin.getLHS() % rhsConst.getValue();
1050 unsigned numSymbols,
1054 assert(flatExprs.size() - numDims - numSymbols - 1 == localExprs.size() &&
1055 "unexpected number of local expressions");
1059 for (
unsigned j = 0;
j < numDims + numSymbols;
j++) {
1060 if (flatExprs[
j] == 0)
1064 expr = expr +
id * flatExprs[
j];
1068 for (
unsigned j = numDims + numSymbols, e = flatExprs.size() - 1;
j < e;
1070 if (flatExprs[
j] == 0)
1072 auto term = localExprs[
j - numDims - numSymbols] * flatExprs[
j];
1077 int64_t constTerm = flatExprs[flatExprs.size() - 1];
1079 expr = expr + constTerm;
1093 unsigned numSymbols,
1096 assert(!flatExprs.empty() &&
"flatExprs cannot be empty");
1099 assert(flatExprs.size() - numDims - numSymbols - 1 == localExprs.size() &&
1100 "unexpected number of local expressions");
1132 auto addEntry = [&](std::pair<unsigned, signed> index, int64_t coefficient,
1134 assert(!llvm::is_contained(indices, index) &&
1135 "Key is already present in indices vector and overwriting will "
1136 "happen in `indexToExprMap` and `coefficients`!");
1138 indices.push_back(index);
1139 coefficients.insert({index, coefficient});
1140 indexToExprMap.insert({index, expr});
1148 unsigned offsetSym = 0;
1149 signed offsetDim = -1;
1150 for (
unsigned j = numDims;
j < numDims + numSymbols; ++
j) {
1151 if (flatExprs[
j] == 0)
1157 std::pair<unsigned, signed> indexEntry(
1158 j - numDims,
std::max(numDims, numSymbols) + offsetSym++);
1159 addEntry(indexEntry, flatExprs[
j],
1167 unsigned lhsPos, rhsPos;
1174 if (flatExprs[numDims + numSymbols + it.index()] == 0)
1176 AffineExpr lhs = cast<AffineBinaryOpExpr>(expr).getLHS();
1177 AffineExpr rhs = cast<AffineBinaryOpExpr>(expr).getRHS();
1178 if (!((isa<AffineDimExpr>(lhs) || isa<AffineSymbolExpr>(lhs)) &&
1179 (isa<AffineDimExpr>(rhs) || isa<AffineSymbolExpr>(rhs) ||
1180 isa<AffineConstantExpr>(rhs)))) {
1183 if (isa<AffineConstantExpr>(rhs)) {
1188 if (isa<AffineDimExpr>(lhs)) {
1189 lhsPos = cast<AffineDimExpr>(lhs).getPosition();
1190 std::pair<unsigned, signed> indexEntry(lhsPos, offsetDim--);
1191 addEntry(indexEntry, flatExprs[numDims + numSymbols + it.index()],
1194 lhsPos = cast<AffineSymbolExpr>(lhs).getPosition();
1195 std::pair<unsigned, signed> indexEntry(
1196 lhsPos,
std::max(numDims, numSymbols) + offsetSym++);
1197 addEntry(indexEntry, flatExprs[numDims + numSymbols + it.index()],
1200 }
else if (isa<AffineDimExpr>(lhs)) {
1206 lhsPos = cast<AffineDimExpr>(lhs).getPosition();
1207 rhsPos = cast<AffineSymbolExpr>(rhs).getPosition();
1208 std::pair<unsigned, signed> indexEntry(lhsPos, rhsPos);
1209 addEntry(indexEntry, flatExprs[numDims + numSymbols + it.index()], expr);
1215 lhsPos = cast<AffineSymbolExpr>(lhs).getPosition();
1216 rhsPos = cast<AffineSymbolExpr>(rhs).getPosition();
1217 std::pair<unsigned, signed> indexEntry(
1218 lhsPos,
std::max(numDims, numSymbols) + offsetSym++);
1219 addEntry(indexEntry, flatExprs[numDims + numSymbols + it.index()], expr);
1221 addedToMap[it.index()] =
true;
1224 for (
unsigned j = 0;
j < numDims; ++
j) {
1225 if (flatExprs[
j] == 0)
1231 std::pair<unsigned, signed> indexEntry(
j, offsetDim--);
1238 llvm::sort(indices);
1239 for (
const std::pair<unsigned, unsigned> index : indices) {
1240 assert(indexToExprMap.lookup(index) &&
1241 "cannot find key in `indexToExprMap` map");
1242 expr = expr + indexToExprMap.lookup(index) * coefficients.lookup(index);
1246 for (
unsigned j = numDims + numSymbols, e = flatExprs.size() - 1;
j < e;
1250 if (flatExprs[
j] == 0 || addedToMap[
j - numDims - numSymbols])
1252 auto term = localExprs[
j - numDims - numSymbols] * flatExprs[
j];
1257 int64_t constTerm = flatExprs.back();
1259 expr = expr + constTerm;
1264 unsigned numSymbols)
1265 : numDims(numDims), numSymbols(numSymbols), numLocals(0) {
1283 if (!isa<AffineConstantExpr>(expr.
getRHS())) {
1290 return addLocalVariableSemiAffine(mulLhs, rhs, a * b, lhs, lhs.size());
1294 int64_t rhsConst = rhs[getConstantIndex()];
1295 for (int64_t &lhsElt : lhs)
1305 assert(lhs.size() == rhs.size());
1307 for (
unsigned i = 0, e = rhs.size(); i < e; i++) {
1336 if (!isa<AffineConstantExpr>(expr.
getRHS())) {
1342 AffineExpr modExpr = dividendExpr % divisorExpr;
1343 return addLocalVariableSemiAffine(modLhs, rhs, modExpr, lhs, lhs.size());
1346 int64_t rhsConst = rhs[getConstantIndex()];
1352 for (i = 0, e = lhs.size(); i < e; i++)
1353 if (lhs[i] % rhsConst != 0)
1356 if (i == lhs.size()) {
1357 std::fill(lhs.begin(), lhs.end(), 0);
1365 uint64_t gcd = rhsConst;
1366 for (int64_t lhsElt : lhs)
1367 gcd = std::gcd(gcd, (uint64_t)
std::abs(lhsElt));
1370 for (int64_t &floorDividendElt : floorDividend)
1371 floorDividendElt = floorDividendElt /
static_cast<int64_t
>(gcd);
1373 int64_t floorDivisor = rhsConst /
static_cast<int64_t
>(gcd);
1382 if ((loc = findLocalId(floorDivExpr)) == -1) {
1385 lhs[getLocalVarStartIndex() +
numLocals - 1] = -rhsConst;
1388 lhs[getLocalVarStartIndex() + loc] = -rhsConst;
1395 return visitDivExpr(expr,
true);
1399 return visitDivExpr(expr,
false);
1415 eq[getSymbolStartIndex() + expr.
getPosition()] = 1;
1423 eq[getConstantIndex()] = expr.
getValue();
1427 LogicalResult SimpleAffineExprFlattener::addLocalVariableSemiAffine(
1430 assert(result.size() == resultSize &&
1431 "`result` vector passed is not of correct size");
1433 if ((loc = findLocalId(localExpr)) == -1) {
1437 std::fill(result.begin(), result.end(), 0);
1439 result[getLocalVarStartIndex() +
numLocals - 1] = 1;
1441 result[getLocalVarStartIndex() + loc] = 1;
1470 if (!isa<AffineConstantExpr>(expr.
getRHS())) {
1477 return addLocalVariableSemiAffine(divLhs, rhs, divExpr, lhs, lhs.size());
1481 int64_t rhsConst = rhs[getConstantIndex()];
1488 for (int64_t lhsElt : lhs)
1489 gcd = std::gcd(gcd, (uint64_t)
std::abs(lhsElt));
1492 for (int64_t &lhsElt : lhs)
1493 lhsElt = lhsElt /
static_cast<int64_t
>(gcd);
1495 int64_t divisor = rhsConst /
static_cast<int64_t
>(gcd);
1511 if ((loc = findLocalId(divExpr)) == -1) {
1518 dividend.back() += divisor - 1;
1524 std::fill(lhs.begin(), lhs.end(), 0);
1526 lhs[getLocalVarStartIndex() +
numLocals - 1] = 1;
1528 lhs[getLocalVarStartIndex() + loc] = 1;
1540 assert(divisor > 0 &&
"positive constant divisor expected");
1542 subExpr.insert(subExpr.begin() + getLocalVarStartIndex() +
numLocals, 0);
1551 subExpr.insert(subExpr.begin() + getLocalVarStartIndex() +
numLocals, 0);
1558 int SimpleAffineExprFlattener::findLocalId(
AffineExpr localExpr) {
1567 unsigned numSymbols) {
1592 return simplifiedExpr;
1596 AffineExpr expr,
unsigned numDims,
unsigned numSymbols,
1597 ArrayRef<std::optional<int64_t>> constLowerBounds,
1598 ArrayRef<std::optional<int64_t>> constUpperBounds,
bool isUpper) {
1600 if (
auto binOpExpr = dyn_cast<AffineBinaryOpExpr>(expr)) {
1604 auto rhsConst = dyn_cast<AffineConstantExpr>(binOpExpr.getRHS());
1605 if (!rhsConst || rhsConst.getValue() < 1)
1606 return std::nullopt;
1609 constLowerBounds, constUpperBounds, isUpper);
1611 return std::nullopt;
1612 return divideFloorSigned(*bound, rhsConst.getValue());
1615 auto rhsConst = dyn_cast<AffineConstantExpr>(binOpExpr.getRHS());
1616 if (rhsConst && rhsConst.getValue() >= 1) {
1619 constLowerBounds, constUpperBounds, isUpper);
1621 return std::nullopt;
1622 return divideCeilSigned(*bound, rhsConst.getValue());
1624 return std::nullopt;
1630 auto rhsConst = dyn_cast<AffineConstantExpr>(binOpExpr.getRHS());
1631 if (rhsConst && rhsConst.getValue() >= 1) {
1632 int64_t rhsConstVal = rhsConst.getValue();
1634 constLowerBounds, constUpperBounds,
1638 constLowerBounds, constUpperBounds, isUpper);
1640 divideFloorSigned(*lb, rhsConstVal) ==
1641 divideFloorSigned(*ub, rhsConstVal))
1642 return isUpper ? mod(*ub, rhsConstVal) : mod(*lb, rhsConstVal);
1643 return isUpper ? rhsConstVal - 1 : 0;
1651 if (failed(simpleResult))
1652 return std::nullopt;
1657 return std::nullopt;
1661 for (
unsigned i = 0, e = numDims + numSymbols; i < e; ++i) {
1662 if (flattenedExpr[i] > 0) {
1663 auto &constBound = isUpper ? constUpperBounds[i] : constLowerBounds[i];
1665 return std::nullopt;
1666 bound += *constBound * flattenedExpr[i];
1667 }
else if (flattenedExpr[i] < 0) {
1668 auto &constBound = isUpper ? constLowerBounds[i] : constUpperBounds[i];
1670 return std::nullopt;
1671 bound += *constBound * flattenedExpr[i];
1675 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)
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.