30 if ((rhs - lhs).isZero()) {
34 const auto &half = field.
half();
36 if (lhs.ult(half) && rhs.ult(half)) {
38 }
else if (lhs.ult(half)) {
44 if (lhs.uge(half) && rhs.ult(half)) {
66 auto one = llvm::APSInt(llvm::APInt(a.getBitWidth(), 1));
82 auto one = llvm::APSInt(llvm::APInt(a.getBitWidth(), 1));
116 auto minVal =
safeMin({v1, v2, v3, v4});
117 auto maxVal =
safeMax({v1, v2, v3, v4});
128 return std::strong_ordering::less;
131 return std::strong_ordering::greater;
133 return std::strong_ordering::equal;
140 w = llvm::APSInt::getUnsigned(0);
145 ensure(
safeGe(w, llvm::APSInt::getUnsigned(0)),
"cannot have negative width");
155 lhs.
getField() == rhs.
getField(),
"interval operations across differing fields is unsupported"
189 if (
lhs.isEntire() ||
rhs.isEntire()) {
198 if (
lhs.isDegenerate() ||
rhs.isDegenerate()) {
199 return lhs.toUnreduced().doUnion(
rhs.toUnreduced()).reduce(f);
209 auto lhsUnred =
lhs.firstUnreduced();
210 auto opt1 =
rhs.firstUnreduced().doUnion(lhsUnred);
211 auto opt2 =
rhs.secondUnreduced().doUnion(lhsUnred);
212 if (opt1.width() <= opt2.width()) {
213 return opt1.reduce(f);
215 return opt2.reduce(f);
218 return lhs.firstUnreduced().doUnion(
rhs.firstUnreduced()).reduce(f);
221 return lhs.secondUnreduced().doUnion(
rhs.firstUnreduced()).reduce(f);
233 llvm::report_fatal_error(
"unhandled join case");
241 if (
lhs.isEmpty() ||
rhs.isEmpty()) {
244 if (
lhs.isEntire()) {
247 if (
rhs.isEntire()) {
250 if (
lhs.isDegenerate() ||
rhs.isDegenerate()) {
251 return lhs.toUnreduced().intersect(
rhs.toUnreduced()).reduce(f);
258 auto maxA = std::max(
lhs.a,
rhs.a);
259 auto minB = std::min(
lhs.b,
rhs.b);
270 return lhs.firstUnreduced().intersect(
rhs.firstUnreduced()).reduce(f);
273 return lhs.secondUnreduced().intersect(
rhs.firstUnreduced()).reduce(f);
276 auto rhsUnred =
rhs.firstUnreduced();
277 auto opt1 =
lhs.firstUnreduced().intersect(rhsUnred).reduce(f);
278 auto opt2 =
lhs.secondUnreduced().intersect(rhsUnred).reduce(f);
279 ensure(!opt1.isEntire() && !opt2.isEntire(),
"impossible intersection");
280 if (opt1.isEmpty()) {
283 if (opt2.isEmpty()) {
286 return opt1.join(opt2);
293 return rhs.intersect(
lhs);
314 if (other.a == f.
zero()) {
317 if (other.b == f.
maxVal()) {
374 return (
lhs.firstUnreduced() +
rhs.firstUnreduced()).reduce(f);
382 if (
lhs == zeroInterval ||
rhs == zeroInterval) {
385 if (
lhs.isEmpty() ||
rhs.isEmpty()) {
388 if (
lhs.isEntire() ||
rhs.isEntire()) {
393 return (
lhs.secondUnreduced() *
rhs.secondUnreduced()).reduce(f);
395 return (
lhs.firstUnreduced() *
rhs.firstUnreduced()).reduce(f);
400 if (
rhs.width() > f.
one()) {
403 if (
rhs.a.isZero()) {
416 if (
lhs.isEmpty() ||
rhs.isEmpty()) {
419 if (
lhs.isDegenerate() &&
rhs.isDegenerate()) {
421 }
else if (
lhs.isDegenerate()) {
423 }
else if (
rhs.isDegenerate()) {
431 if (
lhs.isEmpty() ||
rhs.isEmpty()) {
434 if (
lhs.isDegenerate() &&
rhs.isDegenerate()) {
439 unsigned shiftAmt =
rhs.a.getZExtValue();
440 auto v =
lhs.a.relativeShl(shiftAmt);
448 if (
lhs.isEmpty() ||
rhs.isEmpty()) {
451 if (
lhs.isDegenerate() &&
rhs.isDegenerate()) {
456 unsigned shiftAmt =
rhs.a.getZExtValue();
465 return field.get().zero();
467 return field.get().one();
469 return field.get().prime();
477 lhs.getField() ==
rhs.getField(),
"interval operations across differing fields is unsupported"
479 ensure(
lhs.isBoolean() &&
rhs.isBoolean(),
"operation only supported for boolean-type intervals");
480 const auto &field =
rhs.getField();
482 if (
lhs.isBoolFalse() ||
rhs.isBoolFalse()) {
485 if (
lhs.isBoolTrue() &&
rhs.isBoolTrue()) {
494 lhs.getField() ==
rhs.getField(),
"interval operations across differing fields is unsupported"
496 ensure(
lhs.isBoolean() &&
rhs.isBoolean(),
"operation only supported for boolean-type intervals");
497 const auto &field =
rhs.getField();
499 if (
lhs.isBoolFalse() &&
rhs.isBoolFalse()) {
502 if (
lhs.isBoolTrue() ||
rhs.isBoolTrue()) {
511 lhs.getField() ==
rhs.getField(),
"interval operations across differing fields is unsupported"
513 ensure(
lhs.isBoolean() &&
rhs.isBoolean(),
"operation only supported for boolean-type intervals");
514 const auto &field =
rhs.getField();
518 if (
lhs.isBoolEither() ||
rhs.isBoolEither()) {
522 if (
lhs.isBoolTrue() &&
rhs.isBoolTrue()) {
525 if (
lhs.isBoolTrue() ||
rhs.isBoolTrue()) {
528 if (
lhs.isBoolFalse() &&
rhs.isBoolFalse()) {
536 ensure(iv.
isBoolean(),
"operation only supported for boolean-type intervals");
552 os <<
'(' << a <<
')';
554 os <<
":[ " << a <<
", " << b <<
" ]";
This file defines helpers for manipulating APInts/APSInts for large numbers and operations over those...
Information about the prime finite field used for the interval analysis.
llvm::APSInt one() const
Returns 1 at the bitwidth of the field.
llvm::APSInt zero() const
Returns 0 at the bitwidth of the field.
llvm::APSInt half() const
Returns p / 2.
unsigned bitWidth() const
llvm::APSInt maxVal() const
Returns p - 1, which is the max value possible in a prime field described by p.
llvm::APSInt prime() const
For the prime field p, returns p.
llvm::APSInt reduce(llvm::APSInt i) const
Returns i mod p and reduces the result into the appropriate bitwidth.
Intervals over a finite field.
static Interval True(const Field &f)
Interval intersect(const Interval &rhs) const
Intersect.
static std::string_view TypeName(Type t)
void print(llvm::raw_ostream &os) const
UnreducedInterval toUnreduced() const
Convert to an UnreducedInterval.
static Interval Boolean(const Field &f)
UnreducedInterval firstUnreduced() const
Get the first side of the interval for TypeF intervals, otherwise just get the full interval as an Un...
bool isDegenerate() const
const Field & getField() const
UnreducedInterval secondUnreduced() const
Get the second side of the interval for TypeA, TypeB, and TypeC intervals.
llvm::APSInt width() const
static Interval False(const Field &f)
Interval operator~() const
static bool areOneOf(const Interval &a, const Interval &b)
Interval()
To satisfy the dataflow::ScalarLatticeValue requirements, this class must be default initializable.
Interval difference(const Interval &other) const
Computes and returns this - (this & other) if the operation produces a single interval.
Interval operator-() const
Interval join(const Interval &rhs) const
Union.
An inclusive interval [a, b] where a and b are arbitrary integers not necessarily bound to a given fi...
UnreducedInterval operator-() const
UnreducedInterval intersect(const UnreducedInterval &rhs) const
Compute and return the intersection of this interval and the given RHS.
bool isEmpty() const
Returns true iff width() is zero.
UnreducedInterval(llvm::APSInt x, llvm::APSInt y)
llvm::APSInt width() const
Compute the width of this interval within a given field f.
UnreducedInterval computeLTPart(const UnreducedInterval &rhs) const
Return the part of the interval that is guaranteed to be less than the rhs's max value.
UnreducedInterval computeGEPart(const UnreducedInterval &rhs) const
Return the part of the interval that is greater than or equal to the rhs's lower bound.
bool overlaps(const UnreducedInterval &rhs) const
UnreducedInterval doUnion(const UnreducedInterval &rhs) const
Compute and return the union of this interval and the given RHS.
UnreducedInterval computeGTPart(const UnreducedInterval &rhs) const
Return the part of the interval that is greater than the rhs's lower bound.
Interval reduce(const Field &field) const
Reduce the interval to an interval in the given field.
UnreducedInterval computeLEPart(const UnreducedInterval &rhs) const
Return the part of the interval that is less than or equal to the rhs's upper bound.
llvm::APSInt safeMax(const llvm::APSInt &lhs, const llvm::APSInt &rhs)
FailureOr< Interval > operator/(const Interval &lhs, const Interval &rhs)
Interval operator%(const Interval &lhs, const Interval &rhs)
llvm::APSInt expandingAdd(llvm::APSInt lhs, llvm::APSInt rhs)
Safely add lhs and rhs, expanding the width of the result as necessary.
void ensure(bool condition, llvm::Twine errMsg)
std::strong_ordering operator<=>(const UnreducedInterval &lhs, const UnreducedInterval &rhs)
llvm::APSInt expandingSub(llvm::APSInt lhs, llvm::APSInt rhs)
Safely subtract lhs and rhs, expanding the width of the result as necessary.
UnreducedInterval operator-(const UnreducedInterval &lhs, const UnreducedInterval &rhs)
bool safeGt(const llvm::APSInt &lhs, const llvm::APSInt &rhs)
bool safeEq(const llvm::APSInt &lhs, const llvm::APSInt &rhs)
Interval operator>>(const Interval &lhs, const Interval &rhs)
bool safeLt(const llvm::APSInt &lhs, const llvm::APSInt &rhs)
Interval operator&(const Interval &lhs, const Interval &rhs)
ExpressionValue boolXor(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
llvm::APSInt expandingMul(llvm::APSInt lhs, llvm::APSInt rhs)
Safely multiple lhs and rhs, expanding the width of the result as necessary.
raw_ostream & operator<<(raw_ostream &os, const ConstrainRef &rhs)
bool safeLe(const llvm::APSInt &lhs, const llvm::APSInt &rhs)
UnreducedInterval operator*(const UnreducedInterval &lhs, const UnreducedInterval &rhs)
bool safeGe(const llvm::APSInt &lhs, const llvm::APSInt &rhs)
ExpressionValue intersection(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
const Field & checkFields(const Interval &lhs, const Interval &rhs)
UnreducedInterval operator+(const UnreducedInterval &lhs, const UnreducedInterval &rhs)
ExpressionValue boolNot(llvm::SMTSolverRef solver, const ExpressionValue &val)
llvm::APSInt safeMin(const llvm::APSInt &lhs, const llvm::APSInt &rhs)
ExpressionValue boolOr(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
ExpressionValue boolAnd(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs)