//===-- ExprSMTLIBLetPrinter.cpp ------------------------------------------*- //C++ -*-===// // // The KLEE Symbolic Virtual Machine // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "llvm/Support/raw_ostream.h" #include "llvm/Support/CommandLine.h" #include "klee/util/ExprSMTLIBLetPrinter.h" namespace ExprSMTLIBOptions { llvm::cl::opt useLetExpressions("smtlib-use-let-expressions", llvm::cl::desc("Enables generated SMT-LIBv2 files to use " "(let) expressions (default=on)"), llvm::cl::init(true)); } namespace klee { const char ExprSMTLIBLetPrinter::BINDING_PREFIX[] = "?B"; ExprSMTLIBLetPrinter::ExprSMTLIBLetPrinter() : bindings(), firstEO(), twoOrMoreEO(), disablePrintedAbbreviations(false) { } void ExprSMTLIBLetPrinter::generateOutput() { if (p == NULL || query == NULL || o == NULL) { llvm::errs() << "Can't print SMTLIBv2. Output or query bad!\n"; return; } generateBindings(); if (isHumanReadable()) printNotice(); printOptions(); printSetLogic(); printArrayDeclarations(); printLetExpression(); printAction(); printExit(); } void ExprSMTLIBLetPrinter::scan(const ref &e) { if (isa(e)) return; // we don't need to scan simple constants if (firstEO.insert(e).second) { // We've not seen this expression before if (const ReadExpr *re = dyn_cast(e)) { // 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; // 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)); } else { /* We must of seen the expression before. Add it to * the set of twoOrMoreOccurances. We don't need to * check if the insertion fails. */ twoOrMoreEO.insert(e); } } void ExprSMTLIBLetPrinter::generateBindings() { // Assign a number to each binding that will be used unsigned int counter = 0; for (std::set >::const_iterator i = twoOrMoreEO.begin(); i != twoOrMoreEO.end(); ++i) { bindings.insert(std::make_pair(*i, counter)); ++counter; } } void ExprSMTLIBLetPrinter::printExpression( const ref &e, ExprSMTLIBPrinter::SMTLIB_SORT expectedSort) { std::map, unsigned int>::const_iterator i = bindings.find(e); if (disablePrintedAbbreviations || i == bindings.end()) { /*There is no abbreviation for this expression so print it normally. * Do this by using the parent method. */ ExprSMTLIBPrinter::printExpression(e, expectedSort); } else { // Use binding name e.g. "?B1" /* Handle the corner case where the expectedSort * doesn't match the sort of the abbreviation. Not really very efficient * (calls bindings.find() twice), * we'll cast and call ourself again but with the correct expectedSort. */ if (getSort(e) != expectedSort) { printCastToSort(e, expectedSort); return; } // No casting is needed in this depth of recursion, just print the // abbreviation *p << BINDING_PREFIX << i->second; } } void ExprSMTLIBLetPrinter::reset() { // Let parent clean up first ExprSMTLIBPrinter::reset(); firstEO.clear(); twoOrMoreEO.clear(); bindings.clear(); } void ExprSMTLIBLetPrinter::printLetExpression() { *p << "(assert"; p->pushIndent(); printSeperator(); if (bindings.size() != 0) { // Only print let expression if we have bindings to use. *p << "(let"; p->pushIndent(); printSeperator(); *p << "( "; p->pushIndent(); // Print each binding for (std::map, unsigned int>::const_iterator i = bindings.begin(); i != bindings.end(); ++i) { printSeperator(); *p << "(" << BINDING_PREFIX << i->second << " "; p->pushIndent(); // Disable abbreviations so none are used here. disablePrintedAbbreviations = true; // We can abbreviate SORT_BOOL or SORT_BITVECTOR in let expressions printExpression(i->first, getSort(i->first)); p->popIndent(); printSeperator(); *p << ")"; } p->popIndent(); printSeperator(); *p << ")"; printSeperator(); // Re-enable printing abbreviations. disablePrintedAbbreviations = false; } // print out Expressions with abbreviations. unsigned int numberOfItems = query->constraints.size() + 1; //+1 for query unsigned int itemsLeft = numberOfItems; std::vector >::const_iterator constraint = query->constraints.begin(); /* Produce nested (and () () statements. If the constraint set * is empty then we will only print the "queryAssert". */ for (; itemsLeft != 0; --itemsLeft) { if (itemsLeft >= 2) { *p << "(and"; p->pushIndent(); printSeperator(); printExpression(*constraint, SORT_BOOL); // We must and together bool expressions printSeperator(); ++constraint; continue; } else { // must have 1 item left (i.e. the "queryAssert") if (isHumanReadable()) { *p << "; query"; p->breakLineI(); } printExpression(queryAssert, SORT_BOOL); // The query must be a bool expression } } /* Produce closing brackets for nested "and statements". * Number of "nested ands" = numberOfItems -1 */ itemsLeft = numberOfItems - 1; for (; itemsLeft != 0; --itemsLeft) { p->popIndent(); printSeperator(); *p << ")"; } if (bindings.size() != 0) { // end let expression p->popIndent(); printSeperator(); *p << ")"; printSeperator(); } // end assert p->popIndent(); printSeperator(); *p << ")"; p->breakLineI(); } ExprSMTLIBPrinter *createSMTLIBPrinter() { if (ExprSMTLIBOptions::useLetExpressions) return new ExprSMTLIBLetPrinter(); else return new ExprSMTLIBPrinter(); } }