//===-- Constraints.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/Expr/Constraints.h" #include "klee/Expr/ExprPPrinter.h" #include "klee/Expr/ExprVisitor.h" #include "klee/Support/OptionCategories.h" #include "klee/Module/KModule.h" #include "llvm/IR/Function.h" #include "llvm/Support/CommandLine.h" #include using namespace klee; namespace { llvm::cl::opt RewriteEqualities( "rewrite-equalities", llvm::cl::desc("Rewrite existing constraints when an equality with a " "constant is added (default=true)"), llvm::cl::init(true), llvm::cl::cat(SolvingCat)); } class ExprReplaceVisitor : public ExprVisitor { private: ref src, dst; public: ExprReplaceVisitor(ref _src, ref _dst) : src(_src), dst(_dst) {} Action visitExpr(const Expr &e) { if (e == *src.get()) { return Action::changeTo(dst); } else { return Action::doChildren(); } } Action visitExprPost(const Expr &e) { if (e == *src.get()) { return Action::changeTo(dst); } else { return Action::doChildren(); } } }; class ExprReplaceVisitor2 : public ExprVisitor { private: const std::map< ref, ref > &replacements; public: ExprReplaceVisitor2(const std::map< ref, ref > &_replacements) : ExprVisitor(true), replacements(_replacements) {} Action visitExprPost(const Expr &e) { std::map< ref, ref >::const_iterator it = replacements.find(ref(const_cast(&e))); if (it!=replacements.end()) { return Action::changeTo(it->second); } else { return Action::doChildren(); } } }; bool ConstraintManager::rewriteConstraints(ExprVisitor &visitor) { ConstraintManager::constraints_ty old; bool changed = false; constraints.swap(old); for (ConstraintManager::constraints_ty::iterator it = old.begin(), ie = old.end(); it != ie; ++it) { ref &ce = *it; ref e = visitor.visit(ce); if (e!=ce) { addConstraintInternal(e); // enable further reductions changed = true; } else { constraints.push_back(ce); } } return changed; } ref ConstraintManager::simplifyExpr(ref e) const { if (isa(e)) return e; std::map< ref, ref > equalities; for (ConstraintManager::constraints_ty::const_iterator it = constraints.begin(), ie = constraints.end(); it != ie; ++it) { if (const EqExpr *ee = dyn_cast(*it)) { if (isa(ee->left)) { equalities.insert(std::make_pair(ee->right, ee->left)); } else { equalities.insert(std::make_pair(*it, ConstantExpr::alloc(1, Expr::Bool))); } } else { equalities.insert(std::make_pair(*it, ConstantExpr::alloc(1, Expr::Bool))); } } return ExprReplaceVisitor2(equalities).visit(e); } void ConstraintManager::addConstraintInternal(ref e) { // rewrite any known equalities and split Ands into different conjuncts switch (e->getKind()) { case Expr::Constant: assert(cast(e)->isTrue() && "attempt to add invalid (false) constraint"); break; // split to enable finer grained independence and other optimizations case Expr::And: { BinaryExpr *be = cast(e); addConstraintInternal(be->left); addConstraintInternal(be->right); break; } case Expr::Eq: { if (RewriteEqualities) { // XXX: should profile the effects of this and the overhead. // traversing the constraints looking for equalities is hardly the // slowest thing we do, but it is probably nicer to have a // ConstraintSet ADT which efficiently remembers obvious patterns // (byte-constant comparison). BinaryExpr *be = cast(e); if (isa(be->left)) { ExprReplaceVisitor visitor(be->right, be->left); rewriteConstraints(visitor); } } constraints.push_back(e); break; } default: constraints.push_back(e); break; } } void ConstraintManager::addConstraint(ref e) { e = simplifyExpr(e); addConstraintInternal(e); } ConstraintManager::ConstraintManager(const std::vector> &_constraints) : constraints(_constraints) {} bool ConstraintManager::empty() const { return constraints.empty(); } klee::ref ConstraintManager::back() const { return constraints.back(); } klee::ConstraintManager::constraint_iterator ConstraintManager::begin() const { return constraints.begin(); } klee::ConstraintManager::constraint_iterator ConstraintManager::end() const { return constraints.end(); } size_t ConstraintSet::size() const noexcept { return constraints.size(); } bool ConstraintManager::operator==(const ConstraintManager &other) const { return constraints == other.constraints; }