32 const auto &half = field.
half();
34 if (lhs < half && rhs < half) {
36 }
else if (lhs < half) {
42 if (lhs >= half && rhs < half) {
51 const auto &lhs = *
this;
56 const auto &lhs = *
this;
64 DynamicAPInt bound = rhs.b - 1;
79 DynamicAPInt bound = rhs.a + 1;
98 DynamicAPInt low = lhs.a + rhs.a, high = lhs.b + rhs.b;
107 DynamicAPInt v1 = lhs.a * rhs.a;
108 DynamicAPInt v2 = lhs.a * rhs.b;
109 DynamicAPInt v3 = lhs.b * rhs.a;
110 DynamicAPInt v4 = lhs.b * rhs.b;
112 auto minVal = std::min({v1, v2, v3, v4});
113 auto maxVal = std::max({v1, v2, v3, v4});
123 if ((lhs.a < rhs.a) || ((lhs.a == rhs.a) && (lhs.b < rhs.b))) {
124 return std::strong_ordering::less;
126 if ((lhs.a > rhs.a) || ((lhs.a == rhs.a) && (lhs.b > rhs.b))) {
127 return std::strong_ordering::greater;
129 return std::strong_ordering::equal;
141 ensure(w >= 0,
"cannot have negative width");
149 lhs.
getField() == rhs.
getField(),
"interval operations across differing fields is unsupported"
179 const auto &
lhs = *
this;
183 if (
lhs.isEntire() ||
rhs.isEntire()) {
192 if (
lhs.isDegenerate() ||
rhs.isDegenerate()) {
193 return lhs.toUnreduced().doUnion(
rhs.toUnreduced()).reduce(f);
203 auto lhsUnred =
lhs.firstUnreduced();
204 auto opt1 =
rhs.firstUnreduced().doUnion(lhsUnred);
205 auto opt2 =
rhs.secondUnreduced().doUnion(lhsUnred);
206 if (opt1.width() <= opt2.width()) {
207 return opt1.reduce(f);
209 return opt2.reduce(f);
212 return lhs.firstUnreduced().doUnion(
rhs.firstUnreduced()).reduce(f);
215 return lhs.secondUnreduced().doUnion(
rhs.firstUnreduced()).reduce(f);
227 llvm::report_fatal_error(
"unhandled join case");
232 const auto &
lhs = *
this;
235 if (
lhs.isEmpty() ||
rhs.isEmpty()) {
238 if (
lhs.isEntire()) {
241 if (
rhs.isEntire()) {
244 if (
lhs.isDegenerate() ||
rhs.isDegenerate()) {
245 return lhs.toUnreduced().intersect(
rhs.toUnreduced()).reduce(f);
252 auto maxA = std::max(
lhs.a,
rhs.a);
253 auto minB = std::min(
lhs.b,
rhs.b);
264 return lhs.firstUnreduced().intersect(
rhs.firstUnreduced()).reduce(f);
267 return lhs.secondUnreduced().intersect(
rhs.firstUnreduced()).reduce(f);
270 auto rhsUnred =
rhs.firstUnreduced();
271 auto opt1 =
lhs.firstUnreduced().intersect(rhsUnred).reduce(f);
272 auto opt2 =
lhs.secondUnreduced().intersect(rhsUnred).reduce(f);
273 ensure(!opt1.isEntire() && !opt2.isEntire(),
"impossible intersection");
274 if (opt1.isEmpty()) {
277 if (opt2.isEmpty()) {
280 return opt1.join(opt2);
287 return rhs.intersect(
lhs);
308 if (other.a == f.
zero()) {
311 if (other.b == f.
maxVal()) {
368 return (
lhs.firstUnreduced() +
rhs.firstUnreduced()).reduce(f);
376 if (
lhs == zeroInterval ||
rhs == zeroInterval) {
379 if (
lhs.isEmpty() ||
rhs.isEmpty()) {
382 if (
lhs.isEntire() ||
rhs.isEntire()) {
387 return (
lhs.secondUnreduced() *
rhs.secondUnreduced()).reduce(f);
389 return (
lhs.firstUnreduced() *
rhs.firstUnreduced()).reduce(f);
394 if (
rhs.width() > f.
one()) {
410 if (
lhs.isEmpty() ||
rhs.isEmpty()) {
413 if (
lhs.isDegenerate() &&
rhs.isDegenerate()) {
415 }
else if (
lhs.isDegenerate()) {
417 }
else if (
rhs.isDegenerate()) {
425 if (
lhs.isEmpty() ||
rhs.isEmpty()) {
428 if (
lhs.isDegenerate() &&
rhs.isDegenerate()) {
433 DynamicAPInt v =
lhs.a <<
rhs.a;
441 if (
lhs.isEmpty() ||
rhs.isEmpty()) {
444 if (
lhs.isDegenerate() &&
rhs.isDegenerate()) {
457 return field.get().zero();
459 return field.get().one();
461 return field.get().prime();
469 lhs.getField() ==
rhs.getField(),
"interval operations across differing fields is unsupported"
471 ensure(
lhs.isBoolean() &&
rhs.isBoolean(),
"operation only supported for boolean-type intervals");
472 const auto &field =
rhs.getField();
474 if (
lhs.isBoolFalse() ||
rhs.isBoolFalse()) {
477 if (
lhs.isBoolTrue() &&
rhs.isBoolTrue()) {
486 lhs.getField() ==
rhs.getField(),
"interval operations across differing fields is unsupported"
488 ensure(
lhs.isBoolean() &&
rhs.isBoolean(),
"operation only supported for boolean-type intervals");
489 const auto &field =
rhs.getField();
491 if (
lhs.isBoolFalse() &&
rhs.isBoolFalse()) {
494 if (
lhs.isBoolTrue() ||
rhs.isBoolTrue()) {
503 lhs.getField() ==
rhs.getField(),
"interval operations across differing fields is unsupported"
505 ensure(
lhs.isBoolean() &&
rhs.isBoolean(),
"operation only supported for boolean-type intervals");
506 const auto &field =
rhs.getField();
510 if (
lhs.isBoolEither() ||
rhs.isBoolEither()) {
514 if (
lhs.isBoolTrue() &&
rhs.isBoolTrue()) {
517 if (
lhs.isBoolTrue() ||
rhs.isBoolTrue()) {
520 if (
lhs.isBoolFalse() &&
rhs.isBoolFalse()) {
528 ensure(iv.
isBoolean(),
"operation only supported for boolean-type intervals");
544 os <<
'(' << a <<
')';
546 os <<
":[ " << a <<
", " << b <<
" ]";
This file implements helper methods for constructing DynamicAPInts.
Information about the prime finite field used for the interval analysis.
llvm::DynamicAPInt half() const
Returns p / 2.
llvm::DynamicAPInt zero() const
Returns 0 at the bitwidth of the field.
llvm::DynamicAPInt prime() const
For the prime field p, returns p.
llvm::DynamicAPInt reduce(const llvm::DynamicAPInt &i) const
Returns i mod p and reduces the result into the appropriate bitwidth.
llvm::DynamicAPInt one() const
Returns 1 at the bitwidth of the field.
unsigned bitWidth() const
llvm::DynamicAPInt maxVal() const
Returns p - 1, which is the max value possible in a prime field described by p.
Intervals over a finite field.
static Interval True(const Field &f)
llvm::DynamicAPInt rhs() const
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.
static Interval False(const Field &f)
Interval operator~() const
llvm::DynamicAPInt lhs() const
static bool areOneOf(const Interval &a, const Interval &b)
Interval()
To satisfy the dataflow::ScalarLatticeValue requirements, this class must be default initializable.
llvm::DynamicAPInt width() const
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.
UnreducedInterval(const llvm::DynamicAPInt &x, const llvm::DynamicAPInt &y)
bool isEmpty() const
Returns true iff width() is zero.
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
llvm::DynamicAPInt width() const
Compute the width of this interval within a given field f.
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.
void ensure(bool condition, const llvm::Twine &errMsg)
FailureOr< Interval > operator/(const Interval &lhs, const Interval &rhs)
Interval operator%(const Interval &lhs, const Interval &rhs)
Interval operator<<(const Interval &lhs, const Interval &rhs)
std::strong_ordering operator<=>(const UnreducedInterval &lhs, const UnreducedInterval &rhs)
UnreducedInterval operator-(const UnreducedInterval &lhs, const UnreducedInterval &rhs)
Interval operator>>(const Interval &lhs, const Interval &rhs)
Interval operator&(const Interval &lhs, const Interval &rhs)
ExpressionValue boolXor(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
UnreducedInterval operator*(const UnreducedInterval &lhs, const UnreducedInterval &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)
ExpressionValue boolOr(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs)
ExpressionValue boolAnd(llvm::SMTSolverRef solver, const ExpressionValue &lhs, const ExpressionValue &rhs)