10#define DEBUG_TYPE "cex-solver"
19#include "klee/Support/Debug.h"
22#include "llvm/Support/raw_ostream.h"
32static uint64_t
minOR(uint64_t a, uint64_t b,
33 uint64_t c, uint64_t d) {
34 uint64_t temp, m = ((uint64_t) 1)<<63;
38 if (temp <= b) { a = temp;
break; }
39 }
else if (a & ~c & m) {
41 if (temp <= d) { c = temp;
break; }
48static uint64_t
maxOR(uint64_t a, uint64_t b,
49 uint64_t c, uint64_t d) {
50 uint64_t temp, m = ((uint64_t) 1)<<63;
54 temp = (b - m) | (m - 1);
55 if (temp >= a) { b = temp;
break; }
56 temp = (d - m) | (m -1);
57 if (temp >= c) { d = temp;
break; }
64static uint64_t
minAND(uint64_t a, uint64_t b,
65 uint64_t c, uint64_t d) {
66 uint64_t temp, m = ((uint64_t) 1)<<63;
70 if (temp <= b) { a = temp;
break; }
72 if (temp <= d) { c = temp;
break; }
79static uint64_t
maxAND(uint64_t a, uint64_t b,
80 uint64_t c, uint64_t d) {
81 uint64_t temp, m = ((uint64_t) 1)<<63;
84 temp = (b & ~m) | (m - 1);
85 if (temp >= a) { b = temp;
break; }
86 }
else if (~b & d & m) {
87 temp = (d & ~m) | (m - 1);
88 if (temp >= c) { d = temp;
break; }
117 void print(llvm::raw_ostream &os)
const {
243 bool mayEqual(
const std::uint64_t b)
const noexcept {
244 return m_min <= b && m_max >= b;
252 std::uint64_t
min() const noexcept {
253 assert(!
isEmpty() &&
"cannot get minimum of empty range");
257 std::uint64_t
max() const noexcept {
258 assert(!
isEmpty() &&
"cannot get maximum of empty range");
263 assert((
m_min >> bits) == 0 && (
m_max >> bits) == 0 &&
264 "range is outside given number of bits");
270 std::uint64_t smallest = (
static_cast<std::uint64_t
>(1) << (bits - 1));
271 if (
m_max >= smallest) {
279 assert((
m_min >> bits) == 0 && (
m_max >> bits) == 0 &&
280 "range is outside given number of bits");
282 std::uint64_t smallest = (
static_cast<std::uint64_t
>(1) << (bits - 1));
288 if (m_min < smallest && m_max >= smallest) {
323 for (uint64_t i = 0; i != size; ++i) {
349 return cvd.
min() + (cvd.
max() - cvd.
min()) / 2;
355 std::map<const Array*, CexObjectData*> &
objects;
375 if (index >= array.
size)
376 return ReadExpr::create(
UpdateList(&array, 0),
377 ConstantExpr::alloc(index, array.
getDomain()));
379 std::map<const Array*, CexObjectData*>::iterator it =
objects.find(&array);
380 return ConstantExpr::alloc((it ==
objects.end() ? 127 :
381 it->second->getPossibleValue(index)),
386 std::map<const Array*, CexObjectData*> &
objects;
396 if (index >= array.
size)
397 return ReadExpr::create(
UpdateList(&array, 0),
398 ConstantExpr::alloc(index, array.
getDomain()));
400 std::map<const Array*, CexObjectData*>::iterator it =
objects.find(&array);
402 return ReadExpr::create(
UpdateList(&array, 0),
403 ConstantExpr::alloc(index, array.
getDomain()));
407 return ReadExpr::create(
UpdateList(&array, 0),
408 ConstantExpr::alloc(index, array.
getDomain()));
410 return ConstantExpr::alloc(cvd.
min(), array.
getRange());
414 std::map<const Array*, CexObjectData*> &
objects;
421 std::map<const Array*, CexObjectData*>
objects;
429 for (std::map<const Array*, CexObjectData*>::iterator it =
objects.begin(),
430 ie =
objects.end(); it != ie; ++it)
452 KLEE_DEBUG(llvm::errs() <<
"propogate: " << range <<
" for\n"
463 case Expr::NotOptimized:
break;
473 uint64_t index = CE->getZExtValue();
475 if (index < array->size) {
546 range.
extract(LSBWidth, LSBWidth + MSBWidth));
551 case Expr::Extract: {
577 unsigned outBits = ce->
width;
593 if (CE->getWidth() <= 64) {
601 CexValueData nrange(ConstantExpr::alloc(range.
min(), W)->Sub(CE)->getZExtValue(),
602 ConstantExpr::alloc(range.
max(), W)->Sub(CE)->getZExtValue());
673 case Expr::Xor:
break;
682 if (CE->getWidth() <= 64) {
683 uint64_t value = CE->getZExtValue();
784 assert(0 &&
"invalid expressions (uncanonicalized");
793 case Expr::Constant: {
800 case Expr::NotOptimized:
break;
808 for (
const auto *un = re->
updates.
head.get(); un; un = un->next.get()) {
829 if (range.
min() > cvd.
min()) {
830 assert(range.
min() <= cvd.
max());
833 if (range.
max() < cvd.
max()) {
834 assert(range.
max() >= cvd.
min());
851 case Expr::Extract: {
886 if (CE->getWidth() <= 64) {
887 uint64_t value = CE->getZExtValue();
924 assert(0 &&
"invalid expressions (uncanonicalized");
947 llvm::errs() <<
"-- propogated values --\n";
948 for (std::map<const Array *, CexObjectData *>::iterator
952 const Array *
A = it->first;
955 llvm::errs() <<
A->name <<
"\n";
956 llvm::errs() <<
"possible: [";
957 for (
unsigned i = 0; i <
A->size; ++i) {
959 llvm::errs() <<
", ";
962 llvm::errs() <<
"]\n";
963 llvm::errs() <<
"exact : [";
964 for (
unsigned i = 0; i <
A->size; ++i) {
966 llvm::errs() <<
", ";
969 llvm::errs() <<
"]\n";
985 const std::vector<const Array*> &objects,
986 std::vector< std::vector<unsigned char> > &values,
1009 bool checkExpr,
bool &isValid) {
1010 for (
const auto &constraint : query.
constraints) {
1019 KLEE_DEBUG(cd.
dump());
1022 bool hasSatisfyingAssignment =
true;
1025 hasSatisfyingAssignment =
false;
1034 for (
const auto &constraint : query.
constraints) {
1036 hasSatisfyingAssignment =
false;
1046 if (hasSatisfyingAssignment) {
1062 return IncompleteSolver::None;
1064 return isValid ? IncompleteSolver::MustBeTrue : IncompleteSolver::MayBeFalse;
1084 if (isa<ConstantExpr>(value)) {
1095 const std::vector<const Array*>
1097 std::vector< std::vector<unsigned char> >
1099 bool &hasSolution) {
1109 hasSolution = !isValid;
1114 for (
unsigned i = 0; i != objects.size(); ++i) {
1115 const Array *array = objects[i];
1117 std::vector<unsigned char> data;
1118 data.reserve(array->
size);
1120 for (
unsigned i=0; i < array->
size; i++) {
1123 ConstantExpr::create(i, array->
getDomain()));
1126 if (
ConstantExpr *CE = dyn_cast<ConstantExpr>(value)) {
1127 data.push_back((
unsigned char) CE->getZExtValue(8));
1134 values.push_back(data);
std::vector< ref< Expr > >::iterator A
static uint64_t maxAND(uint64_t a, uint64_t b, uint64_t c, uint64_t d)
static uint64_t minOR(uint64_t a, uint64_t b, uint64_t c, uint64_t d)
static bool propogateValues(const Query &query, CexData &cd, bool checkExpr, bool &isValid)
static uint64_t minAND(uint64_t a, uint64_t b, uint64_t c, uint64_t d)
static uint64_t maxOR(uint64_t a, uint64_t b, uint64_t c, uint64_t d)
llvm::raw_ostream & operator<<(llvm::raw_ostream &os, const ValueRange &vr)
ValueRange evalRangeForExpr(const ref< Expr > &e)
void propogatePossibleValue(ref< Expr > e, uint64_t value)
ref< Expr > evaluateExact(ref< Expr > e)
ref< Expr > evaluatePossible(ref< Expr > e)
void propogateExactValue(ref< Expr > e, uint64_t value)
void propogateExactValues(ref< Expr > e, CexValueData range)
void propogatePossibleValues(ref< Expr > e, CexValueData range)
std::map< const Array *, CexObjectData * > objects
CexObjectData & getObjectData(const Array *A)
void operator=(const CexData &)
std::map< const Array *, CexObjectData * > & objects
ref< Expr > getInitialValue(const Array &array, unsigned index)
CexExactEvaluator(std::map< const Array *, CexObjectData * > &_objects)
std::vector< CexValueData > exactContents
void operator=(const CexObjectData &)
void setExactValues(size_t index, CexValueData values)
const CexValueData getExactValues(size_t index) const
CexObjectData(const CexObjectData &)
void setPossibleValue(size_t index, unsigned char value)
void setPossibleValues(size_t index, CexValueData values)
std::vector< CexValueData > possibleContents
CexObjectData(uint64_t size)
unsigned char getPossibleValue(size_t index) const
getPossibleValue - Return some possible value.
const CexValueData getPossibleValues(size_t index) const
CexPossibleEvaluator(std::map< const Array *, CexObjectData * > &_objects)
std::map< const Array *, CexObjectData * > & objects
ref< Expr > getInitialValue(const Array &array, unsigned index)
CexRangeEvaluator(std::map< const Array *, CexObjectData * > &_objects)
ValueRange getInitialReadRange(const Array &array, ValueRange index)
std::map< const Array *, CexObjectData * > & objects
bool computeValue(const Query &, ref< Expr > &result)
computeValue - Attempt to compute a value for the given expression.
bool computeInitialValues(const Query &, const std::vector< const Array * > &objects, std::vector< std::vector< unsigned char > > &values, bool &hasSolution)
IncompleteSolver::PartialValidity computeTruth(const Query &)
bool isFixed() const noexcept
std::int64_t maxSigned(unsigned bits) const
ValueRange binaryOr(ValueRange b) const
ValueRange srem(const ValueRange &b, unsigned width) const
std::uint64_t min() const noexcept
std::uint64_t max() const noexcept
ValueRange & operator=(const ValueRange &other) noexcept=default
ValueRange binaryAnd(std::uint64_t b) const
ValueRange() noexcept=default
ValueRange(ValueRange &&other) noexcept=default
bool mayEqual(const ValueRange &b) const
ValueRange & operator=(ValueRange &&other) noexcept=default
ValueRange sdiv(const ValueRange &b, unsigned width) const
ValueRange urem(const ValueRange &b, unsigned width) const
ValueRange(std::uint64_t value) noexcept
ValueRange(const ValueRange &other) noexcept=default
ValueRange udiv(const ValueRange &b, unsigned width) const
bool intersects(const ValueRange &b) const
bool operator!=(const ValueRange &b) const noexcept
bool isEmpty() const noexcept
bool operator==(const ValueRange &b) const noexcept
ValueRange set_union(const ValueRange &b) const
ValueRange binaryXor(ValueRange b) const
ValueRange(std::uint64_t _min, std::uint64_t _max) noexcept
ValueRange binaryShiftRight(unsigned bits) const
std::int64_t minSigned(unsigned bits) const
ValueRange mul(const ValueRange &b, unsigned width) const
ValueRange sub(const ValueRange &b, unsigned width) const
ValueRange extract(std::uint64_t lowBit, std::uint64_t maxBit) const
ValueRange add(const ValueRange &b, unsigned width) const
ValueRange set_difference(const ValueRange &b) const
bool isFullRange(unsigned bits) const noexcept
bool mustEqual(const std::uint64_t b) const noexcept
ValueRange concat(const ValueRange &b, unsigned bits) const
ValueRange binaryShiftLeft(unsigned bits) const
void print(llvm::raw_ostream &os) const
ValueRange set_intersection(const ValueRange &b) const
ValueRange binaryAnd(const ValueRange &b) const
ValueRange binaryOr(std::uint64_t b) const
bool mayEqual(const std::uint64_t b) const noexcept
bool mustEqual(const ValueRange &b) const noexcept
bool contains(std::uint64_t value) const
Expr::Width getRange() const
bool isConstantArray() const
const std::vector< ref< ConstantExpr > > constantValues
Expr::Width getDomain() const
ref< Expr > getKid(unsigned i) const
T evaluate(const ref< Expr > &e)
ref< Expr > visit(const ref< Expr > &e)
virtual Kind getKind() const =0
virtual Width getWidth() const =0
unsigned Width
The type of an expression is simply its width, in bits.
bool isFalse() const
isFalse - Is this the false expression.
bool isTrue() const
isTrue - Is this the true expression.
virtual ref< Expr > getKid(unsigned i) const =0
Class representing a one byte read from an array.
Class representing an if-then-else expression.
Class representing a complete list of updates into an array.
ref< UpdateNode > head
pointer to the most recent update node
unsigned withoutRightmostBit(unsigned x)
unsigned maxValueOfNBits(unsigned N)
unsigned isPowerOfTwo(unsigned x)
uint64_t sext(uint64_t l, unsigned outWidth, unsigned inWidth)
Solver * createFastCexSolver(Solver *s)
const ConstraintSet & constraints