aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrea Mattavelli <andreamattavelli@users.noreply.github.com>2017-02-14 14:46:56 +0000
committerGitHub <noreply@github.com>2017-02-14 14:46:56 +0000
commit293f6e05ab8abdfca141eaa348da716b674c30e7 (patch)
tree55128d04f6d03b4308a8ae3e9a5241d2a94794e3
parentc3c3332a039e8e9cc10f93c3acb71c4240d4cab8 (diff)
parent44b24dac6a05ccde0e01b54fd2b787a31e5d8811 (diff)
downloadklee-293f6e05ab8abdfca141eaa348da716b674c30e7.tar.gz
Merge pull request #574 from delcypher/read_expr_missed_constaint_fold
ReadExpr::create() was missing an opportunity to constant fold
-rw-r--r--lib/Expr/Expr.cpp13
-rw-r--r--test/Feature/RewriteEqualities.c4
-rw-r--r--unittests/Expr/ExprTest.cpp151
3 files changed, 167 insertions, 1 deletions
diff --git a/lib/Expr/Expr.cpp b/lib/Expr/Expr.cpp
index 15f52184..ac50dda2 100644
--- a/lib/Expr/Expr.cpp
+++ b/lib/Expr/Expr.cpp
@@ -529,6 +529,7 @@ ref<Expr> ReadExpr::create(const UpdateList &ul, ref<Expr> index) {
// a smart UpdateList so it is not worth rescanning.
const UpdateNode *un = ul.head;
+ bool updateListHasSymbolicWrites = false;
for (; un; un=un->next) {
ref<Expr> cond = EqExpr::create(index, un->index);
@@ -536,10 +537,22 @@ ref<Expr> ReadExpr::create(const UpdateList &ul, ref<Expr> index) {
if (CE->isTrue())
return un->value;
} else {
+ updateListHasSymbolicWrites = true;
break;
}
}
+ if (ul.root->isConstantArray() && !updateListHasSymbolicWrites) {
+ if (ConstantExpr *CE = dyn_cast<ConstantExpr>(index)) {
+ assert(CE->getWidth() <= 64 && "Index too large");
+ uint64_t concreteIndex = CE->getZExtValue();
+ uint64_t size = ul.root->size;
+ if (concreteIndex < size) {
+ return ul.root->constantValues[concreteIndex];
+ }
+ }
+ }
+
return ReadExpr::alloc(ul, index);
}
diff --git a/test/Feature/RewriteEqualities.c b/test/Feature/RewriteEqualities.c
index 6bf199f7..b3cc0ef7 100644
--- a/test/Feature/RewriteEqualities.c
+++ b/test/Feature/RewriteEqualities.c
@@ -5,7 +5,7 @@
// RUN: grep "N0)" %t.klee-out/test000003.kquery
// RUN: rm -rf %t.klee-out
// RUN: %klee --output-dir=%t.klee-out --search=dfs --write-kqueries --rewrite-equalities %t.bc
-// RUN: grep "(Read w8 8 const_arr1)" %t.klee-out/test000003.kquery
+// RUN: FileCheck -input-file=%t.klee-out/test000003.kquery %s
#include <stdio.h>
#include <klee/klee.h>
@@ -19,6 +19,8 @@ int run(unsigned char * x, unsigned char * y) {
if(y[x[2]] < 11){
if(x[2] == 8){
+ // CHECK: (query [(Eq 8 (Read w8 2 x))]
+ // CHECK-NEXT: false)
return 2;
} else{
return 3;
diff --git a/unittests/Expr/ExprTest.cpp b/unittests/Expr/ExprTest.cpp
index 25129d8e..b1f593a5 100644
--- a/unittests/Expr/ExprTest.cpp
+++ b/unittests/Expr/ExprTest.cpp
@@ -113,4 +113,155 @@ TEST(ExprTest, ExtractConcat) {
EXPECT_EQ(Expr::Extract, concat2->getKid(1)->getKind());
}
+TEST(ExprTest, ReadExprFoldingBasic) {
+ unsigned size = 5;
+
+ // Constant array
+ std::vector<ref<ConstantExpr> > Contents(size);
+ for (unsigned i = 0; i < size; ++i)
+ Contents[i] = ConstantExpr::create(i + 1, Expr::Int8);
+ ArrayCache ac;
+ const Array *array =
+ ac.CreateArray("arr", size, &Contents[0], &Contents[0] + size);
+
+ // Basic constant folding rule
+ UpdateList ul(array, 0);
+ ref<Expr> read;
+
+ for (unsigned i = 0; i < size; ++i) {
+ // Constant index (i)
+ read = ReadExpr::create(ul, ConstantExpr::create(i, Expr::Int32));
+ EXPECT_EQ(Expr::Constant, read.get()->getKind());
+ // Read - should be constant folded to Contents[i]
+ // Check that constant folding worked
+ ConstantExpr *c = static_cast<ConstantExpr *>(read.get());
+ EXPECT_EQ(Contents[i]->getZExtValue(), c->getZExtValue());
+ }
+}
+
+TEST(ExprTest, ReadExprFoldingIndexOutOfBound) {
+ unsigned size = 5;
+
+ // Constant array
+ std::vector<ref<ConstantExpr> > Contents(size);
+ for (unsigned i = 0; i < size; ++i)
+ Contents[i] = ConstantExpr::create(i + 1, Expr::Int8);
+ ArrayCache ac;
+ const Array *array =
+ ac.CreateArray("arr", size, &Contents[0], &Contents[0] + size);
+
+ // Constant folding rule with index-out-of-bound
+ // Constant index (128)
+ ref<Expr> index = ConstantExpr::create(128, Expr::Int32);
+ UpdateList ul(array, 0);
+ ref<Expr> read = ReadExpr::create(ul, index);
+ // Read - should not be constant folded
+ // Check that constant folding was not applied
+ EXPECT_EQ(Expr::Read, read.get()->getKind());
+}
+
+TEST(ExprTest, ReadExprFoldingConstantUpdate) {
+ unsigned size = 5;
+
+ // Constant array
+ std::vector<ref<ConstantExpr> > Contents(size);
+ for (unsigned i = 0; i < size; ++i)
+ Contents[i] = ConstantExpr::create(i + 1, Expr::Int8);
+ ArrayCache ac;
+ const Array *array =
+ ac.CreateArray("arr", size, &Contents[0], &Contents[0] + size);
+
+ // Constant folding rule with constant update
+ // Constant index (0)
+ ref<Expr> index = ConstantExpr::create(0, Expr::Int32);
+ UpdateList ul(array, 0);
+ ref<Expr> updateValue = ConstantExpr::create(32, Expr::Int8);
+ ul.extend(index, updateValue);
+ ref<Expr> read = ReadExpr::create(ul, index);
+ // Read - should be constant folded to 32
+ // Check that constant folding worked
+ EXPECT_EQ(Expr::Constant, read.get()->getKind());
+ ConstantExpr *c = static_cast<ConstantExpr *>(read.get());
+ EXPECT_EQ(32, c->getZExtValue());
+}
+
+TEST(ExprTest, ReadExprFoldingConstantMultipleUpdate) {
+ unsigned size = 5;
+
+ // Constant array
+ std::vector<ref<ConstantExpr> > Contents(size);
+ for (unsigned i = 0; i < size; ++i)
+ Contents[i] = ConstantExpr::create(i + 1, Expr::Int8);
+ ArrayCache ac;
+ const Array *array =
+ ac.CreateArray("arr", size, &Contents[0], &Contents[0] + size);
+
+ // Constant folding rule with constant update
+ // Constant index (0)
+ ref<Expr> index = ConstantExpr::create(0, Expr::Int32);
+ UpdateList ul(array, 0);
+ ref<Expr> updateValue = ConstantExpr::create(32, Expr::Int8);
+ ref<Expr> updateValue2 = ConstantExpr::create(64, Expr::Int8);
+ ul.extend(index, updateValue);
+ ul.extend(index, updateValue2);
+ ref<Expr> read = ReadExpr::create(ul, index);
+ // Read - should be constant folded to 64
+ // Check that constant folding worked
+ EXPECT_EQ(Expr::Constant, read.get()->getKind());
+ ConstantExpr *c = static_cast<ConstantExpr *>(read.get());
+ EXPECT_EQ(64, c->getZExtValue());
+}
+
+TEST(ExprTest, ReadExprFoldingSymbolicValueUpdate) {
+ unsigned size = 5;
+
+ // Constant array
+ std::vector<ref<ConstantExpr> > Contents(size);
+ for (unsigned i = 0; i < size; ++i)
+ Contents[i] = ConstantExpr::create(i + 1, Expr::Int8);
+ ArrayCache ac;
+ const Array *array =
+ ac.CreateArray("arr", size, &Contents[0], &Contents[0] + size);
+
+ // Constant folding rule with symbolic update (value)
+ // Constant index (0)
+ ref<Expr> index = ConstantExpr::create(0, Expr::Int32);
+ UpdateList ul(array, 0);
+ const Array *array2 = ac.CreateArray("arr2", 256);
+ ref<Expr> updateValue = ReadExpr::createTempRead(array2, Expr::Int8);
+ ul.extend(index, updateValue);
+ ref<Expr> read = ReadExpr::create(ul, index);
+ // Read - should be constant folded to the symbolic value
+ // Check that constant folding worked
+ EXPECT_EQ(Expr::Read, read.get()->getKind());
+ EXPECT_EQ(updateValue, read);
+}
+
+TEST(ExprTest, ReadExprFoldingSymbolicIndexUpdate) {
+ unsigned size = 5;
+
+ // Constant array
+ std::vector<ref<ConstantExpr> > Contents(size);
+ for (unsigned i = 0; i < size; ++i)
+ Contents[i] = ConstantExpr::create(i + 1, Expr::Int8);
+ ArrayCache ac;
+ const Array *array =
+ ac.CreateArray("arr", size, &Contents[0], &Contents[0] + size);
+
+ // Constant folding rule with symbolic update (index)
+ UpdateList ul(array, 0);
+ const Array *array2 = ac.CreateArray("arr2", 256);
+ ref<Expr> updateIndex = ReadExpr::createTempRead(array2, Expr::Int32);
+ ref<Expr> updateValue = ConstantExpr::create(12, Expr::Int8);
+ ul.extend(updateIndex, updateValue);
+ ref<Expr> read;
+
+ for (unsigned i = 0; i < size; ++i) {
+ // Constant index (i)
+ read = ReadExpr::create(ul, ConstantExpr::create(i, Expr::Int32));
+ // Read - should not be constant folded
+ // Check that constant folding was not applied
+ EXPECT_EQ(Expr::Read, read.get()->getKind());
+ }
+}
}