klee
FastCexSolver.cpp
Go to the documentation of this file.
1//===-- FastCexSolver.cpp -------------------------------------------------===//
2//
3// The KLEE Symbolic Virtual Machine
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#define DEBUG_TYPE "cex-solver"
11#include "klee/Solver/Solver.h"
12
14#include "klee/Expr/Expr.h"
19#include "klee/Support/Debug.h"
20#include "klee/Support/IntEvaluation.h" // FIXME: Use APInt
21
22#include "llvm/Support/raw_ostream.h"
23
24#include <cassert>
25#include <map>
26#include <sstream>
27#include <vector>
28
29using namespace klee;
30
31// Hacker's Delight, pgs 58-63
32static uint64_t minOR(uint64_t a, uint64_t b,
33 uint64_t c, uint64_t d) {
34 uint64_t temp, m = ((uint64_t) 1)<<63;
35 while (m) {
36 if (~a & c & m) {
37 temp = (a | m) & -m;
38 if (temp <= b) { a = temp; break; }
39 } else if (a & ~c & m) {
40 temp = (c | m) & -m;
41 if (temp <= d) { c = temp; break; }
42 }
43 m >>= 1;
44 }
45
46 return a | c;
47}
48static uint64_t maxOR(uint64_t a, uint64_t b,
49 uint64_t c, uint64_t d) {
50 uint64_t temp, m = ((uint64_t) 1)<<63;
51
52 while (m) {
53 if (b & d & m) {
54 temp = (b - m) | (m - 1);
55 if (temp >= a) { b = temp; break; }
56 temp = (d - m) | (m -1);
57 if (temp >= c) { d = temp; break; }
58 }
59 m >>= 1;
60 }
61
62 return b | d;
63}
64static uint64_t minAND(uint64_t a, uint64_t b,
65 uint64_t c, uint64_t d) {
66 uint64_t temp, m = ((uint64_t) 1)<<63;
67 while (m) {
68 if (~a & ~c & m) {
69 temp = (a | m) & -m;
70 if (temp <= b) { a = temp; break; }
71 temp = (c | m) & -m;
72 if (temp <= d) { c = temp; break; }
73 }
74 m >>= 1;
75 }
76
77 return a & c;
78}
79static uint64_t maxAND(uint64_t a, uint64_t b,
80 uint64_t c, uint64_t d) {
81 uint64_t temp, m = ((uint64_t) 1)<<63;
82 while (m) {
83 if (b & ~d & m) {
84 temp = (b & ~m) | (m - 1);
85 if (temp >= a) { b = temp; break; }
86 } else if (~b & d & m) {
87 temp = (d & ~m) | (m - 1);
88 if (temp >= c) { d = temp; break; }
89 }
90 m >>= 1;
91 }
92
93 return b & d;
94}
95
97
99private:
100 std::uint64_t m_min = 1, m_max = 0;
101
102public:
103 ValueRange() noexcept = default;
105 // FIXME: Support large widths.
106 m_min = m_max = ce->getLimitedValue();
107 }
108 explicit ValueRange(std::uint64_t value) noexcept
109 : m_min(value), m_max(value) {}
110 ValueRange(std::uint64_t _min, std::uint64_t _max) noexcept
111 : m_min(_min), m_max(_max) {}
112 ValueRange(const ValueRange &other) noexcept = default;
113 ValueRange &operator=(const ValueRange &other) noexcept = default;
114 ValueRange(ValueRange &&other) noexcept = default;
115 ValueRange &operator=(ValueRange &&other) noexcept = default;
116
117 void print(llvm::raw_ostream &os) const {
118 if (isFixed()) {
119 os << m_min;
120 } else {
121 os << "[" << m_min << "," << m_max << "]";
122 }
123 }
124
125 bool isEmpty() const noexcept { return m_min > m_max; }
126 bool contains(std::uint64_t value) const {
127 return this->intersects(ValueRange(value));
128 }
129 bool intersects(const ValueRange &b) const {
130 return !this->set_intersection(b).isEmpty();
131 }
132
133 bool isFullRange(unsigned bits) const noexcept {
134 return m_min == 0 && m_max == bits64::maxValueOfNBits(bits);
135 }
136
138 return ValueRange(std::max(m_min, b.m_min), std::min(m_max, b.m_max));
139 }
141 return ValueRange(std::min(m_min, b.m_min), std::max(m_max, b.m_max));
142 }
144 if (b.isEmpty() || b.m_min > m_max || b.m_max < m_min) { // no intersection
145 return *this;
146 } else if (b.m_min <= m_min && b.m_max >= m_max) { // empty
147 return ValueRange(1, 0);
148 } else if (b.m_min <= m_min) { // one range out
149 // cannot overflow because b.m_max < m_max
150 return ValueRange(b.m_max + 1, m_max);
151 } else if (b.m_max >= m_max) {
152 // cannot overflow because b.min > m_min
153 return ValueRange(m_min, b.m_min - 1);
154 } else {
155 // two ranges, take bottom
156 return ValueRange(m_min, b.m_min - 1);
157 }
158 }
160 // XXX
161 assert(!isEmpty() && !b.isEmpty() && "XXX");
162 if (isFixed() && b.isFixed()) {
163 return ValueRange(m_min & b.m_min);
164 } else {
165 return ValueRange(minAND(m_min, m_max, b.m_min, b.m_max),
166 maxAND(m_min, m_max, b.m_min, b.m_max));
167 }
168 }
169 ValueRange binaryAnd(std::uint64_t b) const {
170 return binaryAnd(ValueRange(b));
171 }
173 // XXX
174 assert(!isEmpty() && !b.isEmpty() && "XXX");
175 if (isFixed() && b.isFixed()) {
176 return ValueRange(m_min | b.m_min);
177 } else {
178 return ValueRange(minOR(m_min, m_max, b.m_min, b.m_max),
179 maxOR(m_min, m_max, b.m_min, b.m_max));
180 }
181 }
182 ValueRange binaryOr(std::uint64_t b) const { return binaryOr(ValueRange(b)); }
184 if (isFixed() && b.isFixed()) {
185 return ValueRange(m_min ^ b.m_min);
186 } else {
187 std::uint64_t t = m_max | b.m_max;
188 while (!bits64::isPowerOfTwo(t))
190 return ValueRange(0, (t << 1) - 1);
191 }
192 }
193
194 ValueRange binaryShiftLeft(unsigned bits) const {
195 return ValueRange(m_min << bits, m_max << bits);
196 }
197 ValueRange binaryShiftRight(unsigned bits) const {
198 return ValueRange(m_min >> bits, m_max >> bits);
199 }
200
201 ValueRange concat(const ValueRange &b, unsigned bits) const {
202 return binaryShiftLeft(bits).binaryOr(b);
203 }
204 ValueRange extract(std::uint64_t lowBit, std::uint64_t maxBit) const {
205 return binaryShiftRight(lowBit).binaryAnd(
206 bits64::maxValueOfNBits(maxBit - lowBit));
207 }
208
209 ValueRange add(const ValueRange &b, unsigned width) const {
210 return ValueRange(0, bits64::maxValueOfNBits(width));
211 }
212 ValueRange sub(const ValueRange &b, unsigned width) const {
213 return ValueRange(0, bits64::maxValueOfNBits(width));
214 }
215 ValueRange mul(const ValueRange &b, unsigned width) const {
216 return ValueRange(0, bits64::maxValueOfNBits(width));
217 }
218 ValueRange udiv(const ValueRange &b, unsigned width) const {
219 return ValueRange(0, bits64::maxValueOfNBits(width));
220 }
221 ValueRange sdiv(const ValueRange &b, unsigned width) const {
222 return ValueRange(0, bits64::maxValueOfNBits(width));
223 }
224 ValueRange urem(const ValueRange &b, unsigned width) const {
225 return ValueRange(0, bits64::maxValueOfNBits(width));
226 }
227 ValueRange srem(const ValueRange &b, unsigned width) const {
228 return ValueRange(0, bits64::maxValueOfNBits(width));
229 }
230
231 // use min() to get value if true (XXX should we add a method to
232 // make code clearer?)
233 bool isFixed() const noexcept { return m_min == m_max; }
234
235 bool operator==(const ValueRange &b) const noexcept {
236 return m_min == b.m_min && m_max == b.m_max;
237 }
238 bool operator!=(const ValueRange &b) const noexcept { return !(*this == b); }
239
240 bool mustEqual(const std::uint64_t b) const noexcept {
241 return m_min == m_max && m_min == b;
242 }
243 bool mayEqual(const std::uint64_t b) const noexcept {
244 return m_min <= b && m_max >= b;
245 }
246
247 bool mustEqual(const ValueRange &b) const noexcept {
248 return isFixed() && b.isFixed() && m_min == b.m_min;
249 }
250 bool mayEqual(const ValueRange &b) const { return this->intersects(b); }
251
252 std::uint64_t min() const noexcept {
253 assert(!isEmpty() && "cannot get minimum of empty range");
254 return m_min;
255 }
256
257 std::uint64_t max() const noexcept {
258 assert(!isEmpty() && "cannot get maximum of empty range");
259 return m_max;
260 }
261
262 std::int64_t minSigned(unsigned bits) const {
263 assert((m_min >> bits) == 0 && (m_max >> bits) == 0 &&
264 "range is outside given number of bits");
265
266 // if max allows sign bit to be set then it can be smallest value,
267 // otherwise since the range is not empty, min cannot have a sign
268 // bit
269
270 std::uint64_t smallest = (static_cast<std::uint64_t>(1) << (bits - 1));
271 if (m_max >= smallest) {
272 return ints::sext(smallest, 64, bits);
273 } else {
274 return m_min;
275 }
276 }
277
278 std::int64_t maxSigned(unsigned bits) const {
279 assert((m_min >> bits) == 0 && (m_max >> bits) == 0 &&
280 "range is outside given number of bits");
281
282 std::uint64_t smallest = (static_cast<std::uint64_t>(1) << (bits - 1));
283
284 // if max and min have sign bit then max is max, otherwise if only
285 // max has sign bit then max is largest signed integer, otherwise
286 // max is max
287
288 if (m_min < smallest && m_max >= smallest) {
289 return smallest - 1;
290 } else {
291 return ints::sext(m_max, 64, bits);
292 }
293 }
294};
295
296inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
297 const ValueRange &vr) {
298 vr.print(os);
299 return os;
300}
301
302// XXX waste of space, rather have ByteValueRange
304
310 std::vector<CexValueData> possibleContents;
311
316 std::vector<CexValueData> exactContents;
317
318 CexObjectData(const CexObjectData&); // DO NOT IMPLEMENT
319 void operator=(const CexObjectData&); // DO NOT IMPLEMENT
320
321public:
322 CexObjectData(uint64_t size) : possibleContents(size), exactContents(size) {
323 for (uint64_t i = 0; i != size; ++i) {
324 possibleContents[i] = ValueRange(0, 255);
325 exactContents[i] = ValueRange(0, 255);
326 }
327 }
328
329 const CexValueData getPossibleValues(size_t index) const {
330 return possibleContents[index];
331 }
332 void setPossibleValues(size_t index, CexValueData values) {
333 possibleContents[index] = values;
334 }
335 void setPossibleValue(size_t index, unsigned char value) {
336 possibleContents[index] = CexValueData(value);
337 }
338
339 const CexValueData getExactValues(size_t index) const {
340 return exactContents[index];
341 }
342 void setExactValues(size_t index, CexValueData values) {
343 exactContents[index] = values;
344 }
345
347 unsigned char getPossibleValue(size_t index) const {
348 const CexValueData &cvd = possibleContents[index];
349 return cvd.min() + (cvd.max() - cvd.min()) / 2;
350 }
351};
352
353class CexRangeEvaluator : public ExprRangeEvaluator<ValueRange> {
354public:
355 std::map<const Array*, CexObjectData*> &objects;
356 CexRangeEvaluator(std::map<const Array*, CexObjectData*> &_objects)
357 : objects(_objects) {}
358
360 // Check for a concrete read of a constant array.
361 if (array.isConstantArray() &&
362 index.isFixed() &&
363 index.min() < array.size)
364 return ValueRange(array.constantValues[index.min()]->getZExtValue(8));
365
366 return ValueRange(0, 255);
367 }
368};
369
371protected:
372 ref<Expr> getInitialValue(const Array& array, unsigned index) {
373 // If the index is out of range, we cannot assign it a value, since that
374 // value cannot be part of the assignment.
375 if (index >= array.size)
376 return ReadExpr::create(UpdateList(&array, 0),
377 ConstantExpr::alloc(index, array.getDomain()));
378
379 std::map<const Array*, CexObjectData*>::iterator it = objects.find(&array);
380 return ConstantExpr::alloc((it == objects.end() ? 127 :
381 it->second->getPossibleValue(index)),
382 array.getRange());
383 }
384
385public:
386 std::map<const Array*, CexObjectData*> &objects;
387 CexPossibleEvaluator(std::map<const Array*, CexObjectData*> &_objects)
388 : objects(_objects) {}
389};
390
392protected:
393 ref<Expr> getInitialValue(const Array& array, unsigned index) {
394 // If the index is out of range, we cannot assign it a value, since that
395 // value cannot be part of the assignment.
396 if (index >= array.size)
397 return ReadExpr::create(UpdateList(&array, 0),
398 ConstantExpr::alloc(index, array.getDomain()));
399
400 std::map<const Array*, CexObjectData*>::iterator it = objects.find(&array);
401 if (it == objects.end())
402 return ReadExpr::create(UpdateList(&array, 0),
403 ConstantExpr::alloc(index, array.getDomain()));
404
405 CexValueData cvd = it->second->getExactValues(index);
406 if (!cvd.isFixed())
407 return ReadExpr::create(UpdateList(&array, 0),
408 ConstantExpr::alloc(index, array.getDomain()));
409
410 return ConstantExpr::alloc(cvd.min(), array.getRange());
411 }
412
413public:
414 std::map<const Array*, CexObjectData*> &objects;
415 CexExactEvaluator(std::map<const Array*, CexObjectData*> &_objects)
416 : objects(_objects) {}
417};
418
419class CexData {
420public:
421 std::map<const Array*, CexObjectData*> objects;
422
423 CexData(const CexData&); // DO NOT IMPLEMENT
424 void operator=(const CexData&); // DO NOT IMPLEMENT
425
426public:
429 for (std::map<const Array*, CexObjectData*>::iterator it = objects.begin(),
430 ie = objects.end(); it != ie; ++it)
431 delete it->second;
432 }
433
435 CexObjectData *&Entry = objects[A];
436
437 if (!Entry)
438 Entry = new CexObjectData(A->size);
439
440 return *Entry;
441 }
442
443 void propogatePossibleValue(ref<Expr> e, uint64_t value) {
444 propogatePossibleValues(e, CexValueData(value,value));
445 }
446
447 void propogateExactValue(ref<Expr> e, uint64_t value) {
448 propogateExactValues(e, CexValueData(value,value));
449 }
450
452 KLEE_DEBUG(llvm::errs() << "propogate: " << range << " for\n"
453 << e << "\n");
454
455 switch (e->getKind()) {
456 case Expr::Constant:
457 // rather a pity if the constant isn't in the range, but how can
458 // we use this?
459 break;
460
461 // Special
462
463 case Expr::NotOptimized: break;
464
465 case Expr::Read: {
466 ReadExpr *re = cast<ReadExpr>(e);
467 const Array *array = re->updates.root;
468 CexObjectData &cod = getObjectData(array);
469
470 // FIXME: This is imprecise, we need to look through the existing writes
471 // to see if this is an initial read or not.
472 if (ConstantExpr *CE = dyn_cast<ConstantExpr>(re->index)) {
473 uint64_t index = CE->getZExtValue();
474
475 if (index < array->size) {
476 // If the range is fixed, just set that; even if it conflicts with the
477 // previous range it should be a better guess.
478 if (range.isFixed()) {
479 cod.setPossibleValue(index, range.min());
480 } else {
481 CexValueData cvd = cod.getPossibleValues(index);
482 CexValueData tmp = cvd.set_intersection(range);
483
484 if (!tmp.isEmpty())
485 cod.setPossibleValues(index, tmp);
486 }
487 }
488 } else {
489 // XXX fatal("XXX not implemented");
490 }
491 break;
492 }
493
494 case Expr::Select: {
495 SelectExpr *se = cast<SelectExpr>(e);
496 ValueRange cond = evalRangeForExpr(se->cond);
497 if (cond.isFixed()) {
498 if (cond.min()) {
500 } else {
502 }
503 } else {
504 // XXX imprecise... we have a choice here. One method is to
505 // simply force both sides into the specified range (since the
506 // condition is indetermined). This may lose in two ways, the
507 // first is that the condition chosen may limit further
508 // restrict the range in each of the children, however this is
509 // less of a problem as the range will be a superset of legal
510 // values. The other is if the condition ends up being forced
511 // by some other constraints, then we needlessly forced one
512 // side into the given range.
513 //
514 // The other method would be to force the condition to one
515 // side and force that side into the given range. This loses
516 // when we force the condition to an unsatisfiable value
517 // (either because the condition cannot be that, or the
518 // resulting range given that condition is not in the required
519 // range).
520 //
521 // Currently we just force both into the range. A hybrid would
522 // be to evaluate the ranges for each of the children... if
523 // one of the ranges happens to already be a subset of the
524 // required range then it may be preferable to force the
525 // condition to that side.
528 }
529 break;
530 }
531
532 // XXX imprecise... the problem here is that extracting bits
533 // loses information about what bits are connected across the
534 // bytes. if a value can be 1 or 256 then either the top or
535 // lower byte is 0, but just extraction loses this information
536 // and will allow neither,one,or both to be 1.
537 //
538 // we can protect against this in a limited fashion by writing
539 // the extraction a byte at a time, then checking the evaluated
540 // value, isolating for that range, and continuing.
541 case Expr::Concat: {
542 ConcatExpr *ce = cast<ConcatExpr>(e);
543 Expr::Width LSBWidth = ce->getKid(1)->getWidth();
544 Expr::Width MSBWidth = ce->getKid(1)->getWidth();
546 range.extract(LSBWidth, LSBWidth + MSBWidth));
547 propogatePossibleValues(ce->getKid(1), range.extract(0, LSBWidth));
548 break;
549 }
550
551 case Expr::Extract: {
552 // XXX
553 break;
554 }
555
556 // Casting
557
558 // Simply intersect the output range with the range of all possible
559 // outputs and then truncate to the desired number of bits.
560
561 // For ZExt this simplifies to just intersection with the possible input
562 // range.
563 case Expr::ZExt: {
564 CastExpr *ce = cast<CastExpr>(e);
565 unsigned inBits = ce->src->getWidth();
569 break;
570 }
571 // For SExt instead of doing the intersection we just take the output
572 // range minus the impossible values. This is nicer since it is a single
573 // interval.
574 case Expr::SExt: {
575 CastExpr *ce = cast<CastExpr>(e);
576 unsigned inBits = ce->src->getWidth();
577 unsigned outBits = ce->width;
578 ValueRange output =
579 range.set_difference(ValueRange(1<<(inBits-1),
580 (bits64::maxValueOfNBits(outBits) -
581 bits64::maxValueOfNBits(inBits-1)-1)));
584 break;
585 }
586
587 // Binary
588
589 case Expr::Add: {
590 BinaryExpr *be = cast<BinaryExpr>(e);
591 if (ConstantExpr *CE = dyn_cast<ConstantExpr>(be->left)) {
592 // FIXME: Don't depend on width.
593 if (CE->getWidth() <= 64) {
594 // FIXME: Why do we ever propogate empty ranges? It doesn't make
595 // sense.
596 if (range.isEmpty())
597 break;
598
599 // C_0 + X \in [MIN, MAX) ==> X \in [MIN - C_0, MAX - C_0)
600 Expr::Width W = CE->getWidth();
601 CexValueData nrange(ConstantExpr::alloc(range.min(), W)->Sub(CE)->getZExtValue(),
602 ConstantExpr::alloc(range.max(), W)->Sub(CE)->getZExtValue());
603 if (!nrange.isEmpty())
604 propogatePossibleValues(be->right, nrange);
605 }
606 }
607 break;
608 }
609
610 case Expr::And: {
611 BinaryExpr *be = cast<BinaryExpr>(e);
612 if (be->getWidth()==Expr::Bool) {
613 if (range.isFixed()) {
614 ValueRange left = evalRangeForExpr(be->left);
615 ValueRange right = evalRangeForExpr(be->right);
616
617 if (!range.min()) {
618 if (left.mustEqual(0) || right.mustEqual(0)) {
619 // all is well
620 } else {
621 // XXX heuristic, which order
622
624 left = evalRangeForExpr(be->left);
625
626 // see if that worked
627 if (!left.mustEqual(1))
629 }
630 } else {
631 if (!left.mustEqual(1)) propogatePossibleValue(be->left, 1);
632 if (!right.mustEqual(1)) propogatePossibleValue(be->right, 1);
633 }
634 }
635 } else {
636 // XXX
637 }
638 break;
639 }
640
641 case Expr::Or: {
642 BinaryExpr *be = cast<BinaryExpr>(e);
643 if (be->getWidth()==Expr::Bool) {
644 if (range.isFixed()) {
645 ValueRange left = evalRangeForExpr(be->left);
646 ValueRange right = evalRangeForExpr(be->right);
647
648 if (range.min()) {
649 if (left.mustEqual(1) || right.mustEqual(1)) {
650 // all is well
651 } else {
652 // XXX heuristic, which order?
653
654 // force left to value we need
656 left = evalRangeForExpr(be->left);
657
658 // see if that worked
659 if (!left.mustEqual(1))
661 }
662 } else {
663 if (!left.mustEqual(0)) propogatePossibleValue(be->left, 0);
664 if (!right.mustEqual(0)) propogatePossibleValue(be->right, 0);
665 }
666 }
667 } else {
668 // XXX
669 }
670 break;
671 }
672
673 case Expr::Xor: break;
674
675 // Comparison
676
677 case Expr::Eq: {
678 BinaryExpr *be = cast<BinaryExpr>(e);
679 if (range.isFixed()) {
680 if (ConstantExpr *CE = dyn_cast<ConstantExpr>(be->left)) {
681 // FIXME: Handle large widths?
682 if (CE->getWidth() <= 64) {
683 uint64_t value = CE->getZExtValue();
684 if (range.min()) {
685 propogatePossibleValue(be->right, value);
686 } else {
687 CexValueData range;
688 if (value==0) {
689 range = CexValueData(1,
690 bits64::maxValueOfNBits(CE->getWidth()));
691 } else {
692 // FIXME: heuristic / lossy, could be better to pick larger
693 // range?
694 range = CexValueData(0, value - 1);
695 }
696 propogatePossibleValues(be->right, range);
697 }
698 } else {
699 // XXX what now
700 }
701 }
702 }
703 break;
704 }
705
706 case Expr::Not: {
707 if (e->getWidth() == Expr::Bool && range.isFixed()) {
708 propogatePossibleValue(e->getKid(0), !range.min());
709 }
710 break;
711 }
712
713 case Expr::Ult: {
714 BinaryExpr *be = cast<BinaryExpr>(e);
715
716 // XXX heuristic / lossy, what order if conflict
717
718 if (range.isFixed()) {
719 ValueRange left = evalRangeForExpr(be->left);
720 ValueRange right = evalRangeForExpr(be->right);
721
722 uint64_t maxValue = bits64::maxValueOfNBits(be->right->getWidth());
723
724 // XXX should deal with overflow (can lead to empty range)
725
726 if (left.isFixed()) {
727 if (range.min()) {
729 maxValue));
730 } else {
732 }
733 } else if (right.isFixed()) {
734 if (range.min()) {
735 propogatePossibleValues(be->left, CexValueData(0, right.min()-1));
736 } else {
738 maxValue));
739 }
740 } else {
741 // XXX ???
742 }
743 }
744 break;
745 }
746 case Expr::Ule: {
747 BinaryExpr *be = cast<BinaryExpr>(e);
748
749 // XXX heuristic / lossy, what order if conflict
750
751 if (range.isFixed()) {
752 ValueRange left = evalRangeForExpr(be->left);
753 ValueRange right = evalRangeForExpr(be->right);
754
755 // XXX should deal with overflow (can lead to empty range)
756
757 uint64_t maxValue = bits64::maxValueOfNBits(be->right->getWidth());
758 if (left.isFixed()) {
759 if (range.min()) {
761 maxValue));
762 } else {
764 }
765 } else if (right.isFixed()) {
766 if (range.min()) {
768 } else {
770 maxValue));
771 }
772 } else {
773 // XXX ???
774 }
775 }
776 break;
777 }
778
779 case Expr::Ne:
780 case Expr::Ugt:
781 case Expr::Uge:
782 case Expr::Sgt:
783 case Expr::Sge:
784 assert(0 && "invalid expressions (uncanonicalized");
785
786 default:
787 break;
788 }
789 }
790
792 switch (e->getKind()) {
793 case Expr::Constant: {
794 // FIXME: Assert that range contains this constant.
795 break;
796 }
797
798 // Special
799
800 case Expr::NotOptimized: break;
801
802 case Expr::Read: {
803 ReadExpr *re = cast<ReadExpr>(e);
804 const Array *array = re->updates.root;
805 CexObjectData &cod = getObjectData(array);
807
808 for (const auto *un = re->updates.head.get(); un; un = un->next.get()) {
809 CexValueData ui = evalRangeForExpr(un->index);
810
811 // If these indices can't alias, continue propogation
812 if (!ui.mayEqual(index))
813 continue;
814
815 // Otherwise if we know they alias, propogate into the write value.
816 if (ui.mustEqual(index) || re->index == un->index)
817 propogateExactValues(un->value, range);
818 return;
819 }
820
821 // We reached the initial array write, update the exact range if possible.
822 if (index.isFixed()) {
823 if (array->isConstantArray()) {
824 // Verify the range.
826 range);
827 } else {
828 CexValueData cvd = cod.getExactValues(index.min());
829 if (range.min() > cvd.min()) {
830 assert(range.min() <= cvd.max());
831 cvd = CexValueData(range.min(), cvd.max());
832 }
833 if (range.max() < cvd.max()) {
834 assert(range.max() >= cvd.min());
835 cvd = CexValueData(cvd.min(), range.max());
836 }
837 cod.setExactValues(index.min(), cvd);
838 }
839 }
840 break;
841 }
842
843 case Expr::Select: {
844 break;
845 }
846
847 case Expr::Concat: {
848 break;
849 }
850
851 case Expr::Extract: {
852 break;
853 }
854
855 // Casting
856
857 case Expr::ZExt: {
858 break;
859 }
860
861 case Expr::SExt: {
862 break;
863 }
864
865 // Binary
866
867 case Expr::And: {
868 break;
869 }
870
871 case Expr::Or: {
872 break;
873 }
874
875 case Expr::Xor: {
876 break;
877 }
878
879 // Comparison
880
881 case Expr::Eq: {
882 BinaryExpr *be = cast<BinaryExpr>(e);
883 if (range.isFixed()) {
884 if (ConstantExpr *CE = dyn_cast<ConstantExpr>(be->left)) {
885 // FIXME: Handle large widths?
886 if (CE->getWidth() <= 64) {
887 uint64_t value = CE->getZExtValue();
888 if (range.min()) {
889 // If the equality is true, then propogate the value.
890 propogateExactValue(be->right, value);
891 } else {
892 // If the equality is false and the comparison is of booleans,
893 // then we can infer the value to propogate.
894 if (be->right->getWidth() == Expr::Bool)
895 propogateExactValue(be->right, !value);
896 }
897 }
898 }
899 }
900 break;
901 }
902
903 // If a boolean not, and the result is known, propagate it
904 case Expr::Not: {
905 if (e->getWidth() == Expr::Bool && range.isFixed()) {
906 propogateExactValue(e->getKid(0), !range.min());
907 }
908 break;
909 }
910
911 case Expr::Ult: {
912 break;
913 }
914
915 case Expr::Ule: {
916 break;
917 }
918
919 case Expr::Ne:
920 case Expr::Ugt:
921 case Expr::Uge:
922 case Expr::Sgt:
923 case Expr::Sge:
924 assert(0 && "invalid expressions (uncanonicalized");
925
926 default:
927 break;
928 }
929 }
930
933 return ce.evaluate(e);
934 }
935
940 }
941
944 }
945
946 void dump() {
947 llvm::errs() << "-- propogated values --\n";
948 for (std::map<const Array *, CexObjectData *>::iterator
949 it = objects.begin(),
950 ie = objects.end();
951 it != ie; ++it) {
952 const Array *A = it->first;
953 CexObjectData *COD = it->second;
954
955 llvm::errs() << A->name << "\n";
956 llvm::errs() << "possible: [";
957 for (unsigned i = 0; i < A->size; ++i) {
958 if (i)
959 llvm::errs() << ", ";
960 llvm::errs() << COD->getPossibleValues(i);
961 }
962 llvm::errs() << "]\n";
963 llvm::errs() << "exact : [";
964 for (unsigned i = 0; i < A->size; ++i) {
965 if (i)
966 llvm::errs() << ", ";
967 llvm::errs() << COD->getExactValues(i);
968 }
969 llvm::errs() << "]\n";
970 }
971 }
972};
973
974/* *** */
975
976
978public:
981
983 bool computeValue(const Query&, ref<Expr> &result);
984 bool computeInitialValues(const Query&,
985 const std::vector<const Array*> &objects,
986 std::vector< std::vector<unsigned char> > &values,
987 bool &hasSolution);
988};
989
991
993
1008static bool propogateValues(const Query& query, CexData &cd,
1009 bool checkExpr, bool &isValid) {
1010 for (const auto &constraint : query.constraints) {
1011 cd.propogatePossibleValue(constraint, 1);
1012 cd.propogateExactValue(constraint, 1);
1013 }
1014 if (checkExpr) {
1015 cd.propogatePossibleValue(query.expr, 0);
1016 cd.propogateExactValue(query.expr, 0);
1017 }
1018
1019 KLEE_DEBUG(cd.dump());
1020
1021 // Check the result.
1022 bool hasSatisfyingAssignment = true;
1023 if (checkExpr) {
1024 if (!cd.evaluatePossible(query.expr)->isFalse())
1025 hasSatisfyingAssignment = false;
1026
1027 // If the query is known to be true, then we have proved validity.
1028 if (cd.evaluateExact(query.expr)->isTrue()) {
1029 isValid = true;
1030 return true;
1031 }
1032 }
1033
1034 for (const auto &constraint : query.constraints) {
1035 if (hasSatisfyingAssignment && !cd.evaluatePossible(constraint)->isTrue())
1036 hasSatisfyingAssignment = false;
1037
1038 // If this constraint is known to be false, then we can prove anything, so
1039 // the query is valid.
1040 if (cd.evaluateExact(constraint)->isFalse()) {
1041 isValid = true;
1042 return true;
1043 }
1044 }
1045
1046 if (hasSatisfyingAssignment) {
1047 isValid = false;
1048 return true;
1049 }
1050
1051 return false;
1052}
1053
1056 CexData cd;
1057
1058 bool isValid;
1059 bool success = propogateValues(query, cd, true, isValid);
1060
1061 if (!success)
1062 return IncompleteSolver::None;
1063
1064 return isValid ? IncompleteSolver::MustBeTrue : IncompleteSolver::MayBeFalse;
1065}
1066
1067bool FastCexSolver::computeValue(const Query& query, ref<Expr> &result) {
1068 CexData cd;
1069
1070 bool isValid;
1071 bool success = propogateValues(query, cd, false, isValid);
1072
1073 // Check if propogation wasn't able to determine anything.
1074 if (!success)
1075 return false;
1076
1077 // FIXME: We don't have a way to communicate valid constraints back.
1078 if (isValid)
1079 return false;
1080
1081 // Propogation found a satisfying assignment, evaluate the expression.
1082 ref<Expr> value = cd.evaluatePossible(query.expr);
1083
1084 if (isa<ConstantExpr>(value)) {
1085 // FIXME: We should be able to make sure this never fails?
1086 result = value;
1087 return true;
1088 } else {
1089 return false;
1090 }
1091}
1092
1093bool
1095 const std::vector<const Array*>
1096 &objects,
1097 std::vector< std::vector<unsigned char> >
1098 &values,
1099 bool &hasSolution) {
1100 CexData cd;
1101
1102 bool isValid;
1103 bool success = propogateValues(query, cd, true, isValid);
1104
1105 // Check if propogation wasn't able to determine anything.
1106 if (!success)
1107 return false;
1108
1109 hasSolution = !isValid;
1110 if (!hasSolution)
1111 return true;
1112
1113 // Propogation found a satisfying assignment, compute the initial values.
1114 for (unsigned i = 0; i != objects.size(); ++i) {
1115 const Array *array = objects[i];
1116 assert(array);
1117 std::vector<unsigned char> data;
1118 data.reserve(array->size);
1119
1120 for (unsigned i=0; i < array->size; i++) {
1121 ref<Expr> read =
1122 ReadExpr::create(UpdateList(array, 0),
1123 ConstantExpr::create(i, array->getDomain()));
1124 ref<Expr> value = cd.evaluatePossible(read);
1125
1126 if (ConstantExpr *CE = dyn_cast<ConstantExpr>(value)) {
1127 data.push_back((unsigned char) CE->getZExtValue(8));
1128 } else {
1129 // FIXME: When does this happen?
1130 return false;
1131 }
1132 }
1133
1134 values.push_back(data);
1135 }
1136
1137 return true;
1138}
1139
1140
1142 return new Solver(new StagedSolverImpl(new FastCexSolver(), s));
1143}
std::vector< ref< Expr > >::iterator A
Definition: ExprUtil.cpp:137
static uint64_t maxAND(uint64_t a, uint64_t b, uint64_t c, uint64_t d)
static uint64_t minOR(uint64_t a, uint64_t b, uint64_t c, uint64_t d)
static bool propogateValues(const Query &query, CexData &cd, bool checkExpr, bool &isValid)
static uint64_t minAND(uint64_t a, uint64_t b, uint64_t c, uint64_t d)
ValueRange CexValueData
static uint64_t maxOR(uint64_t a, uint64_t b, uint64_t c, uint64_t d)
llvm::raw_ostream & operator<<(llvm::raw_ostream &os, const ValueRange &vr)
ValueRange evalRangeForExpr(const ref< Expr > &e)
void propogatePossibleValue(ref< Expr > e, uint64_t value)
ref< Expr > evaluateExact(ref< Expr > e)
ref< Expr > evaluatePossible(ref< Expr > e)
void dump()
void propogateExactValue(ref< Expr > e, uint64_t value)
CexData(const CexData &)
void propogateExactValues(ref< Expr > e, CexValueData range)
void propogatePossibleValues(ref< Expr > e, CexValueData range)
std::map< const Array *, CexObjectData * > objects
CexObjectData & getObjectData(const Array *A)
void operator=(const CexData &)
std::map< const Array *, CexObjectData * > & objects
ref< Expr > getInitialValue(const Array &array, unsigned index)
CexExactEvaluator(std::map< const Array *, CexObjectData * > &_objects)
std::vector< CexValueData > exactContents
void operator=(const CexObjectData &)
void setExactValues(size_t index, CexValueData values)
const CexValueData getExactValues(size_t index) const
CexObjectData(const CexObjectData &)
void setPossibleValue(size_t index, unsigned char value)
void setPossibleValues(size_t index, CexValueData values)
std::vector< CexValueData > possibleContents
CexObjectData(uint64_t size)
unsigned char getPossibleValue(size_t index) const
getPossibleValue - Return some possible value.
const CexValueData getPossibleValues(size_t index) const
CexPossibleEvaluator(std::map< const Array *, CexObjectData * > &_objects)
std::map< const Array *, CexObjectData * > & objects
ref< Expr > getInitialValue(const Array &array, unsigned index)
CexRangeEvaluator(std::map< const Array *, CexObjectData * > &_objects)
ValueRange getInitialReadRange(const Array &array, ValueRange index)
std::map< const Array *, CexObjectData * > & objects
bool computeValue(const Query &, ref< Expr > &result)
computeValue - Attempt to compute a value for the given expression.
bool computeInitialValues(const Query &, const std::vector< const Array * > &objects, std::vector< std::vector< unsigned char > > &values, bool &hasSolution)
IncompleteSolver::PartialValidity computeTruth(const Query &)
bool isFixed() const noexcept
std::int64_t maxSigned(unsigned bits) const
ValueRange binaryOr(ValueRange b) const
ValueRange srem(const ValueRange &b, unsigned width) const
std::uint64_t min() const noexcept
std::uint64_t max() const noexcept
ValueRange & operator=(const ValueRange &other) noexcept=default
ValueRange binaryAnd(std::uint64_t b) const
ValueRange() noexcept=default
ValueRange(ValueRange &&other) noexcept=default
bool mayEqual(const ValueRange &b) const
ValueRange & operator=(ValueRange &&other) noexcept=default
ValueRange sdiv(const ValueRange &b, unsigned width) const
ValueRange urem(const ValueRange &b, unsigned width) const
ValueRange(std::uint64_t value) noexcept
ValueRange(const ValueRange &other) noexcept=default
ValueRange udiv(const ValueRange &b, unsigned width) const
bool intersects(const ValueRange &b) const
bool operator!=(const ValueRange &b) const noexcept
bool isEmpty() const noexcept
bool operator==(const ValueRange &b) const noexcept
ValueRange set_union(const ValueRange &b) const
ValueRange binaryXor(ValueRange b) const
ValueRange(std::uint64_t _min, std::uint64_t _max) noexcept
ValueRange binaryShiftRight(unsigned bits) const
std::int64_t minSigned(unsigned bits) const
ValueRange mul(const ValueRange &b, unsigned width) const
ValueRange sub(const ValueRange &b, unsigned width) const
ValueRange extract(std::uint64_t lowBit, std::uint64_t maxBit) const
ValueRange add(const ValueRange &b, unsigned width) const
ValueRange set_difference(const ValueRange &b) const
bool isFullRange(unsigned bits) const noexcept
bool mustEqual(const std::uint64_t b) const noexcept
ValueRange concat(const ValueRange &b, unsigned bits) const
ValueRange binaryShiftLeft(unsigned bits) const
void print(llvm::raw_ostream &os) const
ValueRange set_intersection(const ValueRange &b) const
ValueRange binaryAnd(const ValueRange &b) const
ValueRange binaryOr(std::uint64_t b) const
std::uint64_t m_min
bool mayEqual(const std::uint64_t b) const noexcept
bool mustEqual(const ValueRange &b) const noexcept
bool contains(std::uint64_t value) const
std::uint64_t m_max
Expr::Width getRange() const
Definition: Expr.h:530
bool isConstantArray() const
Definition: Expr.h:525
const unsigned size
Definition: Expr.h:489
const std::vector< ref< ConstantExpr > > constantValues
Definition: Expr.h:498
Expr::Width getDomain() const
Definition: Expr.h:529
ref< Expr > left
Definition: Expr.h:370
ref< Expr > right
Definition: Expr.h:370
Width width
Definition: Expr.h:844
ref< Expr > src
Definition: Expr.h:843
ref< Expr > getKid(unsigned i) const
Definition: Expr.h:697
T evaluate(const ref< Expr > &e)
ref< Expr > visit(const ref< Expr > &e)
Definition: ExprVisitor.cpp:26
virtual Kind getKind() const =0
virtual Width getWidth() const =0
unsigned Width
The type of an expression is simply its width, in bits.
Definition: Expr.h:97
bool isFalse() const
isFalse - Is this the false expression.
Definition: Expr.h:1163
bool isTrue() const
isTrue - Is this the true expression.
Definition: Expr.h:1156
virtual ref< Expr > getKid(unsigned i) const =0
Class representing a one byte read from an array.
Definition: Expr.h:565
ref< Expr > index
Definition: Expr.h:572
UpdateList updates
Definition: Expr.h:571
Class representing an if-then-else expression.
Definition: Expr.h:610
ref< Expr > cond
Definition: Expr.h:616
ref< Expr > trueExpr
Definition: Expr.h:616
ref< Expr > falseExpr
Definition: Expr.h:616
Class representing a complete list of updates into an array.
Definition: Expr.h:539
ref< UpdateNode > head
pointer to the most recent update node
Definition: Expr.h:546
const Array * root
Definition: Expr.h:543
Definition: Ref.h:82
static KTest * input
Definition: klee-replay.c:46
unsigned withoutRightmostBit(unsigned x)
Definition: Bits.h:34
unsigned maxValueOfNBits(unsigned N)
Definition: Bits.h:21
unsigned isPowerOfTwo(unsigned x)
Definition: Bits.h:42
uint64_t sext(uint64_t l, unsigned outWidth, unsigned inWidth)
Definition: IntEvaluation.h:50
Definition: main.cpp:291
Solver * createFastCexSolver(Solver *s)
ref< Expr > expr
Definition: Solver.h:35
const ConstraintSet & constraints
Definition: Solver.h:34