about summary refs log tree commit diff homepage
path: root/lib/Expr/ExprSMTLIBPrinter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Expr/ExprSMTLIBPrinter.cpp')
-rw-r--r--lib/Expr/ExprSMTLIBPrinter.cpp150
1 files changed, 123 insertions, 27 deletions
diff --git a/lib/Expr/ExprSMTLIBPrinter.cpp b/lib/Expr/ExprSMTLIBPrinter.cpp
index bbb82d0d..fb7e270e 100644
--- a/lib/Expr/ExprSMTLIBPrinter.cpp
+++ b/lib/Expr/ExprSMTLIBPrinter.cpp
@@ -31,6 +31,19 @@ llvm::cl::opt<bool> humanReadableSMTLIB(
     llvm::cl::desc(
         "Enables generated SMT-LIBv2 files to be human readable (default=off)"),
     llvm::cl::init(false));
+
+llvm::cl::opt<klee::ExprSMTLIBPrinter::AbbreviationMode> abbreviationMode(
+    "smtlib-abbreviation-mode",
+    llvm::cl::desc(
+        "Choose abbreviation mode to use in SMT-LIBv2 files (default=let)"),
+    llvm::cl::values(clEnumValN(klee::ExprSMTLIBPrinter::ABBR_NONE, "none",
+                                "Do not abbreviate"),
+                     clEnumValN(klee::ExprSMTLIBPrinter::ABBR_LET, "let",
+                                "Abbreviate with let"),
+                     clEnumValN(klee::ExprSMTLIBPrinter::ABBR_NAMED, "named",
+                                "Abbreviate with :named annotations"),
+                     clEnumValEnd),
+    llvm::cl::init(klee::ExprSMTLIBPrinter::ABBR_LET));
 }
 
 namespace klee {
@@ -41,6 +54,7 @@ ExprSMTLIBPrinter::ExprSMTLIBPrinter()
       humanReadable(ExprSMTLIBOptions::humanReadableSMTLIB),
       smtlibBoolOptions(), arraysToCallGetValueOn(NULL) {
   setConstantDisplayMode(ExprSMTLIBOptions::argConstantDisplayMode);
+  setAbbreviationMode(ExprSMTLIBOptions::abbreviationMode);
 }
 
 ExprSMTLIBPrinter::~ExprSMTLIBPrinter() {
@@ -60,10 +74,11 @@ void ExprSMTLIBPrinter::setQuery(const Query &q) {
   query = &q;
   reset(); // clear the data structures
   scanAll();
-  negateQueryExpression();
 }
 
 void ExprSMTLIBPrinter::reset() {
+  bindings.clear();
+  seenExprs.clear();
   usedArrays.clear();
   haveConstantArray = false;
 
@@ -154,6 +169,41 @@ void ExprSMTLIBPrinter::printExpression(
     return;
   }
 
+  switch (abbrMode) {
+  case ABBR_NONE:
+    break;
+
+  case ABBR_LET: {
+    BindingMap::iterator i = bindings.find(e);
+    if (i != bindings.end()) {
+      *p << "?B" << i->second;
+      return;
+    }
+    break;
+  }
+
+  case ABBR_NAMED: {
+    BindingMap::iterator i = bindings.find(e);
+    if (i != bindings.end()) {
+      if (i->second > 0) {
+        *p << "(! ";
+        printFullExpression(e, expectedSort);
+        *p << " :named ?B" << i->second << ")";
+        i->second = -i->second;
+      } else {
+        *p << "?B" << -i->second;
+      }
+      return;
+    }
+    break;
+  }
+  }
+
+  printFullExpression(e, expectedSort);
+}
+
+void ExprSMTLIBPrinter::printFullExpression(
+    const ref<Expr> &e, ExprSMTLIBPrinter::SMTLIB_SORT expectedSort) {
   switch (e->getKind()) {
   case Expr::Constant:
     printConstant(cast<ConstantExpr>(e));
@@ -431,7 +481,7 @@ void ExprSMTLIBPrinter::generateOutput() {
   printSetLogic();
   printArrayDeclarations();
   printConstraints();
-  printQuery();
+  printQueryExpr();
   printAction();
   printExit();
 }
@@ -576,24 +626,32 @@ void ExprSMTLIBPrinter::scan(const ref<Expr> &e) {
   if (isa<ConstantExpr>(e))
     return; // we don't need to scan simple constants
 
-  if (const ReadExpr *re = dyn_cast<ReadExpr>(e)) {
+  if (seenExprs.insert(e).second) {
+    // We've not seen this expression before
+
+    if (const ReadExpr *re = dyn_cast<ReadExpr>(e)) {
 
-    // Attempt to insert array and if array wasn't present before do more things
-    if (usedArrays.insert(re->updates.root).second) {
+      // Attempt to insert array and if array wasn't present before do more things
+      if (usedArrays.insert(re->updates.root).second) {
 
-      // check if the array is constant
-      if (re->updates.root->isConstantArray())
-        haveConstantArray = true;
+        // check if the array is constant
+        if (re->updates.root->isConstantArray())
+          haveConstantArray = true;
 
-      // scan the update list
-      scanUpdates(re->updates.head);
+        // scan the update list
+        scanUpdates(re->updates.head);
+      }
     }
-  }
 
-  // recurse into the children
-  Expr *ep = e.get();
-  for (unsigned int i = 0; i < ep->getNumKids(); i++)
-    scan(ep->getKid(i));
+    // recurse into the children
+    Expr *ep = e.get();
+    for (unsigned int i = 0; i < ep->getNumKids(); i++)
+      scan(ep->getKid(i));
+  } else {
+    // Add the expression to the binding map. The semantics of std::map::insert
+    // are such that it will not be inserted twice.
+    bindings.insert(std::make_pair(e, bindings.size()+1));
+  }
 }
 
 void ExprSMTLIBPrinter::scanUpdates(const UpdateNode *un) {
@@ -637,18 +695,52 @@ void ExprSMTLIBPrinter::printOptions() {
   }
 }
 
-void ExprSMTLIBPrinter::printQuery() {
-  if (humanReadable) {
-    *p << "; Query from solver turned into an assert";
-    p->breakLineI();
-  }
-
+void ExprSMTLIBPrinter::printAssert(const ref<Expr> &e) {
   p->pushIndent();
   *p << "(assert";
   p->pushIndent();
   printSeperator();
 
-  printExpression(queryAssert, SORT_BOOL);
+  if (abbrMode == ABBR_LET && bindings.size() != 0) {
+    // Only print let expression if we have bindings to use.
+    *p << "(let";
+    p->pushIndent();
+    printSeperator();
+    *p << "( ";
+    p->pushIndent();
+
+    // Disable abbreviations so none are used here.
+    abbrMode = ABBR_NONE;
+
+    // Print each binding
+    for (BindingMap::const_iterator i = bindings.begin(); i != bindings.end();
+         ++i) {
+      printSeperator();
+      *p << "(?B" << i->second << " ";
+      p->pushIndent();
+
+      // We can abbreviate SORT_BOOL or SORT_BITVECTOR in let expressions
+      printExpression(i->first, getSort(i->first));
+
+      p->popIndent();
+      printSeperator();
+      *p << ")";
+    }
+
+    // Re-enable printing abbreviations.
+    abbrMode = ABBR_LET;
+
+    p->popIndent();
+    printSeperator();
+    *p << ")";
+    printSeperator();
+
+    printExpression(e, SORT_BOOL);
+
+    *p << ")";
+  } else {
+    printExpression(e, SORT_BOOL);
+  }
 
   p->popIndent();
   printSeperator();
@@ -657,6 +749,15 @@ void ExprSMTLIBPrinter::printQuery() {
   p->breakLineI();
 }
 
+void ExprSMTLIBPrinter::printQueryExpr() {
+  if (humanReadable) {
+    *p << "; Query from solver turned into an assert";
+    p->breakLineI();
+  }
+  ref<Expr> queryAssert = Expr::createIsZero(query->expr);
+  printAssert(queryAssert);
+}
+
 ExprSMTLIBPrinter::SMTLIB_SORT ExprSMTLIBPrinter::getSort(const ref<Expr> &e) {
   switch (e->getKind()) {
   case Expr::NotOptimized:
@@ -831,11 +932,6 @@ void ExprSMTLIBPrinter::printLogicalOrBitVectorExpr(
   *p << ")";
 }
 
-void ExprSMTLIBPrinter::negateQueryExpression() {
-  // Negating the query
-  queryAssert = Expr::createIsZero(query->expr);
-}
-
 bool ExprSMTLIBPrinter::setSMTLIBboolOption(SMTLIBboolOptions option,
                                             SMTLIBboolValues value) {
   std::pair<std::map<SMTLIBboolOptions, bool>::iterator, bool> thePair;