diff options
-rw-r--r-- | lib/Expr/Expr.cpp | 13 | ||||
-rw-r--r-- | test/Feature/RewriteEqualities.c | 4 | ||||
-rw-r--r-- | unittests/Expr/ExprTest.cpp | 151 |
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()); + } +} } |