23#include <llvm/ADT/APInt.h>
24#include <llvm/Support/CommandLine.h>
36 llvm::cl::values(clEnumValN(
ALL,
"all",
37 "Combining index and value transformations"),
38 clEnumValN(
INDEX,
"index",
"Index-based transformation"),
39 clEnumValN(
VALUE,
"value",
40 "Value-based transformation at branch (both "
41 "concrete and concrete/symbolic)")),
43 llvm::cl::desc(
"Optimize accesses to either concrete or concrete/symbolic "
44 "arrays. (default=false)"),
49 llvm::cl::desc(
"Maximum ratio of unique values to array size for which the "
50 "value-based transformations are applied."),
51 llvm::cl::init(1.0), llvm::cl::value_desc(
"Unique Values / Array Size"),
55 "array-value-symb-ratio",
56 llvm::cl::desc(
"Maximum ratio of symbolic values to array size for which "
57 "the mixed value-based transformations are applied."),
58 llvm::cl::init(1.0), llvm::cl::value_desc(
"Symbolic Values / Array Size"),
66 assert(0 &&
"invalid width");
68 return ReadExpr::alloc(ul, index);
70 return ConcatExpr::create(
72 ul, AddExpr::create(ConstantExpr::create(1, Expr::Int32), index)),
73 ReadExpr::alloc(ul, index));
75 return ConcatExpr::create4(
77 ul, AddExpr::create(ConstantExpr::create(3, Expr::Int32), index)),
79 ul, AddExpr::create(ConstantExpr::create(2, Expr::Int32), index)),
81 ul, AddExpr::create(ConstantExpr::create(1, Expr::Int32), index)),
82 ReadExpr::alloc(ul, index));
84 return ConcatExpr::create8(
86 ul, AddExpr::create(ConstantExpr::create(7, Expr::Int32), index)),
88 ul, AddExpr::create(ConstantExpr::create(6, Expr::Int32), index)),
90 ul, AddExpr::create(ConstantExpr::create(5, Expr::Int32), index)),
92 ul, AddExpr::create(ConstantExpr::create(4, Expr::Int32), index)),
94 ul, AddExpr::create(ConstantExpr::create(3, Expr::Int32), index)),
96 ul, AddExpr::create(ConstantExpr::create(2, Expr::Int32), index)),
98 ul, AddExpr::create(ConstantExpr::create(1, Expr::Int32), index)),
99 ReadExpr::alloc(ul, index));
105 if (isa<ConstantExpr>(e))
118 return cached->second;
141 if (!idx_valIdx.empty()) {
164 std::vector<const ReadExpr *> reads;
165 std::map<const ReadExpr *, std::pair<ref<Expr>,
Expr::Width>> readInfo;
168 std::reverse(reads.begin(), reads.end());
193 bool success =
false;
195 for (
auto &element : arrays) {
196 const Array *arr = element.first;
199 assert(element.second.size() == 1 &&
"Multiple indexes on the same array");
203 assert((idxt_v.
getWidth() % arr->
range == 0) &&
"Read is not aligned");
206 if (
auto e = idxt_v.
getMul()) {
211 auto ce = dyn_cast<ConstantExpr>(e);
212 assert(ce &&
"Not a constant expression");
213 uint64_t mulVal = (*ce->getAPValue().getRawData());
216 if (width == 1 && mulVal > 1)
221 for (
size_t aIdx = 0; aIdx < arr->
constantValues.size(); aIdx += width) {
223 std::vector<const Array *> objects;
224 std::vector<std::vector<unsigned char>> values;
227 for (
auto &index_it : element.second) {
231 bool assignmentSuccess =
233 success |= assignmentSuccess;
237 if (assignmentSuccess && evaluation->
isTrue()) {
238 if (idx_valIdx.find(idx) == idx_valIdx.end()) {
239 idx_valIdx.insert(std::make_pair(idx, std::vector<
ref<Expr>>()));
241 idx_valIdx[idx].emplace_back(
252 const ref<Expr> &e, std::vector<const ReadExpr *> &reads,
261 for (
auto &read : reads) {
262 auto info = readInfo[read];
265 optimized.insert(std::make_pair(info.first, (*cached).second));
269 if (info.second > width) {
272 unsigned size = read->updates.root->getSize();
273 unsigned bytesPerElement = width / 8;
274 unsigned elementsInArray = size / bytesPerElement;
278 assert(read->updates.root->isConstantArray() &&
279 "Expected concrete array, found symbolic array");
283 std::vector<const UpdateNode *> us;
284 us.reserve(read->updates.getSize());
285 for (
const UpdateNode *un = read->updates.head.get(); un;
289 auto arrayConstValues = read->updates.root->constantValues;
290 for (
auto it = us.rbegin(); it != us.rend(); it++) {
292 auto ce = dyn_cast<ConstantExpr>(un->
index);
293 assert(ce &&
"Not a constant expression");
294 uint64_t index = ce->getAPValue().getZExtValue();
295 assert(index < arrayConstValues.size());
296 auto arrayValue = dyn_cast<ConstantExpr>(un->
value);
297 assert(arrayValue &&
"Not a constant expression");
298 arrayConstValues[index] = arrayValue;
300 std::vector<uint64_t> arrayValues;
302 for (
unsigned i = 0; i < elementsInArray; i++) {
304 for (
unsigned j = 0; j < bytesPerElement; j++) {
306 arrayConstValues[(i * bytesPerElement) + j]
312 arrayValues.push_back(val);
323 optimized.insert(std::make_pair(info.first, opt));
327 toReturn = replacer.
visit(e);
336 for (
auto &read : reads) {
337 auto info = readInfo[read];
340 optimized.insert(std::make_pair(info.first, (*cached).second));
344 if (info.second > width) {
347 unsigned size = read->updates.root->getSize();
348 unsigned bytesPerElement = width / 8;
349 unsigned elementsInArray = size / bytesPerElement;
350 bool symbArray = read->updates.root->isSymbolicArray();
356 auto arrayConstValues = read->updates.root->constantValues;
357 if (arrayConstValues.size() < size) {
359 for (
size_t i = arrayConstValues.size(); i < size; i++) {
366 std::vector<const UpdateNode *> us;
367 us.reserve(read->updates.getSize());
368 for (
const UpdateNode *un = read->updates.head.get(); un; un = un->
next.get())
371 for (
auto it = us.rbegin(); it != us.rend(); it++) {
373 auto ce = dyn_cast<ConstantExpr>(un->
index);
374 assert(ce &&
"Not a constant expression");
375 uint64_t index = ce->getAPValue().getLimitedValue();
376 if (!isa<ConstantExpr>(un->
value)) {
381 dyn_cast<ConstantExpr>(un->
value);
382 assert(arrayValue &&
"Not a constant expression");
383 arrayConstValues[index] = arrayValue;
387 std::vector<std::pair<uint64_t, bool>> arrayValues;
388 unsigned symByteNum = 0;
389 for (
unsigned i = 0; i < elementsInArray; i++) {
391 bool elementIsConcrete =
true;
392 for (
unsigned j = 0; j < bytesPerElement; j++) {
393 if (ba.
get((i * bytesPerElement) + j)) {
394 elementIsConcrete =
false;
398 arrayConstValues[(i * bytesPerElement) + j]
405 if (elementIsConcrete) {
406 arrayValues.emplace_back(val,
true);
409 arrayValues.emplace_back(0,
false);
413 if (((
double)symByteNum / (double)elementsInArray) <=
421 optimized.insert(std::make_pair(info.first, opt));
426 toReturn = replacer.
visit(e);
429 return toReturn ? toReturn : notFound;
433 const ref<Expr> &index, std::vector<uint64_t> &arrayValues,
435 std::vector<std::pair<uint64_t, uint64_t>> ranges;
436 std::vector<uint64_t> values;
437 std::set<uint64_t> unique_array_values;
451 unsigned curr_idx = 0;
452 uint64_t curr_val = arrayValues[0];
453 for (
unsigned i = 0; i < arraySize; i++) {
454 uint64_t temp = arrayValues[i];
455 unique_array_values.insert(curr_val);
456 if (temp != curr_val) {
457 ranges.emplace_back(curr_idx, i);
458 values.push_back(curr_val);
461 if (i == (arraySize - 1)) {
462 ranges.emplace_back(curr_idx, i + 1);
463 values.push_back(curr_val);
465 }
else if (i == (arraySize - 1)) {
466 ranges.emplace_back(curr_idx, i + 1);
467 values.push_back(curr_val);
471 if (((
double)unique_array_values.size() / (
double)(arraySize)) >=
476 std::map<uint64_t, std::vector<std::pair<uint64_t, uint64_t>>> exprMap;
477 for (
size_t i = 0; i < ranges.size(); i++) {
478 if (exprMap.find(values[i]) != exprMap.end()) {
479 exprMap[values[i]].emplace_back(ranges[i].first, ranges[i].second);
481 if (exprMap.find(values[i]) == exprMap.end()) {
482 exprMap.insert(std::make_pair(
483 values[i], std::vector<std::pair<uint64_t, uint64_t>>()));
485 exprMap.find(values[i])->second.emplace_back(ranges[i].first,
492 for (
auto range : exprMap) {
495 temp = builder->
Constant(llvm::APInt(valWidth, range.first,
false));
497 if (range.second.size() == 1) {
498 if (range.second[0].first == (range.second[0].second - 1)) {
500 EqExpr::create(actualIndex,
502 idxWidth, range.second[0].first,
false))),
503 builder->
Constant(llvm::APInt(valWidth, range.first,
false)),
509 SgeExpr::create(actualIndex,
511 idxWidth, range.second[0].first,
false))),
515 idxWidth, range.second[0].second,
false)))),
516 builder->
Constant(llvm::APInt(valWidth, range.first,
false)),
522 if (range.second[0].first == (range.second[0].second - 1)) {
523 currOr = EqExpr::create(actualIndex,
525 idxWidth, range.second[0].first,
false)));
527 currOr = AndExpr::create(
528 SgeExpr::create(actualIndex,
530 idxWidth, range.second[0].first,
false))),
531 SltExpr::create(actualIndex,
533 idxWidth, range.second[0].second,
false))));
535 for (
size_t i = 1; i < range.second.size(); i++) {
537 if (range.second[i].first == (range.second[i].second - 1)) {
538 tempOr = OrExpr::create(
539 EqExpr::create(actualIndex,
541 idxWidth, range.second[i].first,
false))),
545 tempOr = OrExpr::create(
550 idxWidth, range.second[i].first,
false))),
554 idxWidth, range.second[i].second,
false)))),
560 valWidth, range.first,
false)),
574 const ReadExpr *re, std::vector<std::pair<uint64_t, bool>> &arrayValues,
575 Expr::Width width,
unsigned elementsInArray)
const {
577 std::vector<uint64_t> values;
578 std::vector<std::pair<uint64_t, uint64_t>> ranges;
579 std::vector<uint64_t> holes;
580 std::set<uint64_t> unique_array_values;
582 unsigned arraySize = elementsInArray;
583 unsigned curr_idx = 0;
584 uint64_t curr_val = arrayValues[0].first;
586 bool emptyRange =
true;
588 for (
size_t i = 0; i < arrayValues.size(); i++) {
590 if (arrayValues[i].second) {
593 uint64_t temp = arrayValues[i].first;
594 unique_array_values.insert(temp);
595 if (temp != curr_val) {
596 ranges.emplace_back(curr_idx, i);
597 values.push_back(curr_val);
600 if (i == (arraySize - 1)) {
601 ranges.emplace_back(curr_idx, curr_idx + 1);
602 values.push_back(curr_val);
604 }
else if (i == (arraySize - 1)) {
605 ranges.emplace_back(curr_idx, i + 1);
606 values.push_back(curr_val);
612 ranges.emplace_back(curr_idx, i);
613 values.push_back(curr_val);
615 curr_val = arrayValues[i + 1].first;
621 assert(!unique_array_values.empty() &&
"No unique values");
622 assert(!ranges.empty() &&
"No ranges");
625 if (((
double)unique_array_values.size() / (
double)(arraySize)) <=
629 unsigned range_start = 0;
631 result = builder->
Constant(llvm::APInt(width, values[0],
false));
638 for (
size_t i = 1; i < holes.size(); i++) {
652 int new_index_width = new_index->
getWidth();
654 for (
size_t i = range_start; i < ranges.size(); i++) {
656 if (ranges[i].second - 1 == ranges[i].first) {
ref< Expr > extendRead(const UpdateList &ul, const ref< Expr > index, Expr::Width w)
bool isConstantArray() const
const std::vector< ref< ConstantExpr > > constantValues
Expr::Width getDomain() const
static bool generatePartialAssignment(const ref< Expr > &e, ref< Expr > &val, Assignment *&a)
static ref< ConstantExpr > create(uint64_t v, Width w)
static ref< ConstantExpr > alloc(const llvm::APInt &v)
ExprBuilder - Base expression builder class.
virtual ref< Expr > Constant(const llvm::APInt &Value)=0
ref< Expr > getSelectOptExpr(const ref< Expr > &e, std::vector< const ReadExpr * > &reads, std::map< const ReadExpr *, std::pair< ref< Expr >, Expr::Width > > &readInfo, bool isSymbolic)
ExprHashSet cacheExprUnapplicable
ExprHashMap< ref< Expr > > cacheExprOptimized
ref< Expr > buildMixedSelectExpr(const ReadExpr *re, std::vector< std::pair< uint64_t, bool > > &arrayValues, Expr::Width width, unsigned elementsInArray) const
bool computeIndexes(array2idx_ty &arrays, const ref< Expr > &e, mapIndexOptimizedExpr_ty &idx_valIdx) const
ref< Expr > buildConstantSelectExpr(const ref< Expr > &index, std::vector< uint64_t > &arrayValues, Expr::Width width, unsigned elementsInArray) const
ExprHashMap< ref< Expr > > cacheReadExprOptimized
static ref< Expr > createOptExpr(const ref< Expr > &e, const array2idx_ty &arrays, const mapIndexOptimizedExpr_ty &idx_valIdx)
ref< Expr > visit(const ref< Expr > &e)
virtual Width getWidth() const =0
unsigned Width
The type of an expression is simply its width, in bits.
bool isTrue() const
isTrue - Is this the true expression.
Class representing a one byte read from an array.
static ref< Expr > create(ref< Expr > c, ref< Expr > t, ref< Expr > f)
Class representing a complete list of updates into an array.
Class representing a byte update of an array.
const ref< UpdateNode > next
ExprBuilder * createDefaultExprBuilder()
llvm::cl::opt< double > ArrayValueSymbRatio("array-value-symb-ratio", llvm::cl::desc("Maximum ratio of symbolic values to array size for which " "the mixed value-based transformations are applied."), llvm::cl::init(1.0), llvm::cl::value_desc("Symbolic Values / Array Size"), llvm::cl::cat(klee::SolvingCat))
std::map< ref< Expr >, std::vector< ref< Expr > > > mapIndexOptimizedExpr_ty
llvm::cl::opt< ArrayOptimizationType > OptimizeArray("optimize-array", llvm::cl::values(clEnumValN(ALL, "all", "Combining index and value transformations"), clEnumValN(INDEX, "index", "Index-based transformation"), clEnumValN(VALUE, "value", "Value-based transformation at branch (both " "concrete and concrete/symbolic)")), llvm::cl::init(NONE), llvm::cl::desc("Optimize accesses to either concrete or concrete/symbolic " "arrays. (default=false)"), llvm::cl::cat(klee::SolvingCat))
std::map< const Array *, std::vector< ref< Expr > > > array2idx_ty
llvm::cl::opt< double > ArrayValueRatio("array-value-ratio", llvm::cl::desc("Maximum ratio of unique values to array size for which the " "value-based transformations are applied."), llvm::cl::init(1.0), llvm::cl::value_desc("Unique Values / Array Size"), llvm::cl::cat(klee::SolvingCat))
llvm::cl::OptionCategory SolvingCat
void void void klee_warning(const char *msg,...) __attribute__((format(printf