klee
ExprPPrinter.cpp
Go to the documentation of this file.
1//===-- ExprPPrinter.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
11
15
16#include "llvm/Support/CommandLine.h"
17#include "llvm/Support/raw_ostream.h"
18
19#include <map>
20#include <vector>
21
22using namespace klee;
23
24namespace {
25
26llvm::cl::opt<bool> PCWidthAsArg(
27 "pc-width-as-arg", llvm::cl::init(true),
28 llvm::cl::desc(
29 "Print the width as a separate argument, as opposed to a prefix "
30 "to the operation (default=true)"),
31 llvm::cl::cat(klee::ExprCat));
32
33llvm::cl::opt<bool>
34 PCAllWidths("pc-all-widths", llvm::cl::init(false),
35 llvm::cl::desc("Print the width of all operations, including "
36 "booleans (default=false)"),
37 llvm::cl::cat(klee::ExprCat));
38
39llvm::cl::opt<bool>
40 PCPrefixWidth("pc-prefix-width", llvm::cl::init(true),
41 llvm::cl::desc("Print width with 'w' prefix (default=true)"),
42 llvm::cl::cat(klee::ExprCat));
43
44llvm::cl::opt<bool>
45 PCMultibyteReads("pc-multibyte-reads", llvm::cl::init(true),
46 llvm::cl::desc("Print ReadLSB and ReadMSB expressions "
47 "when possible (default=true)"),
48 llvm::cl::cat(klee::ExprCat));
49
50llvm::cl::opt<bool> PCAllConstWidths(
51 "pc-all-const-widths", llvm::cl::init(false),
52 llvm::cl::desc(
53 "Always print the width of constant expressions (default=false)"),
54 llvm::cl::cat(klee::ExprCat));
55
56} // namespace
57
58class PPrinter : public ExprPPrinter {
59public:
60 std::set<const Array*> usedArrays;
61private:
62 std::map<ref<Expr>, unsigned> bindings;
63 std::map<const UpdateNode*, unsigned> updateBindings;
64 std::set< ref<Expr> > couldPrint, shouldPrint;
65 std::set<const UpdateNode*> couldPrintUpdates, shouldPrintUpdates;
66 llvm::raw_ostream &os;
67 unsigned counter;
68 unsigned updateCounter;
69 bool hasScan;
71 std::string newline;
72
76 if (PCAllWidths)
77 return true;
78 return e->getWidth() != Expr::Bool;
79 }
80
81 bool isVerySimple(const ref<Expr> &e) {
82 return isa<ConstantExpr>(e) || bindings.find(e)!=bindings.end();
83 }
84
86 return !un || updateBindings.find(un)!=updateBindings.end();
87 }
88
89
90 // document me!
91 bool isSimple(const ref<Expr> &e) {
92 if (isVerySimple(e)) {
93 return true;
94 } else if (const ReadExpr *re = dyn_cast<ReadExpr>(e)) {
95 return isVerySimple(re->index) &&
96 isVerySimpleUpdate(re->updates.head.get());
97 } else {
98 Expr *ep = e.get();
99 for (unsigned i=0; i<ep->getNumKids(); i++)
100 if (!isVerySimple(ep->getKid(i)))
101 return false;
102 return true;
103 }
104 }
105
106 bool hasSimpleKids(const Expr *ep) {
107 for (unsigned i=0; i<ep->getNumKids(); i++)
108 if (!isSimple(ep->getKid(i)))
109 return false;
110 return true;
111 }
112
113 void scanUpdate(const UpdateNode *un) {
114 // FIXME: This needs to be non-recursive.
115 if (un) {
116 if (couldPrintUpdates.insert(un).second) {
117 scanUpdate(un->next.get());
118 scan1(un->index);
119 scan1(un->value);
120 } else {
121 shouldPrintUpdates.insert(un);
122 }
123 }
124 }
125
126 void scan1(const ref<Expr> &e) {
127 if (!isa<ConstantExpr>(e)) {
128 if (couldPrint.insert(e).second) {
129 Expr *ep = e.get();
130 for (unsigned i=0; i<ep->getNumKids(); i++)
131 scan1(ep->getKid(i));
132 if (const ReadExpr *re = dyn_cast<ReadExpr>(e)) {
133 usedArrays.insert(re->updates.root);
134 scanUpdate(re->updates.head.get());
135 }
136 } else {
137 shouldPrint.insert(e);
138 }
139 }
140 }
141
142 void printUpdateList(const UpdateList &updates, PrintContext &PC) {
143 auto head = updates.head;
144
145 // Special case empty list.
146 if (!head) {
147 // FIXME: We need to do something (assert, mangle, etc.) so that printing
148 // distinct arrays with the same name doesn't fail.
149 PC << updates.root->name;
150 return;
151 }
152
153 // FIXME: Explain this breaking policy.
154 bool openedList = false, nextShouldBreak = false;
155 unsigned outerIndent = PC.pos;
156 unsigned middleIndent = 0;
157 for (auto un = head; un; un = un->next) {
158 // We are done if we hit the cache.
159 std::map<const UpdateNode *, unsigned>::iterator it =
160 updateBindings.find(un.get());
161 if (it!=updateBindings.end()) {
162 if (openedList)
163 PC << "] @ ";
164 PC << "U" << it->second;
165 return;
166 } else if (!hasScan || shouldPrintUpdates.count(un.get())) {
167 if (openedList)
168 PC << "] @";
169 if (un != head)
170 PC.breakLine(outerIndent);
171 PC << "U" << updateCounter << ":";
172 updateBindings.insert(std::make_pair(un.get(), updateCounter++));
173 openedList = nextShouldBreak = false;
174 }
175
176 if (!openedList) {
177 openedList = 1;
178 PC << '[';
179 middleIndent = PC.pos;
180 } else {
181 PC << ',';
182 printSeparator(PC, !nextShouldBreak, middleIndent);
183 }
184 //PC << "(=";
185 //unsigned innerIndent = PC.pos;
186 print(un->index, PC);
187 //printSeparator(PC, isSimple(un->index), innerIndent);
188 PC << "=";
189 print(un->value, PC);
190 //PC << ')';
191
192 nextShouldBreak = !(isa<ConstantExpr>(un->index) &&
193 isa<ConstantExpr>(un->value));
194 }
195
196 if (openedList)
197 PC << ']';
198
199 PC << " @ " << updates.root->name;
200 }
201
203 if (!shouldPrintWidth(e))
204 return;
205
206 if (PCWidthAsArg) {
207 PC << ' ';
208 if (PCPrefixWidth)
209 PC << 'w';
210 }
211
212 PC << e->getWidth();
213 }
214
215
216 bool isReadExprAtOffset(ref<Expr> e, const ReadExpr *base, ref<Expr> offset) {
217 const ReadExpr *re = dyn_cast<ReadExpr>(e.get());
218
219 // right now, all Reads are byte reads but some
220 // transformations might change this
221 if (!re || (re->getWidth() != Expr::Int8))
222 return false;
223
224 // Check if the index follows the stride.
225 // FIXME: How aggressive should this be simplified. The
226 // canonicalizing builder is probably the right choice, but this
227 // is yet another area where we would really prefer it to be
228 // global or else use static methods.
229 return SubExpr::create(re->index, base->index) == offset;
230 }
231
232
241 const ReadExpr* hasOrderedReads(ref<Expr> e, int stride) {
242 assert(e->getKind() == Expr::Concat);
243 assert(stride == 1 || stride == -1);
244
245 const ReadExpr *base = dyn_cast<ReadExpr>(e->getKid(0));
246
247 // right now, all Reads are byte reads but some
248 // transformations might change this
249 if (!base || base->getWidth() != Expr::Int8)
250 return NULL;
251
252 // Get stride expr in proper index width.
253 Expr::Width idxWidth = base->index->getWidth();
254 ref<Expr> strideExpr = ConstantExpr::alloc(stride, idxWidth);
255 ref<Expr> offset = ConstantExpr::create(0, idxWidth);
256
257 e = e->getKid(1);
258
259 // concat chains are unbalanced to the right
260 while (e->getKind() == Expr::Concat) {
261 offset = AddExpr::create(offset, strideExpr);
262 if (!isReadExprAtOffset(e->getKid(0), base, offset))
263 return NULL;
264
265 e = e->getKid(1);
266 }
267
268 offset = AddExpr::create(offset, strideExpr);
269 if (!isReadExprAtOffset(e, base, offset))
270 return NULL;
271
272 if (stride == -1)
273 return cast<ReadExpr>(e.get());
274 else return base;
275 }
276
277#if 0
280 bool hasAllByteReads(const Expr *ep) {
281 switch (ep->kind) {
282 Expr::Read: {
283 // right now, all Reads are byte reads but some
284 // transformations might change this
285 return ep->getWidth() == Expr::Int8;
286 }
287 Expr::Concat: {
288 for (unsigned i=0; i<ep->getNumKids(); ++i) {
289 if (!hashAllByteReads(ep->getKid(i)))
290 return false;
291 }
292 }
293 default: return false;
294 }
295 }
296#endif
297
298 void printRead(const ReadExpr *re, PrintContext &PC, unsigned indent) {
299 print(re->index, PC);
300 printSeparator(PC, isVerySimple(re->index), indent);
301 printUpdateList(re->updates, PC);
302 }
303
304 void printExtract(const ExtractExpr *ee, PrintContext &PC, unsigned indent) {
305 PC << ee->offset << ' ';
306 print(ee->expr, PC);
307 }
308
309 void printExpr(const Expr *ep, PrintContext &PC, unsigned indent, bool printConstWidth=false) {
310 bool simple = hasSimpleKids(ep);
311
312 print(ep->getKid(0), PC);
313 for (unsigned i=1; i<ep->getNumKids(); i++) {
314 printSeparator(PC, simple, indent);
315 print(ep->getKid(i), PC, printConstWidth);
316 }
317 }
318
319public:
320 PPrinter(llvm::raw_ostream &_os) : os(_os), newline("\n") {
321 reset();
322 }
323
324 void setNewline(const std::string &_newline) {
325 newline = _newline;
326 }
327
328 void setForceNoLineBreaks(bool _forceNoLineBreaks) {
329 forceNoLineBreaks = _forceNoLineBreaks;
330 }
331
332 void reset() {
333 counter = 0;
334 updateCounter = 0;
335 hasScan = false;
336 forceNoLineBreaks = false;
337 bindings.clear();
338 updateBindings.clear();
339 couldPrint.clear();
340 shouldPrint.clear();
341 couldPrintUpdates.clear();
342 shouldPrintUpdates.clear();
343 }
344
345 void scan(const ref<Expr> &e) {
346 hasScan = true;
347 scan1(e);
348 }
349
350 void print(const ref<Expr> &e, unsigned level=0) {
351 PrintContext PC(os);
352 PC.pos = level;
353 print(e, PC);
354 }
355
357 bool printWidth) {
358 if (e->getWidth() == Expr::Bool)
359 PC << (e->isTrue() ? "true" : "false");
360 else {
361 if (PCAllConstWidths)
362 printWidth = true;
363
364 if (printWidth)
365 PC << "(w" << e->getWidth() << " ";
366
367 if (e->getWidth() <= 64) {
368 PC << e->getZExtValue();
369 } else {
370 std::string S;
371 e->toString(S);
372 PC << S;
373 }
374
375 if (printWidth)
376 PC << ")";
377 }
378 }
379
380 void print(const ref<Expr> &e, PrintContext &PC, bool printConstWidth=false) {
381 if (ConstantExpr *CE = dyn_cast<ConstantExpr>(e))
382 printConst(CE, PC, printConstWidth);
383 else {
384 std::map<ref<Expr>, unsigned>::iterator it = bindings.find(e);
385 if (it!=bindings.end()) {
386 PC << 'N' << it->second;
387 } else {
388 if (!hasScan || shouldPrint.count(e)) {
389 PC << 'N' << counter << ':';
390 bindings.insert(std::make_pair(e, counter++));
391 }
392
393 // Detect multibyte reads.
394 // FIXME: Hrm. One problem with doing this is that we are
395 // masking the sharing of the indices which aren't
396 // visible. Need to think if this matters... probably not
397 // because if they are offset reads then its either constant,
398 // or they are (base + offset) and base will get printed with
399 // a declaration.
400 if (PCMultibyteReads && e->getKind() == Expr::Concat) {
401 const ReadExpr *base = hasOrderedReads(e, -1);
402 const bool isLSB = (base != nullptr);
403 if (!isLSB)
404 base = hasOrderedReads(e, 1);
405 if (base) {
406 PC << "(Read" << (isLSB ? "LSB" : "MSB");
407 printWidth(PC, e);
408 PC << ' ';
409 printRead(base, PC, PC.pos);
410 PC << ')';
411 return;
412 }
413 }
414
415 PC << '(' << e->getKind();
416 printWidth(PC, e);
417 PC << ' ';
418
419 // Indent at first argument and dispatch to appropriate print
420 // routine for exprs which require special handling.
421 unsigned indent = PC.pos;
422 if (const ReadExpr *re = dyn_cast<ReadExpr>(e)) {
423 printRead(re, PC, indent);
424 } else if (const ExtractExpr *ee = dyn_cast<ExtractExpr>(e)) {
425 printExtract(ee, PC, indent);
426 } else if (e->getKind() == Expr::Concat || e->getKind() == Expr::SExt)
427 printExpr(e.get(), PC, indent, true);
428 else
429 printExpr(e.get(), PC, indent);
430 PC << ")";
431 }
432 }
433 }
434
435 /* Public utility functions */
436
437 void printSeparator(PrintContext &PC, bool simple, unsigned indent) {
438 if (simple || forceNoLineBreaks) {
439 PC << ' ';
440 } else {
441 PC.breakLine(indent);
442 }
443 }
444};
445
447 return new PPrinter(os);
448}
449
450void ExprPPrinter::printOne(llvm::raw_ostream &os,
451 const char *message,
452 const ref<Expr> &e) {
453 PPrinter p(os);
454 p.scan(e);
455
456 // FIXME: Need to figure out what to do here. Probably print as a
457 // "forward declaration" with whatever syntax we pick for that.
458 PrintContext PC(os);
459 PC << message << ": ";
460 p.print(e, PC);
461 PC.breakLine();
462}
463
464void ExprPPrinter::printSingleExpr(llvm::raw_ostream &os, const ref<Expr> &e) {
465 PPrinter p(os);
466 p.scan(e);
467
468 // FIXME: Need to figure out what to do here. Probably print as a
469 // "forward declaration" with whatever syntax we pick for that.
470 PrintContext PC(os);
471 p.print(e, PC);
472}
473
474void ExprPPrinter::printConstraints(llvm::raw_ostream &os,
475 const ConstraintSet &constraints) {
476 printQuery(os, constraints, ConstantExpr::alloc(false, Expr::Bool));
477}
478
479namespace {
480
481struct ArrayPtrsByName {
482 bool operator()(const Array *a1, const Array *a2) const {
483 return a1->name < a2->name;
484 }
485};
486}
487
488void ExprPPrinter::printQuery(llvm::raw_ostream &os,
489 const ConstraintSet &constraints,
490 const ref<Expr> &q,
491 const ref<Expr> *evalExprsBegin,
492 const ref<Expr> *evalExprsEnd,
493 const Array * const *evalArraysBegin,
494 const Array * const *evalArraysEnd,
495 bool printArrayDecls) {
496 PPrinter p(os);
497
498 for (const auto &constraint : constraints)
499 p.scan(constraint);
500 p.scan(q);
501
502 for (const ref<Expr> *it = evalExprsBegin; it != evalExprsEnd; ++it)
503 p.scan(*it);
504
505 PrintContext PC(os);
506
507 // Print array declarations.
508 if (printArrayDecls) {
509 for (const Array * const* it = evalArraysBegin; it != evalArraysEnd; ++it)
510 p.usedArrays.insert(*it);
511 std::vector<const Array *> sortedArray(p.usedArrays.begin(),
512 p.usedArrays.end());
513 std::sort(sortedArray.begin(), sortedArray.end(), ArrayPtrsByName());
514 for (std::vector<const Array *>::iterator it = sortedArray.begin(),
515 ie = sortedArray.end();
516 it != ie; ++it) {
517 const Array *A = *it;
518 PC << "array " << A->name << "[" << A->size << "]"
519 << " : w" << A->domain << " -> w" << A->range << " = ";
520 if (A->isSymbolicArray()) {
521 PC << "symbolic";
522 } else {
523 PC << "[";
524 for (unsigned i = 0, e = A->size; i != e; ++i) {
525 if (i)
526 PC << " ";
527 PC << A->constantValues[i];
528 }
529 PC << "]";
530 }
531 PC.breakLine();
532 }
533 }
534
535 PC << "(query [";
536
537 // Ident at constraint list;
538 unsigned indent = PC.pos;
539 for (auto it = constraints.begin(), ie = constraints.end(); it != ie;) {
540 p.print(*it, PC);
541 ++it;
542 if (it != ie)
543 PC.breakLine(indent);
544 }
545 PC << ']';
546
547 p.printSeparator(PC, constraints.empty(), indent-1);
548 p.print(q, PC);
549
550 // Print expressions to obtain values for, if any.
551 if (evalExprsBegin != evalExprsEnd) {
552 p.printSeparator(PC, q->isFalse(), indent-1);
553 PC << '[';
554 for (const ref<Expr> *it = evalExprsBegin; it != evalExprsEnd; ++it) {
555 p.print(*it, PC, /*printConstWidth*/true);
556 if (it + 1 != evalExprsEnd)
557 PC.breakLine(indent);
558 }
559 PC << ']';
560 }
561
562 // Print arrays to obtain values for, if any.
563 if (evalArraysBegin != evalArraysEnd) {
564 if (evalExprsBegin == evalExprsEnd)
565 PC << " []";
566
567 PC.breakLine(indent - 1);
568 PC << '[';
569 for (const Array * const* it = evalArraysBegin; it != evalArraysEnd; ++it) {
570 PC << (*it)->name;
571 if (it + 1 != evalArraysEnd)
572 PC.breakLine(indent);
573 }
574 PC << ']';
575 }
576
577 PC << ')';
578 PC.breakLine();
579}
std::vector< ref< Expr > >::iterator A
Definition: ExprUtil.cpp:137
void reset()
void printExpr(const Expr *ep, PrintContext &PC, unsigned indent, bool printConstWidth=false)
std::set< ref< Expr > > shouldPrint
void setNewline(const std::string &_newline)
std::set< const UpdateNode * > couldPrintUpdates
std::map< const UpdateNode *, unsigned > updateBindings
void printRead(const ReadExpr *re, PrintContext &PC, unsigned indent)
void printUpdateList(const UpdateList &updates, PrintContext &PC)
bool isSimple(const ref< Expr > &e)
unsigned counter
bool isVerySimpleUpdate(const UpdateNode *un)
bool hasScan
void printWidth(PrintContext &PC, ref< Expr > e)
const ReadExpr * hasOrderedReads(ref< Expr > e, int stride)
void setForceNoLineBreaks(bool _forceNoLineBreaks)
bool shouldPrintWidth(ref< Expr > e)
void print(const ref< Expr > &e, unsigned level=0)
std::map< ref< Expr >, unsigned > bindings
void scanUpdate(const UpdateNode *un)
llvm::raw_ostream & os
bool hasSimpleKids(const Expr *ep)
std::string newline
void print(const ref< Expr > &e, PrintContext &PC, bool printConstWidth=false)
unsigned updateCounter
void printExtract(const ExtractExpr *ee, PrintContext &PC, unsigned indent)
void scan1(const ref< Expr > &e)
void scan(const ref< Expr > &e)
std::set< const UpdateNode * > shouldPrintUpdates
bool isVerySimple(const ref< Expr > &e)
PPrinter(llvm::raw_ostream &_os)
void printSeparator(PrintContext &PC, bool simple, unsigned indent)
std::set< ref< Expr > > couldPrint
bool forceNoLineBreaks
std::set< const Array * > usedArrays
void printConst(const ref< ConstantExpr > &e, PrintContext &PC, bool printWidth)
bool isReadExprAtOffset(ref< Expr > e, const ReadExpr *base, ref< Expr > offset)
unsigned pos
Number of characters on the current line.
Definition: PrintContext.h:41
void breakLine(unsigned indent=0)
Definition: PrintContext.h:52
const std::string name
Definition: Expr.h:486
static ref< ConstantExpr > alloc(const llvm::APInt &v)
Definition: Expr.h:1065
constraint_iterator end() const
constraint_iterator begin() const
bool empty() const
static ExprPPrinter * create(llvm::raw_ostream &os)
static void printSingleExpr(llvm::raw_ostream &os, const ref< Expr > &e)
static void printQuery(llvm::raw_ostream &os, const ConstraintSet &constraints, const ref< Expr > &q, const ref< Expr > *evalExprsBegin=0, const ref< Expr > *evalExprsEnd=0, const Array *const *evalArraysBegin=0, const Array *const *evalArraysEnd=0, bool printArrayDecls=true)
static void printOne(llvm::raw_ostream &os, const char *message, const ref< Expr > &e)
static void printConstraints(llvm::raw_ostream &os, const ConstraintSet &constraints)
Class representing symbolic expressions.
Definition: Expr.h:91
virtual Kind getKind() const =0
virtual Width getWidth() const =0
virtual unsigned getNumKids() 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
static const Width Bool
Definition: Expr.h:100
virtual ref< Expr > getKid(unsigned i) const =0
unsigned offset
Definition: Expr.h:746
ref< Expr > expr
Definition: Expr.h:745
Class representing a one byte read from an array.
Definition: Expr.h:565
ref< Expr > index
Definition: Expr.h:572
Width getWidth() const
Definition: Expr.h:583
UpdateList updates
Definition: Expr.h:571
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
Class representing a byte update of an array.
Definition: Expr.h:451
ref< Expr > index
Definition: Expr.h:459
const ref< UpdateNode > next
Definition: Expr.h:458
ref< Expr > value
Definition: Expr.h:459
T * get() const
Definition: Ref.h:129
int const char * message
Definition: klee.h:75
Definition: main.cpp:291
llvm::cl::OptionCategory ExprCat