00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "klee/util/ExprPPrinter.h"
00011
00012 #include "klee/Constraints.h"
00013
00014 #include "llvm/Support/CommandLine.h"
00015
00016 #include <map>
00017 #include <vector>
00018 #include <iostream>
00019 #include <sstream>
00020 #include <iomanip>
00021
00022 using namespace klee;
00023
00024 namespace {
00025 llvm::cl::opt<bool>
00026 PCWidthAsArg("pc-width-as-arg", llvm::cl::init(true));
00027
00028 llvm::cl::opt<bool>
00029 PCAllWidths("pc-all-widths", llvm::cl::init(false));
00030
00031 llvm::cl::opt<bool>
00032 PCPrefixWidth("pc-prefix-width", llvm::cl::init(true));
00033
00034 llvm::cl::opt<bool>
00035 PCMultibyteReads("pc-multibyte-reads", llvm::cl::init(true));
00036
00037 llvm::cl::opt<bool>
00038 PCAllConstWidths("pc-all-const-widths", llvm::cl::init(false));
00039 }
00040
00043 class PrintContext {
00044 private:
00045 std::ostream &os;
00046 std::stringstream ss;
00047 std::string newline;
00048
00049 public:
00051 unsigned pos;
00052
00053 public:
00054 PrintContext(std::ostream &_os) : os(_os), newline("\n"), pos(0) {}
00055
00056 void setNewline(const std::string &_newline) {
00057 newline = _newline;
00058 }
00059
00060 void breakLine(unsigned indent=0) {
00061 os << newline;
00062 if (indent)
00063 os << std::setw(indent) << ' ';
00064 pos = indent;
00065 }
00066
00069 void write(const std::string &s) {
00070 os << s;
00071 pos += s.length();
00072 }
00073
00074 template <typename T>
00075 PrintContext &operator<<(T elt) {
00076 ss.str("");
00077 ss << elt;
00078 write(ss.str());
00079 return *this;
00080 }
00081 };
00082
00083 class PPrinter : public ExprPPrinter {
00084 std::map<ref<Expr>, unsigned> bindings;
00085 std::map<const UpdateNode*, unsigned> updateBindings;
00086 std::set< ref<Expr> > couldPrint, shouldPrint;
00087 std::set<const UpdateNode*> couldPrintUpdates, shouldPrintUpdates;
00088 std::ostream &os;
00089 unsigned counter;
00090 unsigned updateCounter;
00091 bool hasScan;
00092 std::string newline;
00093
00096 bool shouldPrintWidth(ref<Expr> e) {
00097 if (PCAllWidths)
00098 return true;
00099 return e->getWidth() != Expr::Bool;
00100 }
00101
00102 bool isVerySimple(const ref<Expr> &e) {
00103 return isa<ConstantExpr>(e) || bindings.find(e)!=bindings.end();
00104 }
00105
00106 bool isVerySimpleUpdate(const UpdateNode *un) {
00107 return !un || updateBindings.find(un)!=updateBindings.end();
00108 }
00109
00110
00111
00112 bool isSimple(const ref<Expr> &e) {
00113 if (isVerySimple(e)) {
00114 return true;
00115 } else if (const ReadExpr *re = dyn_cast<ReadExpr>(e)) {
00116 return isVerySimple(re->index) && isVerySimpleUpdate(re->updates.head);
00117 } else {
00118 Expr *ep = e.get();
00119 for (unsigned i=0; i<ep->getNumKids(); i++)
00120 if (!isVerySimple(ep->getKid(i)))
00121 return false;
00122 return true;
00123 }
00124 }
00125
00126 bool hasSimpleKids(const Expr *ep) {
00127 for (unsigned i=0; i<ep->getNumKids(); i++)
00128 if (!isSimple(ep->getKid(i)))
00129 return false;
00130 return true;
00131 }
00132
00133 void scanUpdate(const UpdateNode *un) {
00134 if (un) {
00135 if (couldPrintUpdates.insert(un).second) {
00136 scanUpdate(un->next);
00137 scan1(un->index);
00138 scan1(un->value);
00139 } else {
00140 shouldPrintUpdates.insert(un);
00141 }
00142 }
00143 }
00144
00145 void scan1(const ref<Expr> &e) {
00146 if (!isa<ConstantExpr>(e)) {
00147 if (couldPrint.insert(e).second) {
00148 Expr *ep = e.get();
00149 for (unsigned i=0; i<ep->getNumKids(); i++)
00150 scan1(ep->getKid(i));
00151 if (const ReadExpr *re = dyn_cast<ReadExpr>(e))
00152 scanUpdate(re->updates.head);
00153 } else {
00154 shouldPrint.insert(e);
00155 }
00156 }
00157 }
00158
00159 void printUpdateList(const UpdateList &updates, PrintContext &PC) {
00160 const UpdateNode *head = updates.head;
00161
00162
00163 if (!head) {
00164 if (updates.isRooted) {
00165 PC << "arr" << updates.root->id;
00166 } else {
00167 PC << "[]";
00168 }
00169 return;
00170 }
00171
00172
00173 bool openedList = false, nextShouldBreak = false;
00174 unsigned outerIndent = PC.pos;
00175 unsigned middleIndent = 0;
00176 for (const UpdateNode *un = head; un; un = un->next) {
00177
00178 std::map<const UpdateNode*, unsigned>::iterator it =
00179 updateBindings.find(un);
00180 if (it!=updateBindings.end()) {
00181 if (openedList)
00182 PC << "] @ ";
00183 PC << "U" << it->second;
00184 return;
00185 } else if (!hasScan || shouldPrintUpdates.count(un)) {
00186 if (openedList)
00187 PC << "] @";
00188 if (un != head)
00189 PC.breakLine(outerIndent);
00190 PC << "U" << updateCounter << ":";
00191 updateBindings.insert(std::make_pair(un, updateCounter++));
00192 openedList = nextShouldBreak = false;
00193 }
00194
00195 if (!openedList) {
00196 openedList = 1;
00197 PC << '[';
00198 middleIndent = PC.pos;
00199 } else {
00200 PC << ',';
00201 printSeparator(PC, !nextShouldBreak, middleIndent);
00202 }
00203
00204
00205 print(un->index, PC);
00206
00207 PC << "=";
00208 print(un->value, PC);
00209
00210
00211 nextShouldBreak = !(isa<ConstantExpr>(un->index) &&
00212 isa<ConstantExpr>(un->value));
00213 }
00214
00215 if (openedList)
00216 PC << ']';
00217
00218 if (updates.isRooted)
00219 PC << " @ arr" << updates.root->id;
00220 }
00221
00222 void printWidth(PrintContext &PC, ref<Expr> e) {
00223 if (!shouldPrintWidth(e))
00224 return;
00225
00226 if (PCWidthAsArg) {
00227 PC << ' ';
00228 if (PCPrefixWidth)
00229 PC << 'w';
00230 }
00231
00232 PC << e->getWidth();
00233 }
00234
00235
00236 bool isReadExprAtOffset(ref<Expr> e, const ReadExpr *base, ref<Expr> offset) {
00237 const ReadExpr *re = dyn_cast<ReadExpr>(e.get());
00238
00239
00240
00241 if (!re || (re->getWidth() != Expr::Int8))
00242 return false;
00243
00244
00245
00246
00247
00248
00249 return SubExpr::create(re->index, base->index) == offset;
00250 }
00251
00252
00261 const ReadExpr* hasOrderedReads(ref<Expr> e, int stride) {
00262 assert(e->getKind() == Expr::Concat);
00263 assert(stride == 1 || stride == -1);
00264
00265 const ReadExpr *base = dyn_cast<ReadExpr>(e->getKid(0));
00266
00267
00268
00269 if (!base || base->getWidth() != Expr::Int8)
00270 return false;
00271
00272
00273 Expr::Width idxWidth = base->index->getWidth();
00274 ref<Expr> strideExpr = ConstantExpr::alloc(stride, idxWidth);
00275 ref<Expr> offset = ConstantExpr::create(0, idxWidth);
00276
00277 e = e->getKid(1);
00278
00279
00280 while (e->getKind() == Expr::Concat) {
00281 offset = AddExpr::create(offset, strideExpr);
00282 if (!isReadExprAtOffset(e->getKid(0), base, offset))
00283 return NULL;
00284
00285 e = e->getKid(1);
00286 }
00287
00288 offset = AddExpr::create(offset, strideExpr);
00289 if (!isReadExprAtOffset(e, base, offset))
00290 return NULL;
00291
00292 if (stride == -1)
00293 return cast<ReadExpr>(e.get());
00294 else return base;
00295 }
00296
00297 #if 0
00300 bool hasAllByteReads(const Expr *ep) {
00301 switch (ep->kind) {
00302 Expr::Read: {
00303
00304
00305 return ep->getWidth() == Expr::Int8;
00306 }
00307 Expr::Concat: {
00308 for (unsigned i=0; i<ep->getNumKids(); ++i) {
00309 if (!hashAllByteReads(ep->getKid(i)))
00310 return false;
00311 }
00312 }
00313 default: return false;
00314 }
00315 }
00316 #endif
00317
00318 void printRead(const ReadExpr *re, PrintContext &PC, unsigned indent) {
00319 print(re->index, PC);
00320 printSeparator(PC, isVerySimple(re->index), indent);
00321 printUpdateList(re->updates, PC);
00322 }
00323
00324 void printExtract(const ExtractExpr *ee, PrintContext &PC, unsigned indent) {
00325 PC << ee->offset << ' ';
00326 print(ee->expr, PC);
00327 }
00328
00329 void printExpr(const Expr *ep, PrintContext &PC, unsigned indent, bool printConstWidth=false) {
00330 bool simple = hasSimpleKids(ep);
00331
00332 print(ep->getKid(0), PC);
00333 for (unsigned i=1; i<ep->getNumKids(); i++) {
00334 printSeparator(PC, simple, indent);
00335 print(ep->getKid(i), PC, printConstWidth);
00336 }
00337 }
00338
00339 public:
00340 PPrinter(std::ostream &_os) : os(_os), newline("\n") {
00341 reset();
00342 }
00343
00344 void setNewline(const std::string &_newline) {
00345 newline = _newline;
00346 }
00347
00348 void reset() {
00349 counter = 0;
00350 updateCounter = 0;
00351 hasScan = false;
00352 bindings.clear();
00353 updateBindings.clear();
00354 couldPrint.clear();
00355 shouldPrint.clear();
00356 couldPrintUpdates.clear();
00357 shouldPrintUpdates.clear();
00358 }
00359
00360 void scan(const ref<Expr> &e) {
00361 hasScan = true;
00362 scan1(e);
00363 }
00364
00365 void print(const ref<Expr> &e, unsigned level=0) {
00366 PrintContext PC(os);
00367 PC.pos = level;
00368 print(e, PC);
00369 }
00370
00371 void printConst(const ref<ConstantExpr> &e, PrintContext &PC,
00372 bool printWidth) {
00373 if (e->getWidth() == Expr::Bool)
00374 PC << (e->getConstantValue() ? "true" : "false");
00375 else {
00376 if (PCAllConstWidths)
00377 printWidth = true;
00378
00379 if (printWidth)
00380 PC << "(w" << e->getWidth() << " ";
00381
00382 PC << e->getConstantValue();
00383
00384 if (printWidth)
00385 PC << ")";
00386 }
00387 }
00388
00389 void print(const ref<Expr> &e, PrintContext &PC, bool printConstWidth=false) {
00390 if (ConstantExpr *CE = dyn_cast<ConstantExpr>(e))
00391 printConst(CE, PC, printConstWidth);
00392 else {
00393 std::map<ref<Expr>, unsigned>::iterator it = bindings.find(e);
00394 if (it!=bindings.end()) {
00395 PC << 'N' << it->second;
00396 } else {
00397 if (!hasScan || shouldPrint.count(e)) {
00398 PC << 'N' << counter << ':';
00399 bindings.insert(std::make_pair(e, counter++));
00400 }
00401
00402
00403
00404 if (const EqExpr *ee = dyn_cast<EqExpr>(e)) {
00405 if (ee->left == ConstantExpr::alloc(false, Expr::Bool)) {
00406 PC << "(Not";
00407 printWidth(PC, e);
00408 PC << ' ';
00409 print(ee->right, PC);
00410 PC << ')';
00411 return;
00412 }
00413 }
00414
00415
00416
00417
00418
00419
00420
00421
00422 if (PCMultibyteReads && e->getKind() == Expr::Concat) {
00423 const ReadExpr *base = hasOrderedReads(e, -1);
00424 int isLSB = (base != NULL);
00425 if (!isLSB)
00426 base = hasOrderedReads(e, 1);
00427 if (base) {
00428 PC << "(Read" << (isLSB ? "LSB" : "MSB");
00429 printWidth(PC, e);
00430 PC << ' ';
00431 printRead(base, PC, PC.pos);
00432 PC << ')';
00433 return;
00434 }
00435 }
00436
00437 PC << '(' << e->getKind();
00438 printWidth(PC, e);
00439 PC << ' ';
00440
00441
00442
00443 unsigned indent = PC.pos;
00444 if (const ReadExpr *re = dyn_cast<ReadExpr>(e)) {
00445 printRead(re, PC, indent);
00446 } else if (const ExtractExpr *ee = dyn_cast<ExtractExpr>(e)) {
00447 printExtract(ee, PC, indent);
00448 } else if (e->getKind() == Expr::Concat || e->getKind() == Expr::SExt)
00449 printExpr(e.get(), PC, indent, true);
00450 else
00451 printExpr(e.get(), PC, indent);
00452 PC << ")";
00453 }
00454 }
00455 }
00456
00457
00458
00459 void printSeparator(PrintContext &PC, bool simple, unsigned indent) {
00460 if (simple) {
00461 PC << ' ';
00462 } else {
00463 PC.breakLine(indent);
00464 }
00465 }
00466 };
00467
00468 ExprPPrinter *klee::ExprPPrinter::create(std::ostream &os) {
00469 return new PPrinter(os);
00470 }
00471
00472 void ExprPPrinter::printOne(std::ostream &os,
00473 const char *message,
00474 const ref<Expr> &e) {
00475 PPrinter p(os);
00476 p.scan(e);
00477
00478
00479
00480 PrintContext PC(os);
00481 PC << message << ": ";
00482 p.print(e, PC);
00483 PC.breakLine();
00484 }
00485
00486 void ExprPPrinter::printSingleExpr(std::ostream &os, const ref<Expr> &e) {
00487 PPrinter p(os);
00488 p.scan(e);
00489
00490
00491
00492 PrintContext PC(os);
00493 p.print(e, PC);
00494 }
00495
00496 void ExprPPrinter::printConstraints(std::ostream &os,
00497 const ConstraintManager &constraints) {
00498 printQuery(os, constraints, ConstantExpr::alloc(false, Expr::Bool));
00499 }
00500
00501
00502 void ExprPPrinter::printQuery(std::ostream &os,
00503 const ConstraintManager &constraints,
00504 const ref<Expr> &q,
00505 const ref<Expr> *evalExprsBegin,
00506 const ref<Expr> *evalExprsEnd,
00507 const Array * const *evalArraysBegin,
00508 const Array * const *evalArraysEnd) {
00509 PPrinter p(os);
00510
00511 for (ConstraintManager::const_iterator it = constraints.begin(),
00512 ie = constraints.end(); it != ie; ++it)
00513 p.scan(*it);
00514 p.scan(q);
00515
00516 for (const ref<Expr> *it = evalExprsBegin; it != evalExprsEnd; ++it)
00517 p.scan(*it);
00518
00519 PrintContext PC(os);
00520 PC << "(query [";
00521
00522
00523 unsigned indent = PC.pos;
00524 for (ConstraintManager::const_iterator it = constraints.begin(),
00525 ie = constraints.end(); it != ie;) {
00526 p.print(*it, PC);
00527 ++it;
00528 if (it != ie)
00529 PC.breakLine(indent);
00530 }
00531 PC << ']';
00532
00533 p.printSeparator(PC, constraints.empty(), indent-1);
00534 p.print(q, PC);
00535
00536
00537 if (evalExprsBegin != evalExprsEnd) {
00538 PC.breakLine(indent - 1);
00539 PC << '[';
00540 for (const ref<Expr> *it = evalExprsBegin; it != evalExprsEnd; ++it) {
00541 p.print(*it, PC);
00542 if (it + 1 != evalExprsEnd)
00543 PC.breakLine(indent);
00544 }
00545 PC << ']';
00546 }
00547
00548
00549 if (evalArraysBegin != evalArraysEnd) {
00550 if (evalExprsBegin == evalExprsEnd)
00551 PC << " []";
00552
00553 PC.breakLine(indent - 1);
00554 PC << '[';
00555 for (const Array * const* it = evalArraysBegin; it != evalArraysEnd; ++it) {
00556 PC << "arr" << (*it)->id;
00557 if (it + 1 != evalArraysEnd)
00558 PC.breakLine(indent);
00559 }
00560 PC << ']';
00561 }
00562
00563 PC << ')';
00564 PC.breakLine();
00565 }