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();
347 bool canDivide = rhsMin.isStrictlyPositive() || rhsMax.isNegative();
350 auto sdiv = [&fixup](
const APInt &a,
351 const APInt &
b) -> std::optional<APInt> {
352 bool overflowed =
false;
353 APInt
result = a.sdiv_ov(
b, overflowed);
354 return overflowed ? std::optional<APInt>() : fixup(a,
b,
result);
356 return minMaxBy(sdiv, {lhsMin, lhsMax}, {rhsMin, rhsMax},
365 [](
const APInt &lhs,
const APInt &rhs,
373 auto ceilDivSIFix = [](
const APInt &lhs,
const APInt &rhs,
374 const APInt &
result) -> std::optional<APInt> {
375 if (!lhs.srem(rhs).isZero() && lhs.isNonNegative() == rhs.isNonNegative()) {
376 bool overflowed =
false;
378 result.sadd_ov(APInt(
result.getBitWidth(), 1), overflowed);
379 return overflowed ? std::optional<APInt>() : corrected;
387 if (lhs.isMinSignedValue() && rhs.sgt(1)) {
393 if (lhs.smin().isMinSignedValue() && lhs.smax().sgt(lhs.smin())) {
407 auto floorDivSIFix = [](
const APInt &lhs,
const APInt &rhs,
408 const APInt &
result) -> std::optional<APInt> {
409 if (!lhs.srem(rhs).isZero() && lhs.isNonNegative() != rhs.isNonNegative()) {
410 bool overflowed =
false;
412 result.ssub_ov(APInt(
result.getBitWidth(), 1), overflowed);
413 return overflowed ? std::optional<APInt>() : corrected;
427 const APInt &lhsMin = lhs.smin(), &lhsMax = lhs.smax(), &rhsMin = rhs.smin(),
428 &rhsMax = rhs.smax();
430 unsigned width = rhsMax.getBitWidth();
431 APInt smin = APInt::getSignedMinValue(width);
432 APInt smax = APInt::getSignedMaxValue(width);
434 bool canBound = (rhsMin.isStrictlyPositive() || rhsMax.isNegative());
436 APInt maxDivisor = rhsMin.isStrictlyPositive() ? rhsMax : rhsMin.abs();
437 bool canNegativeDividend = lhsMin.isNegative();
438 bool canPositiveDividend = lhsMax.isStrictlyPositive();
439 APInt zero = APInt::getZero(maxDivisor.getBitWidth());
440 APInt maxPositiveResult = maxDivisor - 1;
441 APInt minNegativeResult = -maxPositiveResult;
442 smin = canNegativeDividend ? minNegativeResult : zero;
443 smax = canPositiveDividend ? maxPositiveResult : zero;
445 if (rhsMin == rhsMax) {
446 if ((lhsMax - lhsMin).
ult(maxDivisor)) {
447 APInt minRem = lhsMin.srem(maxDivisor);
448 APInt maxRem = lhsMax.srem(maxDivisor);
449 if (minRem.sle(maxRem)) {
450 smin = std::move(minRem);
451 smax = std::move(maxRem);
466 const APInt &rhsMin = rhs.umin(), &rhsMax = rhs.umax();
468 unsigned width = rhsMin.getBitWidth();
469 APInt umin = APInt::getZero(width);
471 APInt umax = llvm::APIntOps::umin((rhsMax - 1), lhs.umax());
473 if (!rhsMin.isZero()) {
475 if (rhsMin == rhsMax) {
476 const APInt &lhsMin = lhs.umin(), &lhsMax = lhs.umax();
477 if ((lhsMax - lhsMin).
ult(rhsMax)) {
478 APInt minRem = lhsMin.urem(rhsMax);
479 APInt maxRem = lhsMax.urem(rhsMax);
480 if (minRem.ule(maxRem)) {
481 umin = std::move(minRem);
482 umax = std::move(maxRem);
498 const APInt &smin = lhs.smin().sgt(rhs.smin()) ? lhs.smin() : rhs.smin();
499 const APInt &smax = lhs.smax().sgt(rhs.smax()) ? lhs.smax() : rhs.smax();
507 const APInt &umin = lhs.umin().ugt(rhs.umin()) ? lhs.umin() : rhs.umin();
508 const APInt &umax = lhs.umax().ugt(rhs.umax()) ? lhs.umax() : rhs.umax();
516 const APInt &smin = lhs.smin().slt(rhs.smin()) ? lhs.smin() : rhs.smin();
517 const APInt &smax = lhs.smax().slt(rhs.smax()) ? lhs.smax() : rhs.smax();
525 const APInt &umin = lhs.umin().ult(rhs.umin()) ? lhs.umin() : rhs.umin();
526 const APInt &umax = lhs.umax().ult(rhs.umax()) ? lhs.umax() : rhs.umax();
538static std::tuple<APInt, APInt>
540 APInt leftVal = bound.
umin(), rightVal = bound.
umax();
541 unsigned bitwidth = leftVal.getBitWidth();
542 unsigned differingBits = bitwidth - (leftVal ^ rightVal).countl_zero();
543 leftVal.clearLowBits(differingBits);
544 rightVal.setLowBits(differingBits);
545 return std::make_tuple(std::move(leftVal), std::move(rightVal));
552 auto andi = [](
const APInt &a,
const APInt &
b) -> std::optional<APInt> {
555 std::array<APInt, 2> lhsBounds = {std::move(lhsZeros), std::move(lhsOnes)};
556 std::array<APInt, 2> rhsBounds = {std::move(rhsZeros), std::move(rhsOnes)};
557 return minMaxBy(andi, lhsBounds, rhsBounds,
false);
564 auto ori = [](
const APInt &a,
const APInt &
b) -> std::optional<APInt> {
567 std::array<APInt, 2> lhsBounds = {std::move(lhsZeros), std::move(lhsOnes)};
568 std::array<APInt, 2> rhsBounds = {std::move(rhsZeros), std::move(rhsOnes)};
569 return minMaxBy(ori, lhsBounds, rhsBounds,
false);
575 APInt leftVal = bound.
umin(), rightVal = bound.
umax();
576 unsigned bitwidth = leftVal.getBitWidth();
577 unsigned differingBits =
578 bitwidth - (std::move(leftVal) ^ rightVal).countl_zero();
579 return APInt::getLowBitsSet(bitwidth, differingBits);
588 APInt res = lhs.umin() ^ rhs.umin();
589 APInt
min = res & ~mask;
590 APInt
max = std::move(res) | mask;
602 const APInt &rhsUMin = rhs.umin(), &rhsUMax = rhs.umax();
607 const APInt &r) -> std::optional<APInt> {
608 bool overflowed =
false;
611 : l.ushl_ov(r, overflowed);
612 return overflowed ? std::optional<APInt>() :
result;
615 const APInt &r) -> std::optional<APInt> {
616 bool overflowed =
false;
619 : l.sshl_ov(r, overflowed);
620 return overflowed ? std::optional<APInt>() :
result;
624 minMaxBy(ushl, {lhs.umin(), lhs.umax()}, {rhsUMin, rhsUMax},
627 minMaxBy(sshl, {lhs.smin(), lhs.smax()}, {rhsUMin, rhsUMax},
636 auto ashr = [](
const APInt &l,
const APInt &r) -> std::optional<APInt> {
637 return r.uge(r.getBitWidth()) ? std::optional<APInt>() : l.ashr(r);
640 return minMaxBy(ashr, {lhs.smin(), lhs.smax()}, {rhs.umin(), rhs.umax()},
648 auto lshr = [](
const APInt &l,
const APInt &r) -> std::optional<APInt> {
649 return r.uge(r.getBitWidth()) ? std::optional<APInt>() : l.lshr(r);
651 return minMaxBy(lshr, {lhs.umin(), lhs.umax()}, {rhs.umin(), rhs.umax()},
682 llvm_unreachable(
"unknown cmp predicate value");
690 return lhs.smax().sle(rhs.smin());
692 return lhs.smax().slt(rhs.smin());
694 return lhs.umax().ule(rhs.umin());
696 return lhs.umax().ult(rhs.umin());
698 return lhs.smin().sge(rhs.smax());
700 return lhs.smin().sgt(rhs.smax());
702 return lhs.umin().uge(rhs.umax());
704 return lhs.umin().ugt(rhs.umax());
706 std::optional<APInt> lhsConst = lhs.getConstantValue();
707 std::optional<APInt> rhsConst = rhs.getConstantValue();
708 return lhsConst && rhsConst && lhsConst == rhsConst;
744 APInt zero = APInt::getZero(width);
745 APInt typeMax = APInt::getSignedMaxValue(width);
747 auto shapedTy = cast<ShapedType>(op.getShapedValue().getType());
748 if (!shapedTy.hasRank())
751 int64_t rank = shapedTy.getRank();
756 minDim = std::max(minDim, dim.
smin().getSExtValue());
757 maxDim = std::min(maxDim, dim.
smax().getSExtValue());
760 std::optional<ConstantIntRanges>
result;
767 for (
int64_t i = minDim; i <= maxDim; ++i) {
768 int64_t length = shapedTy.getDimSize(i);
770 if (ShapedType::isDynamic(length))
783 unsigned width = val.
smin().getBitWidth();
785 APInt clampedUMin = val.
umin().ult(one) ? one : val.
umin();
786 APInt clampedSMin = val.
smin().slt(one) ? one : val.
smin();
797 auto constExpr = cast<AffineConstantExpr>(expr);
802 auto dimExpr = cast<AffineDimExpr>(expr);
803 unsigned pos = dimExpr.getPosition();
804 assert(pos < dimRanges.size() &&
"Dimension index out of bounds");
805 return dimRanges[pos];
808 auto symbolExpr = cast<AffineSymbolExpr>(expr);
809 unsigned pos = symbolExpr.getPosition();
810 assert(pos < symbolRanges.size() &&
"Symbol index out of bounds");
811 return symbolRanges[pos];
814 auto binExpr = cast<AffineBinaryOpExpr>(expr);
819 std::array<ConstantIntRanges, 2> operands = {std::move(lhs),
824 auto binExpr = cast<AffineBinaryOpExpr>(expr);
829 std::array<ConstantIntRanges, 2> operands = {std::move(lhs),
834 auto binExpr = cast<AffineBinaryOpExpr>(expr);
841 const APInt &lhsMin = lhs.smin();
842 const APInt &lhsMax = lhs.smax();
843 const APInt &rhsMin = rhs.smin();
844 const APInt &rhsMax = rhs.smax();
845 unsigned width = rhsMin.getBitWidth();
852 APInt umin = APInt::getZero(width);
853 APInt umax = rhsMax - 1;
858 if (rhsMin.isStrictlyPositive() && lhsMin.isNonNegative() &&
859 lhsMax.ult(rhsMin)) {
866 else if (rhsMin == rhsMax && lhsMin.isNonNegative() &&
867 (lhsMax - lhsMin).ult(rhsMax) &&
868 lhsMin.udiv(rhsMax) == lhsMax.udiv(rhsMax)) {
872 umin = lhsMin.urem(rhsMax);
873 umax = lhsMax.urem(rhsMax);
875 assert(umin.ule(umax) &&
876 "Range should be contiguous for non-negative dividend");
882 auto binExpr = cast<AffineBinaryOpExpr>(expr);
890 std::array<ConstantIntRanges, 2> operands = {std::move(lhs),
891 std::move(clampedRhs)};
895 auto binExpr = cast<AffineBinaryOpExpr>(expr);
903 std::array<ConstantIntRanges, 2> operands = {std::move(lhs),
904 std::move(clampedRhs)};
908 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