IndependentSolver.cpp

Go to the documentation of this file.
00001 //===-- IndependentSolver.cpp ---------------------------------------------===//
00002 //
00003 //                     The KLEE Symbolic Virtual Machine
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 
00010 #include "klee/Solver.h"
00011 
00012 #include "klee/Expr.h"
00013 #include "klee/Constraints.h"
00014 #include "klee/SolverImpl.h"
00015 
00016 #include "klee/util/ExprUtil.h"
00017 
00018 #include "llvm/Support/Streams.h"
00019 
00020 #include <map>
00021 #include <vector>
00022 
00023 using namespace klee;
00024 using namespace llvm;
00025 
00026 template<class T>
00027 class DenseSet {
00028   typedef std::set<T> set_ty;
00029   set_ty s;
00030 
00031 public:
00032   DenseSet() {}
00033 
00034   void add(T x) {
00035     s.insert(x);
00036   }
00037   void add(T start, T end) {
00038     for (; start<end; start++)
00039       s.insert(start);
00040   }
00041 
00042   // returns true iff set is changed by addition
00043   bool add(const DenseSet &b) {
00044     bool modified = false;
00045     for (typename set_ty::const_iterator it = b.s.begin(), ie = b.s.end(); 
00046          it != ie; ++it) {
00047       if (modified || !s.count(*it)) {
00048         modified = true;
00049         s.insert(*it);
00050       }
00051     }
00052     return modified;
00053   }
00054 
00055   bool intersects(const DenseSet &b) {
00056     for (typename set_ty::iterator it = s.begin(), ie = s.end(); 
00057          it != ie; ++it)
00058       if (b.s.count(*it))
00059         return true;
00060     return false;
00061   }
00062 
00063   void print(std::ostream &os) const {
00064     bool first = true;
00065     os << "{";
00066     for (typename set_ty::iterator it = s.begin(), ie = s.end(); 
00067          it != ie; ++it) {
00068       if (first) {
00069         first = false;
00070       } else {
00071         os << ",";
00072       }
00073       os << *it;
00074     }
00075     os << "}";
00076   }
00077 };
00078 
00079 template<class T>
00080 inline std::ostream &operator<<(std::ostream &os, const DenseSet<T> &dis) {
00081   dis.print(os);
00082   return os;
00083 }
00084 
00085 class IndependentElementSet {
00086   typedef std::map<const Array*, DenseSet<unsigned> > elements_ty;
00087   elements_ty elements;
00088   std::set<const Array*> wholeObjects;
00089 
00090 public:
00091   IndependentElementSet() {}
00092   IndependentElementSet(ref<Expr> e) {
00093     std::vector< ref<ReadExpr> > reads;
00094     findReads(e, /* visitUpdates= */ true, reads);
00095     for (unsigned i = 0; i != reads.size(); ++i) {
00096       ReadExpr *re = reads[i].get();
00097       if (re->updates.isRooted) {
00098         const Array *array = re->updates.root;
00099         if (!wholeObjects.count(array)) {
00100           if (ConstantExpr *CE = dyn_cast<ConstantExpr>(re->index)) {
00101             DenseSet<unsigned> &dis = elements[array];
00102             dis.add((unsigned) CE->getConstantValue());
00103           } else {
00104             elements_ty::iterator it2 = elements.find(array);
00105             if (it2!=elements.end())
00106               elements.erase(it2);
00107             wholeObjects.insert(array);
00108           }
00109         }
00110       }
00111     }
00112   }
00113   IndependentElementSet(const IndependentElementSet &ies) : 
00114     elements(ies.elements),
00115     wholeObjects(ies.wholeObjects) {}    
00116 
00117   IndependentElementSet &operator=(const IndependentElementSet &ies) {
00118     elements = ies.elements;
00119     wholeObjects = ies.wholeObjects;
00120     return *this;
00121   }
00122 
00123   void print(std::ostream &os) const {
00124     os << "{";
00125     bool first = true;
00126     for (std::set<const Array*>::iterator it = wholeObjects.begin(), 
00127            ie = wholeObjects.end(); it != ie; ++it) {
00128       const Array *array = *it;
00129 
00130       if (first) {
00131         first = false;
00132       } else {
00133         os << ", ";
00134       }
00135 
00136       os << "MO" << array->id;
00137     }
00138     for (elements_ty::const_iterator it = elements.begin(), ie = elements.end();
00139          it != ie; ++it) {
00140       const Array *array = it->first;
00141       const DenseSet<unsigned> &dis = it->second;
00142 
00143       if (first) {
00144         first = false;
00145       } else {
00146         os << ", ";
00147       }
00148 
00149       os << "MO" << array->id << " : " << dis;
00150     }
00151     os << "}";
00152   }
00153 
00154   // more efficient when this is the smaller set
00155   bool intersects(const IndependentElementSet &b) {
00156     for (std::set<const Array*>::iterator it = wholeObjects.begin(), 
00157            ie = wholeObjects.end(); it != ie; ++it) {
00158       const Array *array = *it;
00159       if (b.wholeObjects.count(array) || 
00160           b.elements.find(array) != b.elements.end())
00161         return true;
00162     }
00163     for (elements_ty::iterator it = elements.begin(), ie = elements.end();
00164          it != ie; ++it) {
00165       const Array *array = it->first;
00166       if (b.wholeObjects.count(array))
00167         return true;
00168       elements_ty::const_iterator it2 = b.elements.find(array);
00169       if (it2 != b.elements.end()) {
00170         if (it->second.intersects(it2->second))
00171           return true;
00172       }
00173     }
00174     return false;
00175   }
00176 
00177   // returns true iff set is changed by addition
00178   bool add(const IndependentElementSet &b) {
00179     bool modified = false;
00180     for (std::set<const Array*>::const_iterator it = b.wholeObjects.begin(), 
00181            ie = b.wholeObjects.end(); it != ie; ++it) {
00182       const Array *array = *it;
00183       elements_ty::iterator it2 = elements.find(array);
00184       if (it2!=elements.end()) {
00185         modified = true;
00186         elements.erase(it2);
00187         wholeObjects.insert(array);
00188       } else {
00189         if (!wholeObjects.count(array)) {
00190           modified = true;
00191           wholeObjects.insert(array);
00192         }
00193       }
00194     }
00195     for (elements_ty::const_iterator it = b.elements.begin(), 
00196            ie = b.elements.end(); it != ie; ++it) {
00197       const Array *array = it->first;
00198       if (!wholeObjects.count(array)) {
00199         elements_ty::iterator it2 = elements.find(array);
00200         if (it2==elements.end()) {
00201           modified = true;
00202           elements.insert(*it);
00203         } else {
00204           if (it2->second.add(it->second))
00205             modified = true;
00206         }
00207       }
00208     }
00209     return modified;
00210   }
00211 };
00212 
00213 inline std::ostream &operator<<(std::ostream &os, const IndependentElementSet &ies) {
00214   ies.print(os);
00215   return os;
00216 }
00217 
00218 static 
00219 IndependentElementSet getIndependentConstraints(const Query& query,
00220                                                 std::vector< ref<Expr> > &result) {
00221   IndependentElementSet eltsClosure(query.expr);
00222   std::vector< std::pair<ref<Expr>, IndependentElementSet> > worklist;
00223 
00224   for (ConstraintManager::const_iterator it = query.constraints.begin(), 
00225          ie = query.constraints.end(); it != ie; ++it)
00226     worklist.push_back(std::make_pair(*it, IndependentElementSet(*it)));
00227 
00228   // XXX This should be more efficient (in terms of low level copy stuff).
00229   bool done = false;
00230   do {
00231     done = true;
00232     std::vector< std::pair<ref<Expr>, IndependentElementSet> > newWorklist;
00233     for (std::vector< std::pair<ref<Expr>, IndependentElementSet> >::iterator
00234            it = worklist.begin(), ie = worklist.end(); it != ie; ++it) {
00235       if (it->second.intersects(eltsClosure)) {
00236         if (eltsClosure.add(it->second))
00237           done = false;
00238         result.push_back(it->first);
00239       } else {
00240         newWorklist.push_back(*it);
00241       }
00242     }
00243     worklist.swap(newWorklist);
00244   } while (!done);
00245 
00246   if (0) {
00247     std::set< ref<Expr> > reqset(result.begin(), result.end());
00248     llvm::cerr << "--\n";
00249     llvm::cerr << "Q: " << query.expr << "\n";
00250     llvm::cerr << "\telts: " << IndependentElementSet(query.expr) << "\n";
00251     int i = 0;
00252   for (ConstraintManager::const_iterator it = query.constraints.begin(), 
00253          ie = query.constraints.end(); it != ie; ++it) {
00254       llvm::cerr << "C" << i++ << ": " << *it;
00255       llvm::cerr << " " << (reqset.count(*it) ? "(required)" : "(independent)") << "\n";
00256       llvm::cerr << "\telts: " << IndependentElementSet(*it) << "\n";
00257     }
00258     llvm::cerr << "elts closure: " << eltsClosure << "\n";
00259   }
00260 
00261   return eltsClosure;
00262 }
00263 
00264 class IndependentSolver : public SolverImpl {
00265 private:
00266   Solver *solver;
00267 
00268 public:
00269   IndependentSolver(Solver *_solver) 
00270     : solver(_solver) {}
00271   ~IndependentSolver() { delete solver; }
00272 
00273   bool computeTruth(const Query&, bool &isValid);
00274   bool computeValidity(const Query&, Solver::Validity &result);
00275   bool computeValue(const Query&, ref<Expr> &result);
00276   bool computeInitialValues(const Query& query,
00277                             const std::vector<const Array*> &objects,
00278                             std::vector< std::vector<unsigned char> > &values,
00279                             bool &hasSolution) {
00280     return solver->impl->computeInitialValues(query, objects, values,
00281                                               hasSolution);
00282   }
00283 };
00284   
00285 bool IndependentSolver::computeValidity(const Query& query,
00286                                         Solver::Validity &result) {
00287   std::vector< ref<Expr> > required;
00288   IndependentElementSet eltsClosure =
00289     getIndependentConstraints(query, required);
00290   ConstraintManager tmp(required);
00291   return solver->impl->computeValidity(Query(tmp, query.expr), 
00292                                        result);
00293 }
00294 
00295 bool IndependentSolver::computeTruth(const Query& query, bool &isValid) {
00296   std::vector< ref<Expr> > required;
00297   IndependentElementSet eltsClosure = 
00298     getIndependentConstraints(query, required);
00299   ConstraintManager tmp(required);
00300   return solver->impl->computeTruth(Query(tmp, query.expr), 
00301                                     isValid);
00302 }
00303 
00304 bool IndependentSolver::computeValue(const Query& query, ref<Expr> &result) {
00305   std::vector< ref<Expr> > required;
00306   IndependentElementSet eltsClosure = 
00307     getIndependentConstraints(query, required);
00308   ConstraintManager tmp(required);
00309   return solver->impl->computeValue(Query(tmp, query.expr), result);
00310 }
00311 
00312 Solver *klee::createIndependentSolver(Solver *s) {
00313   return new Solver(new IndependentSolver(s));
00314 }

Generated on Fri Jun 5 03:31:32 2009 for klee by  doxygen 1.5.8