aboutsummaryrefslogtreecommitdiffhomepage
path: root/lib/Solver
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Solver')
-rw-r--r--lib/Solver/CachingSolver.cpp241
-rw-r--r--lib/Solver/CexCachingSolver.cpp313
-rw-r--r--lib/Solver/ConstantDivision.cpp146
-rw-r--r--lib/Solver/ConstantDivision.h51
-rw-r--r--lib/Solver/FastCexSolver.cpp959
-rw-r--r--lib/Solver/IncompleteSolver.cpp136
-rw-r--r--lib/Solver/IndependentSolver.cpp314
-rwxr-xr-xlib/Solver/Makefile16
-rw-r--r--lib/Solver/PCLoggingSolver.cpp134
-rw-r--r--lib/Solver/STPBuilder.cpp819
-rw-r--r--lib/Solver/STPBuilder.h125
-rw-r--r--lib/Solver/Solver.cpp643
-rw-r--r--lib/Solver/SolverStats.cpp23
-rw-r--r--lib/Solver/SolverStats.h32
14 files changed, 3952 insertions, 0 deletions
diff --git a/lib/Solver/CachingSolver.cpp b/lib/Solver/CachingSolver.cpp
new file mode 100644
index 00000000..517e133b
--- /dev/null
+++ b/lib/Solver/CachingSolver.cpp
@@ -0,0 +1,241 @@
+//===-- CachingSolver.cpp - Caching expression solver ---------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "klee/Solver.h"
+
+#include "klee/Constraints.h"
+#include "klee/Expr.h"
+#include "klee/IncompleteSolver.h"
+#include "klee/SolverImpl.h"
+
+#include "SolverStats.h"
+
+#include <tr1/unordered_map>
+
+using namespace klee;
+
+class CachingSolver : public SolverImpl {
+private:
+ ref<Expr> canonicalizeQuery(ref<Expr> originalQuery,
+ bool &negationUsed);
+
+ void cacheInsert(const Query& query,
+ IncompleteSolver::PartialValidity result);
+
+ bool cacheLookup(const Query& query,
+ IncompleteSolver::PartialValidity &result);
+
+ struct CacheEntry {
+ CacheEntry(const ConstraintManager &c, ref<Expr> q)
+ : constraints(c), query(q) {}
+
+ CacheEntry(const CacheEntry &ce)
+ : constraints(ce.constraints), query(ce.query) {}
+
+ ConstraintManager constraints;
+ ref<Expr> query;
+
+ bool operator==(const CacheEntry &b) const {
+ return constraints==b.constraints && *query.get()==*b.query.get();
+ }
+ };
+
+ struct CacheEntryHash {
+ unsigned operator()(const CacheEntry &ce) const {
+ unsigned result = ce.query.hash();
+
+ for (ConstraintManager::constraint_iterator it = ce.constraints.begin();
+ it != ce.constraints.end(); ++it)
+ result ^= it->hash();
+
+ return result;
+ }
+ };
+
+ typedef std::tr1::unordered_map<CacheEntry,
+ IncompleteSolver::PartialValidity,
+ CacheEntryHash> cache_map;
+
+ Solver *solver;
+ cache_map cache;
+
+public:
+ CachingSolver(Solver *s) : solver(s) {}
+ ~CachingSolver() { cache.clear(); delete solver; }
+
+ bool computeValidity(const Query&, Solver::Validity &result);
+ bool computeTruth(const Query&, bool &isValid);
+ bool computeValue(const Query& query, ref<Expr> &result) {
+ return solver->impl->computeValue(query, result);
+ }
+ bool computeInitialValues(const Query& query,
+ const std::vector<const Array*> &objects,
+ std::vector< std::vector<unsigned char> > &values,
+ bool &hasSolution) {
+ return solver->impl->computeInitialValues(query, objects, values,
+ hasSolution);
+ }
+};
+
+/** @returns the canonical version of the given query. The reference
+ negationUsed is set to true if the original query was negated in
+ the canonicalization process. */
+ref<Expr> CachingSolver::canonicalizeQuery(ref<Expr> originalQuery,
+ bool &negationUsed) {
+ ref<Expr> negatedQuery = Expr::createNot(originalQuery);
+
+ // select the "smaller" query to the be canonical representation
+ if (originalQuery.compare(negatedQuery) < 0) {
+ negationUsed = false;
+ return originalQuery;
+ } else {
+ negationUsed = true;
+ return negatedQuery;
+ }
+}
+
+/** @returns true on a cache hit, false of a cache miss. Reference
+ value result only valid on a cache hit. */
+bool CachingSolver::cacheLookup(const Query& query,
+ IncompleteSolver::PartialValidity &result) {
+ bool negationUsed;
+ ref<Expr> canonicalQuery = canonicalizeQuery(query.expr, negationUsed);
+
+ CacheEntry ce(query.constraints, canonicalQuery);
+ cache_map::iterator it = cache.find(ce);
+
+ if (it != cache.end()) {
+ result = (negationUsed ?
+ IncompleteSolver::negatePartialValidity(it->second) :
+ it->second);
+ return true;
+ }
+
+ return false;
+}
+
+/// Inserts the given query, result pair into the cache.
+void CachingSolver::cacheInsert(const Query& query,
+ IncompleteSolver::PartialValidity result) {
+ bool negationUsed;
+ ref<Expr> canonicalQuery = canonicalizeQuery(query.expr, negationUsed);
+
+ CacheEntry ce(query.constraints, canonicalQuery);
+ IncompleteSolver::PartialValidity cachedResult =
+ (negationUsed ? IncompleteSolver::negatePartialValidity(result) : result);
+
+ cache.insert(std::make_pair(ce, cachedResult));
+}
+
+bool CachingSolver::computeValidity(const Query& query,
+ Solver::Validity &result) {
+ IncompleteSolver::PartialValidity cachedResult;
+ bool tmp, cacheHit = cacheLookup(query, cachedResult);
+
+ if (cacheHit) {
+ ++stats::queryCacheHits;
+
+ switch(cachedResult) {
+ case IncompleteSolver::MustBeTrue:
+ result = Solver::True;
+ return true;
+ case IncompleteSolver::MustBeFalse:
+ result = Solver::False;
+ return true;
+ case IncompleteSolver::TrueOrFalse:
+ result = Solver::Unknown;
+ return true;
+ case IncompleteSolver::MayBeTrue: {
+ if (!solver->impl->computeTruth(query, tmp))
+ return false;
+ if (tmp) {
+ cacheInsert(query, IncompleteSolver::MustBeTrue);
+ result = Solver::True;
+ return true;
+ } else {
+ cacheInsert(query, IncompleteSolver::TrueOrFalse);
+ result = Solver::Unknown;
+ return true;
+ }
+ }
+ case IncompleteSolver::MayBeFalse: {
+ if (!solver->impl->computeTruth(query.negateExpr(), tmp))
+ return false;
+ if (tmp) {
+ cacheInsert(query, IncompleteSolver::MustBeFalse);
+ result = Solver::False;
+ return true;
+ } else {
+ cacheInsert(query, IncompleteSolver::TrueOrFalse);
+ result = Solver::Unknown;
+ return true;
+ }
+ }
+ default: assert(0 && "unreachable");
+ }
+ }
+
+ ++stats::queryCacheMisses;
+
+ if (!solver->impl->computeValidity(query, result))
+ return false;
+
+ switch (result) {
+ case Solver::True:
+ cachedResult = IncompleteSolver::MustBeTrue; break;
+ case Solver::False:
+ cachedResult = IncompleteSolver::MustBeFalse; break;
+ default:
+ cachedResult = IncompleteSolver::TrueOrFalse; break;
+ }
+
+ cacheInsert(query, cachedResult);
+ return true;
+}
+
+bool CachingSolver::computeTruth(const Query& query,
+ bool &isValid) {
+ IncompleteSolver::PartialValidity cachedResult;
+ bool cacheHit = cacheLookup(query, cachedResult);
+
+ // a cached result of MayBeTrue forces us to check whether
+ // a False assignment exists.
+ if (cacheHit && cachedResult != IncompleteSolver::MayBeTrue) {
+ ++stats::queryCacheHits;
+ isValid = (cachedResult == IncompleteSolver::MustBeTrue);
+ return true;
+ }
+
+ ++stats::queryCacheMisses;
+
+ // cache miss: query solver
+ if (!solver->impl->computeTruth(query, isValid))
+ return false;
+
+ if (isValid) {
+ cachedResult = IncompleteSolver::MustBeTrue;
+ } else if (cacheHit) {
+ // We know a true assignment exists, and query isn't valid, so
+ // must be TrueOrFalse.
+ assert(cachedResult == IncompleteSolver::MayBeTrue);
+ cachedResult = IncompleteSolver::TrueOrFalse;
+ } else {
+ cachedResult = IncompleteSolver::MayBeFalse;
+ }
+
+ cacheInsert(query, cachedResult);
+ return true;
+}
+
+///
+
+Solver *klee::createCachingSolver(Solver *_solver) {
+ return new Solver(new CachingSolver(_solver));
+}
diff --git a/lib/Solver/CexCachingSolver.cpp b/lib/Solver/CexCachingSolver.cpp
new file mode 100644
index 00000000..79bc985d
--- /dev/null
+++ b/lib/Solver/CexCachingSolver.cpp
@@ -0,0 +1,313 @@
+//===-- CexCachingSolver.cpp ----------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "klee/Solver.h"
+
+#include "klee/Constraints.h"
+#include "klee/Expr.h"
+#include "klee/SolverImpl.h"
+#include "klee/TimerStatIncrementer.h"
+#include "klee/util/Assignment.h"
+#include "klee/util/ExprUtil.h"
+#include "klee/util/ExprVisitor.h"
+#include "klee/Internal/ADT/MapOfSets.h"
+
+#include "SolverStats.h"
+
+#include "llvm/Support/CommandLine.h"
+
+using namespace klee;
+using namespace llvm;
+
+namespace {
+ cl::opt<bool>
+ DebugCexCacheCheckBinding("debug-cex-cache-check-binding");
+
+ cl::opt<bool>
+ CexCacheTryAll("cex-cache-try-all",
+ cl::desc("try substituting all counterexamples before asking STP"),
+ cl::init(false));
+
+ cl::opt<bool>
+ CexCacheExperimental("cex-cache-exp", cl::init(false));
+
+}
+
+///
+
+typedef std::set< ref<Expr> > KeyType;
+
+struct AssignmentLessThan {
+ bool operator()(const Assignment *a, const Assignment *b) {
+ return a->bindings < b->bindings;
+ }
+};
+
+
+class CexCachingSolver : public SolverImpl {
+ typedef std::set<Assignment*, AssignmentLessThan> assignmentsTable_ty;
+
+ Solver *solver;
+
+ MapOfSets<ref<Expr>, Assignment*> cache;
+ // memo table
+ assignmentsTable_ty assignmentsTable;
+
+ bool searchForAssignment(KeyType &key,
+ Assignment *&result);
+
+ bool lookupAssignment(const Query& query, Assignment *&result);
+
+ bool getAssignment(const Query& query, Assignment *&result);
+
+public:
+ CexCachingSolver(Solver *_solver) : solver(_solver) {}
+ ~CexCachingSolver();
+
+ bool computeTruth(const Query&, bool &isValid);
+ bool computeValidity(const Query&, Solver::Validity &result);
+ bool computeValue(const Query&, ref<Expr> &result);
+ bool computeInitialValues(const Query&,
+ const std::vector<const Array*> &objects,
+ std::vector< std::vector<unsigned char> > &values,
+ bool &hasSolution);
+};
+
+///
+
+struct NullAssignment {
+ bool operator()(Assignment *a) const { return !a; }
+};
+
+struct NonNullAssignment {
+ bool operator()(Assignment *a) const { return a!=0; }
+};
+
+struct NullOrSatisfyingAssignment {
+ KeyType &key;
+
+ NullOrSatisfyingAssignment(KeyType &_key) : key(_key) {}
+
+ bool operator()(Assignment *a) const {
+ return !a || a->satisfies(key.begin(), key.end());
+ }
+};
+
+bool CexCachingSolver::searchForAssignment(KeyType &key, Assignment *&result) {
+ Assignment * const *lookup = cache.lookup(key);
+ if (lookup) {
+ result = *lookup;
+ return true;
+ }
+
+ if (CexCacheTryAll) {
+ Assignment **lookup = cache.findSuperset(key, NonNullAssignment());
+ if (!lookup) lookup = cache.findSubset(key, NullAssignment());
+ if (lookup) {
+ result = *lookup;
+ return true;
+ }
+ for (assignmentsTable_ty::iterator it = assignmentsTable.begin(),
+ ie = assignmentsTable.end(); it != ie; ++it) {
+ Assignment *a = *it;
+ if (a->satisfies(key.begin(), key.end())) {
+ result = a;
+ return true;
+ }
+ }
+ } else {
+ // XXX which order? one is sure to be better
+ Assignment **lookup = cache.findSuperset(key, NonNullAssignment());
+ if (!lookup) lookup = cache.findSubset(key, NullOrSatisfyingAssignment(key));
+ if (lookup) {
+ result = *lookup;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool CexCachingSolver::lookupAssignment(const Query &query,
+ Assignment *&result) {
+ KeyType key(query.constraints.begin(), query.constraints.end());
+ ref<Expr> neg = Expr::createNot(query.expr);
+ if (neg.isConstant()) {
+ if (!neg.getConstantValue()) {
+ result = (Assignment*) 0;
+ return true;
+ }
+ } else {
+ key.insert(neg);
+ }
+
+ return searchForAssignment(key, result);
+}
+
+bool CexCachingSolver::getAssignment(const Query& query, Assignment *&result) {
+ KeyType key(query.constraints.begin(), query.constraints.end());
+ ref<Expr> neg = Expr::createNot(query.expr);
+ if (neg.isConstant()) {
+ if (!neg.getConstantValue()) {
+ result = (Assignment*) 0;
+ return true;
+ }
+ } else {
+ key.insert(neg);
+ }
+
+ if (!searchForAssignment(key, result)) {
+ // need to solve
+
+ std::vector<const Array*> objects;
+ findSymbolicObjects(key.begin(), key.end(), objects);
+
+ std::vector< std::vector<unsigned char> > values;
+ bool hasSolution;
+ if (!solver->impl->computeInitialValues(query, objects, values,
+ hasSolution))
+ return false;
+
+ Assignment *binding;
+ if (hasSolution) {
+ binding = new Assignment(objects, values);
+
+ // memoization
+ std::pair<assignmentsTable_ty::iterator, bool>
+ res = assignmentsTable.insert(binding);
+ if (!res.second) {
+ delete binding;
+ binding = *res.first;
+ }
+
+ if (DebugCexCacheCheckBinding)
+ assert(binding->satisfies(key.begin(), key.end()));
+ } else {
+ binding = (Assignment*) 0;
+ }
+
+ result = binding;
+ cache.insert(key, binding);
+ }
+
+ return true;
+}
+
+///
+
+CexCachingSolver::~CexCachingSolver() {
+ cache.clear();
+ delete solver;
+ for (assignmentsTable_ty::iterator it = assignmentsTable.begin(),
+ ie = assignmentsTable.end(); it != ie; ++it)
+ delete *it;
+}
+
+bool CexCachingSolver::computeValidity(const Query& query,
+ Solver::Validity &result) {
+ TimerStatIncrementer t(stats::cexCacheTime);
+ Assignment *a;
+ if (!getAssignment(query.withFalse(), a))
+ return false;
+ assert(a && "computeValidity() must have assignment");
+ ref<Expr> q = a->evaluate(query.expr);
+ assert(q.isConstant() && "assignment evaluation did not result in constant");
+
+ if (q.getConstantValue()) {
+ if (!getAssignment(query, a))
+ return false;
+ result = !a ? Solver::True : Solver::Unknown;
+ } else {
+ if (!getAssignment(query.negateExpr(), a))
+ return false;
+ result = !a ? Solver::False : Solver::Unknown;
+ }
+
+ return true;
+}
+
+bool CexCachingSolver::computeTruth(const Query& query,
+ bool &isValid) {
+ TimerStatIncrementer t(stats::cexCacheTime);
+
+ // There is a small amount of redundancy here. We only need to know
+ // truth and do not really need to compute an assignment. This means
+ // that we could check the cache to see if we already know that
+ // state ^ query has no assignment. In that case, by the validity of
+ // state, we know that state ^ !query must have an assignment, and
+ // so query cannot be true (valid). This does get hits, but doesn't
+ // really seem to be worth the overhead.
+
+ if (CexCacheExperimental) {
+ Assignment *a;
+ if (lookupAssignment(query.negateExpr(), a) && !a)
+ return false;
+ }
+
+ Assignment *a;
+ if (!getAssignment(query, a))
+ return false;
+
+ isValid = !a;
+
+ return true;
+}
+
+bool CexCachingSolver::computeValue(const Query& query,
+ ref<Expr> &result) {
+ TimerStatIncrementer t(stats::cexCacheTime);
+
+ Assignment *a;
+ if (!getAssignment(query.withFalse(), a))
+ return false;
+ assert(a && "computeValue() must have assignment");
+ result = a->evaluate(query.expr);
+ assert(result.isConstant() &&
+ "assignment evaluation did not result in constant");
+ return true;
+}
+
+bool
+CexCachingSolver::computeInitialValues(const Query& query,
+ const std::vector<const Array*>
+ &objects,
+ std::vector< std::vector<unsigned char> >
+ &values,
+ bool &hasSolution) {
+ TimerStatIncrementer t(stats::cexCacheTime);
+ Assignment *a;
+ if (!getAssignment(query, a))
+ return false;
+ hasSolution = !!a;
+
+ if (!a)
+ return true;
+
+ // FIXME: We should use smarter assignment for result so we don't
+ // need redundant copy.
+ values = std::vector< std::vector<unsigned char> >(objects.size());
+ for (unsigned i=0; i < objects.size(); ++i) {
+ const Array *os = objects[i];
+ Assignment::bindings_ty::iterator it = a->bindings.find(os);
+
+ if (it == a->bindings.end()) {
+ values[i] = std::vector<unsigned char>(os->size, 0);
+ } else {
+ values[i] = it->second;
+ }
+ }
+
+ return true;
+}
+
+///
+
+Solver *klee::createCexCachingSolver(Solver *_solver) {
+ return new Solver(new CexCachingSolver(_solver));
+}
diff --git a/lib/Solver/ConstantDivision.cpp b/lib/Solver/ConstantDivision.cpp
new file mode 100644
index 00000000..c8f8f3d5
--- /dev/null
+++ b/lib/Solver/ConstantDivision.cpp
@@ -0,0 +1,146 @@
+//===-- ConstantDivision.cpp ----------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ConstantDivision.h"
+
+#include "klee/util/Bits.h"
+
+#include <algorithm>
+#include <cassert>
+
+namespace klee {
+
+/* Macros and functions which define the basic bit-level operations
+ * needed to implement quick division operations.
+ *
+ * Based on Hacker's Delight (2003) by Henry S. Warren, Jr.
+ */
+
+/* 32 -- number of bits in the integer type on this architecture */
+
+/* 2^32 -- NUM_BITS=32 requires 64 bits to represent this unsigned value */
+#define TWO_TO_THE_32_U64 (1ULL << 32)
+
+/* 2e31 -- NUM_BITS=32 requires 64 bits to represent this signed value */
+#define TWO_TO_THE_31_S64 (1LL << 31)
+
+/* ABS(x) -- positive x */
+#define ABS(x) ( ((x)>0)?x:-(x) ) /* fails if x is the min value of its type */
+
+/* XSIGN(x) -- -1 if x<0 and 0 otherwise */
+#define XSIGN(x) ( (x) >> 31 )
+
+/* LOG2_CEIL(x) -- logarithm base 2 of x, rounded up */
+#define LOG2_CEIL(x) ( 32 - ldz(x - 1) )
+
+/* ones(x) -- counts the number of bits in x with the value 1 */
+static uint32_t ones( register uint32_t x ) {
+ x -= ((x >> 1) & 0x55555555);
+ x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
+ x = (((x >> 4) + x) & 0x0f0f0f0f);
+ x += (x >> 8);
+ x += (x >> 16);
+
+ return( x & 0x0000003f );
+}
+
+/* ldz(x) -- counts the number of leading zeroes in a 32-bit word */
+static uint32_t ldz( register uint32_t x ) {
+ x |= (x >> 1);
+ x |= (x >> 2);
+ x |= (x >> 4);
+ x |= (x >> 8);
+ x |= (x >> 16);
+
+ return 32 - ones(x);
+}
+
+/* exp_base_2(n) -- 2^n computed as an integer */
+static uint32_t exp_base_2( register int32_t n ) {
+ register uint32_t x = ~n & (n - 32);
+ x = x >> 31;
+ return( x << n );
+}
+
+// A simple algorithm: Iterate over all contiguous regions of 1 bits
+// in x starting with the lowest bits.
+//
+// For a particular range where x is 1 for bits [low,high) then:
+// 1) if the range is just one bit, simple add it
+// 2) if the range is more than one bit, replace with an add
+// of the high bit and a subtract of the low bit. we apply
+// one useful optimization: if we were going to add the bit
+// below the one we wish to subtract, we simply change that
+// add to a subtract instead of subtracting the low bit itself.
+// Obviously we must take care when high==64.
+void ComputeMultConstants64(uint64_t multiplicand,
+ uint64_t &add, uint64_t &sub) {
+ uint64_t x = multiplicand;
+ add = sub = 0;
+
+ while (x) {
+ // Determine rightmost contiguous region of 1s.
+ unsigned low = bits64::indexOfRightmostBit(x);
+ uint64_t lowbit = 1LL << low;
+ uint64_t p = x + lowbit;
+ uint64_t q = bits64::isolateRightmostBit(p);
+ unsigned high = q ? bits64::indexOfSingleBit(q) : 64;
+
+ if (high==low+1) { // Just one bit...
+ add |= lowbit;
+ } else {
+ // Rewrite as +(1<<high) - (1<<low).
+
+ // Optimize +(1<<x) - (1<<(x+1)) to -(1<<x).
+ if (low && (add & (lowbit>>1))) {
+ add ^= lowbit>>1;
+ sub ^= lowbit>>1;
+ } else {
+ sub |= lowbit;
+ }
+
+ if (high!=64)
+ add |= 1LL << high;
+ }
+
+ x = p ^ q;
+ }
+
+ assert(multiplicand == add - sub);
+}
+
+void ComputeUDivConstants32(uint32_t d, uint32_t &mprime, uint32_t &sh1,
+ uint32_t &sh2) {
+ int32_t l = LOG2_CEIL( d ); /* signed so l-1 => -1 when l=0 (see sh2) */
+ uint32_t mid = exp_base_2(l) - d;
+
+ mprime = (TWO_TO_THE_32_U64 * mid / d) + 1;
+ sh1 = std::min( l, 1 );
+ sh2 = std::max( l-1, 0 );
+}
+
+void ComputeSDivConstants32(int32_t d, int32_t &mprime, int32_t &dsign,
+ int32_t &shpost ) {
+ uint64_t abs_d = ABS( (int64_t)d ); /* use 64-bits in case d is INT32_MIN */
+
+ /* LOG2_CEIL works on 32-bits, so we cast abs_d. The only possible value
+ * outside the 32-bit rep. is 2^31. This is special cased to save computer
+ * time since 64-bit routines would be overkill. */
+ int32_t l = std::max( 1U, LOG2_CEIL((uint32_t)abs_d) );
+ if( abs_d == TWO_TO_THE_31_S64 ) l = 31;
+
+ uint32_t mid = exp_base_2( l - 1 );
+ uint64_t m = TWO_TO_THE_32_U64 * mid / abs_d + 1ULL;
+
+ mprime = m - TWO_TO_THE_32_U64; /* implicit cast to 32-bits signed */
+ dsign = XSIGN( d );
+ shpost = l - 1;
+}
+
+}
diff --git a/lib/Solver/ConstantDivision.h b/lib/Solver/ConstantDivision.h
new file mode 100644
index 00000000..9e3e9c95
--- /dev/null
+++ b/lib/Solver/ConstantDivision.h
@@ -0,0 +1,51 @@
+//===-- ConstantDivision.h --------------------------------------*- C++ -*-===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __UTIL_CONSTANTDIVISION_H__
+#define __UTIL_CONSTANTDIVISION_H__
+
+#include <stdint.h>
+
+namespace klee {
+
+/// ComputeMultConstants64 - Compute add and sub such that add-sub==x,
+/// while attempting to minimize the number of bits in add and sub
+/// combined.
+void ComputeMultConstants64(uint64_t x, uint64_t &add_out,
+ uint64_t &sub_out);
+
+/// Compute the constants to perform a quicker equivalent of a division of some
+/// 32-bit unsigned integer n by a known constant d (also a 32-bit unsigned
+/// integer). The constants to compute n/d without explicit division will be
+/// stored in mprime, sh1, and sh2 (unsigned 32-bit integers).
+///
+/// @param d - denominator (divisor)
+///
+/// @param [out] mprime
+/// @param [out] sh1
+/// @param [out] sh2
+void ComputeUDivConstants32(uint32_t d, uint32_t &mprime, uint32_t &sh1,
+ uint32_t &sh2);
+
+/// Compute the constants to perform a quicker equivalent of a division of some
+/// 32-bit signed integer n by a known constant d (also a 32-bit signed
+/// integer). The constants to compute n/d without explicit division will be
+/// stored in mprime, dsign, and shpost (signed 32-bit integers).
+///
+/// @param d - denominator (divisor)
+///
+/// @param [out] mprime
+/// @param [out] dsign
+/// @param [out] shpost
+void ComputeSDivConstants32(int32_t d, int32_t &mprime, int32_t &dsign,
+ int32_t &shpost);
+
+}
+
+#endif
diff --git a/lib/Solver/FastCexSolver.cpp b/lib/Solver/FastCexSolver.cpp
new file mode 100644
index 00000000..d2bc27c6
--- /dev/null
+++ b/lib/Solver/FastCexSolver.cpp
@@ -0,0 +1,959 @@
+//===-- FastCexSolver.cpp -------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "klee/Solver.h"
+
+#include "klee/Constraints.h"
+#include "klee/Expr.h"
+#include "klee/IncompleteSolver.h"
+#include "klee/util/ExprEvaluator.h"
+#include "klee/util/ExprRangeEvaluator.h"
+#include "klee/util/ExprVisitor.h"
+// FIXME: Use APInt.
+#include "klee/Internal/Support/IntEvaluation.h"
+
+#include <iostream>
+#include <sstream>
+#include <cassert>
+#include <map>
+#include <vector>
+
+using namespace klee;
+
+/***/
+
+//#define LOG
+#ifdef LOG
+std::ostream *theLog;
+#endif
+
+ // Hacker's Delight, pgs 58-63
+static uint64_t minOR(uint64_t a, uint64_t b,
+ uint64_t c, uint64_t d) {
+ uint64_t temp, m = ((uint64_t) 1)<<63;
+ while (m) {
+ if (~a & c & m) {
+ temp = (a | m) & -m;
+ if (temp <= b) { a = temp; break; }
+ } else if (a & ~c & m) {
+ temp = (c | m) & -m;
+ if (temp <= d) { c = temp; break; }
+ }
+ m >>= 1;
+ }
+
+ return a | c;
+}
+static uint64_t maxOR(uint64_t a, uint64_t b,
+ uint64_t c, uint64_t d) {
+ uint64_t temp, m = ((uint64_t) 1)<<63;
+
+ while (m) {
+ if (b & d & m) {
+ temp = (b - m) | (m - 1);
+ if (temp >= a) { b = temp; break; }
+ temp = (d - m) | (m -1);
+ if (temp >= c) { d = temp; break; }
+ }
+ m >>= 1;
+ }
+
+ return b | d;
+}
+static uint64_t minAND(uint64_t a, uint64_t b,
+ uint64_t c, uint64_t d) {
+ uint64_t temp, m = ((uint64_t) 1)<<63;
+ while (m) {
+ if (~a & ~c & m) {
+ temp = (a | m) & -m;
+ if (temp <= b) { a = temp; break; }
+ temp = (c | m) & -m;
+ if (temp <= d) { c = temp; break; }
+ }
+ m >>= 1;
+ }
+
+ return a & c;
+}
+static uint64_t maxAND(uint64_t a, uint64_t b,
+ uint64_t c, uint64_t d) {
+ uint64_t temp, m = ((uint64_t) 1)<<63;
+ while (m) {
+ if (b & ~d & m) {
+ temp = (b & ~m) | (m - 1);
+ if (temp >= a) { b = temp; break; }
+ } else if (~b & d & m) {
+ temp = (d & ~m) | (m - 1);
+ if (temp >= c) { d = temp; break; }
+ }
+ m >>= 1;
+ }
+
+ return b & d;
+}
+
+///
+
+class ValueRange {
+private:
+ uint64_t m_min, m_max;
+
+public:
+ ValueRange() : m_min(1),m_max(0) {}
+ ValueRange(uint64_t value) : m_min(value), m_max(value) {}
+ ValueRange(uint64_t _min, uint64_t _max) : m_min(_min), m_max(_max) {}
+ ValueRange(const ValueRange &b) : m_min(b.m_min), m_max(b.m_max) {}
+
+ void print(std::ostream &os) const {
+ if (isFixed()) {
+ os << m_min;
+ } else {
+ os << "[" << m_min << "," << m_max << "]";
+ }
+ }
+
+ bool isEmpty() const {
+ return m_min>m_max;
+ }
+ bool contains(uint64_t value) const {
+ return this->intersects(ValueRange(value));
+ }
+ bool intersects(const ValueRange &b) const {
+ return !this->set_intersection(b).isEmpty();
+ }
+
+ bool isFullRange(unsigned bits) {
+ return m_min==0 && m_max==bits64::maxValueOfNBits(bits);
+ }
+
+ ValueRange set_intersection(const ValueRange &b) const {
+ return ValueRange(std::max(m_min,b.m_min), std::min(m_max,b.m_max));
+ }
+ ValueRange set_union(const ValueRange &b) const {
+ return ValueRange(std::min(m_min,b.m_min), std::max(m_max,b.m_max));
+ }
+ ValueRange set_difference(const ValueRange &b) const {
+ if (b.isEmpty() || b.m_min > m_max || b.m_max < m_min) { // no intersection
+ return *this;
+ } else if (b.m_min <= m_min && b.m_max >= m_max) { // empty
+ return ValueRange(1,0);
+ } else if (b.m_min <= m_min) { // one range out
+ // cannot overflow because b.m_max < m_max
+ return ValueRange(b.m_max+1, m_max);
+ } else if (b.m_max >= m_max) {
+ // cannot overflow because b.min > m_min
+ return ValueRange(m_min, b.m_min-1);
+ } else {
+ // two ranges, take bottom
+ return ValueRange(m_min, b.m_min-1);
+ }
+ }
+ ValueRange binaryAnd(const ValueRange &b) const {
+ // XXX
+ assert(!isEmpty() && !b.isEmpty() && "XXX");
+ if (isFixed() && b.isFixed()) {
+ return ValueRange(m_min & b.m_min);
+ } else {
+ return ValueRange(minAND(m_min, m_max, b.m_min, b.m_max),
+ maxAND(m_min, m_max, b.m_min, b.m_max));
+ }
+ }
+ ValueRange binaryAnd(uint64_t b) const { return binaryAnd(ValueRange(b)); }
+ ValueRange binaryOr(ValueRange b) const {
+ // XXX
+ assert(!isEmpty() && !b.isEmpty() && "XXX");
+ if (isFixed() && b.isFixed()) {
+ return ValueRange(m_min | b.m_min);
+ } else {
+ return ValueRange(minOR(m_min, m_max, b.m_min, b.m_max),
+ maxOR(m_min, m_max, b.m_min, b.m_max));
+ }
+ }
+ ValueRange binaryOr(uint64_t b) const { return binaryOr(ValueRange(b)); }
+ ValueRange binaryXor(ValueRange b) const {
+ if (isFixed() && b.isFixed()) {
+ return ValueRange(m_min ^ b.m_min);
+ } else {
+ uint64_t t = m_max | b.m_max;
+ while (!bits64::isPowerOfTwo(t))
+ t = bits64::withoutRightmostBit(t);
+ return ValueRange(0, (t<<1)-1);
+ }
+ }
+
+ ValueRange binaryShiftLeft(unsigned bits) const {
+ return ValueRange(m_min<<bits, m_max<<bits);
+ }
+ ValueRange binaryShiftRight(unsigned bits) const {
+ return ValueRange(m_min>>bits, m_max>>bits);
+ }
+
+ ValueRange concat(const ValueRange &b, unsigned bits) const {
+ return binaryShiftLeft(bits).binaryOr(b);
+ }
+ ValueRange extract(uint64_t lowBit, uint64_t maxBit) const {
+ return binaryShiftRight(lowBit).binaryAnd(bits64::maxValueOfNBits(maxBit-lowBit));
+ }
+
+ ValueRange add(const ValueRange &b, unsigned width) const {
+ return ValueRange(0, bits64::maxValueOfNBits(width));
+ }
+ ValueRange sub(const ValueRange &b, unsigned width) const {
+ return ValueRange(0, bits64::maxValueOfNBits(width));
+ }
+ ValueRange mul(const ValueRange &b, unsigned width) const {
+ return ValueRange(0, bits64::maxValueOfNBits(width));
+ }
+ ValueRange udiv(const ValueRange &b, unsigned width) const {
+ return ValueRange(0, bits64::maxValueOfNBits(width));
+ }
+ ValueRange sdiv(const ValueRange &b, unsigned width) const {
+ return ValueRange(0, bits64::maxValueOfNBits(width));
+ }
+ ValueRange urem(const ValueRange &b, unsigned width) const {
+ return ValueRange(0, bits64::maxValueOfNBits(width));
+ }
+ ValueRange srem(const ValueRange &b, unsigned width) const {
+ return ValueRange(0, bits64::maxValueOfNBits(width));
+ }
+
+ // use min() to get value if true (XXX should we add a method to
+ // make code clearer?)
+ bool isFixed() const { return m_min==m_max; }
+
+ bool operator==(const ValueRange &b) const { return m_min==b.m_min && m_max==b.m_max; }
+ bool operator!=(const ValueRange &b) const { return !(*this==b); }
+
+ bool mustEqual(const uint64_t b) const { return m_min==m_max && m_min==b; }
+ bool mayEqual(const uint64_t b) const { return m_min<=b && m_max>=b; }
+
+ bool mustEqual(const ValueRange &b) const { return isFixed() && b.isFixed() && m_min==b.m_min; }
+ bool mayEqual(const ValueRange &b) const { return this->intersects(b); }
+
+ uint64_t min() const {
+ assert(!isEmpty() && "cannot get minimum of empty range");
+ return m_min;
+ }
+
+ uint64_t max() const {
+ assert(!isEmpty() && "cannot get maximum of empty range");
+ return m_max;
+ }
+
+ int64_t minSigned(unsigned bits) const {
+ assert((m_min>>bits)==0 && (m_max>>bits)==0 &&
+ "range is outside given number of bits");
+
+ // if max allows sign bit to be set then it can be smallest value,
+ // otherwise since the range is not empty, min cannot have a sign
+ // bit
+
+ uint64_t smallest = ((uint64_t) 1 << (bits-1));
+ if (m_max >= smallest) {
+ return ints::sext(smallest, 64, bits);
+ } else {
+ return m_min;
+ }
+ }
+
+ int64_t maxSigned(unsigned bits) const {
+ assert((m_min>>bits)==0 && (m_max>>bits)==0 &&
+ "range is outside given number of bits");
+
+ uint64_t smallest = ((uint64_t) 1 << (bits-1));
+
+ // if max and min have sign bit then max is max, otherwise if only
+ // max has sign bit then max is largest signed integer, otherwise
+ // max is max
+
+ if (m_min < smallest && m_max >= smallest) {
+ return smallest - 1;
+ } else {
+ return ints::sext(m_max, 64, bits);
+ }
+ }
+};
+
+inline std::ostream &operator<<(std::ostream &os, const ValueRange &vr) {
+ vr.print(os);
+ return os;
+}
+
+// used to find all memory object ids and the maximum size of any
+// object state that references them (for symbolic size).
+class ObjectFinder : public ExprVisitor {
+protected:
+ Action visitRead(const ReadExpr &re) {
+ addUpdates(re.updates);
+ return Action::doChildren();
+ }
+
+ // XXX nice if this information was cached somewhere, used by
+ // independence as well right?
+ void addUpdates(const UpdateList &ul) {
+ for (const UpdateNode *un=ul.head; un; un=un->next) {
+ visit(un->index);
+ visit(un->value);
+ }
+
+ addObject(*ul.root);
+ }
+
+public:
+ void addObject(const Array& array) {
+ unsigned id = array.id;
+ std::map<unsigned,unsigned>::iterator it = results.find(id);
+
+ // FIXME: Not 64-bit size clean.
+ if (it == results.end()) {
+ results[id] = (unsigned) array.size;
+ } else {
+ it->second = std::max(it->second, (unsigned) array.size);
+ }
+ }
+
+public:
+ std::map<unsigned, unsigned> results;
+};
+
+// XXX waste of space, rather have ByteValueRange
+typedef ValueRange CexValueData;
+
+class CexObjectData {
+public:
+ unsigned size;
+ CexValueData *values;
+
+public:
+ CexObjectData(unsigned _size) : size(_size), values(new CexValueData[size]) {
+ for (unsigned i=0; i<size; i++)
+ values[i] = ValueRange(0, 255);
+ }
+};
+
+class CexRangeEvaluator : public ExprRangeEvaluator<ValueRange> {
+public:
+ std::map<unsigned, CexObjectData> &objectValues;
+ CexRangeEvaluator(std::map<unsigned, CexObjectData> &_objectValues)
+ : objectValues(_objectValues) {}
+
+ ValueRange getInitialReadRange(const Array &os, ValueRange index) {
+ return ValueRange(0, 255);
+ }
+};
+
+class CexConstifier : public ExprEvaluator {
+protected:
+ ref<Expr> getInitialValue(const Array& array, unsigned index) {
+ std::map<unsigned, CexObjectData>::iterator it =
+ objectValues.find(array.id);
+ assert(it != objectValues.end() && "missing object?");
+ CexObjectData &cod = it->second;
+
+ if (index >= cod.size) {
+ return ReadExpr::create(UpdateList(&array, true, 0),
+ ref<Expr>(index, Expr::Int32));
+ } else {
+ CexValueData &cvd = cod.values[index];
+ assert(cvd.min() == cvd.max() && "value is not fixed");
+ return ref<Expr>(cvd.min(), Expr::Int8);
+ }
+ }
+
+public:
+ std::map<unsigned, CexObjectData> &objectValues;
+ CexConstifier(std::map<unsigned, CexObjectData> &_objectValues)
+ : objectValues(_objectValues) {}
+};
+
+class CexData {
+public:
+ std::map<unsigned, CexObjectData> objectValues;
+
+public:
+ CexData(ObjectFinder &finder) {
+ for (std::map<unsigned,unsigned>::iterator it = finder.results.begin(),
+ ie = finder.results.end(); it != ie; ++it) {
+ objectValues.insert(std::pair<unsigned, CexObjectData>(it->first,
+ CexObjectData(it->second)));
+ }
+ }
+ ~CexData() {
+ for (std::map<unsigned, CexObjectData>::iterator it = objectValues.begin(),
+ ie = objectValues.end(); it != ie; ++it)
+ delete[] it->second.values;
+ }
+
+ void forceExprToValue(ref<Expr> e, uint64_t value) {
+ forceExprToRange(e, CexValueData(value,value));
+ }
+
+ void forceExprToRange(ref<Expr> e, CexValueData range) {
+#ifdef LOG
+ // *theLog << "force: " << e << " to " << range << "\n";
+#endif
+ switch (e.getKind()) {
+ case Expr::Constant: {
+ // rather a pity if the constant isn't in the range, but how can
+ // we use this?
+ break;
+ }
+
+ // Special
+
+ case Expr::NotOptimized: break;
+
+ case Expr::Read: {
+ ReadExpr *re = static_ref_cast<ReadExpr>(e);
+ const Array *array = re->updates.root;
+ CexObjectData &cod = objectValues.find(array->id)->second;
+
+ // XXX we need to respect the version here and object state chain
+
+ if (re->index.isConstant() &&
+ re->index.getConstantValue() < array->size) {
+ CexValueData &cvd = cod.values[re->index.getConstantValue()];
+ CexValueData tmp = cvd.set_intersection(range);
+
+ if (tmp.isEmpty()) {
+ if (range.isFixed()) // ranges conflict, if new one is fixed use that
+ cvd = range;
+ } else {
+ cvd = tmp;
+ }
+ } else {
+ // XXX fatal("XXX not implemented");
+ }
+
+ break;
+ }
+
+ case Expr::Select: {
+ SelectExpr *se = static_ref_cast<SelectExpr>(e);
+ ValueRange cond = evalRangeForExpr(se->cond);
+ if (cond.isFixed()) {
+ if (cond.min()) {
+ forceExprToRange(se->trueExpr, range);
+ } else {
+ forceExprToRange(se->falseExpr, range);
+ }
+ } else {
+ // XXX imprecise... we have a choice here. One method is to
+ // simply force both sides into the specified range (since the
+ // condition is indetermined). This may lose in two ways, the
+ // first is that the condition chosen may limit further
+ // restrict the range in each of the children, however this is
+ // less of a problem as the range will be a superset of legal
+ // values. The other is if the condition ends up being forced
+ // by some other constraints, then we needlessly forced one
+ // side into the given range.
+ //
+ // The other method would be to force the condition to one
+ // side and force that side into the given range. This loses
+ // when we force the condition to an unsatisfiable value
+ // (either because the condition cannot be that, or the
+ // resulting range given that condition is not in the required
+ // range).
+ //
+ // Currently we just force both into the range. A hybrid would
+ // be to evaluate the ranges for each of the children... if
+ // one of the ranges happens to already be a subset of the
+ // required range then it may be preferable to force the
+ // condition to that side.
+ forceExprToRange(se->trueExpr, range);
+ forceExprToRange(se->falseExpr, range);
+ }
+ break;
+ }
+
+ // XXX imprecise... the problem here is that extracting bits
+ // loses information about what bits are connected across the
+ // bytes. if a value can be 1 or 256 then either the top or
+ // lower byte is 0, but just extraction loses this information
+ // and will allow neither,one,or both to be 1.
+ //
+ // we can protect against this in a limited fashion by writing
+ // the extraction a byte at a time, then checking the evaluated
+ // value, isolating for that range, and continuing.
+ case Expr::Concat: {
+ ConcatExpr *ce = static_ref_cast<ConcatExpr>(e);
+ if (ce->is2ByteConcat()) {
+ forceExprToRange(ce->getKid(0), range.extract( 8, 16));
+ forceExprToRange(ce->getKid(1), range.extract( 0, 8));
+ }
+ else if (ce->is4ByteConcat()) {
+ forceExprToRange(ce->getKid(0), range.extract(24, 32));
+ forceExprToRange(ce->getKid(1), range.extract(16, 24));
+ forceExprToRange(ce->getKid(2), range.extract( 8, 16));
+ forceExprToRange(ce->getKid(3), range.extract( 0, 8));
+ }
+ else if (ce->is8ByteConcat()) {
+ forceExprToRange(ce->getKid(0), range.extract(56, 64));
+ forceExprToRange(ce->getKid(1), range.extract(48, 56));
+ forceExprToRange(ce->getKid(2), range.extract(40, 48));
+ forceExprToRange(ce->getKid(3), range.extract(32, 40));
+ forceExprToRange(ce->getKid(4), range.extract(24, 32));
+ forceExprToRange(ce->getKid(5), range.extract(16, 24));
+ forceExprToRange(ce->getKid(6), range.extract( 8, 16));
+ forceExprToRange(ce->getKid(7), range.extract( 0, 8));
+ }
+
+ break;
+ }
+
+ case Expr::Extract: {
+ // XXX
+ break;
+ }
+
+ // Casting
+
+ // Simply intersect the output range with the range of all
+ // possible outputs and then truncate to the desired number of
+ // bits.
+
+ // For ZExt this simplifies to just intersection with the
+ // possible input range.
+ case Expr::ZExt: {
+ CastExpr *ce = static_ref_cast<CastExpr>(e);
+ unsigned inBits = ce->src.getWidth();
+ ValueRange input = range.set_intersection(ValueRange(0, bits64::maxValueOfNBits(inBits)));
+ forceExprToRange(ce->src, input);
+ break;
+ }
+ // For SExt instead of doing the intersection we just take the output range
+ // minus the impossible values. This is nicer since it is a single interval.
+ case Expr::SExt: {
+ CastExpr *ce = static_ref_cast<CastExpr>(e);
+ unsigned inBits = ce->src.getWidth();
+ unsigned outBits = ce->width;
+ ValueRange output = range.set_difference(ValueRange(1<<(inBits-1),
+ (bits64::maxValueOfNBits(outBits)-
+ bits64::maxValueOfNBits(inBits-1)-1)));
+ ValueRange input = output.binaryAnd(bits64::maxValueOfNBits(inBits));
+ forceExprToRange(ce->src, input);
+ break;
+ }
+
+ // Binary
+
+ case Expr::And: {
+ BinaryExpr *be = static_ref_cast<BinaryExpr>(e);
+ if (be->getWidth()==Expr::Bool) {
+ if (range.isFixed()) {
+ ValueRange left = evalRangeForExpr(be->left);
+ ValueRange right = evalRangeForExpr(be->right);
+
+ if (!range.min()) {
+ if (left.mustEqual(0) || right.mustEqual(0)) {
+ // all is well
+ } else {
+ // XXX heuristic, which order
+
+ forceExprToValue(be->left, 0);
+ left = evalRangeForExpr(be->left);
+
+ // see if that worked
+ if (!left.mustEqual(1))
+ forceExprToValue(be->right, 0);
+ }
+ } else {
+ if (!left.mustEqual(1)) forceExprToValue(be->left, 1);
+ if (!right.mustEqual(1)) forceExprToValue(be->right, 1);
+ }
+ }
+ } else {
+ // XXX
+ }
+ break;
+ }
+
+ case Expr::Or: {
+ BinaryExpr *be = static_ref_cast<BinaryExpr>(e);
+ if (be->getWidth()==Expr::Bool) {
+ if (range.isFixed()) {
+ ValueRange left = evalRangeForExpr(be->left);
+ ValueRange right = evalRangeForExpr(be->right);
+
+ if (range.min()) {
+ if (left.mustEqual(1) || right.mustEqual(1)) {
+ // all is well
+ } else {
+ // XXX heuristic, which order?
+
+ // force left to value we need
+ forceExprToValue(be->left, 1);
+ left = evalRangeForExpr(be->left);
+
+ // see if that worked
+ if (!left.mustEqual(1))
+ forceExprToValue(be->right, 1);
+ }
+ } else {
+ if (!left.mustEqual(0)) forceExprToValue(be->left, 0);
+ if (!right.mustEqual(0)) forceExprToValue(be->right, 0);
+ }
+ }
+ } else {
+ // XXX
+ }
+ break;
+ }
+
+ case Expr::Xor: break;
+
+ // Comparison
+
+ case Expr::Eq: {
+ BinaryExpr *be = static_ref_cast<BinaryExpr>(e);
+ if (range.isFixed()) {
+ if (be->left.isConstant()) {
+ uint64_t value = be->left.getConstantValue();
+ if (range.min()) {
+ forceExprToValue(be->right, value);
+ } else {
+ if (value==0) {
+ forceExprToRange(be->right,
+ CexValueData(1,
+ ints::sext(1,
+ be->right.getWidth(),
+ 1)));
+ } else {
+ // XXX heuristic / lossy, could be better to pick larger range?
+ forceExprToRange(be->right, CexValueData(0, value-1));
+ }
+ }
+ } else {
+ // XXX what now
+ }
+ }
+ break;
+ }
+
+ case Expr::Ult: {
+ BinaryExpr *be = static_ref_cast<BinaryExpr>(e);
+
+ // XXX heuristic / lossy, what order if conflict
+
+ if (range.isFixed()) {
+ ValueRange left = evalRangeForExpr(be->left);
+ ValueRange right = evalRangeForExpr(be->right);
+
+ uint64_t maxValue = bits64::maxValueOfNBits(be->right.getWidth());
+
+ // XXX should deal with overflow (can lead to empty range)
+
+ if (left.isFixed()) {
+ if (range.min()) {
+ forceExprToRange(be->right, CexValueData(left.min()+1, maxValue));
+ } else {
+ forceExprToRange(be->right, CexValueData(0, left.min()));
+ }
+ } else if (right.isFixed()) {
+ if (range.min()) {
+ forceExprToRange(be->left, CexValueData(0, right.min()-1));
+ } else {
+ forceExprToRange(be->left, CexValueData(right.min(), maxValue));
+ }
+ } else {
+ // XXX ???
+ }
+ }
+ break;
+ }
+ case Expr::Ule: {
+ BinaryExpr *be = static_ref_cast<BinaryExpr>(e);
+
+ // XXX heuristic / lossy, what order if conflict
+
+ if (range.isFixed()) {
+ ValueRange left = evalRangeForExpr(be->left);
+ ValueRange right = evalRangeForExpr(be->right);
+
+ // XXX should deal with overflow (can lead to empty range)
+
+ uint64_t maxValue = bits64::maxValueOfNBits(be->right.getWidth());
+ if (left.isFixed()) {
+ if (range.min()) {
+ forceExprToRange(be->right, CexValueData(left.min(), maxValue));
+ } else {
+ forceExprToRange(be->right, CexValueData(0, left.min()-1));
+ }
+ } else if (right.isFixed()) {
+ if (range.min()) {
+ forceExprToRange(be->left, CexValueData(0, right.min()));
+ } else {
+ forceExprToRange(be->left, CexValueData(right.min()+1, maxValue));
+ }
+ } else {
+ // XXX ???
+ }
+ }
+ break;
+ }
+
+ case Expr::Ne:
+ case Expr::Ugt:
+ case Expr::Uge:
+ case Expr::Sgt:
+ case Expr::Sge:
+ assert(0 && "invalid expressions (uncanonicalized");
+
+ default:
+ break;
+ }
+ }
+
+ void fixValues() {
+ for (std::map<unsigned, CexObjectData>::iterator it = objectValues.begin(),
+ ie = objectValues.end(); it != ie; ++it) {
+ CexObjectData &cod = it->second;
+ for (unsigned i=0; i<cod.size; i++) {
+ CexValueData &cvd = cod.values[i];
+ cvd = CexValueData(cvd.min() + (cvd.max()-cvd.min())/2);
+ }
+ }
+ }
+
+ ValueRange evalRangeForExpr(ref<Expr> &e) {
+ CexRangeEvaluator ce(objectValues);
+ return ce.evaluate(e);
+ }
+
+ bool exprMustBeValue(ref<Expr> e, uint64_t value) {
+ CexConstifier cc(objectValues);
+ ref<Expr> v = cc.visit(e);
+ if (!v.isConstant()) return false;
+ // XXX reenable once all reads and vars are fixed
+ // assert(v.isConstant() && "not all values have been fixed");
+ return v.getConstantValue()==value;
+ }
+};
+
+/* *** */
+
+
+class FastCexSolver : public IncompleteSolver {
+public:
+ FastCexSolver();
+ ~FastCexSolver();
+
+ IncompleteSolver::PartialValidity computeTruth(const Query&);
+ bool computeValue(const Query&, ref<Expr> &result);
+ bool computeInitialValues(const Query&,
+ const std::vector<const Array*> &objects,
+ std::vector< std::vector<unsigned char> > &values,
+ bool &hasSolution);
+};
+
+FastCexSolver::FastCexSolver() { }
+
+FastCexSolver::~FastCexSolver() { }
+
+IncompleteSolver::PartialValidity
+FastCexSolver::computeTruth(const Query& query) {
+#ifdef LOG
+ std::ostringstream log;
+ theLog = &log;
+ // log << "------ start FastCexSolver::mustBeTrue ------\n";
+ log << "-- QUERY --\n";
+ unsigned i=0;
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ log << " C" << i++ << ": " << *it << ", \n";
+ log << " Q : " << query.expr << "\n";
+#endif
+
+ ObjectFinder of;
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ of.visit(*it);
+ of.visit(query.expr);
+ CexData cd(of);
+
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ cd.forceExprToValue(*it, 1);
+ cd.forceExprToValue(query.expr, 0);
+
+#ifdef LOG
+ log << " -- ranges --\n";
+ for (std::map<unsigned, CexObjectData>::iterator it = objectValues.begin(),
+ ie = objectValues.end(); it != ie; ++it) {
+ CexObjectData &cod = it->second;
+ log << " arr" << it->first << "[" << cod.size << "] = [";
+ unsigned continueFrom=cod.size-1;
+ for (; continueFrom>0; continueFrom--)
+ if (cod.values[continueFrom-1]!=cod.values[continueFrom])
+ break;
+ for (unsigned i=0; i<cod.size; i++) {
+ log << cod.values[i];
+ if (i<cod.size-1) {
+ log << ", ";
+ if (i==continueFrom) {
+ log << "...";
+ break;
+ }
+ }
+ }
+ log << "]\n";
+ }
+#endif
+
+ // this could be done lazily of course
+ cd.fixValues();
+
+#ifdef LOG
+ log << " -- fixed values --\n";
+ for (std::map<unsigned, CexObjectData>::iterator it = objectValues.begin(),
+ ie = objectValues.end(); it != ie; ++it) {
+ CexObjectData &cod = it->second;
+ log << " arr" << it->first << "[" << cod.size << "] = [";
+ unsigned continueFrom=cod.size-1;
+ for (; continueFrom>0; continueFrom--)
+ if (cod.values[continueFrom-1]!=cod.values[continueFrom])
+ break;
+ for (unsigned i=0; i<cod.size; i++) {
+ log << cod.values[i];
+ if (i<cod.size-1) {
+ log << ", ";
+ if (i==continueFrom) {
+ log << "...";
+ break;
+ }
+ }
+ }
+ log << "]\n";
+ }
+#endif
+
+ // check the result
+
+ bool isGood = true;
+
+ if (!cd.exprMustBeValue(query.expr, 0)) isGood = false;
+
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ if (!cd.exprMustBeValue(*it, 1))
+ isGood = false;
+
+#ifdef LOG
+ log << " -- evaluating result --\n";
+
+ i=0;
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it) {
+ bool res = cd.exprMustBeValue(*it, 1);
+ log << " C" << i++ << ": " << (res?"true":"false") << "\n";
+ }
+ log << " Q : "
+ << (cd.exprMustBeValue(query.expr, 0)?"true":"false") << "\n";
+
+ log << "\n\n";
+#endif
+
+ return isGood ? IncompleteSolver::MayBeFalse : IncompleteSolver::None;
+}
+
+bool FastCexSolver::computeValue(const Query& query, ref<Expr> &result) {
+ ObjectFinder of;
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ of.visit(*it);
+ of.visit(query.expr);
+ CexData cd(of);
+
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ cd.forceExprToValue(*it, 1);
+
+ // this could be done lazily of course
+ cd.fixValues();
+
+ // check the result
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ if (!cd.exprMustBeValue(*it, 1))
+ return false;
+
+ CexConstifier cc(cd.objectValues);
+ ref<Expr> value = cc.visit(query.expr);
+
+ if (value.isConstant()) {
+ result = value;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool
+FastCexSolver::computeInitialValues(const Query& query,
+ const std::vector<const Array*>
+ &objects,
+ std::vector< std::vector<unsigned char> >
+ &values,
+ bool &hasSolution) {
+ ObjectFinder of;
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ of.visit(*it);
+ of.visit(query.expr);
+ for (unsigned i = 0; i != objects.size(); ++i)
+ of.addObject(*objects[i]);
+ CexData cd(of);
+
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ cd.forceExprToValue(*it, 1);
+ cd.forceExprToValue(query.expr, 0);
+
+ // this could be done lazily of course
+ cd.fixValues();
+
+ // check the result
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ if (!cd.exprMustBeValue(*it, 1))
+ return false;
+ if (!cd.exprMustBeValue(query.expr, 0))
+ return false;
+
+ hasSolution = true;
+ CexConstifier cc(cd.objectValues);
+ for (unsigned i = 0; i != objects.size(); ++i) {
+ const Array *array = objects[i];
+ std::vector<unsigned char> data;
+ data.reserve(array->size);
+
+ for (unsigned i=0; i < array->size; i++) {
+ ref<Expr> value =
+ cc.visit(ReadExpr::create(UpdateList(array, true, 0),
+ ConstantExpr::create(i,
+ kMachinePointerType)));
+
+ if (value.isConstant()) {
+ data.push_back(value.getConstantValue());
+ } else {
+ // FIXME: When does this happen?
+ return false;
+ }
+ }
+
+ values.push_back(data);
+ }
+
+ return true;
+}
+
+
+Solver *klee::createFastCexSolver(Solver *s) {
+ return new Solver(new StagedSolverImpl(new FastCexSolver(), s));
+}
diff --git a/lib/Solver/IncompleteSolver.cpp b/lib/Solver/IncompleteSolver.cpp
new file mode 100644
index 00000000..f473f70b
--- /dev/null
+++ b/lib/Solver/IncompleteSolver.cpp
@@ -0,0 +1,136 @@
+//===-- IncompleteSolver.cpp ----------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "klee/IncompleteSolver.h"
+
+#include "klee/Constraints.h"
+
+using namespace klee;
+using namespace llvm;
+
+/***/
+
+IncompleteSolver::PartialValidity
+IncompleteSolver::negatePartialValidity(PartialValidity pv) {
+ switch(pv) {
+ case MustBeTrue: return MustBeFalse;
+ case MustBeFalse: return MustBeTrue;
+ case MayBeTrue: return MayBeFalse;
+ case MayBeFalse: return MayBeTrue;
+ case TrueOrFalse: return TrueOrFalse;
+ default: assert(0 && "invalid partial validity");
+ }
+}
+
+IncompleteSolver::PartialValidity
+IncompleteSolver::computeValidity(const Query& query) {
+ PartialValidity trueResult = computeTruth(query);
+
+ if (trueResult == MustBeTrue) {
+ return MustBeTrue;
+ } else {
+ PartialValidity falseResult = computeTruth(query.negateExpr());
+
+ if (falseResult == MustBeTrue) {
+ return MustBeFalse;
+ } else {
+ bool trueCorrect = trueResult != None,
+ falseCorrect = falseResult != None;
+
+ if (trueCorrect && falseCorrect) {
+ return TrueOrFalse;
+ } else if (trueCorrect) { // ==> trueResult == MayBeFalse
+ return MayBeFalse;
+ } else if (falseCorrect) { // ==> falseResult == MayBeFalse
+ return MayBeTrue;
+ } else {
+ return None;
+ }
+ }
+ }
+}
+
+/***/
+
+StagedSolverImpl::StagedSolverImpl(IncompleteSolver *_primary,
+ Solver *_secondary)
+ : primary(_primary),
+ secondary(_secondary) {
+}
+
+StagedSolverImpl::~StagedSolverImpl() {
+ delete primary;
+ delete secondary;
+}
+
+bool StagedSolverImpl::computeTruth(const Query& query, bool &isValid) {
+ IncompleteSolver::PartialValidity trueResult = primary->computeTruth(query);
+
+ if (trueResult != IncompleteSolver::None) {
+ isValid = (trueResult == IncompleteSolver::MustBeTrue);
+ return true;
+ }
+
+ return secondary->impl->computeTruth(query, isValid);
+}
+
+bool StagedSolverImpl::computeValidity(const Query& query,
+ Solver::Validity &result) {
+ bool tmp;
+
+ switch(primary->computeValidity(query)) {
+ case IncompleteSolver::MustBeTrue:
+ result = Solver::True;
+ break;
+ case IncompleteSolver::MustBeFalse:
+ result = Solver::False;
+ break;
+ case IncompleteSolver::TrueOrFalse:
+ result = Solver::Unknown;
+ break;
+ case IncompleteSolver::MayBeTrue:
+ if (!secondary->impl->computeTruth(query, tmp))
+ return false;
+ result = tmp ? Solver::True : Solver::Unknown;
+ break;
+ case IncompleteSolver::MayBeFalse:
+ if (!secondary->impl->computeTruth(query.negateExpr(), tmp))
+ return false;
+ result = tmp ? Solver::False : Solver::Unknown;
+ break;
+ default:
+ if (!secondary->impl->computeValidity(query, result))
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+bool StagedSolverImpl::computeValue(const Query& query,
+ ref<Expr> &result) {
+ if (primary->computeValue(query, result))
+ return true;
+
+ return secondary->impl->computeValue(query, result);
+}
+
+bool
+StagedSolverImpl::computeInitialValues(const Query& query,
+ const std::vector<const Array*>
+ &objects,
+ std::vector< std::vector<unsigned char> >
+ &values,
+ bool &hasSolution) {
+ if (primary->computeInitialValues(query, objects, values, hasSolution))
+ return true;
+
+ return secondary->impl->computeInitialValues(query, objects, values,
+ hasSolution);
+}
diff --git a/lib/Solver/IndependentSolver.cpp b/lib/Solver/IndependentSolver.cpp
new file mode 100644
index 00000000..c966aff6
--- /dev/null
+++ b/lib/Solver/IndependentSolver.cpp
@@ -0,0 +1,314 @@
+//===-- IndependentSolver.cpp ---------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "klee/Solver.h"
+
+#include "klee/Expr.h"
+#include "klee/Constraints.h"
+#include "klee/SolverImpl.h"
+
+#include "klee/util/ExprUtil.h"
+
+#include "llvm/Support/Streams.h"
+
+#include <map>
+#include <vector>
+
+using namespace klee;
+using namespace llvm;
+
+template<class T>
+class DenseSet {
+ typedef std::set<T> set_ty;
+ set_ty s;
+
+public:
+ DenseSet() {}
+
+ void add(T x) {
+ s.insert(x);
+ }
+ void add(T start, T end) {
+ for (; start<end; start++)
+ s.insert(start);
+ }
+
+ // returns true iff set is changed by addition
+ bool add(const DenseSet &b) {
+ bool modified = false;
+ for (typename set_ty::const_iterator it = b.s.begin(), ie = b.s.end();
+ it != ie; ++it) {
+ if (modified || !s.count(*it)) {
+ modified = true;
+ s.insert(*it);
+ }
+ }
+ return modified;
+ }
+
+ bool intersects(const DenseSet &b) {
+ for (typename set_ty::iterator it = s.begin(), ie = s.end();
+ it != ie; ++it)
+ if (b.s.count(*it))
+ return true;
+ return false;
+ }
+
+ void print(std::ostream &os) const {
+ bool first = true;
+ os << "{";
+ for (typename set_ty::iterator it = s.begin(), ie = s.end();
+ it != ie; ++it) {
+ if (first) {
+ first = false;
+ } else {
+ os << ",";
+ }
+ os << *it;
+ }
+ os << "}";
+ }
+};
+
+template<class T>
+inline std::ostream &operator<<(std::ostream &os, const DenseSet<T> &dis) {
+ dis.print(os);
+ return os;
+}
+
+class IndependentElementSet {
+ typedef std::map<const Array*, DenseSet<unsigned> > elements_ty;
+ elements_ty elements;
+ std::set<const Array*> wholeObjects;
+
+public:
+ IndependentElementSet() {}
+ IndependentElementSet(ref<Expr> e) {
+ std::vector< ref<ReadExpr> > reads;
+ findReads(e, /* visitUpdates= */ true, reads);
+ for (unsigned i = 0; i != reads.size(); ++i) {
+ ReadExpr *re = reads[i].get();
+ if (re->updates.isRooted) {
+ const Array *array = re->updates.root;
+ if (!wholeObjects.count(array)) {
+ if (re->index.isConstant()) {
+ DenseSet<unsigned> &dis = elements[array];
+ dis.add((unsigned) re->index.getConstantValue());
+ } else {
+ elements_ty::iterator it2 = elements.find(array);
+ if (it2!=elements.end())
+ elements.erase(it2);
+ wholeObjects.insert(array);
+ }
+ }
+ }
+ }
+ }
+ IndependentElementSet(const IndependentElementSet &ies) :
+ elements(ies.elements),
+ wholeObjects(ies.wholeObjects) {}
+
+ IndependentElementSet &operator=(const IndependentElementSet &ies) {
+ elements = ies.elements;
+ wholeObjects = ies.wholeObjects;
+ return *this;
+ }
+
+ void print(std::ostream &os) const {
+ os << "{";
+ bool first = true;
+ for (std::set<const Array*>::iterator it = wholeObjects.begin(),
+ ie = wholeObjects.end(); it != ie; ++it) {
+ const Array *array = *it;
+
+ if (first) {
+ first = false;
+ } else {
+ os << ", ";
+ }
+
+ os << "MO" << array->id;
+ }
+ for (elements_ty::const_iterator it = elements.begin(), ie = elements.end();
+ it != ie; ++it) {
+ const Array *array = it->first;
+ const DenseSet<unsigned> &dis = it->second;
+
+ if (first) {
+ first = false;
+ } else {
+ os << ", ";
+ }
+
+ os << "MO" << array->id << " : " << dis;
+ }
+ os << "}";
+ }
+
+ // more efficient when this is the smaller set
+ bool intersects(const IndependentElementSet &b) {
+ for (std::set<const Array*>::iterator it = wholeObjects.begin(),
+ ie = wholeObjects.end(); it != ie; ++it) {
+ const Array *array = *it;
+ if (b.wholeObjects.count(array) ||
+ b.elements.find(array) != b.elements.end())
+ return true;
+ }
+ for (elements_ty::iterator it = elements.begin(), ie = elements.end();
+ it != ie; ++it) {
+ const Array *array = it->first;
+ if (b.wholeObjects.count(array))
+ return true;
+ elements_ty::const_iterator it2 = b.elements.find(array);
+ if (it2 != b.elements.end()) {
+ if (it->second.intersects(it2->second))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // returns true iff set is changed by addition
+ bool add(const IndependentElementSet &b) {
+ bool modified = false;
+ for (std::set<const Array*>::const_iterator it = b.wholeObjects.begin(),
+ ie = b.wholeObjects.end(); it != ie; ++it) {
+ const Array *array = *it;
+ elements_ty::iterator it2 = elements.find(array);
+ if (it2!=elements.end()) {
+ modified = true;
+ elements.erase(it2);
+ wholeObjects.insert(array);
+ } else {
+ if (!wholeObjects.count(array)) {
+ modified = true;
+ wholeObjects.insert(array);
+ }
+ }
+ }
+ for (elements_ty::const_iterator it = b.elements.begin(),
+ ie = b.elements.end(); it != ie; ++it) {
+ const Array *array = it->first;
+ if (!wholeObjects.count(array)) {
+ elements_ty::iterator it2 = elements.find(array);
+ if (it2==elements.end()) {
+ modified = true;
+ elements.insert(*it);
+ } else {
+ if (it2->second.add(it->second))
+ modified = true;
+ }
+ }
+ }
+ return modified;
+ }
+};
+
+inline std::ostream &operator<<(std::ostream &os, const IndependentElementSet &ies) {
+ ies.print(os);
+ return os;
+}
+
+static
+IndependentElementSet getIndependentConstraints(const Query& query,
+ std::vector< ref<Expr> > &result) {
+ IndependentElementSet eltsClosure(query.expr);
+ std::vector< std::pair<ref<Expr>, IndependentElementSet> > worklist;
+
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ worklist.push_back(std::make_pair(*it, IndependentElementSet(*it)));
+
+ // XXX This should be more efficient (in terms of low level copy stuff).
+ bool done = false;
+ do {
+ done = true;
+ std::vector< std::pair<ref<Expr>, IndependentElementSet> > newWorklist;
+ for (std::vector< std::pair<ref<Expr>, IndependentElementSet> >::iterator
+ it = worklist.begin(), ie = worklist.end(); it != ie; ++it) {
+ if (it->second.intersects(eltsClosure)) {
+ if (eltsClosure.add(it->second))
+ done = false;
+ result.push_back(it->first);
+ } else {
+ newWorklist.push_back(*it);
+ }
+ }
+ worklist.swap(newWorklist);
+ } while (!done);
+
+ if (0) {
+ std::set< ref<Expr> > reqset(result.begin(), result.end());
+ llvm::cerr << "--\n";
+ llvm::cerr << "Q: " << query.expr << "\n";
+ llvm::cerr << "\telts: " << IndependentElementSet(query.expr) << "\n";
+ int i = 0;
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it) {
+ llvm::cerr << "C" << i++ << ": " << *it;
+ llvm::cerr << " " << (reqset.count(*it) ? "(required)" : "(independent)") << "\n";
+ llvm::cerr << "\telts: " << IndependentElementSet(*it) << "\n";
+ }
+ llvm::cerr << "elts closure: " << eltsClosure << "\n";
+ }
+
+ return eltsClosure;
+}
+
+class IndependentSolver : public SolverImpl {
+private:
+ Solver *solver;
+
+public:
+ IndependentSolver(Solver *_solver)
+ : solver(_solver) {}
+ ~IndependentSolver() { delete solver; }
+
+ bool computeTruth(const Query&, bool &isValid);
+ bool computeValidity(const Query&, Solver::Validity &result);
+ bool computeValue(const Query&, ref<Expr> &result);
+ bool computeInitialValues(const Query& query,
+ const std::vector<const Array*> &objects,
+ std::vector< std::vector<unsigned char> > &values,
+ bool &hasSolution) {
+ return solver->impl->computeInitialValues(query, objects, values,
+ hasSolution);
+ }
+};
+
+bool IndependentSolver::computeValidity(const Query& query,
+ Solver::Validity &result) {
+ std::vector< ref<Expr> > required;
+ IndependentElementSet eltsClosure =
+ getIndependentConstraints(query, required);
+ ConstraintManager tmp(required);
+ return solver->impl->computeValidity(Query(tmp, query.expr),
+ result);
+}
+
+bool IndependentSolver::computeTruth(const Query& query, bool &isValid) {
+ std::vector< ref<Expr> > required;
+ IndependentElementSet eltsClosure =
+ getIndependentConstraints(query, required);
+ ConstraintManager tmp(required);
+ return solver->impl->computeTruth(Query(tmp, query.expr),
+ isValid);
+}
+
+bool IndependentSolver::computeValue(const Query& query, ref<Expr> &result) {
+ std::vector< ref<Expr> > required;
+ IndependentElementSet eltsClosure =
+ getIndependentConstraints(query, required);
+ ConstraintManager tmp(required);
+ return solver->impl->computeValue(Query(tmp, query.expr), result);
+}
+
+Solver *klee::createIndependentSolver(Solver *s) {
+ return new Solver(new IndependentSolver(s));
+}
diff --git a/lib/Solver/Makefile b/lib/Solver/Makefile
new file mode 100755
index 00000000..11d3d330
--- /dev/null
+++ b/lib/Solver/Makefile
@@ -0,0 +1,16 @@
+#===-- lib/Solver/Makefile ---------------------------------*- Makefile -*--===#
+#
+# The KLEE Symbolic Virtual Machine
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+#===------------------------------------------------------------------------===#
+
+LEVEL=../..
+
+LIBRARYNAME=kleaverSolver
+DONT_BUILD_RELINKED=1
+BUILD_ARCHIVE=1
+
+include $(LEVEL)/Makefile.common
diff --git a/lib/Solver/PCLoggingSolver.cpp b/lib/Solver/PCLoggingSolver.cpp
new file mode 100644
index 00000000..4b787acb
--- /dev/null
+++ b/lib/Solver/PCLoggingSolver.cpp
@@ -0,0 +1,134 @@
+//===-- PCLoggingSolver.cpp -----------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "klee/Solver.h"
+
+// FIXME: This should not be here.
+#include "klee/ExecutionState.h"
+#include "klee/Expr.h"
+#include "klee/SolverImpl.h"
+#include "klee/Statistics.h"
+#include "klee/util/ExprPPrinter.h"
+#include "klee/Internal/Support/QueryLog.h"
+#include "klee/Internal/System/Time.h"
+
+#include "llvm/Support/CommandLine.h"
+
+#include <fstream>
+
+using namespace klee;
+using namespace llvm;
+using namespace klee::util;
+
+///
+
+class PCLoggingSolver : public SolverImpl {
+ Solver *solver;
+ std::ofstream os;
+ ExprPPrinter *printer;
+ unsigned queryCount;
+ double startTime;
+
+ void startQuery(const Query& query, const char *typeName) {
+ Statistic *S = theStatisticManager->getStatisticByName("Instructions");
+ uint64_t instructions = S ? S->getValue() : 0;
+ os << "# Query " << queryCount++ << " -- "
+ << "Type: " << typeName << ", "
+ << "Instructions: " << instructions << "\n";
+ printer->printQuery(os, query.constraints, query.expr);
+
+ startTime = getWallTime();
+ }
+
+ void finishQuery(bool success) {
+ double delta = getWallTime() - startTime;
+ os << "# " << (success ? "OK" : "FAIL") << " -- "
+ << "Elapsed: " << delta << "\n";
+ }
+
+public:
+ PCLoggingSolver(Solver *_solver, std::string path)
+ : solver(_solver),
+ os(path.c_str(), std::ios::trunc),
+ printer(ExprPPrinter::create(os)),
+ queryCount(0) {
+ }
+ ~PCLoggingSolver() {
+ delete printer;
+ delete solver;
+ }
+
+ bool computeTruth(const Query& query, bool &isValid) {
+ startQuery(query, "Truth");
+ bool success = solver->impl->computeTruth(query, isValid);
+ finishQuery(success);
+ if (success)
+ os << "# Is Valid: " << (isValid ? "true" : "false") << "\n";
+ os << "\n";
+ return success;
+ }
+
+ bool computeValidity(const Query& query, Solver::Validity &result) {
+ startQuery(query, "Validity");
+ bool success = solver->impl->computeValidity(query, result);
+ finishQuery(success);
+ if (success)
+ os << "# Validity: " << result << "\n";
+ os << "\n";
+ return success;
+ }
+
+ bool computeValue(const Query& query, ref<Expr> &result) {
+ startQuery(query, "Value");
+ bool success = solver->impl->computeValue(query, result);
+ finishQuery(success);
+ if (success)
+ os << "# Result: " << result << "\n";
+ os << "\n";
+ return success;
+ }
+
+ bool computeInitialValues(const Query& query,
+ const std::vector<const Array*> &objects,
+ std::vector< std::vector<unsigned char> > &values,
+ bool &hasSolution) {
+ // FIXME: Add objects to output.
+ startQuery(query, "InitialValues");
+ bool success = solver->impl->computeInitialValues(query, objects,
+ values, hasSolution);
+ finishQuery(success);
+ if (success) {
+ os << "# Solvable: " << (hasSolution ? "true" : "false") << "\n";
+ if (hasSolution) {
+ std::vector< std::vector<unsigned char> >::iterator
+ values_it = values.begin();
+ for (std::vector<const Array*>::const_iterator i = objects.begin(),
+ e = objects.end(); i != e; ++i, ++values_it) {
+ const Array *array = *i;
+ std::vector<unsigned char> &data = *values_it;
+ os << "# arr" << array->id << " = [";
+ for (unsigned j = 0; j < array->size; j++) {
+ os << (int) data[j];
+ if (j+1 < array->size)
+ os << ",";
+ }
+ os << "]\n";
+ }
+ }
+ }
+ os << "\n";
+ return success;
+ }
+};
+
+///
+
+Solver *klee::createPCLoggingSolver(Solver *_solver, std::string path) {
+ return new Solver(new PCLoggingSolver(_solver, path));
+}
diff --git a/lib/Solver/STPBuilder.cpp b/lib/Solver/STPBuilder.cpp
new file mode 100644
index 00000000..33aee035
--- /dev/null
+++ b/lib/Solver/STPBuilder.cpp
@@ -0,0 +1,819 @@
+//===-- STPBuilder.cpp ----------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "STPBuilder.h"
+
+#include "klee/Expr.h"
+#include "klee/Solver.h"
+#include "klee/util/Bits.h"
+
+#include "ConstantDivision.h"
+#include "SolverStats.h"
+
+#include "llvm/Support/CommandLine.h"
+
+#define vc_bvBoolExtract IAMTHESPAWNOFSATAN
+// unclear return
+#define vc_bvLeftShiftExpr IAMTHESPAWNOFSATAN
+#define vc_bvRightShiftExpr IAMTHESPAWNOFSATAN
+// bad refcnt'ng
+#define vc_bvVar32LeftShiftExpr IAMTHESPAWNOFSATAN
+#define vc_bvVar32RightShiftExpr IAMTHESPAWNOFSATAN
+#define vc_bvVar32DivByPowOfTwoExpr IAMTHESPAWNOFSATAN
+#define vc_bvCreateMemoryArray IAMTHESPAWNOFSATAN
+#define vc_bvReadMemoryArray IAMTHESPAWNOFSATAN
+#define vc_bvWriteToMemoryArray IAMTHESPAWNOFSATAN
+
+#include <algorithm> // max, min
+#include <cassert>
+#include <iostream>
+#include <map>
+#include <sstream>
+#include <vector>
+
+using namespace klee;
+
+namespace {
+ llvm::cl::opt<bool>
+ UseConstructHash("use-construct-hash",
+ llvm::cl::desc("Use hash-consing during STP query construction."),
+ llvm::cl::init(true));
+}
+
+///
+
+/***/
+
+STPBuilder::STPBuilder(::VC _vc, bool _optimizeDivides)
+ : vc(_vc), optimizeDivides(_optimizeDivides)
+{
+ tempVars[0] = buildVar("__tmpInt8", 8);
+ tempVars[1] = buildVar("__tmpInt16", 16);
+ tempVars[2] = buildVar("__tmpInt32", 32);
+ tempVars[3] = buildVar("__tmpInt64", 64);
+}
+
+STPBuilder::~STPBuilder() {
+}
+
+///
+
+/* Warning: be careful about what c_interface functions you use. Some of
+ them look like they cons memory but in fact don't, which is bad when
+ you call vc_DeleteExpr on them. */
+
+::VCExpr STPBuilder::buildVar(const char *name, unsigned width) {
+ // XXX don't rebuild if this stuff cons's
+ ::Type t = (width==1) ? vc_boolType(vc) : vc_bvType(vc, width);
+ ::VCExpr res = vc_varExpr(vc, (char*) name, t);
+ vc_DeleteExpr(t);
+ return res;
+}
+
+::VCExpr STPBuilder::buildArray(const char *name, unsigned indexWidth, unsigned valueWidth) {
+ // XXX don't rebuild if this stuff cons's
+ ::Type t1 = vc_bvType(vc, indexWidth);
+ ::Type t2 = vc_bvType(vc, valueWidth);
+ ::Type t = vc_arrayType(vc, t1, t2);
+ ::VCExpr res = vc_varExpr(vc, (char*) name, t);
+ vc_DeleteExpr(t);
+ vc_DeleteExpr(t2);
+ vc_DeleteExpr(t1);
+ return res;
+}
+
+ExprHandle STPBuilder::getTempVar(Expr::Width w) {
+ switch (w) {
+ case Expr::Int8: return tempVars[0];
+ case Expr::Int16: return tempVars[1];
+ case Expr::Int32: return tempVars[2];
+ case Expr::Int64: return tempVars[3];
+ default:
+ assert(0 && "invalid type");
+ }
+}
+
+ExprHandle STPBuilder::getTrue() {
+ return vc_trueExpr(vc);
+}
+ExprHandle STPBuilder::getFalse() {
+ return vc_falseExpr(vc);
+}
+ExprHandle STPBuilder::bvOne(unsigned width) {
+ return bvConst32(width, 1);
+}
+ExprHandle STPBuilder::bvZero(unsigned width) {
+ return bvConst32(width, 0);
+}
+ExprHandle STPBuilder::bvMinusOne(unsigned width) {
+ return bvConst64(width, (int64_t) -1);
+}
+ExprHandle STPBuilder::bvConst32(unsigned width, uint32_t value) {
+ return vc_bvConstExprFromInt(vc, width, value);
+}
+ExprHandle STPBuilder::bvConst64(unsigned width, uint64_t value) {
+ return vc_bvConstExprFromLL(vc, width, value);
+}
+
+ExprHandle STPBuilder::bvBoolExtract(ExprHandle expr, int bit) {
+ return vc_eqExpr(vc, bvExtract(expr, bit, bit), bvOne(1));
+}
+ExprHandle STPBuilder::bvExtract(ExprHandle expr, unsigned top, unsigned bottom) {
+ return vc_bvExtract(vc, expr, top, bottom);
+}
+ExprHandle STPBuilder::eqExpr(ExprHandle a, ExprHandle b) {
+ return vc_eqExpr(vc, a, b);
+}
+
+// logical right shift
+ExprHandle STPBuilder::bvRightShift(ExprHandle expr, unsigned amount, unsigned shiftBits) {
+ unsigned width = vc_getBVLength(vc, expr);
+ unsigned shift = amount & ((1<<shiftBits) - 1);
+
+ if (shift==0) {
+ return expr;
+ } else if (shift>=width) {
+ return bvZero(width);
+ } else {
+ return vc_bvConcatExpr(vc,
+ bvZero(shift),
+ bvExtract(expr, width - 1, shift));
+ }
+}
+
+// logical left shift
+ExprHandle STPBuilder::bvLeftShift(ExprHandle expr, unsigned amount, unsigned shiftBits) {
+ unsigned width = vc_getBVLength(vc, expr);
+ unsigned shift = amount & ((1<<shiftBits) - 1);
+
+ if (shift==0) {
+ return expr;
+ } else if (shift>=width) {
+ return bvZero(width);
+ } else {
+ // stp shift does "expr @ [0 x s]" which we then have to extract,
+ // rolling our own gives slightly smaller exprs
+ return vc_bvConcatExpr(vc,
+ bvExtract(expr, width - shift - 1, 0),
+ bvZero(shift));
+ }
+}
+
+// left shift by a variable amount on an expression of the specified width
+ExprHandle STPBuilder::bvVarLeftShift(ExprHandle expr, ExprHandle amount, unsigned width) {
+ ExprHandle res = bvZero(width);
+
+ int shiftBits = getShiftBits( width );
+
+ //get the shift amount (looking only at the bits appropriate for the given width)
+ ExprHandle shift = vc_bvExtract( vc, amount, shiftBits - 1, 0 );
+
+ //construct a big if-then-elif-elif-... with one case per possible shift amount
+ for( int i=width-1; i>=0; i-- ) {
+ res = vc_iteExpr(vc,
+ eqExpr(shift, bvConst32(shiftBits, i)),
+ bvLeftShift(expr, i, shiftBits),
+ res);
+ }
+ return res;
+}
+
+// logical right shift by a variable amount on an expression of the specified width
+ExprHandle STPBuilder::bvVarRightShift(ExprHandle expr, ExprHandle amount, unsigned width) {
+ ExprHandle res = bvZero(width);
+
+ int shiftBits = getShiftBits( width );
+
+ //get the shift amount (looking only at the bits appropriate for the given width)
+ ExprHandle shift = vc_bvExtract( vc, amount, shiftBits - 1, 0 );
+
+ //construct a big if-then-elif-elif-... with one case per possible shift amount
+ for( int i=width-1; i>=0; i-- ) {
+ res = vc_iteExpr(vc,
+ eqExpr(shift, bvConst32(shiftBits, i)),
+ bvRightShift(expr, i, shiftBits),
+ res);
+ }
+
+ return res;
+}
+
+// arithmetic right shift by a variable amount on an expression of the specified width
+ExprHandle STPBuilder::bvVarArithRightShift(ExprHandle expr, ExprHandle amount, unsigned width) {
+ int shiftBits = getShiftBits( width );
+
+ //get the shift amount (looking only at the bits appropriate for the given width)
+ ExprHandle shift = vc_bvExtract( vc, amount, shiftBits - 1, 0 );
+
+ //get the sign bit to fill with
+ ExprHandle signedBool = bvBoolExtract(expr, width-1);
+
+ //start with the result if shifting by width-1
+ ExprHandle res = constructAShrByConstant(expr, width-1, signedBool, shiftBits);
+
+ //construct a big if-then-elif-elif-... with one case per possible shift amount
+ // XXX more efficient to move the ite on the sign outside all exprs?
+ // XXX more efficient to sign extend, right shift, then extract lower bits?
+ for( int i=width-2; i>=0; i-- ) {
+ res = vc_iteExpr(vc,
+ eqExpr(shift, bvConst32(shiftBits,i)),
+ constructAShrByConstant(expr,
+ i,
+ signedBool,
+ shiftBits),
+ res);
+ }
+
+ return res;
+}
+
+ExprHandle STPBuilder::constructAShrByConstant(ExprHandle expr,
+ unsigned amount,
+ ExprHandle isSigned,
+ unsigned shiftBits) {
+ unsigned width = vc_getBVLength(vc, expr);
+ unsigned shift = amount & ((1<<shiftBits) - 1);
+
+ if (shift==0) {
+ return expr;
+ } else if (shift>=width-1) {
+ return vc_iteExpr(vc, isSigned, bvMinusOne(width), bvZero(width));
+ } else {
+ return vc_iteExpr(vc,
+ isSigned,
+ ExprHandle(vc_bvConcatExpr(vc,
+ bvMinusOne(shift),
+ bvExtract(expr, width - 1, shift))),
+ bvRightShift(expr, shift, shiftBits));
+ }
+}
+
+ExprHandle STPBuilder::constructMulByConstant(ExprHandle expr, unsigned width, uint64_t x) {
+ unsigned shiftBits = getShiftBits(width);
+ uint64_t add, sub;
+ ExprHandle res = 0;
+
+ // expr*x == expr*(add-sub) == expr*add - expr*sub
+ ComputeMultConstants64(x, add, sub);
+
+ // legal, these would overflow completely
+ add = bits64::truncateToNBits(add, width);
+ sub = bits64::truncateToNBits(sub, width);
+
+ for (int j=63; j>=0; j--) {
+ uint64_t bit = 1LL << j;
+
+ if ((add&bit) || (sub&bit)) {
+ assert(!((add&bit) && (sub&bit)) && "invalid mult constants");
+ ExprHandle op = bvLeftShift(expr, j, shiftBits);
+
+ if (add&bit) {
+ if (res) {
+ res = vc_bvPlusExpr(vc, width, res, op);
+ } else {
+ res = op;
+ }
+ } else {
+ if (res) {
+ res = vc_bvMinusExpr(vc, width, res, op);
+ } else {
+ res = vc_bvUMinusExpr(vc, op);
+ }
+ }
+ }
+ }
+
+ if (!res)
+ res = bvZero(width);
+
+ return res;
+}
+
+/*
+ * Compute the 32-bit unsigned integer division of n by a divisor d based on
+ * the constants derived from the constant divisor d.
+ *
+ * Returns n/d without doing explicit division. The cost is 2 adds, 3 shifts,
+ * and a (64-bit) multiply.
+ *
+ * @param n numerator (dividend) as an expression
+ * @param width number of bits used to represent the value
+ * @param d the divisor
+ *
+ * @return n/d without doing explicit division
+ */
+ExprHandle STPBuilder::constructUDivByConstant(ExprHandle expr_n, unsigned width, uint64_t d) {
+ assert(width==32 && "can only compute udiv constants for 32-bit division");
+
+ // Compute the constants needed to compute n/d for constant d w/o
+ // division by d.
+ uint32_t mprime, sh1, sh2;
+ ComputeUDivConstants32(d, mprime, sh1, sh2);
+ ExprHandle expr_sh1 = bvConst32( 32, sh1);
+ ExprHandle expr_sh2 = bvConst32( 32, sh2);
+
+ // t1 = MULUH(mprime, n) = ( (uint64_t)mprime * (uint64_t)n ) >> 32
+ ExprHandle expr_n_64 = vc_bvConcatExpr( vc, bvZero(32), expr_n ); //extend to 64 bits
+ ExprHandle t1_64bits = constructMulByConstant( expr_n_64, 64, (uint64_t)mprime );
+ ExprHandle t1 = vc_bvExtract( vc, t1_64bits, 63, 32 ); //upper 32 bits
+
+ // n/d = (((n - t1) >> sh1) + t1) >> sh2;
+ ExprHandle n_minus_t1 = vc_bvMinusExpr( vc, width, expr_n, t1 );
+ ExprHandle shift_sh1 = bvVarRightShift( n_minus_t1, expr_sh1, 32 );
+ ExprHandle plus_t1 = vc_bvPlusExpr( vc, width, shift_sh1, t1 );
+ ExprHandle res = bvVarRightShift( plus_t1, expr_sh2, 32 );
+
+ return res;
+}
+
+/*
+ * Compute the 32-bitnsigned integer division of n by a divisor d based on
+ * the constants derived from the constant divisor d.
+ *
+ * Returns n/d without doing explicit division. The cost is 3 adds, 3 shifts,
+ * a (64-bit) multiply, and an XOR.
+ *
+ * @param n numerator (dividend) as an expression
+ * @param width number of bits used to represent the value
+ * @param d the divisor
+ *
+ * @return n/d without doing explicit division
+ */
+ExprHandle STPBuilder::constructSDivByConstant(ExprHandle expr_n, unsigned width, uint64_t d) {
+ assert(width==32 && "can only compute udiv constants for 32-bit division");
+
+ // Compute the constants needed to compute n/d for constant d w/o division by d.
+ int32_t mprime, dsign, shpost;
+ ComputeSDivConstants32(d, mprime, dsign, shpost);
+ ExprHandle expr_dsign = bvConst32( 32, dsign);
+ ExprHandle expr_shpost = bvConst32( 32, shpost);
+
+ // q0 = n + MULSH( mprime, n ) = n + (( (int64_t)mprime * (int64_t)n ) >> 32)
+ int64_t mprime_64 = (int64_t)mprime;
+
+ ExprHandle expr_n_64 = vc_bvSignExtend( vc, expr_n, 64 );
+ ExprHandle mult_64 = constructMulByConstant( expr_n_64, 64, mprime_64 );
+ ExprHandle mulsh = vc_bvExtract( vc, mult_64, 63, 32 ); //upper 32-bits
+ ExprHandle n_plus_mulsh = vc_bvPlusExpr( vc, width, expr_n, mulsh );
+
+ // Improved variable arithmetic right shift: sign extend, shift,
+ // extract.
+ ExprHandle extend_npm = vc_bvSignExtend( vc, n_plus_mulsh, 64 );
+ ExprHandle shift_npm = bvVarRightShift( extend_npm, expr_shpost, 64 );
+ ExprHandle shift_shpost = vc_bvExtract( vc, shift_npm, 31, 0 ); //lower 32-bits
+
+ // XSIGN(n) is -1 if n is negative, positive one otherwise
+ ExprHandle is_signed = bvBoolExtract( expr_n, 31 );
+ ExprHandle neg_one = bvMinusOne(32);
+ ExprHandle xsign_of_n = vc_iteExpr( vc, is_signed, neg_one, bvZero(32) );
+
+ // q0 = (n_plus_mulsh >> shpost) - XSIGN(n)
+ ExprHandle q0 = vc_bvMinusExpr( vc, width, shift_shpost, xsign_of_n );
+
+ // n/d = (q0 ^ dsign) - dsign
+ ExprHandle q0_xor_dsign = vc_bvXorExpr( vc, q0, expr_dsign );
+ ExprHandle res = vc_bvMinusExpr( vc, width, q0_xor_dsign, expr_dsign );
+
+ return res;
+}
+
+::VCExpr STPBuilder::getInitialArray(const Array *root) {
+ if (root->stpInitialArray) {
+ return root->stpInitialArray;
+ } else {
+ char buf[32];
+ sprintf(buf, "arr%d", root->id);
+ root->stpInitialArray = buildArray(buf, 32, 8);
+ return root->stpInitialArray;
+ }
+}
+
+ExprHandle STPBuilder::getInitialRead(const Array *root, unsigned index) {
+ return vc_readExpr(vc, getInitialArray(root), bvConst32(32, index));
+}
+
+::VCExpr STPBuilder::getArrayForUpdate(const Array *root,
+ const UpdateNode *un) {
+ if (!un) {
+ return getInitialArray(root);
+ } else {
+ // FIXME: This really needs to be non-recursive.
+ if (!un->stpArray)
+ un->stpArray = vc_writeExpr(vc,
+ getArrayForUpdate(root, un->next),
+ construct(un->index, 0),
+ construct(un->value, 0));
+
+ return un->stpArray;
+ }
+}
+
+/** if *width_out!=1 then result is a bitvector,
+ otherwise it is a bool */
+ExprHandle STPBuilder::construct(ref<Expr> e, int *width_out) {
+ if (!UseConstructHash || e.isConstant()) {
+ return constructActual(e, width_out);
+ } else {
+ ExprHashMap< std::pair<ExprHandle, unsigned> >::iterator it =
+ constructed.find(e);
+ if (it!=constructed.end()) {
+ if (width_out)
+ *width_out = it->second.second;
+ return it->second.first;
+ } else {
+ int width;
+ if (!width_out) width_out = &width;
+ ExprHandle res = constructActual(e, width_out);
+ constructed.insert(std::make_pair(e, std::make_pair(res, *width_out)));
+ return res;
+ }
+ }
+}
+
+
+/** if *width_out!=1 then result is a bitvector,
+ otherwise it is a bool */
+ExprHandle STPBuilder::constructActual(ref<Expr> e, int *width_out) {
+ int width;
+ if (!width_out) width_out = &width;
+
+ ++stats::queryConstructs;
+
+ switch(e.getKind()) {
+
+ case Expr::Constant: {
+ uint64_t asUInt64 = e.getConstantValue();
+ *width_out = e.getWidth();
+
+ if (*width_out > 64)
+ assert(0 && "constructActual: width > 64");
+
+ if (*width_out == 1)
+ return asUInt64 ? getTrue() : getFalse();
+ else if (*width_out <= 32)
+ return bvConst32(*width_out, asUInt64);
+ else return bvConst64(*width_out, asUInt64);
+ }
+
+ // Special
+ case Expr::NotOptimized: {
+ NotOptimizedExpr *noe = static_ref_cast<NotOptimizedExpr>(e);
+ return construct(noe->src, width_out);
+ }
+
+ case Expr::Read: {
+ ReadExpr *re = static_ref_cast<ReadExpr>(e);
+ *width_out = 8;
+ return vc_readExpr(vc,
+ getArrayForUpdate(re->updates.root, re->updates.head),
+ construct(re->index, 0));
+ }
+
+ case Expr::Select: {
+ SelectExpr *se = static_ref_cast<SelectExpr>(e);
+ ExprHandle cond = construct(se->cond, 0);
+ ExprHandle tExpr = construct(se->trueExpr, width_out);
+ ExprHandle fExpr = construct(se->falseExpr, width_out);
+ return vc_iteExpr(vc, cond, tExpr, fExpr);
+ }
+
+ case Expr::Concat: {
+ ConcatExpr *ce = static_ref_cast<ConcatExpr>(e);
+ unsigned numKids = ce->getNumKids();
+ ExprHandle res = construct(ce->getKid(numKids-1), 0);
+ for (int i=numKids-2; i>=0; i--) {
+ res = vc_bvConcatExpr(vc, construct(ce->getKid(i), 0), res);
+ }
+ *width_out = ce->getWidth();
+ return res;
+ }
+
+ case Expr::Extract: {
+ ExtractExpr *ee = static_ref_cast<ExtractExpr>(e);
+ ExprHandle src = construct(ee->expr, width_out);
+ *width_out = ee->getWidth();
+ if (*width_out==1) {
+ return bvBoolExtract(src, 0);
+ } else {
+ return vc_bvExtract(vc, src, ee->offset + *width_out - 1, ee->offset);
+ }
+ }
+
+ // Casting
+
+ case Expr::ZExt: {
+ int srcWidth;
+ CastExpr *ce = static_ref_cast<CastExpr>(e);
+ ExprHandle src = construct(ce->src, &srcWidth);
+ *width_out = ce->getWidth();
+ if (srcWidth==1) {
+ return vc_iteExpr(vc, src, bvOne(*width_out), bvZero(*width_out));
+ } else {
+ return vc_bvConcatExpr(vc, bvZero(*width_out-srcWidth), src);
+ }
+ }
+
+ case Expr::SExt: {
+ int srcWidth;
+ CastExpr *ce = static_ref_cast<CastExpr>(e);
+ ExprHandle src = construct(ce->src, &srcWidth);
+ *width_out = ce->getWidth();
+ if (srcWidth==1) {
+ return vc_iteExpr(vc, src, bvMinusOne(*width_out), bvZero(*width_out));
+ } else {
+ return vc_bvSignExtend(vc, src, *width_out);
+ }
+ }
+
+ // Arithmetic
+
+ case Expr::Add: {
+ AddExpr *ae = static_ref_cast<AddExpr>(e);
+ ExprHandle left = construct(ae->left, width_out);
+ ExprHandle right = construct(ae->right, width_out);
+ assert(*width_out!=1 && "uncanonicalized add");
+ return vc_bvPlusExpr(vc, *width_out, left, right);
+ }
+
+ case Expr::Sub: {
+ SubExpr *se = static_ref_cast<SubExpr>(e);
+ ExprHandle left = construct(se->left, width_out);
+ ExprHandle right = construct(se->right, width_out);
+ assert(*width_out!=1 && "uncanonicalized sub");
+ return vc_bvMinusExpr(vc, *width_out, left, right);
+ }
+
+ case Expr::Mul: {
+ MulExpr *me = static_ref_cast<MulExpr>(e);
+ ExprHandle right = construct(me->right, width_out);
+ assert(*width_out!=1 && "uncanonicalized mul");
+
+ if (me->left.isConstant()) {
+ return constructMulByConstant(right, *width_out, me->left.getConstantValue());
+ } else {
+ ExprHandle left = construct(me->left, width_out);
+ return vc_bvMultExpr(vc, *width_out, left, right);
+ }
+ }
+
+ case Expr::UDiv: {
+ UDivExpr *de = static_ref_cast<UDivExpr>(e);
+ ExprHandle left = construct(de->left, width_out);
+ assert(*width_out!=1 && "uncanonicalized udiv");
+
+ if (de->right.isConstant()) {
+ uint64_t divisor = de->right.getConstantValue();
+
+ if (bits64::isPowerOfTwo(divisor)) {
+ return bvRightShift(left,
+ bits64::indexOfSingleBit(divisor),
+ getShiftBits(*width_out));
+ } else if (optimizeDivides) {
+ if (*width_out == 32) //only works for 32-bit division
+ return constructUDivByConstant( left, *width_out, (uint32_t)divisor );
+ }
+ }
+
+ ExprHandle right = construct(de->right, width_out);
+ return vc_bvDivExpr(vc, *width_out, left, right);
+ }
+
+ case Expr::SDiv: {
+ SDivExpr *de = static_ref_cast<SDivExpr>(e);
+ ExprHandle left = construct(de->left, width_out);
+ assert(*width_out!=1 && "uncanonicalized sdiv");
+
+ if (de->right.isConstant()) {
+ uint64_t divisor = de->right.getConstantValue();
+
+ if (optimizeDivides) {
+ if (*width_out == 32) //only works for 32-bit division
+ return constructSDivByConstant( left, *width_out, divisor);
+ }
+ }
+
+ // XXX need to test for proper handling of sign, not sure I
+ // trust STP
+ ExprHandle right = construct(de->right, width_out);
+ return vc_sbvDivExpr(vc, *width_out, left, right);
+ }
+
+ case Expr::URem: {
+ URemExpr *de = static_ref_cast<URemExpr>(e);
+ ExprHandle left = construct(de->left, width_out);
+ assert(*width_out!=1 && "uncanonicalized urem");
+
+ if (de->right.isConstant()) {
+ uint64_t divisor = de->right.getConstantValue();
+
+ if (bits64::isPowerOfTwo(divisor)) {
+ unsigned bits = bits64::indexOfSingleBit(divisor);
+
+ // special case for modding by 1 or else we bvExtract -1:0
+ if (bits == 0) {
+ return bvZero(*width_out);
+ } else {
+ return vc_bvConcatExpr(vc,
+ bvZero(*width_out - bits),
+ bvExtract(left, bits - 1, 0));
+ }
+ }
+
+ //use fast division to compute modulo without explicit division for constant divisor
+ if (optimizeDivides) {
+ if (*width_out == 32) { //only works for 32-bit division
+ ExprHandle quotient = constructUDivByConstant( left, *width_out, (uint32_t)divisor );
+ ExprHandle quot_times_divisor = constructMulByConstant( quotient, *width_out, divisor );
+ ExprHandle rem = vc_bvMinusExpr( vc, *width_out, left, quot_times_divisor );
+ return rem;
+ }
+ }
+ }
+
+ ExprHandle right = construct(de->right, width_out);
+ return vc_bvModExpr(vc, *width_out, left, right);
+ }
+
+ case Expr::SRem: {
+ SRemExpr *de = static_ref_cast<SRemExpr>(e);
+ ExprHandle left = construct(de->left, width_out);
+ ExprHandle right = construct(de->right, width_out);
+ assert(*width_out!=1 && "uncanonicalized srem");
+
+#if 0 //not faster per first benchmark
+ if (optimizeDivides) {
+ if (ConstantExpr *cre = de->right->asConstant()) {
+ uint64_t divisor = cre->asUInt64;
+
+ //use fast division to compute modulo without explicit division for constant divisor
+ if( *width_out == 32 ) { //only works for 32-bit division
+ ExprHandle quotient = constructSDivByConstant( left, *width_out, divisor );
+ ExprHandle quot_times_divisor = constructMulByConstant( quotient, *width_out, divisor );
+ ExprHandle rem = vc_bvMinusExpr( vc, *width_out, left, quot_times_divisor );
+ return rem;
+ }
+ }
+ }
+#endif
+
+ // XXX implement my fast path and test for proper handling of sign
+ return vc_sbvModExpr(vc, *width_out, left, right);
+ }
+
+ // Binary
+
+ case Expr::And: {
+ AndExpr *ae = static_ref_cast<AndExpr>(e);
+ ExprHandle left = construct(ae->left, width_out);
+ ExprHandle right = construct(ae->right, width_out);
+ if (*width_out==1) {
+ return vc_andExpr(vc, left, right);
+ } else {
+ return vc_bvAndExpr(vc, left, right);
+ }
+ }
+ case Expr::Or: {
+ OrExpr *oe = static_ref_cast<OrExpr>(e);
+ ExprHandle left = construct(oe->left, width_out);
+ ExprHandle right = construct(oe->right, width_out);
+ if (*width_out==1) {
+ return vc_orExpr(vc, left, right);
+ } else {
+ return vc_bvOrExpr(vc, left, right);
+ }
+ }
+
+ case Expr::Xor: {
+ XorExpr *xe = static_ref_cast<XorExpr>(e);
+ ExprHandle left = construct(xe->left, width_out);
+ ExprHandle right = construct(xe->right, width_out);
+
+ if (*width_out==1) {
+ // XXX check for most efficient?
+ return vc_iteExpr(vc, left,
+ ExprHandle(vc_notExpr(vc, right)), right);
+ } else {
+ return vc_bvXorExpr(vc, left, right);
+ }
+ }
+
+ case Expr::Shl: {
+ ShlExpr *se = static_ref_cast<ShlExpr>(e);
+ ExprHandle left = construct(se->left, width_out);
+ assert(*width_out!=1 && "uncanonicalized shl");
+
+ if (se->right.isConstant()) {
+ return bvLeftShift(left, se->right.getConstantValue(), getShiftBits(*width_out));
+ } else {
+ int shiftWidth;
+ ExprHandle amount = construct(se->right, &shiftWidth);
+ return bvVarLeftShift( left, amount, *width_out );
+ }
+ }
+
+ case Expr::LShr: {
+ LShrExpr *lse = static_ref_cast<LShrExpr>(e);
+ ExprHandle left = construct(lse->left, width_out);
+ unsigned shiftBits = getShiftBits(*width_out);
+ assert(*width_out!=1 && "uncanonicalized lshr");
+
+ if (lse->right.isConstant()) {
+ return bvRightShift(left, (unsigned) lse->right.getConstantValue(), shiftBits);
+ } else {
+ int shiftWidth;
+ ExprHandle amount = construct(lse->right, &shiftWidth);
+ return bvVarRightShift( left, amount, *width_out );
+ }
+ }
+
+ case Expr::AShr: {
+ AShrExpr *ase = static_ref_cast<AShrExpr>(e);
+ ExprHandle left = construct(ase->left, width_out);
+ assert(*width_out!=1 && "uncanonicalized ashr");
+
+ if (ase->right.isConstant()) {
+ unsigned shift = (unsigned) ase->right.getConstantValue();
+ ExprHandle signedBool = bvBoolExtract(left, *width_out-1);
+ return constructAShrByConstant(left, shift, signedBool, getShiftBits(*width_out));
+ } else {
+ int shiftWidth;
+ ExprHandle amount = construct(ase->right, &shiftWidth);
+ return bvVarArithRightShift( left, amount, *width_out );
+ }
+ }
+
+ // Comparison
+
+ case Expr::Eq: {
+ EqExpr *ee = static_ref_cast<EqExpr>(e);
+ ExprHandle left = construct(ee->left, width_out);
+ ExprHandle right = construct(ee->right, width_out);
+ if (*width_out==1) {
+ if (ee->left.isConstant()) {
+ assert(!ee->left.getConstantValue() && "uncanonicalized eq");
+ return vc_notExpr(vc, right);
+ } else {
+ return vc_iffExpr(vc, left, right);
+ }
+ } else {
+ *width_out = 1;
+ return vc_eqExpr(vc, left, right);
+ }
+ }
+
+ case Expr::Ult: {
+ UltExpr *ue = static_ref_cast<UltExpr>(e);
+ ExprHandle left = construct(ue->left, width_out);
+ ExprHandle right = construct(ue->right, width_out);
+ assert(*width_out!=1 && "uncanonicalized ult");
+ *width_out = 1;
+ return vc_bvLtExpr(vc, left, right);
+ }
+
+ case Expr::Ule: {
+ UleExpr *ue = static_ref_cast<UleExpr>(e);
+ ExprHandle left = construct(ue->left, width_out);
+ ExprHandle right = construct(ue->right, width_out);
+ assert(*width_out!=1 && "uncanonicalized ule");
+ *width_out = 1;
+ return vc_bvLeExpr(vc, left, right);
+ }
+
+ case Expr::Slt: {
+ SltExpr *se = static_ref_cast<SltExpr>(e);
+ ExprHandle left = construct(se->left, width_out);
+ ExprHandle right = construct(se->right, width_out);
+ assert(*width_out!=1 && "uncanonicalized slt");
+ *width_out = 1;
+ return vc_sbvLtExpr(vc, left, right);
+ }
+
+ case Expr::Sle: {
+ SleExpr *se = static_ref_cast<SleExpr>(e);
+ ExprHandle left = construct(se->left, width_out);
+ ExprHandle right = construct(se->right, width_out);
+ assert(*width_out!=1 && "uncanonicalized sle");
+ *width_out = 1;
+ return vc_sbvLeExpr(vc, left, right);
+ }
+
+ // unused due to canonicalization
+#if 0
+ case Expr::Ne:
+ case Expr::Ugt:
+ case Expr::Uge:
+ case Expr::Sgt:
+ case Expr::Sge:
+#endif
+
+ default:
+ assert(0 && "unhandled Expr type");
+ return vc_trueExpr(vc);
+ }
+}
diff --git a/lib/Solver/STPBuilder.h b/lib/Solver/STPBuilder.h
new file mode 100644
index 00000000..6382bc1f
--- /dev/null
+++ b/lib/Solver/STPBuilder.h
@@ -0,0 +1,125 @@
+//===-- STPBuilder.h --------------------------------------------*- C++ -*-===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __UTIL_STPBUILDER_H__
+#define __UTIL_STPBUILDER_H__
+
+#include "klee/util/ExprHashMap.h"
+#include "klee/Config/config.h"
+
+#include <vector>
+#include <map>
+
+#define Expr VCExpr
+#include "stp/c_interface.h"
+
+#if ENABLE_STPLOG == 1
+#include "stp/stplog.h"
+#endif
+#undef Expr
+
+namespace klee {
+ class ExprHolder {
+ friend class ExprHandle;
+ ::VCExpr expr;
+ unsigned count;
+
+ public:
+ ExprHolder(const ::VCExpr _expr) : expr(_expr), count(0) {}
+ ~ExprHolder() {
+ if (expr) vc_DeleteExpr(expr);
+ }
+ };
+
+ class ExprHandle {
+ ExprHolder *H;
+
+ public:
+ ExprHandle() : H(new ExprHolder(0)) { H->count++; }
+ ExprHandle(::VCExpr _expr) : H(new ExprHolder(_expr)) { H->count++; }
+ ExprHandle(const ExprHandle &b) : H(b.H) { H->count++; }
+ ~ExprHandle() { if (--H->count == 0) delete H; }
+
+ ExprHandle &operator=(const ExprHandle &b) {
+ if (--H->count == 0) delete H;
+ H = b.H;
+ H->count++;
+ return *this;
+ }
+
+ operator bool () { return H->expr; }
+ operator ::VCExpr () { return H->expr; }
+ };
+
+class STPBuilder {
+ ::VC vc;
+ ExprHandle tempVars[4];
+ ExprHashMap< std::pair<ExprHandle, unsigned> > constructed;
+
+ /// optimizeDivides - Rewrite division and reminders by constants
+ /// into multiplies and shifts. STP should probably handle this for
+ /// use.
+ bool optimizeDivides;
+
+private:
+ unsigned getShiftBits(unsigned amount) {
+ return (amount == 64) ? 6 : 5;
+ }
+
+ ExprHandle bvOne(unsigned width);
+ ExprHandle bvZero(unsigned width);
+ ExprHandle bvMinusOne(unsigned width);
+ ExprHandle bvConst32(unsigned width, uint32_t value);
+ ExprHandle bvConst64(unsigned width, uint64_t value);
+
+ ExprHandle bvBoolExtract(ExprHandle expr, int bit);
+ ExprHandle bvExtract(ExprHandle expr, unsigned top, unsigned bottom);
+ ExprHandle eqExpr(ExprHandle a, ExprHandle b);
+
+ //logical left and right shift (not arithmetic)
+ ExprHandle bvLeftShift(ExprHandle expr, unsigned shift, unsigned shiftBits);
+ ExprHandle bvRightShift(ExprHandle expr, unsigned amount, unsigned shiftBits);
+ ExprHandle bvVarLeftShift(ExprHandle expr, ExprHandle amount, unsigned width);
+ ExprHandle bvVarRightShift(ExprHandle expr, ExprHandle amount, unsigned width);
+ ExprHandle bvVarArithRightShift(ExprHandle expr, ExprHandle amount, unsigned width);
+
+ ExprHandle constructAShrByConstant(ExprHandle expr, unsigned shift,
+ ExprHandle isSigned, unsigned shiftBits);
+ ExprHandle constructMulByConstant(ExprHandle expr, unsigned width, uint64_t x);
+ ExprHandle constructUDivByConstant(ExprHandle expr_n, unsigned width, uint64_t d);
+ ExprHandle constructSDivByConstant(ExprHandle expr_n, unsigned width, uint64_t d);
+
+ ::VCExpr getInitialArray(const Array *os);
+ ::VCExpr getArrayForUpdate(const Array *root, const UpdateNode *un);
+
+ ExprHandle constructActual(ref<Expr> e, int *width_out);
+ ExprHandle construct(ref<Expr> e, int *width_out);
+
+ ::VCExpr buildVar(const char *name, unsigned width);
+ ::VCExpr buildArray(const char *name, unsigned indexWidth, unsigned valueWidth);
+
+public:
+ STPBuilder(::VC _vc, bool _optimizeDivides=true);
+ ~STPBuilder();
+
+ ExprHandle getTrue();
+ ExprHandle getFalse();
+ ExprHandle getTempVar(Expr::Width w);
+ ExprHandle getInitialRead(const Array *os, unsigned index);
+
+ ExprHandle construct(ref<Expr> e) {
+ ExprHandle res = construct(e, 0);
+ constructed.clear();
+ return res;
+ }
+};
+
+}
+
+#endif
diff --git a/lib/Solver/Solver.cpp b/lib/Solver/Solver.cpp
new file mode 100644
index 00000000..24d3ef86
--- /dev/null
+++ b/lib/Solver/Solver.cpp
@@ -0,0 +1,643 @@
+//===-- Solver.cpp --------------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "klee/Solver.h"
+#include "klee/SolverImpl.h"
+
+#include "SolverStats.h"
+#include "STPBuilder.h"
+
+#include "klee/Constraints.h"
+#include "klee/Expr.h"
+#include "klee/TimerStatIncrementer.h"
+#include "klee/util/Assignment.h"
+#include "klee/util/ExprPPrinter.h"
+#include "klee/util/ExprUtil.h"
+#include "klee/Internal/Support/Timer.h"
+
+#define vc_bvBoolExtract IAMTHESPAWNOFSATAN
+
+#include <cassert>
+#include <map>
+#include <vector>
+
+#include <sys/wait.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+using namespace klee;
+
+/***/
+
+const char *Solver::validity_to_str(Validity v) {
+ switch (v) {
+ default: return "Unknown";
+ case True: return "True";
+ case False: return "False";
+ }
+}
+
+Solver::~Solver() {
+ delete impl;
+}
+
+SolverImpl::~SolverImpl() {
+}
+
+bool Solver::evaluate(const Query& query, Validity &result) {
+ assert(query.expr.getWidth() == Expr::Bool && "Invalid expression type!");
+
+ // Maintain invariants implementation expect.
+ if (query.expr.isConstant()) {
+ result = query.expr.getConstantValue() ? True : False;
+ return true;
+ }
+
+ return impl->computeValidity(query, result);
+}
+
+bool SolverImpl::computeValidity(const Query& query, Solver::Validity &result) {
+ bool isTrue, isFalse;
+ if (!computeTruth(query, isTrue))
+ return false;
+ if (isTrue) {
+ result = Solver::True;
+ } else {
+ if (!computeTruth(query.negateExpr(), isFalse))
+ return false;
+ result = isFalse ? Solver::False : Solver::Unknown;
+ }
+ return true;
+}
+
+bool Solver::mustBeTrue(const Query& query, bool &result) {
+ assert(query.expr.getWidth() == Expr::Bool && "Invalid expression type!");
+
+ // Maintain invariants implementation expect.
+ if (query.expr.isConstant()) {
+ result = query.expr.getConstantValue() ? true : false;
+ return true;
+ }
+
+ return impl->computeTruth(query, result);
+}
+
+bool Solver::mustBeFalse(const Query& query, bool &result) {
+ return mustBeTrue(query.negateExpr(), result);
+}
+
+bool Solver::mayBeTrue(const Query& query, bool &result) {
+ bool res;
+ if (!mustBeFalse(query, res))
+ return false;
+ result = !res;
+ return true;
+}
+
+bool Solver::mayBeFalse(const Query& query, bool &result) {
+ bool res;
+ if (!mustBeTrue(query, res))
+ return false;
+ result = !res;
+ return true;
+}
+
+bool Solver::getValue(const Query& query, ref<Expr> &result) {
+ // Maintain invariants implementation expect.
+ if (query.expr.isConstant()) {
+ result = query.expr;
+ return true;
+ }
+
+ return impl->computeValue(query, result);
+}
+
+bool
+Solver::getInitialValues(const Query& query,
+ const std::vector<const Array*> &objects,
+ std::vector< std::vector<unsigned char> > &values) {
+ bool hasSolution;
+ bool success =
+ impl->computeInitialValues(query, objects, values, hasSolution);
+ // FIXME: Propogate this out.
+ if (!hasSolution)
+ return false;
+
+ return success;
+}
+
+std::pair< ref<Expr>, ref<Expr> > Solver::getRange(const Query& query) {
+ ref<Expr> e = query.expr;
+ Expr::Width width = e.getWidth();
+ uint64_t min, max;
+
+ if (width==1) {
+ Solver::Validity result;
+ if (!evaluate(query, result))
+ assert(0 && "computeValidity failed");
+ switch (result) {
+ case Solver::True:
+ min = max = 1; break;
+ case Solver::False:
+ min = max = 0; break;
+ default:
+ min = 0, max = 1; break;
+ }
+ } else if (e.isConstant()) {
+ min = max = e.getConstantValue();
+ } else {
+ // binary search for # of useful bits
+ uint64_t lo=0, hi=width, mid, bits=0;
+ while (lo<hi) {
+ mid = (lo+hi)/2;
+ bool res;
+ bool success =
+ mustBeTrue(query.withExpr(
+ EqExpr::create(LShrExpr::create(e,
+ ConstantExpr::create(mid,
+ width)),
+ ConstantExpr::create(0, width))),
+ res);
+ assert(success && "FIXME: Unhandled solver failure");
+ if (res) {
+ hi = mid;
+ } else {
+ lo = mid+1;
+ }
+
+ bits = lo;
+ }
+
+ // could binary search for training zeros and offset
+ // min max but unlikely to be very useful
+
+ // check common case
+ bool res = false;
+ bool success =
+ mayBeTrue(query.withExpr(EqExpr::create(e, ConstantExpr::create(0,
+ width))),
+ res);
+ assert(success && "FIXME: Unhandled solver failure");
+ if (res) {
+ min = 0;
+ } else {
+ // binary search for min
+ lo=0, hi=bits64::maxValueOfNBits(bits);
+ while (lo<hi) {
+ mid = (lo+hi)/2;
+ bool res = false;
+ bool success =
+ mayBeTrue(query.withExpr(UleExpr::create(e,
+ ConstantExpr::create(mid,
+ width))),
+ res);
+ assert(success && "FIXME: Unhandled solver failure");
+ if (res) {
+ hi = mid;
+ } else {
+ lo = mid+1;
+ }
+ }
+
+ min = lo;
+ }
+
+ // binary search for max
+ lo=min, hi=bits64::maxValueOfNBits(bits);
+ while (lo<hi) {
+ mid = (lo+hi)/2;
+ bool res;
+ bool success =
+ mustBeTrue(query.withExpr(UleExpr::create(e,
+ ConstantExpr::create(mid,
+ width))),
+ res);
+ assert(success && "FIXME: Unhandled solver failure");
+ if (res) {
+ hi = mid;
+ } else {
+ lo = mid+1;
+ }
+ }
+
+ max = lo;
+ }
+
+ return std::make_pair(ConstantExpr::create(min, width),
+ ConstantExpr::create(max, width));
+}
+
+/***/
+
+class ValidatingSolver : public SolverImpl {
+private:
+ Solver *solver, *oracle;
+
+public:
+ ValidatingSolver(Solver *_solver, Solver *_oracle)
+ : solver(_solver), oracle(_oracle) {}
+ ~ValidatingSolver() { delete solver; }
+
+ bool computeValidity(const Query&, Solver::Validity &result);
+ bool computeTruth(const Query&, bool &isValid);
+ bool computeValue(const Query&, ref<Expr> &result);
+ bool computeInitialValues(const Query&,
+ const std::vector<const Array*> &objects,
+ std::vector< std::vector<unsigned char> > &values,
+ bool &hasSolution);
+};
+
+bool ValidatingSolver::computeTruth(const Query& query,
+ bool &isValid) {
+ bool answer;
+
+ if (!solver->impl->computeTruth(query, isValid))
+ return false;
+ if (!oracle->impl->computeTruth(query, answer))
+ return false;
+
+ if (isValid != answer)
+ assert(0 && "invalid solver result (computeTruth)");
+
+ return true;
+}
+
+bool ValidatingSolver::computeValidity(const Query& query,
+ Solver::Validity &result) {
+ Solver::Validity answer;
+
+ if (!solver->impl->computeValidity(query, result))
+ return false;
+ if (!oracle->impl->computeValidity(query, answer))
+ return false;
+
+ if (result != answer)
+ assert(0 && "invalid solver result (computeValidity)");
+
+ return true;
+}
+
+bool ValidatingSolver::computeValue(const Query& query,
+ ref<Expr> &result) {
+ bool answer;
+
+ if (!solver->impl->computeValue(query, result))
+ return false;
+ // We don't want to compare, but just make sure this is a legal
+ // solution.
+ if (!oracle->impl->computeTruth(query.withExpr(NeExpr::create(query.expr,
+ result)),
+ answer))
+ return false;
+
+ if (answer)
+ assert(0 && "invalid solver result (computeValue)");
+
+ return true;
+}
+
+bool
+ValidatingSolver::computeInitialValues(const Query& query,
+ const std::vector<const Array*>
+ &objects,
+ std::vector< std::vector<unsigned char> >
+ &values,
+ bool &hasSolution) {
+ bool answer;
+
+ if (!solver->impl->computeInitialValues(query, objects, values,
+ hasSolution))
+ return false;
+
+ if (hasSolution) {
+ // Assert the bindings as constraints, and verify that the
+ // conjunction of the actual constraints is satisfiable.
+ std::vector< ref<Expr> > bindings;
+ for (unsigned i = 0; i != values.size(); ++i) {
+ const Array *array = objects[i];
+ for (unsigned j=0; j<array->size; j++) {
+ unsigned char value = values[i][j];
+ bindings.push_back(EqExpr::create(ReadExpr::create(UpdateList(array,
+ true, 0),
+ ref<Expr>(j, Expr::Int32)),
+ ref<Expr>(value, Expr::Int8)));
+ }
+ }
+ ConstraintManager tmp(bindings);
+ ref<Expr> constraints = Expr::createNot(query.expr);
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ constraints = AndExpr::create(constraints, *it);
+
+ if (!oracle->impl->computeTruth(Query(tmp, constraints), answer))
+ return false;
+ if (!answer)
+ assert(0 && "invalid solver result (computeInitialValues)");
+ } else {
+ if (!oracle->impl->computeTruth(query, answer))
+ return false;
+ if (!answer)
+ assert(0 && "invalid solver result (computeInitialValues)");
+ }
+
+ return true;
+}
+
+Solver *klee::createValidatingSolver(Solver *s, Solver *oracle) {
+ return new Solver(new ValidatingSolver(s, oracle));
+}
+
+/***/
+
+class STPSolverImpl : public SolverImpl {
+private:
+ /// The solver we are part of, for access to public information.
+ STPSolver *solver;
+ VC vc;
+ STPBuilder *builder;
+ double timeout;
+ bool useForkedSTP;
+
+public:
+ STPSolverImpl(STPSolver *_solver, bool _useForkedSTP);
+ ~STPSolverImpl();
+
+ char *getConstraintLog(const Query&);
+ void setTimeout(double _timeout) { timeout = _timeout; }
+
+ bool computeTruth(const Query&, bool &isValid);
+ bool computeValue(const Query&, ref<Expr> &result);
+ bool computeInitialValues(const Query&,
+ const std::vector<const Array*> &objects,
+ std::vector< std::vector<unsigned char> > &values,
+ bool &hasSolution);
+};
+
+static unsigned char *shared_memory_ptr;
+static const unsigned shared_memory_size = 1<<20;
+static int shared_memory_id;
+
+static void stp_error_handler(const char* err_msg) {
+ fprintf(stderr, "error: STP Error: %s\n", err_msg);
+ abort();
+}
+
+STPSolverImpl::STPSolverImpl(STPSolver *_solver, bool _useForkedSTP)
+ : solver(_solver),
+ vc(vc_createValidityChecker()),
+ builder(new STPBuilder(vc)),
+ timeout(0.0),
+ useForkedSTP(_useForkedSTP)
+{
+ assert(vc && "unable to create validity checker");
+ assert(builder && "unable to create STPBuilder");
+
+ vc_registerErrorHandler(::stp_error_handler);
+
+ if (useForkedSTP) {
+ shared_memory_id = shmget(IPC_PRIVATE, shared_memory_size, IPC_CREAT | 0700);
+ assert(shared_memory_id>=0 && "shmget failed");
+ shared_memory_ptr = (unsigned char*) shmat(shared_memory_id, NULL, 0);
+ assert(shared_memory_ptr!=(void*)-1 && "shmat failed");
+ shmctl(shared_memory_id, IPC_RMID, NULL);
+ }
+}
+
+STPSolverImpl::~STPSolverImpl() {
+ delete builder;
+
+ vc_Destroy(vc);
+}
+
+/***/
+
+STPSolver::STPSolver(bool useForkedSTP)
+ : Solver(new STPSolverImpl(this, useForkedSTP))
+{
+}
+
+char *STPSolver::getConstraintLog(const Query &query) {
+ return static_cast<STPSolverImpl*>(impl)->getConstraintLog(query);
+}
+
+void STPSolver::setTimeout(double timeout) {
+ static_cast<STPSolverImpl*>(impl)->setTimeout(timeout);
+}
+
+/***/
+
+char *STPSolverImpl::getConstraintLog(const Query &query) {
+ vc_push(vc);
+ for (std::vector< ref<Expr> >::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ vc_assertFormula(vc, builder->construct(*it));
+ assert(query.expr == ref<Expr>(0, Expr::Bool) &&
+ "Unexpected expression in query!");
+
+ char *buffer;
+ unsigned long length;
+ vc_printQueryStateToBuffer(vc, builder->getFalse(),
+ &buffer, &length, false);
+ vc_pop(vc);
+
+ return buffer;
+}
+
+bool STPSolverImpl::computeTruth(const Query& query,
+ bool &isValid) {
+ std::vector<const Array*> objects;
+ std::vector< std::vector<unsigned char> > values;
+ bool hasSolution;
+
+ if (!computeInitialValues(query, objects, values, hasSolution))
+ return false;
+
+ isValid = !hasSolution;
+ return true;
+}
+
+bool STPSolverImpl::computeValue(const Query& query,
+ ref<Expr> &result) {
+ std::vector<const Array*> objects;
+ std::vector< std::vector<unsigned char> > values;
+ bool hasSolution;
+
+ // Find the object used in the expression, and compute an assignment
+ // for them.
+ findSymbolicObjects(query.expr, objects);
+ if (!computeInitialValues(query.withFalse(), objects, values, hasSolution))
+ return false;
+ assert(hasSolution && "state has invalid constraint set");
+
+ // Evaluate the expression with the computed assignment.
+ Assignment a(objects, values);
+ result = a.evaluate(query.expr);
+
+ return true;
+}
+
+static void runAndGetCex(::VC vc, STPBuilder *builder, ::VCExpr q,
+ const std::vector<const Array*> &objects,
+ std::vector< std::vector<unsigned char> > &values,
+ bool &hasSolution) {
+ // XXX I want to be able to timeout here, safely
+ hasSolution = !vc_query(vc, q);
+
+ if (hasSolution) {
+ values.reserve(objects.size());
+ for (std::vector<const Array*>::const_iterator
+ it = objects.begin(), ie = objects.end(); it != ie; ++it) {
+ const Array *array = *it;
+ std::vector<unsigned char> data;
+
+ data.reserve(array->size);
+ for (unsigned offset = 0; offset < array->size; offset++) {
+ ExprHandle counter =
+ vc_getCounterExample(vc, builder->getInitialRead(array, offset));
+ unsigned char val = getBVUnsigned(counter);
+ data.push_back(val);
+ }
+
+ values.push_back(data);
+ }
+ }
+}
+
+static void stpTimeoutHandler(int x) {
+ _exit(52);
+}
+
+static bool runAndGetCexForked(::VC vc,
+ STPBuilder *builder,
+ ::VCExpr q,
+ const std::vector<const Array*> &objects,
+ std::vector< std::vector<unsigned char> >
+ &values,
+ bool &hasSolution,
+ double timeout) {
+ unsigned char *pos = shared_memory_ptr;
+ unsigned sum = 0;
+ for (std::vector<const Array*>::const_iterator
+ it = objects.begin(), ie = objects.end(); it != ie; ++it)
+ sum += (*it)->size;
+ assert(sum<shared_memory_size && "not enough shared memory for counterexample");
+
+ fflush(stdout);
+ fflush(stderr);
+ int pid = fork();
+ if (pid==-1) {
+ fprintf(stderr, "error: fork failed (for STP)");
+ return false;
+ }
+
+ if (pid == 0) {
+ if (timeout) {
+ ::alarm(0); /* Turn off alarm so we can safely set signal handler */
+ ::signal(SIGALRM, stpTimeoutHandler);
+ ::alarm(std::max(1, (int)timeout));
+ }
+ unsigned res = vc_query(vc, q);
+ if (!res) {
+ for (std::vector<const Array*>::const_iterator
+ it = objects.begin(), ie = objects.end(); it != ie; ++it) {
+ const Array *array = *it;
+ for (unsigned offset = 0; offset < array->size; offset++) {
+ ExprHandle counter =
+ vc_getCounterExample(vc, builder->getInitialRead(array, offset));
+ *pos++ = getBVUnsigned(counter);
+ }
+ }
+ }
+ _exit(res);
+ } else {
+ int status;
+ int res = waitpid(pid, &status, 0);
+
+ if (res<0) {
+ fprintf(stderr, "error: waitpid() for STP failed");
+ return false;
+ }
+
+ // From timed_run.py: It appears that linux at least will on
+ // "occasion" return a status when the process was terminated by a
+ // signal, so test signal first.
+ if (WIFSIGNALED(status) || !WIFEXITED(status)) {
+ fprintf(stderr, "error: STP did not return successfully");
+ return false;
+ }
+
+ int exitcode = WEXITSTATUS(status);
+ if (exitcode==0) {
+ hasSolution = true;
+ } else if (exitcode==1) {
+ hasSolution = false;
+ } else if (exitcode==52) {
+ fprintf(stderr, "error: STP timed out");
+ return false;
+ } else {
+ fprintf(stderr, "error: STP did not return a recognized code");
+ return false;
+ }
+
+ if (hasSolution) {
+ values = std::vector< std::vector<unsigned char> >(objects.size());
+ unsigned i=0;
+ for (std::vector<const Array*>::const_iterator
+ it = objects.begin(), ie = objects.end(); it != ie; ++it) {
+ const Array *array = *it;
+ std::vector<unsigned char> &data = values[i++];
+ data.insert(data.begin(), pos, pos + array->size);
+ pos += array->size;
+ }
+ }
+
+ return true;
+ }
+}
+
+bool
+STPSolverImpl::computeInitialValues(const Query &query,
+ const std::vector<const Array*>
+ &objects,
+ std::vector< std::vector<unsigned char> >
+ &values,
+ bool &hasSolution) {
+ TimerStatIncrementer t(stats::queryTime);
+
+ vc_push(vc);
+
+ for (ConstraintManager::const_iterator it = query.constraints.begin(),
+ ie = query.constraints.end(); it != ie; ++it)
+ vc_assertFormula(vc, builder->construct(*it));
+
+ ++stats::queries;
+ ++stats::queryCounterexamples;
+
+ ExprHandle stp_e = builder->construct(query.expr);
+
+ bool success;
+ if (useForkedSTP) {
+ success = runAndGetCexForked(vc, builder, stp_e, objects, values,
+ hasSolution, timeout);
+ } else {
+ runAndGetCex(vc, builder, stp_e, objects, values, hasSolution);
+ success = true;
+ }
+
+ if (success) {
+ if (hasSolution)
+ ++stats::queriesInvalid;
+ else
+ ++stats::queriesValid;
+ }
+
+ vc_pop(vc);
+
+ return success;
+}
diff --git a/lib/Solver/SolverStats.cpp b/lib/Solver/SolverStats.cpp
new file mode 100644
index 00000000..9d48792a
--- /dev/null
+++ b/lib/Solver/SolverStats.cpp
@@ -0,0 +1,23 @@
+//===-- SolverStats.cpp ---------------------------------------------------===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SolverStats.h"
+
+using namespace klee;
+
+Statistic stats::cexCacheTime("CexCacheTime", "CCtime");
+Statistic stats::queries("Queries", "Q");
+Statistic stats::queriesInvalid("QueriesInvalid", "Qiv");
+Statistic stats::queriesValid("QueriesValid", "Qv");
+Statistic stats::queryCacheHits("QueryCacheHits", "QChits") ;
+Statistic stats::queryCacheMisses("QueryCacheMisses", "QCmisses");
+Statistic stats::queryConstructTime("QueryConstructTime", "QBtime") ;
+Statistic stats::queryConstructs("QueriesConstructs", "QB");
+Statistic stats::queryCounterexamples("QueriesCEX", "Qcex");
+Statistic stats::queryTime("QueryTime", "Qtime");
diff --git a/lib/Solver/SolverStats.h b/lib/Solver/SolverStats.h
new file mode 100644
index 00000000..6fee7699
--- /dev/null
+++ b/lib/Solver/SolverStats.h
@@ -0,0 +1,32 @@
+//===-- SolverStats.h -------------------------------------------*- C++ -*-===//
+//
+// The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef KLEE_SOLVERSTATS_H
+#define KLEE_SOLVERSTATS_H
+
+#include "klee/Statistic.h"
+
+namespace klee {
+namespace stats {
+
+ extern Statistic cexCacheTime;
+ extern Statistic queries;
+ extern Statistic queriesInvalid;
+ extern Statistic queriesValid;
+ extern Statistic queryCacheHits;
+ extern Statistic queryCacheMisses;
+ extern Statistic queryConstructTime;
+ extern Statistic queryConstructs;
+ extern Statistic queryCounterexamples;
+ extern Statistic queryTime;
+
+}
+}
+
+#endif