From a53fade6e85394ef95dfaaa1c264149e85ea5451 Mon Sep 17 00:00:00 2001 From: Andrea Mattavelli Date: Wed, 22 Nov 2017 17:18:07 +0000 Subject: Added support for KLEE index-based array optimization --- lib/Expr/ArrayExprOptimizer.cpp | 135 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 lib/Expr/ArrayExprOptimizer.cpp (limited to 'lib/Expr/ArrayExprOptimizer.cpp') diff --git a/lib/Expr/ArrayExprOptimizer.cpp b/lib/Expr/ArrayExprOptimizer.cpp new file mode 100644 index 00000000..d3e8cbab --- /dev/null +++ b/lib/Expr/ArrayExprOptimizer.cpp @@ -0,0 +1,135 @@ +#include "klee/ArrayExprOptimizer.h" + +#include "klee/ArrayExprRewriter.h" +#include "klee/util/BitArray.h" + +#include + +using namespace klee; + +namespace klee { +llvm::cl::opt OptimizeArray( + "optimize-array", + llvm::cl::values( + clEnumValN(INDEX, "index", "Index-based transformation"), + clEnumValEnd), + llvm::cl::init(NONE), + llvm::cl::desc("Optimize accesses to either concrete or concrete/symbolic " + "arrays. (default=off)")); +}; + +void ExprOptimizer::optimizeExpr(const ref &e, ref &result, + bool valueOnly) { + unsigned hash = e->hash(); + if (cacheExprUnapplicable.find(hash) != cacheExprUnapplicable.end()) { + return; + } + + // Find cached expressions + auto cached = cacheExprOptimized.find(hash); + if (cached != cacheExprOptimized.end()) { + result = cached->second; + return; + } + + // ----------------------- INDEX-BASED OPTIMIZATION ------------------------- + if (!valueOnly && OptimizeArray == INDEX) { + array2idx_ty arrays; + ConstantArrayExprVisitor aev(arrays); + aev.visit(e); + + if (arrays.size() == 0 || aev.isIncompatible()) { + // We do not optimize expressions other than those with concrete + // arrays with a symbolic index + // If we cannot optimize the expression, we return a failure only + // when we are not combining the optimizations + if (OptimizeArray == INDEX) { + cacheExprUnapplicable.insert(hash); + return; + } + } else { + mapIndexOptimizedExpr_ty idx_valIdx; + + // Compute those indexes s.t. orig_expr =equisat= (k==i|k==j|..) + if (computeIndexes(arrays, e, idx_valIdx)) { + if (idx_valIdx.size() > 0) { + // Create new expression on indexes + result = ExprRewriter::createOptExpr(e, arrays, idx_valIdx); + } else { + klee_warning("OPT_I: infeasible branch!"); + result = ConstantExpr::create(0, Expr::Bool); + } + // Add new expression to cache + if (result.get()) { + klee_warning("OPT_I: successful"); + cacheExprOptimized[hash] = result; + } else { + klee_warning("OPT_I: unsuccessful"); + } + } else { + klee_warning("OPT_I: unsuccessful"); + cacheExprUnapplicable.insert(hash); + } + } + } +} + +bool ExprOptimizer::computeIndexes(array2idx_ty &arrays, const ref &e, + mapIndexOptimizedExpr_ty &idx_valIdx) const { + bool success = false; + // For each constant array found + for (auto &element : arrays) { + const Array *arr = element.first; + + assert(arr->isConstantArray() && "Array is not concrete"); + assert(element.second.size() == 1 && "Multiple indexes on the same array"); + + IndexTransformationExprVisitor idxt_v(arr); + idxt_v.visit(e); + assert((idxt_v.getWidth() % arr->range == 0) && "Read is not aligned"); + Expr::Width width = idxt_v.getWidth() / arr->range; + + if (idxt_v.getMul().get()) { + // If we have a MulExpr in the index, we can optimize our search by + // skipping all those indexes that are not multiple of such value. + // In fact, they will be rejected by the MulExpr interpreter since it + // will not find any integer solution + Expr &e = *idxt_v.getMul(); + ConstantExpr &ce = static_cast(e); + uint64_t mulVal = (*ce.getAPValue().getRawData()); + // So far we try to limit this optimization, but we may try some more + // aggressive conditions (i.e. mulVal > width) + if (width == 1 && mulVal > 1) + width = mulVal; + } + + // For each concrete value 'i' stored in the array + for (size_t aIdx = 0; aIdx < arr->constantValues.size(); aIdx += width) { + Assignment *a = new Assignment(); + v_arr_ty objects; + std::vector > values; + + // For each symbolic index Expr(k) found + for (auto &index_it : element.second) { + ref idx = index_it; + ref val = ConstantExpr::alloc(aIdx, arr->getDomain()); + // We create a partial assignment on 'k' s.t. Expr(k)==i + bool assignmentSuccess = + AssignmentGenerator::generatePartialAssignment(idx, val, a); + success |= assignmentSuccess; + + // If the assignment satisfies both the expression 'e' and the PC + ref evaluation = a->evaluate(e); + if (assignmentSuccess && evaluation->isTrue()) { + if (idx_valIdx.find(idx) == idx_valIdx.end()) { + idx_valIdx.insert(std::make_pair(idx, std::vector >())); + } + idx_valIdx[idx] + .push_back(ConstantExpr::alloc(aIdx, arr->getDomain())); + } + } + delete a; + } + } + return success; +} -- cgit 1.4.1