20#include "llvm/ADT/ArrayRef.h"
21#include "llvm/ADT/STLExtras.h"
23#include "llvm/Support/Debug.h"
32#define DEBUG_TYPE "int-range-analysis"
43 std::function<std::optional<APInt>(
const APInt &,
const APInt &)>;
48 const APInt &minRight,
50 const APInt &maxRight,
bool isSigned) {
51 std::optional<APInt> maybeMin = op(minLeft, minRight);
52 std::optional<APInt> maybeMax = op(maxLeft, maxRight);
53 if (maybeMin && maybeMax)
62 unsigned width = lhs[0].getBitWidth();
64 isSigned ? APInt::getSignedMaxValue(width) : APInt::getMaxValue(width);
66 isSigned ? APInt::getSignedMinValue(width) : APInt::getZero(width);
67 for (
const APInt &left : lhs) {
68 for (
const APInt &right : rhs) {
69 std::optional<APInt> maybeThisResult = op(left, right);
72 APInt
result = std::move(*maybeThisResult);
90 llvm::transform(argRanges, std::back_inserter(truncated),
100 LLVM_DEBUG(llvm::dbgs() <<
"Index handling: 64-bit result = " << sixtyFour
101 <<
" 32-bit = " << thirtyTwo <<
"\n");
102 bool truncEqual =
false;
105 truncEqual = (thirtyTwo == sixtyFourAsThirtyTwo);
108 truncEqual = (thirtyTwo.smin() == sixtyFourAsThirtyTwo.
smin() &&
109 thirtyTwo.smax() == sixtyFourAsThirtyTwo.
smax());
112 truncEqual = (thirtyTwo.umin() == sixtyFourAsThirtyTwo.
umin() &&
113 thirtyTwo.umax() == sixtyFourAsThirtyTwo.
umax());
124 unsigned int destWidth) {
125 APInt umin = range.
umin().zext(destWidth);
126 APInt umax = range.
umax().zext(destWidth);
127 APInt smin = range.
smin().sext(destWidth);
128 APInt smax = range.
smax().sext(destWidth);
129 return {umin, umax, smin, smax};
133 unsigned destWidth) {
134 APInt umin = range.
umin().zext(destWidth);
135 APInt umax = range.
umax().zext(destWidth);
140 unsigned destWidth) {
141 APInt smin = range.
smin().sext(destWidth);
142 APInt smax = range.
smax().sext(destWidth);
147 unsigned int destWidth) {
152 bool hasUnsignedRollover =
153 range.
umin().lshr(destWidth) != range.
umax().lshr(destWidth);
154 APInt umin = hasUnsignedRollover ? APInt::getZero(destWidth)
155 : range.umin().trunc(destWidth);
156 APInt umax = hasUnsignedRollover ? APInt::getMaxValue(destWidth)
157 : range.umax().trunc(destWidth);
168 APInt sminHighPart = range.
smin().ashr(destWidth - 1);
169 APInt smaxHighPart = range.
smax().ashr(destWidth - 1);
170 bool hasSignedOverflow =
171 (sminHighPart != smaxHighPart) &&
172 !(sminHighPart.isAllOnes() &&
173 (smaxHighPart.isAllOnes() || smaxHighPart.isZero())) &&
174 !(sminHighPart.isZero() && smaxHighPart.isZero());
175 APInt smin = hasSignedOverflow ? APInt::getSignedMinValue(destWidth)
176 : range.
smin().trunc(destWidth);
177 APInt smax = hasSignedOverflow ? APInt::getSignedMaxValue(destWidth)
178 : range.
smax().trunc(destWidth);
179 return {umin, umax, smin, smax};
192 const APInt &
b) -> std::optional<APInt> {
193 bool overflowed =
false;
196 : a.uadd_ov(
b, overflowed);
197 return overflowed ? std::optional<APInt>() :
result;
200 const APInt &
b) -> std::optional<APInt> {
201 bool overflowed =
false;
204 : a.sadd_ov(
b, overflowed);
205 return overflowed ? std::optional<APInt>() :
result;
209 uadd, lhs.umin(), rhs.umin(), lhs.umax(), rhs.umax(),
false);
211 sadd, lhs.smin(), rhs.smin(), lhs.smax(), rhs.smax(),
true);
225 const APInt &
b) -> std::optional<APInt> {
226 bool overflowed =
false;
229 : a.usub_ov(
b, overflowed);
230 return overflowed ? std::optional<APInt>() :
result;
233 const APInt &
b) -> std::optional<APInt> {
234 bool overflowed =
false;
237 : a.ssub_ov(
b, overflowed);
238 return overflowed ? std::optional<APInt>() :
result;
241 usub, lhs.umin(), rhs.umax(), lhs.umax(), rhs.umin(),
false);
243 ssub, lhs.smin(), rhs.smax(), lhs.smax(), rhs.smin(),
true);
257 const APInt &
b) -> std::optional<APInt> {
258 bool overflowed =
false;
261 : a.umul_ov(
b, overflowed);
262 return overflowed ? std::optional<APInt>() :
result;
265 const APInt &
b) -> std::optional<APInt> {
266 bool overflowed =
false;
269 : a.smul_ov(
b, overflowed);
270 return overflowed ? std::optional<APInt>() :
result;
274 minMaxBy(umul, {lhs.umin(), lhs.umax()}, {rhs.umin(), rhs.umax()},
277 minMaxBy(smul, {lhs.smin(), lhs.smax()}, {rhs.smin(), rhs.smax()},
289 const APInt &lhs,
const APInt &rhs,
const APInt &
result)>;
294 const APInt &lhsMin = lhs.
umin(), &lhsMax = lhs.umax(), &rhsMin = rhs.umin(),
295 &rhsMax = rhs.umax();
296 if (!rhsMin.isZero() && !rhsMax.isZero()) {
297 auto udiv = [&fixup](
const APInt &a,
298 const APInt &
b) -> std::optional<APInt> {
299 return fixup(a,
b, a.udiv(
b));
301 return minMaxBy(udiv, {lhsMin, lhsMax}, {rhsMin, rhsMax},
305 APInt umin = APInt::getZero(rhsMin.getBitWidth());
306 if (lhsMin.uge(rhsMax) && !rhsMax.isZero())
307 umin = lhsMin.udiv(rhsMax);
310 const APInt &umax = lhsMax;
317 [](
const APInt &lhs,
const APInt &rhs,
325 auto ceilDivUIFix = [](
const APInt &lhs,
const APInt &rhs,
326 const APInt &
result) -> std::optional<APInt> {
327 if (!lhs.urem(rhs).isZero()) {
328 bool overflowed =
false;
330 result.uadd_ov(APInt(
result.getBitWidth(), 1), overflowed);
331 return overflowed ? std::optional<APInt>() : corrected;
345 const APInt &lhsMin = lhs.
smin(), &lhsMax = lhs.smax(), &rhsMin = rhs.smin(),
346 &rhsMax = rhs.smax();
349 unsigned width = rhsMin.getBitWidth();
350 if (rhsMin.sgt(rhsMax))
352 bool canDivide = rhsMin.isStrictlyPositive() || rhsMax.isNegative();
355 auto sdiv = [&fixup](
const APInt &a,
356 const APInt &
b) -> std::optional<APInt> {
357 bool overflowed =
false;
358 APInt
result = a.sdiv_ov(
b, overflowed);
359 return overflowed ? std::optional<APInt>() : fixup(a,
b,
result);
361 return minMaxBy(sdiv, {lhsMin, lhsMax}, {rhsMin, rhsMax},
365 std::optional<ConstantIntRanges>
result;
366 if (rhsMin.isNegative())
370 if (rhsMax.isStrictlyPositive()) {
381 [](
const APInt &lhs,
const APInt &rhs,
389 auto ceilDivSIFix = [](
const APInt &lhs,
const APInt &rhs,
390 const APInt &
result) -> std::optional<APInt> {
391 if (!lhs.srem(rhs).isZero() && lhs.isNonNegative() == rhs.isNonNegative()) {
392 bool overflowed =
false;
394 result.sadd_ov(APInt(
result.getBitWidth(), 1), overflowed);
395 return overflowed ? std::optional<APInt>() : corrected;
403 if (lhs.isMinSignedValue() && rhs.sgt(1)) {
409 if (lhs.smin().isMinSignedValue() && lhs.smax().sgt(lhs.smin())) {
416 if (lhs.smin().isMinSignedValue() && rhs.smax().sgt(1) && rhs.smin().sle(2)) {
418 APInt two(lhs.smin().getBitWidth(), 2);
429 auto floorDivSIFix = [](
const APInt &lhs,
const APInt &rhs,
430 const APInt &
result) -> std::optional<APInt> {
431 if (!lhs.srem(rhs).isZero() && lhs.isNonNegative() != rhs.isNonNegative()) {
432 bool overflowed =
false;
434 result.ssub_ov(APInt(
result.getBitWidth(), 1), overflowed);
435 return overflowed ? std::optional<APInt>() : corrected;
449 const APInt &lhsMin = lhs.smin(), &lhsMax = lhs.smax(), &rhsMin = rhs.smin(),
450 &rhsMax = rhs.smax();
452 unsigned width = rhsMax.getBitWidth();
453 if (rhsMin.sgt(rhsMax) || (rhsMin.isZero() && rhsMax.isZero()))
457 APInt maxDivisor = llvm::APIntOps::umax(rhsMin.abs(), rhsMax.abs());
458 APInt zero = APInt::getZero(width);
459 APInt maxPositiveResult = maxDivisor - 1;
461 APInt smin = llvm::APIntOps::smax(llvm::APIntOps::smin(lhsMin, zero),
463 APInt smax = llvm::APIntOps::smin(llvm::APIntOps::smax(lhsMax, zero),
466 if (rhsMin == rhsMax) {
467 if ((lhsMax - lhsMin).
ult(maxDivisor)) {
468 APInt minRem = lhsMin.srem(maxDivisor);
469 APInt maxRem = lhsMax.srem(maxDivisor);
470 if (minRem.sle(maxRem)) {
471 smin = std::move(minRem);
472 smax = std::move(maxRem);
486 const APInt &rhsMin = rhs.umin(), &rhsMax = rhs.umax();
488 unsigned width = rhsMin.getBitWidth();
489 APInt umin = APInt::getZero(width);
491 APInt umax = llvm::APIntOps::umin((rhsMax - 1), lhs.umax());
493 if (!rhsMin.isZero()) {
495 if (rhsMin == rhsMax) {
496 const APInt &lhsMin = lhs.umin(), &lhsMax = lhs.umax();
497 if ((lhsMax - lhsMin).
ult(rhsMax)) {
498 APInt minRem = lhsMin.urem(rhsMax);
499 APInt maxRem = lhsMax.urem(rhsMax);
500 if (minRem.ule(maxRem)) {
501 umin = std::move(minRem);
502 umax = std::move(maxRem);
518 const APInt &smin = lhs.smin().sgt(rhs.smin()) ? lhs.smin() : rhs.smin();
519 const APInt &smax = lhs.smax().sgt(rhs.smax()) ? lhs.smax() : rhs.smax();
527 const APInt &umin = lhs.umin().ugt(rhs.umin()) ? lhs.umin() : rhs.umin();
528 const APInt &umax = lhs.umax().ugt(rhs.umax()) ? lhs.umax() : rhs.umax();
536 const APInt &smin = lhs.smin().slt(rhs.smin()) ? lhs.smin() : rhs.smin();
537 const APInt &smax = lhs.smax().slt(rhs.smax()) ? lhs.smax() : rhs.smax();
545 const APInt &umin = lhs.umin().ult(rhs.umin()) ? lhs.umin() : rhs.umin();
546 const APInt &umax = lhs.umax().ult(rhs.umax()) ? lhs.umax() : rhs.umax();
558static std::tuple<APInt, APInt>
560 APInt leftVal = bound.
umin(), rightVal = bound.
umax();
561 unsigned bitwidth = leftVal.getBitWidth();
562 unsigned differingBits = bitwidth - (leftVal ^ rightVal).countl_zero();
563 leftVal.clearLowBits(differingBits);
564 rightVal.setLowBits(differingBits);
565 return std::make_tuple(std::move(leftVal), std::move(rightVal));
572 auto andi = [](
const APInt &a,
const APInt &
b) -> std::optional<APInt> {
575 std::array<APInt, 2> lhsBounds = {std::move(lhsZeros), std::move(lhsOnes)};
576 std::array<APInt, 2> rhsBounds = {std::move(rhsZeros), std::move(rhsOnes)};
577 return minMaxBy(andi, lhsBounds, rhsBounds,
false);
584 auto ori = [](
const APInt &a,
const APInt &
b) -> std::optional<APInt> {
587 std::array<APInt, 2> lhsBounds = {std::move(lhsZeros), std::move(lhsOnes)};
588 std::array<APInt, 2> rhsBounds = {std::move(rhsZeros), std::move(rhsOnes)};
589 return minMaxBy(ori, lhsBounds, rhsBounds,
false);
595 APInt leftVal = bound.
umin(), rightVal = bound.
umax();
596 unsigned bitwidth = leftVal.getBitWidth();
597 unsigned differingBits =
598 bitwidth - (std::move(leftVal) ^ rightVal).countl_zero();
599 return APInt::getLowBitsSet(bitwidth, differingBits);
608 APInt res = lhs.umin() ^ rhs.umin();
609 APInt
min = res & ~mask;
610 APInt
max = std::move(res) | mask;
622 const APInt &rhsUMin = rhs.umin(), &rhsUMax = rhs.umax();
627 const APInt &r) -> std::optional<APInt> {
628 bool overflowed =
false;
631 : l.ushl_ov(r, overflowed);
632 return overflowed ? std::optional<APInt>() :
result;
635 const APInt &r) -> std::optional<APInt> {
636 bool overflowed =
false;
639 : l.sshl_ov(r, overflowed);
640 return overflowed ? std::optional<APInt>() :
result;
644 minMaxBy(ushl, {lhs.umin(), lhs.umax()}, {rhsUMin, rhsUMax},
647 minMaxBy(sshl, {lhs.smin(), lhs.smax()}, {rhsUMin, rhsUMax},
656 auto ashr = [](
const APInt &l,
const APInt &r) -> std::optional<APInt> {
657 return r.uge(r.getBitWidth()) ? std::optional<APInt>() : l.ashr(r);
660 return minMaxBy(ashr, {lhs.smin(), lhs.smax()}, {rhs.umin(), rhs.umax()},
668 auto lshr = [](
const APInt &l,
const APInt &r) -> std::optional<APInt> {
669 return r.uge(r.getBitWidth()) ? std::optional<APInt>() : l.lshr(r);
671 return minMaxBy(lshr, {lhs.umin(), lhs.umax()}, {rhs.umin(), rhs.umax()},
702 llvm_unreachable(
"unknown cmp predicate value");
710 return lhs.smax().sle(rhs.smin());
712 return lhs.smax().slt(rhs.smin());
714 return lhs.umax().ule(rhs.umin());
716 return lhs.umax().ult(rhs.umin());
718 return lhs.smin().sge(rhs.smax());
720 return lhs.smin().sgt(rhs.smax());
722 return lhs.umin().uge(rhs.umax());
724 return lhs.umin().ugt(rhs.umax());
726 std::optional<APInt> lhsConst = lhs.getConstantValue();
727 std::optional<APInt> rhsConst = rhs.getConstantValue();
728 return lhsConst && rhsConst && lhsConst == rhsConst;
764 APInt zero = APInt::getZero(width);
765 APInt typeMax = APInt::getSignedMaxValue(width);
767 auto shapedTy = cast<ShapedType>(op.getShapedValue().getType());
768 if (!shapedTy.hasRank())
771 int64_t rank = shapedTy.getRank();
776 minDim = std::max(minDim, dim.
smin().getSExtValue());
777 maxDim = std::min(maxDim, dim.
smax().getSExtValue());
780 std::optional<ConstantIntRanges>
result;
787 for (
int64_t i = minDim; i <= maxDim; ++i) {
788 int64_t length = shapedTy.getDimSize(i);
790 if (ShapedType::isDynamic(length))
803 unsigned width = val.
smin().getBitWidth();
805 APInt clampedUMin = val.
umin().ult(one) ? one : val.
umin();
806 APInt clampedSMin = val.
smin().slt(one) ? one : val.
smin();
817 auto constExpr = cast<AffineConstantExpr>(expr);
822 auto dimExpr = cast<AffineDimExpr>(expr);
823 unsigned pos = dimExpr.getPosition();
824 assert(pos < dimRanges.size() &&
"Dimension index out of bounds");
825 return dimRanges[pos];
828 auto symbolExpr = cast<AffineSymbolExpr>(expr);
829 unsigned pos = symbolExpr.getPosition();
830 assert(pos < symbolRanges.size() &&
"Symbol index out of bounds");
831 return symbolRanges[pos];
834 auto binExpr = cast<AffineBinaryOpExpr>(expr);
839 std::array<ConstantIntRanges, 2> operands = {std::move(lhs),
844 auto binExpr = cast<AffineBinaryOpExpr>(expr);
849 std::array<ConstantIntRanges, 2> operands = {std::move(lhs),
854 auto binExpr = cast<AffineBinaryOpExpr>(expr);
861 const APInt &lhsMin = lhs.smin();
862 const APInt &lhsMax = lhs.smax();
863 const APInt &rhsMin = rhs.smin();
864 const APInt &rhsMax = rhs.smax();
865 unsigned width = rhsMin.getBitWidth();
872 APInt umin = APInt::getZero(width);
873 APInt umax = rhsMax - 1;
878 if (rhsMin.isStrictlyPositive() && lhsMin.isNonNegative() &&
879 lhsMax.ult(rhsMin)) {
886 else if (rhsMin == rhsMax && lhsMin.isNonNegative() &&
887 (lhsMax - lhsMin).ult(rhsMax) &&
888 lhsMin.udiv(rhsMax) == lhsMax.udiv(rhsMax)) {
892 umin = lhsMin.urem(rhsMax);
893 umax = lhsMax.urem(rhsMax);
895 assert(umin.ule(umax) &&
896 "Range should be contiguous for non-negative dividend");
902 auto binExpr = cast<AffineBinaryOpExpr>(expr);
910 std::array<ConstantIntRanges, 2> operands = {std::move(lhs),
911 std::move(clampedRhs)};
915 auto binExpr = cast<AffineBinaryOpExpr>(expr);
923 std::array<ConstantIntRanges, 2> operands = {std::move(lhs),
924 std::move(clampedRhs)};
928 llvm_unreachable(
"unknown affine expression kind");
static ConstantIntRanges inferDivSRange(const ConstantIntRanges &lhs, const ConstantIntRanges &rhs, DivisionFixupFn fixup)
static bool isStaticallyTrue(intrange::CmpPredicate pred, const ConstantIntRanges &lhs, const ConstantIntRanges &rhs)
static intrange::CmpPredicate invertPredicate(intrange::CmpPredicate pred)
static ConstantIntRanges minMaxBy(ConstArithFn op, ArrayRef< APInt > lhs, ArrayRef< APInt > rhs, bool isSigned)
Compute the minimum and maximum of (op(l, r) for l in lhs for r in rhs), ignoring unbounded values.
std::function< std::optional< APInt >(const APInt &, const APInt &)> ConstArithStdFn
static std::tuple< APInt, APInt > widenBitwiseBounds(const ConstantIntRanges &bound)
"Widen" bounds - if 0bvvvvv?
static ConstantIntRanges inferDivURange(const ConstantIntRanges &lhs, const ConstantIntRanges &rhs, DivisionFixupFn fixup)
function_ref< std::optional< APInt >(const APInt &, const APInt &)> ConstArithFn
Function that evaluates the result of doing something on arithmetic constants and returns std::nullop...
static ConstantIntRanges clampToPositive(const ConstantIntRanges &val)
static ConstantIntRanges computeBoundsBy(ConstArithFn op, const APInt &minLeft, const APInt &minRight, const APInt &maxLeft, const APInt &maxRight, bool isSigned)
Compute op(minLeft, minRight) and op(maxLeft, maxRight) if possible, If either computation overflows,...
static APInt getVaryingBitsMask(const ConstantIntRanges &bound)
Get bitmask of all bits which can change while iterating in [bound.umin(), bound.umax()].
function_ref< std::optional< APInt >( const APInt &lhs, const APInt &rhs, const APInt &result)> DivisionFixupFn
Fix up division results (ex.
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
static Value min(ImplicitLocOpBuilder &builder, Value value, Value bound)
Base type for affine expression.
AffineExprKind getKind() const
Return the classification for this type.
A set of arbitrary-precision integers representing bounds on a given integer value.
static ConstantIntRanges maxRange(unsigned bitwidth)
Create a ConstantIntRanges with the maximum bounds for the width bitwidth, that is - [0,...
const APInt & smax() const
The maximum value of an integer when it is interpreted as signed.
static ConstantIntRanges constant(const APInt &value)
Create a ConstantIntRanges with a constant value - that is, with the bounds [value,...
static ConstantIntRanges fromUnsigned(const APInt &umin, const APInt &umax)
Create an ConstantIntRanges with the unsigned minimum and maximum equal to umin and umax and the sign...
const APInt & smin() const
The minimum value of an integer when it is interpreted as signed.
static ConstantIntRanges range(const APInt &min, const APInt &max, bool isSigned)
Create a ConstantIntRanges whose minimum is min and maximum is max with isSigned specifying if the mi...
ConstantIntRanges intersection(const ConstantIntRanges &other) const
Returns the intersection (computed separately for signed and unsigned bounds) of this range and other...
static ConstantIntRanges fromSigned(const APInt &smin, const APInt &smax)
Create an ConstantIntRanges with the signed minimum and maximum equal to smin and smax,...
static unsigned getStorageBitwidth(Type type)
Return the bitwidth that should be used for integer ranges describing type.
const APInt & umax() const
The maximum value of an integer when it is interpreted as unsigned.
const APInt & umin() const
The minimum value of an integer when it is interpreted as unsigned.
ConstantIntRanges rangeUnion(const ConstantIntRanges &other) const
Returns the union (computed separately for signed and unsigned bounds) of this range and other.
This lattice value represents the integer range of an SSA value.
const ConstantIntRanges & getValue() const
Get the known integer value range.
bool isUninitialized() const
Whether the range is uninitialized.
ConstantIntRanges inferAnd(ArrayRef< ConstantIntRanges > argRanges)
ConstantIntRanges inferShl(ArrayRef< ConstantIntRanges > argRanges, OverflowFlags ovfFlags=OverflowFlags::None)
ConstantIntRanges inferIndexOp(const InferRangeFn &inferFn, ArrayRef< ConstantIntRanges > argRanges, CmpMode mode)
Compute inferFn on ranges, whose size should be the index storage bitwidth.
ConstantIntRanges inferShrS(ArrayRef< ConstantIntRanges > argRanges)
ConstantIntRanges extSIRange(const ConstantIntRanges &range, unsigned destWidth)
Use the signed values in range to sign-extend it to destWidth.
std::optional< bool > evaluatePred(CmpPredicate pred, const ConstantIntRanges &lhs, const ConstantIntRanges &rhs)
Returns a boolean value if pred is statically true or false for anypossible inputs falling within lhs...
ConstantIntRanges inferMinS(ArrayRef< ConstantIntRanges > argRanges)
ConstantIntRanges inferMaxU(ArrayRef< ConstantIntRanges > argRanges)
ConstantIntRanges inferRemS(ArrayRef< ConstantIntRanges > argRanges)
ConstantIntRanges inferAffineExpr(AffineExpr expr, ArrayRef< ConstantIntRanges > dimRanges, ArrayRef< ConstantIntRanges > symbolRanges)
Infer the integer range for an affine expression given ranges for its dimensions and symbols.
CmpPredicate
Copy of the enum from arith and index to allow the common integer range infrastructure to not depend ...
ConstantIntRanges inferOr(ArrayRef< ConstantIntRanges > argRanges)
ConstantIntRanges extRange(const ConstantIntRanges &range, unsigned destWidth)
Independently zero-extend the unsigned values and sign-extend the signed values in range to destWidth...
ConstantIntRanges inferSub(ArrayRef< ConstantIntRanges > argRanges, OverflowFlags ovfFlags=OverflowFlags::None)
std::function< ConstantIntRanges(ArrayRef< ConstantIntRanges >)> InferRangeFn
Function that performs inference on an array of ConstantIntRanges, abstracted away here to permit wri...
ConstantIntRanges inferAdd(ArrayRef< ConstantIntRanges > argRanges, OverflowFlags ovfFlags=OverflowFlags::None)
ConstantIntRanges truncRange(const ConstantIntRanges &range, unsigned destWidth)
Truncate range to destWidth bits, taking care to handle cases such as the truncation of [255,...
ConstantIntRanges inferDivU(ArrayRef< ConstantIntRanges > argRanges)
ConstantIntRanges inferCeilDivS(ArrayRef< ConstantIntRanges > argRanges)
ConstantIntRanges inferMinU(ArrayRef< ConstantIntRanges > argRanges)
ConstantIntRanges inferMul(ArrayRef< ConstantIntRanges > argRanges, OverflowFlags ovfFlags=OverflowFlags::None)
ConstantIntRanges inferXor(ArrayRef< ConstantIntRanges > argRanges)
ConstantIntRanges inferDivS(ArrayRef< ConstantIntRanges > argRanges)
ConstantIntRanges inferShrU(ArrayRef< ConstantIntRanges > argRanges)
ConstantIntRanges inferRemU(ArrayRef< ConstantIntRanges > argRanges)
static constexpr unsigned indexMinWidth
ConstantIntRanges inferFloorDivS(ArrayRef< ConstantIntRanges > argRanges)
static constexpr unsigned indexMaxWidth
ConstantIntRanges inferCeilDivU(ArrayRef< ConstantIntRanges > argRanges)
ConstantIntRanges extUIRange(const ConstantIntRanges &range, unsigned destWidth)
Use the unsigned values in range to zero-extend it to destWidth.
ConstantIntRanges inferShapedDimOpInterface(ShapedDimOpInterface op, const IntegerValueRange &maybeDim)
Returns the integer range for the result of a ShapedDimOpInterface given the optional inferred ranges...
ConstantIntRanges inferMaxS(ArrayRef< ConstantIntRanges > argRanges)
Include the generated interface declarations.
@ 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.
llvm::function_ref< Fn > function_ref