00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "klee/Solver.h"
00011
00012 #include "klee/Constraints.h"
00013 #include "klee/Expr.h"
00014 #include "klee/SolverImpl.h"
00015 #include "klee/TimerStatIncrementer.h"
00016 #include "klee/util/Assignment.h"
00017 #include "klee/util/ExprUtil.h"
00018 #include "klee/util/ExprVisitor.h"
00019 #include "klee/Internal/ADT/MapOfSets.h"
00020
00021 #include "SolverStats.h"
00022
00023 #include "llvm/Support/CommandLine.h"
00024
00025 using namespace klee;
00026 using namespace llvm;
00027
00028 namespace {
00029 cl::opt<bool>
00030 DebugCexCacheCheckBinding("debug-cex-cache-check-binding");
00031
00032 cl::opt<bool>
00033 CexCacheTryAll("cex-cache-try-all",
00034 cl::desc("try substituting all counterexamples before asking STP"),
00035 cl::init(false));
00036
00037 cl::opt<bool>
00038 CexCacheExperimental("cex-cache-exp", cl::init(false));
00039
00040 }
00041
00043
00044 typedef std::set< ref<Expr> > KeyType;
00045
00046 struct AssignmentLessThan {
00047 bool operator()(const Assignment *a, const Assignment *b) {
00048 return a->bindings < b->bindings;
00049 }
00050 };
00051
00052
00053 class CexCachingSolver : public SolverImpl {
00054 typedef std::set<Assignment*, AssignmentLessThan> assignmentsTable_ty;
00055
00056 Solver *solver;
00057
00058 MapOfSets<ref<Expr>, Assignment*> cache;
00059
00060 assignmentsTable_ty assignmentsTable;
00061
00062 bool searchForAssignment(KeyType &key,
00063 Assignment *&result);
00064
00065 bool lookupAssignment(const Query& query, Assignment *&result);
00066
00067 bool getAssignment(const Query& query, Assignment *&result);
00068
00069 public:
00070 CexCachingSolver(Solver *_solver) : solver(_solver) {}
00071 ~CexCachingSolver();
00072
00073 bool computeTruth(const Query&, bool &isValid);
00074 bool computeValidity(const Query&, Solver::Validity &result);
00075 bool computeValue(const Query&, ref<Expr> &result);
00076 bool computeInitialValues(const Query&,
00077 const std::vector<const Array*> &objects,
00078 std::vector< std::vector<unsigned char> > &values,
00079 bool &hasSolution);
00080 };
00081
00083
00084 struct NullAssignment {
00085 bool operator()(Assignment *a) const { return !a; }
00086 };
00087
00088 struct NonNullAssignment {
00089 bool operator()(Assignment *a) const { return a!=0; }
00090 };
00091
00092 struct NullOrSatisfyingAssignment {
00093 KeyType &key;
00094
00095 NullOrSatisfyingAssignment(KeyType &_key) : key(_key) {}
00096
00097 bool operator()(Assignment *a) const {
00098 return !a || a->satisfies(key.begin(), key.end());
00099 }
00100 };
00101
00102 bool CexCachingSolver::searchForAssignment(KeyType &key, Assignment *&result) {
00103 Assignment * const *lookup = cache.lookup(key);
00104 if (lookup) {
00105 result = *lookup;
00106 return true;
00107 }
00108
00109 if (CexCacheTryAll) {
00110 Assignment **lookup = cache.findSuperset(key, NonNullAssignment());
00111 if (!lookup) lookup = cache.findSubset(key, NullAssignment());
00112 if (lookup) {
00113 result = *lookup;
00114 return true;
00115 }
00116 for (assignmentsTable_ty::iterator it = assignmentsTable.begin(),
00117 ie = assignmentsTable.end(); it != ie; ++it) {
00118 Assignment *a = *it;
00119 if (a->satisfies(key.begin(), key.end())) {
00120 result = a;
00121 return true;
00122 }
00123 }
00124 } else {
00125
00126 Assignment **lookup = cache.findSuperset(key, NonNullAssignment());
00127 if (!lookup) lookup = cache.findSubset(key, NullOrSatisfyingAssignment(key));
00128 if (lookup) {
00129 result = *lookup;
00130 return true;
00131 }
00132 }
00133
00134 return false;
00135 }
00136
00137 bool CexCachingSolver::lookupAssignment(const Query &query,
00138 Assignment *&result) {
00139 KeyType key(query.constraints.begin(), query.constraints.end());
00140 ref<Expr> neg = Expr::createNot(query.expr);
00141 if (ConstantExpr *CE = dyn_cast<ConstantExpr>(neg)) {
00142 if (!CE->getConstantValue()) {
00143 result = (Assignment*) 0;
00144 return true;
00145 }
00146 } else {
00147 key.insert(neg);
00148 }
00149
00150 return searchForAssignment(key, result);
00151 }
00152
00153 bool CexCachingSolver::getAssignment(const Query& query, Assignment *&result) {
00154 KeyType key(query.constraints.begin(), query.constraints.end());
00155 ref<Expr> neg = Expr::createNot(query.expr);
00156 if (ConstantExpr *CE = dyn_cast<ConstantExpr>(neg)) {
00157 if (!CE->getConstantValue()) {
00158 result = (Assignment*) 0;
00159 return true;
00160 }
00161 } else {
00162 key.insert(neg);
00163 }
00164
00165 if (!searchForAssignment(key, result)) {
00166
00167
00168 std::vector<const Array*> objects;
00169 findSymbolicObjects(key.begin(), key.end(), objects);
00170
00171 std::vector< std::vector<unsigned char> > values;
00172 bool hasSolution;
00173 if (!solver->impl->computeInitialValues(query, objects, values,
00174 hasSolution))
00175 return false;
00176
00177 Assignment *binding;
00178 if (hasSolution) {
00179 binding = new Assignment(objects, values);
00180
00181
00182 std::pair<assignmentsTable_ty::iterator, bool>
00183 res = assignmentsTable.insert(binding);
00184 if (!res.second) {
00185 delete binding;
00186 binding = *res.first;
00187 }
00188
00189 if (DebugCexCacheCheckBinding)
00190 assert(binding->satisfies(key.begin(), key.end()));
00191 } else {
00192 binding = (Assignment*) 0;
00193 }
00194
00195 result = binding;
00196 cache.insert(key, binding);
00197 }
00198
00199 return true;
00200 }
00201
00203
00204 CexCachingSolver::~CexCachingSolver() {
00205 cache.clear();
00206 delete solver;
00207 for (assignmentsTable_ty::iterator it = assignmentsTable.begin(),
00208 ie = assignmentsTable.end(); it != ie; ++it)
00209 delete *it;
00210 }
00211
00212 bool CexCachingSolver::computeValidity(const Query& query,
00213 Solver::Validity &result) {
00214 TimerStatIncrementer t(stats::cexCacheTime);
00215 Assignment *a;
00216 if (!getAssignment(query.withFalse(), a))
00217 return false;
00218 assert(a && "computeValidity() must have assignment");
00219 ref<Expr> q = a->evaluate(query.expr);
00220 assert(isa<ConstantExpr>(q) &&
00221 "assignment evaluation did not result in constant");
00222
00223 if (cast<ConstantExpr>(q)->getConstantValue()) {
00224 if (!getAssignment(query, a))
00225 return false;
00226 result = !a ? Solver::True : Solver::Unknown;
00227 } else {
00228 if (!getAssignment(query.negateExpr(), a))
00229 return false;
00230 result = !a ? Solver::False : Solver::Unknown;
00231 }
00232
00233 return true;
00234 }
00235
00236 bool CexCachingSolver::computeTruth(const Query& query,
00237 bool &isValid) {
00238 TimerStatIncrementer t(stats::cexCacheTime);
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248 if (CexCacheExperimental) {
00249 Assignment *a;
00250 if (lookupAssignment(query.negateExpr(), a) && !a)
00251 return false;
00252 }
00253
00254 Assignment *a;
00255 if (!getAssignment(query, a))
00256 return false;
00257
00258 isValid = !a;
00259
00260 return true;
00261 }
00262
00263 bool CexCachingSolver::computeValue(const Query& query,
00264 ref<Expr> &result) {
00265 TimerStatIncrementer t(stats::cexCacheTime);
00266
00267 Assignment *a;
00268 if (!getAssignment(query.withFalse(), a))
00269 return false;
00270 assert(a && "computeValue() must have assignment");
00271 result = a->evaluate(query.expr);
00272 assert(isa<ConstantExpr>(result) &&
00273 "assignment evaluation did not result in constant");
00274 return true;
00275 }
00276
00277 bool
00278 CexCachingSolver::computeInitialValues(const Query& query,
00279 const std::vector<const Array*>
00280 &objects,
00281 std::vector< std::vector<unsigned char> >
00282 &values,
00283 bool &hasSolution) {
00284 TimerStatIncrementer t(stats::cexCacheTime);
00285 Assignment *a;
00286 if (!getAssignment(query, a))
00287 return false;
00288 hasSolution = !!a;
00289
00290 if (!a)
00291 return true;
00292
00293
00294
00295 values = std::vector< std::vector<unsigned char> >(objects.size());
00296 for (unsigned i=0; i < objects.size(); ++i) {
00297 const Array *os = objects[i];
00298 Assignment::bindings_ty::iterator it = a->bindings.find(os);
00299
00300 if (it == a->bindings.end()) {
00301 values[i] = std::vector<unsigned char>(os->size, 0);
00302 } else {
00303 values[i] = it->second;
00304 }
00305 }
00306
00307 return true;
00308 }
00309
00311
00312 Solver *klee::createCexCachingSolver(Solver *_solver) {
00313 return new Solver(new CexCachingSolver(_solver));
00314 }