aboutsummaryrefslogtreecommitdiffhomepage
path: root/lib/Expr/AssignmentGenerator.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/AssignmentGenerator.cpp
parent916b72a7955cbb06d1a10640f8c6daea14da523e (diff)
downloadklee-a53fade6e85394ef95dfaaa1c264149e85ea5451.tar.gz
Added support for KLEE index-based array optimization
Diffstat (limited to 'lib/Expr/AssignmentGenerator.cpp')
-rw-r--r--lib/Expr/AssignmentGenerator.cpp327
1 files changed, 327 insertions, 0 deletions
diff --git a/lib/Expr/AssignmentGenerator.cpp b/lib/Expr/AssignmentGenerator.cpp
new file mode 100644
index 00000000..755263f0
--- /dev/null
+++ b/lib/Expr/AssignmentGenerator.cpp
@@ -0,0 +1,327 @@
+#include "klee/AssignmentGenerator.h"
+
+#include "llvm/Support/raw_ostream.h"
+
+using namespace klee;
+
+bool AssignmentGenerator::generatePartialAssignment(const ref<Expr> &e,
+ ref<Expr> &val,
+ Assignment *&a) {
+ return helperGenerateAssignment(e, val, a, e->getWidth(), false);
+}
+
+bool AssignmentGenerator::helperGenerateAssignment(const ref<Expr> &e,
+ ref<Expr> &val,
+ Assignment *&a,
+ Expr::Width width,
+ bool sign) {
+ Expr &ep = *e.get();
+ switch (ep.getKind()) {
+
+ // ARITHMETIC
+ case Expr::Add: {
+ // val = val - kid
+ ref<Expr> kid_val;
+ ref<Expr> kid_expr;
+ if (isa<ConstantExpr>(ep.getKid(0))) {
+ kid_val = ep.getKid(0);
+ kid_expr = ep.getKid(1);
+ } else if (isa<ConstantExpr>(ep.getKid(1))) {
+ kid_val = ep.getKid(1);
+ kid_expr = ep.getKid(0);
+ } else {
+ return false;
+ }
+ if (!ExtractExpr::create(kid_val, kid_val.get()->getWidth() - 1, 1).get()->isZero()) {
+ // FIXME: really bad hack to support those cases in which KLEE creates
+ // Add expressions with negative values
+ val = createAddExpr(kid_val, val);
+ } else {
+ val = createSubExpr(kid_val, val);
+ }
+ return helperGenerateAssignment(kid_expr, val, a, width, sign);
+ }
+ case Expr::Sub: {
+ // val = val + kid
+ ref<Expr> kid_val;
+ ref<Expr> kid_expr;
+ if (isa<ConstantExpr>(ep.getKid(0))) {
+ kid_val = ep.getKid(0);
+ kid_expr = ep.getKid(1);
+ } else if (isa<ConstantExpr>(ep.getKid(1))) {
+ kid_val = ep.getKid(1);
+ kid_expr = ep.getKid(0);
+ } else {
+ return false;
+ }
+ val = createAddExpr(kid_val, val);
+ return helperGenerateAssignment(kid_expr, val, a, width, sign);
+ }
+ case Expr::Mul: {
+ // val = val / kid (check for sign)
+ ref<Expr> kid_val;
+ ref<Expr> kid_expr;
+ if (isa<ConstantExpr>(ep.getKid(0))) {
+ kid_val = ep.getKid(0);
+ kid_expr = ep.getKid(1);
+ } else if (isa<ConstantExpr>(ep.getKid(1))) {
+ kid_val = ep.getKid(1);
+ kid_expr = ep.getKid(0);
+ } else {
+ return false;
+ }
+
+ if (kid_val.get()->isZero()) {
+ return false;
+ } else if (!createDivRem(kid_val, val, sign)->isZero()) {
+ return false;
+ }
+ val = createDivExpr(kid_val, val, sign);
+ return helperGenerateAssignment(kid_expr, val, a, width, sign);
+ }
+ case Expr::UDiv:
+ // val = val * kid
+ // no break, falling down to case SDiv
+ case Expr::SDiv: {
+ // val = val * kid
+ ref<Expr> kid_val;
+ ref<Expr> kid_expr;
+ if (isa<ConstantExpr>(ep.getKid(0))) {
+ kid_val = ep.getKid(0);
+ kid_expr = ep.getKid(1);
+ } else if (isa<ConstantExpr>(ep.getKid(1))) {
+ kid_val = ep.getKid(1);
+ kid_expr = ep.getKid(0);
+ } else {
+ return false;
+ }
+ val = createMulExpr(kid_val, val);
+ return helperGenerateAssignment(kid_expr, val, a, width, sign);
+ }
+
+ // LOGICAL
+ case Expr::LShr: {
+ if (!isa<ConstantExpr>(ep.getKid(1))) {
+ return false;
+ }
+ ref<Expr> kid_val = ep.getKid(1);
+ val = createShlExpr(val, kid_val);
+ return helperGenerateAssignment(ep.getKid(0), val, a, width, sign);
+ }
+ case Expr::Shl: {
+ if (!isa<ConstantExpr>(ep.getKid(1))) {
+ return false;
+ }
+ ref<Expr> kid_val = ep.getKid(1);
+ val = createLShrExpr(val, kid_val);
+ return helperGenerateAssignment(ep.getKid(0), val, a, width, sign);
+ }
+ case Expr::Not: {
+ return helperGenerateAssignment(ep.getKid(0), val, a, width, sign);
+ }
+ case Expr::And: {
+ // val = val & kid
+ ref<Expr> kid_val;
+ ref<Expr> kid_expr;
+ if (isa<ConstantExpr>(ep.getKid(0))) {
+ kid_val = ep.getKid(0);
+ kid_expr = ep.getKid(1);
+ } else if (isa<ConstantExpr>(ep.getKid(1))) {
+ kid_val = ep.getKid(1);
+ kid_expr = ep.getKid(0);
+ } else {
+ return false;
+ }
+ val = createAndExpr(kid_val, val);
+ return helperGenerateAssignment(kid_expr, val, a, width, sign);
+ }
+
+ // CASTING
+ case Expr::ZExt: {
+ val = createExtractExpr(ep.getKid(0), val);
+ return helperGenerateAssignment(ep.getKid(0), val, a, width, false);
+ }
+ case Expr::SExt: {
+ val = createExtractExpr(ep.getKid(0), val);
+ return helperGenerateAssignment(ep.getKid(0), val, a, width, true);
+ }
+
+ // SPECIAL
+ case Expr::Concat: {
+ ReadExpr *base = hasOrderedReads(&ep);
+ if (base) {
+ return helperGenerateAssignment(ref<Expr>(base), val, a, ep.getWidth(),
+ sign);
+ } else {
+ klee_warning("Not supported");
+ ep.printKind(llvm::errs(), ep.getKind());
+ return false;
+ }
+ }
+ case Expr::Extract: {
+ val = createExtendExpr(ep.getKid(0), val);
+ return helperGenerateAssignment(ep.getKid(0), val, a, width, sign);
+ }
+
+ // READ
+ case Expr::Read: {
+ ReadExpr &re = static_cast<ReadExpr &>(ep);
+ if (isa<ConstantExpr>(re.index)) {
+ if (re.updates.root->isSymbolicArray()) {
+ ConstantExpr &index = static_cast<ConstantExpr &>(*re.index.get());
+ std::vector<unsigned char> c_value =
+ getIndexedValue(getByteValue(val), index, re.updates.root->size);
+ if (c_value.size() == 0) {
+ return false;
+ }
+ if (a->bindings.find(re.updates.root) == a->bindings.end()) {
+ a->bindings.insert(std::make_pair(re.updates.root, c_value));
+ } else {
+ return false;
+ }
+ }
+ } else {
+ return helperGenerateAssignment(re.index, val, a, width, sign);
+ }
+ return true;
+ }
+ default:
+ std::string type_str;
+ llvm::raw_string_ostream rso(type_str);
+ ep.printKind(rso, ep.getKind());
+ klee_warning("%s is not supported", rso.str().c_str());
+ return false;
+ }
+}
+
+bool AssignmentGenerator::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 *AssignmentGenerator::hasOrderedReads(ref<Expr> e) {
+ assert(e->getKind() == Expr::Concat);
+
+ const ReadExpr *base = dyn_cast<ReadExpr>(e->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);
+
+ e = e->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());
+}
+
+ref<Expr> AssignmentGenerator::createSubExpr(const ref<Expr> &l, ref<Expr> &r) {
+ return SubExpr::create(r, l);
+}
+
+ref<Expr> AssignmentGenerator::createAddExpr(const ref<Expr> &l, ref<Expr> &r) {
+ return AddExpr::create(r, l);
+}
+
+ref<Expr> AssignmentGenerator::createMulExpr(const ref<Expr> &l, ref<Expr> &r) {
+ return MulExpr::create(r, l);
+}
+
+ref<Expr> AssignmentGenerator::createDivRem(const ref<Expr> &l, ref<Expr> &r,
+ bool sign) {
+ if (sign)
+ return SRemExpr::create(r, l);
+ else
+ return URemExpr::create(r, l);
+}
+
+ref<Expr> AssignmentGenerator::createDivExpr(const ref<Expr> &l, ref<Expr> &r,
+ bool sign) {
+ if (sign)
+ return SDivExpr::create(r, l);
+ else
+ return UDivExpr::create(r, l);
+}
+
+ref<Expr> AssignmentGenerator::createShlExpr(const ref<Expr> &l, ref<Expr> &r) {
+ return ShlExpr::create(r, l);
+}
+
+ref<Expr> AssignmentGenerator::createLShrExpr(const ref<Expr> &l,
+ ref<Expr> &r) {
+ return LShrExpr::create(r, l);
+}
+
+ref<Expr> AssignmentGenerator::createAndExpr(const ref<Expr> &l, ref<Expr> &r) {
+ return AndExpr::create(r, l);
+}
+
+ref<Expr> AssignmentGenerator::createExtractExpr(const ref<Expr> &l,
+ ref<Expr> &r) {
+ return ExtractExpr::create(r, 0, l.get()->getWidth());
+}
+
+ref<Expr> AssignmentGenerator::createExtendExpr(const ref<Expr> &l,
+ ref<Expr> &r) {
+ if (l.get()->getKind() == Expr::ZExt) {
+ return ZExtExpr::create(r, l.get()->getWidth());
+ } else {
+ return SExtExpr::create(r, l.get()->getWidth());
+ }
+}
+
+std::vector<unsigned char> AssignmentGenerator::getByteValue(ref<Expr> &val) {
+ std::vector<unsigned char> toReturn;
+ if (ConstantExpr *value = dyn_cast<ConstantExpr>(val)) {
+ for (unsigned w = 0; w < val.get()->getWidth() / 8; ++w) {
+ ref<ConstantExpr> byte = value->Extract(w * 8, Expr::Int8);
+ unsigned char mem_val;
+ byte->toMemory(&mem_val);
+ toReturn.push_back(mem_val);
+ }
+ }
+ return toReturn;
+}
+
+std::vector<unsigned char>
+AssignmentGenerator::getIndexedValue(const std::vector<unsigned char> &c_val,
+ ConstantExpr &index,
+ const unsigned int size) {
+ std::vector<unsigned char> toReturn;
+ const llvm::APInt index_val = index.getAPValue();
+ assert(!index_val.isSignBit() && "Negative index");
+ const uint64_t id = index_val.getZExtValue() / c_val.size();
+ uint64_t arraySize = size / c_val.size();
+ for (uint64_t i = 0; i < arraySize; ++i) {
+ if (i == id) {
+ for (unsigned arr_i = 0; arr_i < c_val.size(); ++arr_i) {
+ toReturn.push_back(c_val[arr_i]);
+ }
+ } else {
+ for (unsigned arr_i = 0; arr_i < c_val.size(); ++arr_i) {
+ toReturn.push_back(0);
+ }
+ }
+ }
+
+ return toReturn;
+}