//===-- ArrayExprRewriter.cpp ---------------------------------------------===// // // The KLEE Symbolic Virtual Machine // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "ArrayExprRewriter.h" #include #include #include #include #include #include #include "ArrayExprVisitor.h" #include "klee/util/BitArray.h" using namespace klee; ref ExprRewriter::createOptExpr(const ref &e, const array2idx_ty &arrays, const mapIndexOptimizedExpr_ty &idx_valIdx) { return rewrite(e, arrays, idx_valIdx); } ref ExprRewriter::rewrite(const ref &e, const array2idx_ty &arrays, const mapIndexOptimizedExpr_ty &idx_valIdx) { ref notFound; std::vector> eqExprs; bool invert = false; for (auto &element : arrays) { const Array *arr = element.first; std::vector> indexes = element.second; IndexTransformationExprVisitor idxt_v(arr); idxt_v.visit(e); assert((idxt_v.getWidth() % element.first->range == 0) && "Read is not aligned"); Expr::Width width = idxt_v.getWidth() / element.first->range; if (!idxt_v.getMul().isNull()) { // 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 auto e = idxt_v.getMul(); auto ce = dyn_cast(e); assert(ce && "Not a constant expression"); llvm::APInt val = ce->getAPValue(); uint64_t mulVal = val.getZExtValue(); // 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 (std::vector>::const_iterator index_it = indexes.begin(); index_it != indexes.end(); ++index_it) { if (idx_valIdx.find((*index_it)) == idx_valIdx.end()) { continue; } auto opt_indexes = idx_valIdx.at((*index_it)); if (opt_indexes.empty()) { // We continue with other solutions continue; } else if (opt_indexes.size() == 1) { // We treat this case as a special one, and we create an EqExpr (e.g. // k==i) eqExprs.push_back(createEqExpr((*index_it), opt_indexes[0])); } else { Expr::Width idxWidth = (*index_it).get()->getWidth(); unsigned set = 0; BitArray ba(arr->size / width); for (auto &vals : opt_indexes) { auto ce = dyn_cast(vals); llvm::APInt v = ce->getAPValue(); ba.set(v.getZExtValue() / width); set++; } if (set > 0 && set < arr->size / width) invert = ((float)set / (float)(arr->size / width)) > 0.5 ? true : false; int start = -1; for (unsigned i = 0; i < arr->size / width; ++i) { if ((!invert && ba.get(i)) || (invert && !ba.get(i))) { if (start < 0) start = i; } else { if (start >= 0) { if (i - start == 1) { eqExprs.push_back(createEqExpr( (*index_it), ConstantExpr::create(start * width, idxWidth))); } else { // create range expr ref s = ConstantExpr::create(start * width, idxWidth); ref e = ConstantExpr::create((i - 1) * width, idxWidth); eqExprs.push_back(createRangeExpr((*index_it), s, e)); } start = -1; } } } if (start >= 0) { if ((arr->size / width) - start == 1) { eqExprs.push_back(createEqExpr( (*index_it), ConstantExpr::create(start * width, idxWidth))); } else { // create range expr ref s = ConstantExpr::create(start * width, idxWidth); ref e = ConstantExpr::create( ((arr->size / width) - 1) * width, idxWidth); eqExprs.push_back(createRangeExpr((*index_it), s, e)); } } } } } if (eqExprs.empty()) { return notFound; } else if (eqExprs.size() == 1) { if (isa(eqExprs[0])) { return EqExpr::alloc( ConstantExpr::alloc(invert ? 0 : 1, (eqExprs[0])->getWidth()), eqExprs[0]); } return invert ? NotExpr::alloc(eqExprs[0]) : eqExprs[0]; } else { // We have found at least 2 indexes, we combine them using an OrExpr (e.g. // k==i|k==j) ref orExpr = concatenateOrExpr(eqExprs.begin(), eqExprs.end()); // Create Eq expression for true branch return EqExpr::alloc( ConstantExpr::alloc(invert ? 0 : 1, (orExpr)->getWidth()), orExpr); } } ref ExprRewriter::concatenateOrExpr( const std::vector>::const_iterator begin, const std::vector>::const_iterator end) { if (begin + 2 == end) { return OrExpr::alloc(ZExtExpr::alloc((*begin), Expr::Int32), ZExtExpr::alloc((*(begin + 1)), Expr::Int32)); } else { return OrExpr::alloc(ZExtExpr::alloc((*begin), Expr::Int32), concatenateOrExpr(begin + 1, end)); } } ref ExprRewriter::createEqExpr(const ref &index, const ref &valIndex) { return EqExpr::alloc(valIndex, index); } ref ExprRewriter::createRangeExpr(const ref &index, const ref &valStart, const ref &valEnd) { return AndExpr::alloc(UleExpr::alloc(valStart, index), UleExpr::alloc(index, valEnd)); }