about summary refs log tree commit diff homepage
path: root/lib/Core/ImpliedValue.cpp
diff options
context:
space:
mode:
authorDaniel Dunbar <daniel@zuster.org>2009-05-21 04:36:41 +0000
committerDaniel Dunbar <daniel@zuster.org>2009-05-21 04:36:41 +0000
commit6f290d8f9e9d7faac295cb51fc96884a18f4ded4 (patch)
tree46e7d426abc0c9f06ac472ac6f7f9e661b5d78cb /lib/Core/ImpliedValue.cpp
parenta55960edd4dcd7535526de8d2277642522aa0209 (diff)
downloadklee-6f290d8f9e9d7faac295cb51fc96884a18f4ded4.tar.gz
Initial KLEE checkin.
 - Lots more tweaks, documentation, and web page content is needed,
   but this should compile & work on OS X & Linux.


git-svn-id: https://llvm.org/svn/llvm-project/klee/trunk@72205 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Core/ImpliedValue.cpp')
-rw-r--r--lib/Core/ImpliedValue.cpp274
1 files changed, 274 insertions, 0 deletions
diff --git a/lib/Core/ImpliedValue.cpp b/lib/Core/ImpliedValue.cpp
new file mode 100644
index 00000000..386c8d80
--- /dev/null
+++ b/lib/Core/ImpliedValue.cpp
@@ -0,0 +1,274 @@
+//===-- ImpliedValue.cpp --------------------------------------------------===//
+//
+//                     The KLEE Symbolic Virtual Machine
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ImpliedValue.h"
+
+#include "klee/Constraints.h"
+#include "klee/Expr.h"
+#include "klee/Solver.h"
+// FIXME: Use APInt.
+#include "klee/Internal/Support/IntEvaluation.h"
+
+#include "klee/util/ExprUtil.h"
+
+#include <iostream>
+#include <map>
+#include <set>
+
+using namespace klee;
+
+// XXX we really want to do some sort of canonicalization of exprs
+// globally so that cases below become simpler
+static void _getImpliedValue(ref<Expr> e,
+                             uint64_t value,
+                             ImpliedValueList &results) {
+  switch (e.getKind()) {
+    
+  case Expr::Constant: {
+    assert(value == e.getConstantValue() && "error in implied value calculation");
+    break;
+  }
+
+    // Special
+
+  case Expr::NotOptimized: break;
+
+  case Expr::Read: {
+    // XXX in theory it is possible to descend into a symbolic index
+    // under certain circumstances (all values known, known value
+    // unique, or range known, max / min hit). Seems unlikely this
+    // would work often enough to be worth the effort.
+    ReadExpr *re = static_ref_cast<ReadExpr>(e);
+    results.push_back(std::make_pair(re, 
+                                     ConstantExpr::create(value, e.getWidth())));
+    break;
+  }
+    
+  case Expr::Select: {
+    // not much to do, could improve with range analysis
+    SelectExpr *se = static_ref_cast<SelectExpr>(e);
+    
+    if (se->trueExpr.isConstant()) {
+      if (se->falseExpr.isConstant()) {
+        if (se->trueExpr.getConstantValue() != se->falseExpr.getConstantValue()) {
+          if (value == se->trueExpr.getConstantValue()) {
+            _getImpliedValue(se->cond, 1, results);
+          } else {
+            assert(value == se->falseExpr.getConstantValue() &&
+                   "err in implied value calculation");
+            _getImpliedValue(se->cond, 0, results);
+          }
+        }
+      }
+    }
+    break;
+  }
+
+  case Expr::Concat: {
+    ConcatExpr *ce = static_ref_cast<ConcatExpr>(e);
+    _getImpliedValue(ce->getKid(0), (value >> ce->getKid(1).getWidth()) & ((1 << ce->getKid(0).getWidth()) - 1), results);
+    _getImpliedValue(ce->getKid(1), value & ((1 << ce->getKid(1).getWidth()) - 1), results);
+    break;
+  }
+    
+  case Expr::Extract: {
+    // XXX, could do more here with "some bits" mask
+    break;
+  }
+
+    // Casting
+
+  case Expr::ZExt: 
+  case Expr::SExt: {
+    CastExpr *ce = static_ref_cast<CastExpr>(e);
+    _getImpliedValue(ce->src, 
+                     bits64::truncateToNBits(value, 
+					     ce->src.getWidth()),
+                     results);
+    break;
+  }
+
+    // Arithmetic
+
+  case Expr::Add: { // constants on left
+    BinaryExpr *be = static_ref_cast<BinaryExpr>(e);
+    if (be->left.isConstant()) {
+      uint64_t nvalue = ints::sub(value,
+                                  be->left.getConstantValue(),
+                                  be->left.getWidth());
+      _getImpliedValue(be->right, nvalue, results);
+    }
+    break;
+  }
+  case Expr::Sub: { // constants on left
+    BinaryExpr *be = static_ref_cast<BinaryExpr>(e);
+    if (be->left.isConstant()) {
+      uint64_t nvalue = ints::sub(be->left.getConstantValue(),
+                                  value,
+                                  be->left.getWidth());
+      _getImpliedValue(be->right, nvalue, results);
+    }
+    break;
+  }
+  case Expr::Mul: {
+    // XXX can do stuff here, but need valid mask and other things
+    // because of bits that might be lost
+    break;
+  }
+
+  case Expr::UDiv:
+  case Expr::SDiv:
+  case Expr::URem:
+  case Expr::SRem:
+    // no, no, no
+    break;
+
+    // Binary
+
+  case Expr::And: {
+    BinaryExpr *be = static_ref_cast<BinaryExpr>(e);
+    if (be->getWidth() == Expr::Bool) {
+      if (value) {
+        _getImpliedValue(be->left, value, results);
+        _getImpliedValue(be->right, value, results);
+      }
+    } else {
+      // XXX, we can basically propogate a mask here
+      // where we know "some bits". may or may not be
+      // useful.
+    }
+    break;
+  }
+  case Expr::Or: {
+    BinaryExpr *be = static_ref_cast<BinaryExpr>(e);
+    if (!value) {
+      _getImpliedValue(be->left, 0, results);
+      _getImpliedValue(be->right, 0, results);
+    } else {
+      // XXX, can do more?
+    }
+    break;
+  }
+  case Expr::Xor: { // constants on left
+    BinaryExpr *be = static_ref_cast<BinaryExpr>(e);
+    if (be->left.isConstant()) {
+      _getImpliedValue(be->right, value ^ be->left.getConstantValue(), results);
+    }
+    break;
+  }
+
+    // Comparison
+  case Expr::Ne: 
+    value = !value;
+    /* fallthru */
+  case Expr::Eq: {
+    EqExpr *ee = static_ref_cast<EqExpr>(e);
+    if (value) {
+      if (ee->left.isConstant())
+        _getImpliedValue(ee->right, ee->left.getConstantValue(), results);
+    } else {
+      // look for limited value range, woohoo
+      //
+      // in general anytime one side was restricted to two values we
+      // can apply this trick. the only obvious case where this
+      // occurs, aside from booleans, is as the result of a select
+      // expression where the true and false branches are single
+      // valued and distinct.
+      
+      if (ee->left.isConstant()) {
+        if (ee->left.getWidth() == Expr::Bool) {
+          _getImpliedValue(ee->right, !ee->left.getConstantValue(), results);
+        }
+      }
+    }
+    break;
+  }
+    
+  default:
+    break;
+  }
+}
+    
+void ImpliedValue::getImpliedValues(ref<Expr> e, 
+                                    ref<Expr> value, 
+                                    ImpliedValueList &results) {
+  assert(value.isConstant() && "non-constant in place of constant");
+  _getImpliedValue(e, value.getConstantValue(), results);
+}
+
+void ImpliedValue::checkForImpliedValues(Solver *S, ref<Expr> e, 
+                                         ref<Expr> value) {
+  assert(value.isConstant() && "non-constant in place of constant");
+
+  std::vector<ref<ReadExpr> > reads;
+  std::map<ref<ReadExpr>, ref<Expr> > found;
+  ImpliedValueList results;
+
+  getImpliedValues(e, value, results);
+
+  for (ImpliedValueList::iterator i = results.begin(), ie = results.end();
+       i != ie; ++i) {
+    std::map<ref<ReadExpr>, ref<Expr> >::iterator it = found.find(i->first);
+    if (it != found.end()) {
+      assert(it->second.getConstantValue() == i->second.getConstantValue() &&
+             "I don't think so Scott");
+    } else {
+      found.insert(std::make_pair(i->first, i->second));
+    }
+  }
+
+  findReads(e, false, reads);
+  std::set< ref<ReadExpr> > readsSet(reads.begin(), reads.end());
+  reads = std::vector< ref<ReadExpr> >(readsSet.begin(), readsSet.end());
+
+  std::vector<ref<Expr> > assumption;
+  assumption.push_back(EqExpr::create(e, value));
+
+  // obscure... we need to make sure that all the read indices are
+  // bounds checked. if we don't do this we can end up constructing
+  // invalid counterexamples because STP will happily make out of
+  // bounds indices which will not get picked up. this is of utmost
+  // importance if we are being backed by the CexCachingSolver.
+
+  for (std::vector< ref<ReadExpr> >::iterator i = reads.begin(), 
+         ie = reads.end(); i != ie; ++i) {
+    ReadExpr *re = i->get();
+    ref<Expr> size = ref<Expr>(re->updates.root->size, kMachinePointerType);
+    assumption.push_back(UltExpr::create(re->index, size));
+  }
+
+  ConstraintManager assume(assumption);
+  for (std::vector< ref<ReadExpr> >::iterator i = reads.begin(), 
+         ie = reads.end(); i != ie; ++i) {
+    ref<ReadExpr> var = *i;
+    ref<Expr> possible;
+    bool success = S->getValue(Query(assume, var), possible);
+    assert(success && "FIXME: Unhandled solver failure");    
+    std::map<ref<ReadExpr>, ref<Expr> >::iterator it = found.find(var);
+    bool res;
+    success = S->mustBeTrue(Query(assume, EqExpr::create(var, possible)), res);
+    assert(success && "FIXME: Unhandled solver failure");    
+    if (res) {
+      if (it != found.end()) {
+        assert(possible.getConstantValue() == it->second.getConstantValue());
+        found.erase(it);
+      }
+    } else {
+      if (it!=found.end()) {
+        ref<Expr> binding = it->second;
+        llvm::cerr << "checkForImpliedValues: " << e  << " = " << value << "\n"
+                   << "\t\t implies " << var << " == " << binding
+                   << " (error)\n";
+        assert(0);
+      }
+    }
+  }
+
+  assert(found.empty());
+}