about summary refs log tree commit diff homepage
path: root/lib/Expr/ArrayExprVisitor.cpp
diff options
context:
space:
mode:
authorAndrea Mattavelli <andreamattavelli@gmail.com>2017-11-22 17:18:07 +0000
committerCristian Cadar <c.cadar@imperial.ac.uk>2018-10-23 18:53:46 +0300
commita53fade6e85394ef95dfaaa1c264149e85ea5451 (patch)
treee8d10b1cd288c0b013b5dc8039bdb3b8dbf42d8d /lib/Expr/ArrayExprVisitor.cpp
parent916b72a7955cbb06d1a10640f8c6daea14da523e (diff)
downloadklee-a53fade6e85394ef95dfaaa1c264149e85ea5451.tar.gz
Added support for KLEE index-based array optimization
Diffstat (limited to 'lib/Expr/ArrayExprVisitor.cpp')
-rw-r--r--lib/Expr/ArrayExprVisitor.cpp171
1 files changed, 171 insertions, 0 deletions
diff --git a/lib/Expr/ArrayExprVisitor.cpp b/lib/Expr/ArrayExprVisitor.cpp
new file mode 100644
index 00000000..26ddbb95
--- /dev/null
+++ b/lib/Expr/ArrayExprVisitor.cpp
@@ -0,0 +1,171 @@
+#include "klee/util/ArrayExprVisitor.h"
+
+#include "klee/Internal/Support/ErrorHandling.h"
+
+#include <algorithm>
+
+using namespace klee;
+
+//------------------------------ HELPER FUNCTIONS ---------------------------//
+bool ArrayExprHelper::isReadExprAtOffset(ref<Expr> e, const ReadExpr *base,
+                                         ref<Expr> offset) {
+  const ReadExpr *re = dyn_cast<ReadExpr>(e.get());
+  if (!re || (re->getWidth() != Expr::Int8))
+    return false;
+  return SubExpr::create(re->index, base->index) == offset;
+}
+
+ReadExpr *ArrayExprHelper::hasOrderedReads(const ConcatExpr &ce) {
+  const ReadExpr *base = dyn_cast<ReadExpr>(ce.getKid(0));
+
+  // right now, all Reads are byte reads but some
+  // transformations might change this
+  if (!base || base->getWidth() != Expr::Int8)
+    return NULL;
+
+  // Get stride expr in proper index width.
+  Expr::Width idxWidth = base->index->getWidth();
+  ref<Expr> strideExpr = ConstantExpr::alloc(-1, idxWidth);
+  ref<Expr> offset = ConstantExpr::create(0, idxWidth);
+
+  ref<Expr> e = ce.getKid(1);
+
+  // concat chains are unbalanced to the right
+  while (e->getKind() == Expr::Concat) {
+    offset = AddExpr::create(offset, strideExpr);
+    if (!isReadExprAtOffset(e->getKid(0), base, offset))
+      return NULL;
+    e = e->getKid(1);
+  }
+
+  offset = AddExpr::create(offset, strideExpr);
+  if (!isReadExprAtOffset(e, base, offset))
+    return NULL;
+
+  return cast<ReadExpr>(e.get());
+}
+
+//--------------------------- INDEX-BASED OPTIMIZATION-----------------------//
+ExprVisitor::Action
+ConstantArrayExprVisitor::visitConcat(const ConcatExpr &ce) {
+  ReadExpr *base = ArrayExprHelper::hasOrderedReads(ce);
+  if (base) {
+    // It is an interesting ReadExpr if it contains a concrete array
+    // that is read at a symbolic index
+    if (base->updates.root->isConstantArray() &&
+        !isa<ConstantExpr>(base->index)) {
+      for (const UpdateNode *un = base->updates.head; un; un = un->next) {
+        if (!isa<ConstantExpr>(un->index) || !isa<ConstantExpr>(un->value)) {
+          incompatible = true;
+          return Action::skipChildren();
+        }
+      }
+      IndexCompatibilityExprVisitor compatible;
+      compatible.visit(base->index);
+      if (compatible.isCompatible() &&
+          addedIndexes.find(base->index.get()->hash()) == addedIndexes.end()) {
+        if (arrays.find(base->updates.root) == arrays.end()) {
+          arrays.insert(
+              std::make_pair(base->updates.root, std::vector<ref<Expr> >()));
+        } else {
+          // Another possible index to resolve, currently unsupported
+          incompatible = true;
+          return Action::skipChildren();
+        }
+        arrays.find(base->updates.root)->second.push_back(base->index);
+        addedIndexes.insert(base->index.get()->hash());
+      } else if (compatible.hasInnerReads()) {
+        // This Read has an inner Read, we want to optimize the inner one
+        // to create a cascading effect during assignment evaluation
+        return Action::doChildren();
+      }
+      return Action::skipChildren();
+    }
+  }
+  return Action::doChildren();
+}
+ExprVisitor::Action ConstantArrayExprVisitor::visitRead(const ReadExpr &re) {
+  // It is an interesting ReadExpr if it contains a concrete array
+  // that is read at a symbolic index
+  if (re.updates.root->isConstantArray() && !isa<ConstantExpr>(re.index)) {
+    for (const UpdateNode *un = re.updates.head; un; un = un->next) {
+      if (!isa<ConstantExpr>(un->index) || !isa<ConstantExpr>(un->value)) {
+        incompatible = true;
+        return Action::skipChildren();
+      }
+    }
+    IndexCompatibilityExprVisitor compatible;
+    compatible.visit(re.index);
+    if (compatible.isCompatible() &&
+        addedIndexes.find(re.index.get()->hash()) == addedIndexes.end()) {
+      if (arrays.find(re.updates.root) == arrays.end()) {
+        arrays.insert(
+            std::make_pair(re.updates.root, std::vector<ref<Expr> >()));
+      } else {
+        // Another possible index to resolve, currently unsupported
+        incompatible = true;
+        return Action::skipChildren();
+      }
+      arrays.find(re.updates.root)->second.push_back(re.index);
+      addedIndexes.insert(re.index.get()->hash());
+    } else if (compatible.hasInnerReads()) {
+      // This Read has an inner Read, we want to optimize the inner one
+      // to create a cascading effect during assignment evaluation
+      return Action::doChildren();
+    }
+    return Action::skipChildren();
+  } else if (re.updates.root->isSymbolicArray()) {
+    incompatible = true;
+  }
+
+  return Action::doChildren();
+}
+
+ExprVisitor::Action
+IndexCompatibilityExprVisitor::visitRead(const ReadExpr &re) {
+  if (re.updates.head) {
+    compatible = false;
+    return Action::skipChildren();
+  } else if (re.updates.root->isConstantArray() &&
+             !isa<ConstantExpr>(re.index)) {
+    compatible = false;
+    inner = true;
+    return Action::skipChildren();
+  }
+  return Action::doChildren();
+}
+ExprVisitor::Action IndexCompatibilityExprVisitor::visitURem(const URemExpr &) {
+  compatible = false;
+  return Action::skipChildren();
+}
+ExprVisitor::Action IndexCompatibilityExprVisitor::visitSRem(const SRemExpr &) {
+  compatible = false;
+  return Action::skipChildren();
+}
+ExprVisitor::Action IndexCompatibilityExprVisitor::visitOr(const OrExpr &) {
+  compatible = false;
+  return Action::skipChildren();
+}
+
+ExprVisitor::Action
+IndexTransformationExprVisitor::visitConcat(const ConcatExpr &ce) {
+  if (ReadExpr *re = dyn_cast<ReadExpr>(ce.getKid(0))) {
+    if (re->updates.root->hash() == array->hash() && width < ce.getWidth()) {
+      if (width == Expr::InvalidWidth)
+        width = ce.getWidth();
+    }
+  } else if (ReadExpr *re = dyn_cast<ReadExpr>(ce.getKid(1))) {
+    if (re->updates.root->hash() == array->hash() && width < ce.getWidth()) {
+      if (width == Expr::InvalidWidth)
+        width = ce.getWidth();
+    }
+  }
+  return Action::doChildren();
+}
+ExprVisitor::Action IndexTransformationExprVisitor::visitMul(const MulExpr &e) {
+  if (isa<ConstantExpr>(e.getKid(0)))
+    mul = e.getKid(0);
+  else if (isa<ConstantExpr>(e.getKid(0)))
+    mul = e.getKid(1);
+  return Action::doChildren();
+}