//===-- IndependentSolver.cpp ---------------------------------------------===// // // The KLEE Symbolic Virtual Machine // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #define DEBUG_TYPE "independent-solver" #include "klee/Solver.h" #include "klee/Expr.h" #include "klee/Constraints.h" #include "klee/SolverImpl.h" #include "klee/Internal/Support/Debug.h" #include "klee/util/ExprUtil.h" #include "llvm/Support/raw_ostream.h" #include #include #include using namespace klee; using namespace llvm; template class DenseSet { typedef std::set set_ty; set_ty s; public: DenseSet() {} void add(T x) { s.insert(x); } void add(T start, T end) { for (; start inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const ::DenseSet &dis) { dis.print(os); return os; } class IndependentElementSet { typedef std::map > elements_ty; elements_ty elements; std::set wholeObjects; public: IndependentElementSet() {} IndependentElementSet(ref e) { std::vector< ref > reads; findReads(e, /* visitUpdates= */ true, reads); for (unsigned i = 0; i != reads.size(); ++i) { ReadExpr *re = reads[i].get(); const Array *array = re->updates.root; // Reads of a constant array don't alias. if (re->updates.root->isConstantArray() && !re->updates.head) continue; if (!wholeObjects.count(array)) { if (ConstantExpr *CE = dyn_cast(re->index)) { ::DenseSet &dis = elements[array]; dis.add((unsigned) CE->getZExtValue(32)); } 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(llvm::raw_ostream &os) const { os << "{"; bool first = true; for (std::set::iterator it = wholeObjects.begin(), ie = wholeObjects.end(); it != ie; ++it) { const Array *array = *it; if (first) { first = false; } else { os << ", "; } os << "MO" << array->name; } for (elements_ty::const_iterator it = elements.begin(), ie = elements.end(); it != ie; ++it) { const Array *array = it->first; const ::DenseSet &dis = it->second; if (first) { first = false; } else { os << ", "; } os << "MO" << array->name << " : " << dis; } os << "}"; } // more efficient when this is the smaller set bool intersects(const IndependentElementSet &b) { for (std::set::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_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 llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const IndependentElementSet &ies) { ies.print(os); return os; } static IndependentElementSet getIndependentConstraints(const Query& query, std::vector< ref > &result) { IndependentElementSet eltsClosure(query.expr); std::vector< std::pair, 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, IndependentElementSet> > newWorklist; for (std::vector< std::pair, 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); KLEE_DEBUG( std::set< ref > reqset(result.begin(), result.end()); errs() << "--\n"; errs() << "Q: " << query.expr << "\n"; errs() << "\telts: " << IndependentElementSet(query.expr) << "\n"; int i = 0; for (ConstraintManager::const_iterator it = query.constraints.begin(), ie = query.constraints.end(); it != ie; ++it) { errs() << "C" << i++ << ": " << *it; errs() << " " << (reqset.count(*it) ? "(required)" : "(independent)") << "\n"; errs() << "\telts: " << IndependentElementSet(*it) << "\n"; } errs() << "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 &result); bool computeInitialValues(const Query& query, const std::vector &objects, std::vector< std::vector > &values, bool &hasSolution) { return solver->impl->computeInitialValues(query, objects, values, hasSolution); } SolverRunStatus getOperationStatusCode(); char *getConstraintLog(const Query&); void setCoreSolverTimeout(double timeout); }; bool IndependentSolver::computeValidity(const Query& query, Solver::Validity &result) { std::vector< ref > 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 > 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 &result) { std::vector< ref > required; IndependentElementSet eltsClosure = getIndependentConstraints(query, required); ConstraintManager tmp(required); return solver->impl->computeValue(Query(tmp, query.expr), result); } SolverImpl::SolverRunStatus IndependentSolver::getOperationStatusCode() { return solver->impl->getOperationStatusCode(); } char *IndependentSolver::getConstraintLog(const Query& query) { return solver->impl->getConstraintLog(query); } void IndependentSolver::setCoreSolverTimeout(double timeout) { solver->impl->setCoreSolverTimeout(timeout); } Solver *klee::createIndependentSolver(Solver *s) { return new Solver(new IndependentSolver(s)); }