ExprPPrinter.cpp

Go to the documentation of this file.
00001 //===-- ExprPPrinter.cpp -   ----------------------------------------------===//
00002 //
00003 //                     The KLEE Symbolic Virtual Machine
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
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   // document me!
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     // Special case empty list.
00163     if (!head) {
00164       if (updates.isRooted) {
00165         PC << "arr" << updates.root->id;
00166       } else {
00167         PC << "[]";
00168       }
00169       return;
00170     }
00171 
00172     // FIXME: Explain this breaking policy.
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       // We are done if we hit the cache.
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       //PC << "(=";
00204       //unsigned innerIndent = PC.pos;
00205       print(un->index, PC);
00206       //printSeparator(PC, isSimple(un->index), innerIndent);
00207       PC << "=";
00208       print(un->value, PC);
00209       //PC << ')';
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     // right now, all Reads are byte reads but some
00240     // transformations might change this
00241     if (!re || (re->getWidth() != Expr::Int8))
00242       return false;
00243       
00244     // Check if the index follows the stride. 
00245     // FIXME: How aggressive should this be simplified. The
00246     // canonicalizing builder is probably the right choice, but this
00247     // is yet another area where we would really prefer it to be
00248     // global or else use static methods.
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     // right now, all Reads are byte reads but some
00268     // transformations might change this
00269     if (!base || base->getWidth() != Expr::Int8)
00270       return false;
00271     
00272     // Get stride expr in proper index width.
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     // concat chains are unbalanced to the right
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         // right now, all Reads are byte reads but some
00304         // transformations might change this
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         // Detect Not.
00403         // FIXME: This should be in common code.
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         // Detect multibyte reads.
00416         // FIXME: Hrm. One problem with doing this is that we are
00417         // masking the sharing of the indices which aren't
00418         // visible. Need to think if this matters... probably not
00419         // because if they are offset reads then its either constant,
00420         // or they are (base + offset) and base will get printed with
00421         // a declaration.
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         // Indent at first argument and dispatch to appropriate print
00442         // routine for exprs which require special handling.
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   /* Public utility functions */
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   // FIXME: Need to figure out what to do here. Probably print as a
00479   // "forward declaration" with whatever syntax we pick for that.
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   // FIXME: Need to figure out what to do here. Probably print as a
00491   // "forward declaration" with whatever syntax we pick for that.
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   // Ident at constraint list;
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   // Print expressions to obtain values for, if any.
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   // Print arrays to obtain values for, if any.
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 }

Generated on Fri Jun 5 03:31:32 2009 for klee by  doxygen 1.5.8