From 15599d18443655e8974cc4e07755182fc2abb011 Mon Sep 17 00:00:00 2001 From: trevor_hansen Date: Sat, 25 Jul 2009 06:14:49 +0000 Subject: [PATCH] No semantic change. Automatically layout the code using Eclipse. The layout configuation file is added to the root directory "format_config.xml" git-svn-id: https://stp-fast-prover.svn.sourceforge.net/svnroot/stp-fast-prover/trunk/stp@87 e59a4935-1847-0410-ae03-e826735625c1 --- AST/AST.cpp | 3431 +++++++++-------- AST/AST.h | 3730 +++++++++--------- AST/ASTUtil.cpp | 70 +- AST/BitBlast.cpp | 1902 +++++----- AST/SimpBool.cpp | 859 +++-- AST/ToCNF.cpp | 3397 +++++++++-------- AST/ToSAT.cpp | 2970 ++++++++------- AST/Transform.cpp | 1223 +++--- AST/asttest.cpp | 38 +- AST/bbtest.cpp | 178 +- AST/cnftest.cpp | 70 +- AST/printer/CPrinter.cpp | 97 +- AST/printer/SMTLIBPrinter.cpp | 57 +- AST/printer/dotPrinter.cpp | 41 +- AST/printer/printers.h | 7 +- bitvec/consteval.cpp | 2191 +++++------ format_config.xml | 151 + simplifier/bvsolver.cpp | 1438 +++---- simplifier/bvsolver.h | 257 +- simplifier/simplifier.cpp | 6688 +++++++++++++++++---------------- 20 files changed, 15111 insertions(+), 13684 deletions(-) create mode 100644 format_config.xml diff --git a/AST/AST.cpp b/AST/AST.cpp index 6f7c6e5..a032833 100644 --- a/AST/AST.cpp +++ b/AST/AST.cpp @@ -11,1681 +11,1788 @@ #include -namespace BEEV { - //some global variables that are set through commandline options. it - //is best that these variables remain global. Default values set - //here - // - //collect statistics on certain functions - bool stats = false; - //print DAG nodes - bool print_nodes = false; - //tentative global var to allow for variable activity optimization - //in the SAT solver. deprecated. - bool variable_activity_optimize = false; - //run STP in optimized mode - bool optimize = true; - //do sat refinement, i.e. underconstraint the problem, and feed to - //SAT. if this works, great. else, add a set of suitable constraints - //to re-constraint the problem correctly, and call SAT again, until - //all constraints have been added. - bool arrayread_refinement = true; - //flag to control write refinement - bool arraywrite_refinement = true; - //check the counterexample against the original input to STP - bool check_counterexample = false; - //construct the counterexample in terms of original variable based - //on the counterexample returned by SAT solver - bool construct_counterexample = true; - bool print_counterexample = false; - //if this option is true then print the way dawson wants using a - //different printer. do not use this printer. - bool print_arrayval_declaredorder = false; - //flag to decide whether to print "valid/invalid" or not - bool print_output = false; - //do linear search in the array values of an input array. experimental - bool linear_search = false; - //print the variable order chosen by the sat solver while it is - //solving. - bool print_sat_varorder = false; - //turn on word level bitvector solver - bool wordlevel_solve = true; - //turn off XOR flattening - bool xor_flatten = false; - - //the smtlib parser has been turned on - bool smtlib_parser_enable = false; - //print the input back - bool print_STPinput_back = false; - - enum BEEV::inputStatus input_status = NOT_DECLARED; - - // Used only in smtlib lexer/parser - ASTNode SingleBitOne; - ASTNode SingleBitZero; - - //global BEEVMGR for the parser - BeevMgr * globalBeevMgr_for_parser; - - void (*vc_error_hdlr)(const char* err_msg) = NULL; - /** This is reusable empty vector, for representing empty children arrays */ - ASTVec _empty_ASTVec; - //////////////////////////////////////////////////////////////// - // ASTInternal members - //////////////////////////////////////////////////////////////// - /** Trivial but virtual destructor */ - ASTInternal::~ASTInternal() { } - - //////////////////////////////////////////////////////////////// - // ASTInterior members - //////////////////////////////////////////////////////////////// - /** Copy constructor */ - // ASTInterior::ASTInterior(const ASTInterior &int_node) - // { - // _kind = int_node._kind; - // _children = int_node._children; - // } - - /** Trivial but virtual destructor */ - ASTInterior::~ASTInterior() { } - - // FIXME: Darn it! I think this ends up copying the children twice! - /** Either return an old node or create it if it doesn't exist. - Note that nodes are physically allocated in the hash table. */ - - // There is an inelegance here that I don't know how to solve. I'd - // like to heap allocate and do some other initialization on keys only - // if they aren't in the hash table. It would be great if the - // "insert" method took a "creator" class so that I could do that - // between when it notices that the key is not there and when it - // inserts it. Alternatively, it would be great if I could insert the - // temporary key and replace it if it actually got inserted. But STL - // hash_set doesn't have the creator feature and paternalistically - // declares that keys are immutable, even though (it seems to me) that - // they could be mutated if the hash value and eq values did not - // change. - - ASTInterior *BeevMgr::LookupOrCreateInterior(ASTInterior *n_ptr) { - ASTInteriorSet::iterator it; - - if ((it = _interior_unique_table.find(n_ptr)) == _interior_unique_table.end()) { - // Make a new ASTInterior node - // We want (NOT alpha) always to have alpha.nodenum + 1. - if (n_ptr->GetKind() == NOT) { - n_ptr->SetNodeNum(n_ptr->GetChildren()[0].GetNodeNum()+1); - } - else { - n_ptr->SetNodeNum(NewNodeNum()); - } - pair p = _interior_unique_table.insert(n_ptr); - return *(p.first); - } - else - // Delete the temporary node, and return the found node. - delete n_ptr; - return *it; - } - - size_t ASTInterior::ASTInteriorHasher::operator() (const ASTInterior *int_node_ptr) const { - //size_t hashval = 0; - size_t hashval = ((size_t) int_node_ptr->GetKind()); - const ASTVec &ch = int_node_ptr->GetChildren(); - ASTVec::const_iterator iend = ch.end(); - for (ASTVec::const_iterator i = ch.begin(); i != iend; i++) { - //Using "One at a time hash" by Bob Jenkins - hashval += i->Hash(); - hashval += (hashval << 10); - hashval ^= (hashval >> 6); - } - - hashval += (hashval << 3); - hashval ^= (hashval >> 11); - hashval += (hashval << 15); - return hashval; - //return hashval += ((size_t) int_node_ptr->GetKind()); - } - - - void ASTInterior::CleanUp() { - // cout << "Deleting node " << this->GetNodeNum() << endl; - _bm._interior_unique_table.erase(this); - delete this; - } - - //////////////////////////////////////////////////////////////// - // ASTNode members - //////////////////////////////////////////////////////////////// - //ASTNode constructors are inlined in AST.h - bool ASTNode::IsAlreadyPrinted() const { - BeevMgr &bm = GetBeevMgr(); - return (bm.AlreadyPrintedSet.find(*this) != bm.AlreadyPrintedSet.end()); - } - - void ASTNode::nodeprint(ostream& os, bool c_friendly) const - { +namespace BEEV +{ +//some global variables that are set through commandline options. it +//is best that these variables remain global. Default values set +//here +// +//collect statistics on certain functions +bool stats = false; +//print DAG nodes +bool print_nodes = false; +//tentative global var to allow for variable activity optimization +//in the SAT solver. deprecated. +bool variable_activity_optimize = false; +//run STP in optimized mode +bool optimize = true; +//do sat refinement, i.e. underconstraint the problem, and feed to +//SAT. if this works, great. else, add a set of suitable constraints +//to re-constraint the problem correctly, and call SAT again, until +//all constraints have been added. +bool arrayread_refinement = true; +//flag to control write refinement +bool arraywrite_refinement = true; +//check the counterexample against the original input to STP +bool check_counterexample = false; +//construct the counterexample in terms of original variable based +//on the counterexample returned by SAT solver +bool construct_counterexample = true; +bool print_counterexample = false; +//if this option is true then print the way dawson wants using a +//different printer. do not use this printer. +bool print_arrayval_declaredorder = false; +//flag to decide whether to print "valid/invalid" or not +bool print_output = false; +//do linear search in the array values of an input array. experimental +bool linear_search = false; +//print the variable order chosen by the sat solver while it is +//solving. +bool print_sat_varorder = false; +//turn on word level bitvector solver +bool wordlevel_solve = true; +//turn off XOR flattening +bool xor_flatten = false; + +//the smtlib parser has been turned on +bool smtlib_parser_enable = false; +//print the input back +bool print_STPinput_back = false; + +enum BEEV::inputStatus input_status = NOT_DECLARED; + +// Used only in smtlib lexer/parser +ASTNode SingleBitOne; +ASTNode SingleBitZero; + +//global BEEVMGR for the parser +BeevMgr * globalBeevMgr_for_parser; + +void (*vc_error_hdlr)(const char* err_msg) = NULL; +/** This is reusable empty vector, for representing empty children arrays */ +ASTVec _empty_ASTVec; +//////////////////////////////////////////////////////////////// +// ASTInternal members +//////////////////////////////////////////////////////////////// +/** Trivial but virtual destructor */ +ASTInternal::~ASTInternal() +{ +} + +//////////////////////////////////////////////////////////////// +// ASTInterior members +//////////////////////////////////////////////////////////////// +/** Copy constructor */ +// ASTInterior::ASTInterior(const ASTInterior &int_node) +// { +// _kind = int_node._kind; +// _children = int_node._children; +// } + +/** Trivial but virtual destructor */ +ASTInterior::~ASTInterior() +{ +} + +// FIXME: Darn it! I think this ends up copying the children twice! +/** Either return an old node or create it if it doesn't exist. + Note that nodes are physically allocated in the hash table. */ + +// There is an inelegance here that I don't know how to solve. I'd +// like to heap allocate and do some other initialization on keys only +// if they aren't in the hash table. It would be great if the +// "insert" method took a "creator" class so that I could do that +// between when it notices that the key is not there and when it +// inserts it. Alternatively, it would be great if I could insert the +// temporary key and replace it if it actually got inserted. But STL +// hash_set doesn't have the creator feature and paternalistically +// declares that keys are immutable, even though (it seems to me) that +// they could be mutated if the hash value and eq values did not +// change. + +ASTInterior *BeevMgr::LookupOrCreateInterior(ASTInterior *n_ptr) +{ + ASTInteriorSet::iterator it; + + if ((it = _interior_unique_table.find(n_ptr)) == _interior_unique_table.end()) + { + // Make a new ASTInterior node + // We want (NOT alpha) always to have alpha.nodenum + 1. + if (n_ptr->GetKind() == NOT) + { + n_ptr->SetNodeNum(n_ptr->GetChildren()[0].GetNodeNum() + 1); + } + else + { + n_ptr->SetNodeNum(NewNodeNum()); + } + pair p = _interior_unique_table.insert(n_ptr); + return *(p.first); + } + else + // Delete the temporary node, and return the found node. + delete n_ptr; + return *it; +} + +size_t ASTInterior::ASTInteriorHasher::operator()(const ASTInterior *int_node_ptr) const +{ + //size_t hashval = 0; + size_t hashval = ((size_t) int_node_ptr->GetKind()); + const ASTVec &ch = int_node_ptr->GetChildren(); + ASTVec::const_iterator iend = ch.end(); + for (ASTVec::const_iterator i = ch.begin(); i != iend; i++) + { + //Using "One at a time hash" by Bob Jenkins + hashval += i->Hash(); + hashval += (hashval << 10); + hashval ^= (hashval >> 6); + } + + hashval += (hashval << 3); + hashval ^= (hashval >> 11); + hashval += (hashval << 15); + return hashval; + //return hashval += ((size_t) int_node_ptr->GetKind()); +} + +void ASTInterior::CleanUp() +{ + // cout << "Deleting node " << this->GetNodeNum() << endl; + _bm._interior_unique_table.erase(this); + delete this; +} + +//////////////////////////////////////////////////////////////// +// ASTNode members +//////////////////////////////////////////////////////////////// +//ASTNode constructors are inlined in AST.h +bool ASTNode::IsAlreadyPrinted() const +{ + BeevMgr &bm = GetBeevMgr(); + return (bm.AlreadyPrintedSet.find(*this) != bm.AlreadyPrintedSet.end()); +} + +void ASTNode::nodeprint(ostream& os, bool c_friendly) const +{ _int_node_ptr->nodeprint(os, c_friendly); - } - - void ASTNode::MarkAlreadyPrinted() const { - // FIXME: Fetching BeevMgr is annoying. Can we put this in lispprinter class? - BeevMgr &bm = GetBeevMgr(); - bm.AlreadyPrintedSet.insert(*this); - } - - // Get the name from a symbol (char *). It's an error if kind != SYMBOL - const char * const ASTNode::GetName() const { - if (GetKind() != SYMBOL) - FatalError("GetName: Called GetName on a non-symbol: ", *this); - return ((ASTSymbol *) _int_node_ptr)->GetName(); - } - - void ASTNode::NFASTPrint(int l, int max, int prefix) const { - //**************************************** - // stop - //**************************************** - if(l > max){ - return; - } - - //**************************************** - // print - //**************************************** - printf("[%10d]", 0); - for(int i = 0; i < prefix; i++){ - printf(" "); - } - cout << GetKind(); - printf("\n"); - - //**************************************** - // recurse - //**************************************** - - const ASTVec &children = GetChildren(); - ASTVec::const_iterator it = children.begin(); - for(; it != children.end(); it++) { - it->NFASTPrint(l+1, max, prefix+1); - } - } - - // Print in lisp format - ostream &ASTNode::LispPrint(ostream &os, int indentation) const { - // Clear the PrintMap - BeevMgr& bm = GetBeevMgr(); - bm.AlreadyPrintedSet.clear(); - LispPrint_indent(os, indentation); - printf("\n"); - return os; - } - - // Print newline and indentation, then print the thing. - ostream &ASTNode::LispPrint_indent(ostream &os, - int indentation) const - { - os << endl << spaces(indentation); - LispPrint1(os, indentation); - return os; - } - - /** Internal function to print in lisp format. Assume newline - and indentation printed already before first line. Recursive - calls will have newline & indent, though */ - ostream &ASTNode::LispPrint1(ostream &os, int indentation) const { - if (!IsDefined()) { - os << ""; - return os; - } - Kind kind = GetKind(); - // FIXME: figure out how to avoid symbols with same names as kinds. -// if (kind == READ) { -// const ASTVec &children = GetChildren(); -// children[0].LispPrint1(os, indentation); -// os << "[" << children[1] << "]"; -// } else - if(kind == BVGETBIT) { - const ASTVec &children = GetChildren(); - // child 0 is a symbol. Print without the NodeNum. - os << GetNodeNum() << ":"; - - - - children[0]._int_node_ptr->nodeprint(os); - //os << "{" << children[1].GetBVConst() << "}"; - os << "{"; - children[1]._int_node_ptr->nodeprint(os); - os << "}"; - } else if (kind == NOT) { - const ASTVec &children = GetChildren(); - os << GetNodeNum() << ":"; - os << "(NOT "; - children[0].LispPrint1(os, indentation); - os << ")"; - } - else if (Degree() == 0) { - // Symbol or a kind with no children print as index:NAME if shared, - // even if they have been printed before. - os << GetNodeNum() << ":"; - _int_node_ptr->nodeprint(os); - // os << "(" << _int_node_ptr->_ref_count << ")"; - // os << "{" << GetValueWidth() << "}"; - } - else if (IsAlreadyPrinted()) { - // print non-symbols as "[index]" if seen before. - os << "[" << GetNodeNum() << "]"; - // << "(" << _int_node_ptr->_ref_count << ")"; - } - else { - MarkAlreadyPrinted(); - const ASTVec &children = GetChildren(); - os << GetNodeNum() << ":" - //<< "(" << _int_node_ptr->_ref_count << ")" - << "(" << kind << " "; - // os << "{" << GetValueWidth() << "}"; - ASTVec::const_iterator iend = children.end(); - for (ASTVec::const_iterator i = children.begin(); i != iend; i++) { - i->LispPrint_indent(os, indentation+2); +} + +void ASTNode::MarkAlreadyPrinted() const +{ + // FIXME: Fetching BeevMgr is annoying. Can we put this in lispprinter class? + BeevMgr &bm = GetBeevMgr(); + bm.AlreadyPrintedSet.insert(*this); +} + +// Get the name from a symbol (char *). It's an error if kind != SYMBOL +const char * const ASTNode::GetName() const +{ + if (GetKind() != SYMBOL) + FatalError("GetName: Called GetName on a non-symbol: ", *this); + return ((ASTSymbol *) _int_node_ptr)->GetName(); +} + +void ASTNode::NFASTPrint(int l, int max, int prefix) const +{ + //**************************************** + // stop + //**************************************** + if (l > max) + { + return; } - os << ")"; - } - return os; - } - - //print in PRESENTATION LANGUAGE - // - //two pass algorithm: - // - //1. In the first pass, letize this Node, N: i.e. if a node - //1. appears more than once in N, then record this fact. - // - //2. In the second pass print a "global let" and then print N - //2. as follows: Every occurence of a node occuring more than - //2. once is replaced with the corresponding let variable. - ostream& ASTNode::PL_Print(ostream &os, - int indentation) const { - // Clear the PrintMap - BeevMgr& bm = GetBeevMgr(); - bm.PLPrintNodeSet.clear(); - bm.NodeLetVarMap.clear(); - bm.NodeLetVarVec.clear(); - bm.NodeLetVarMap1.clear(); - - //pass 1: letize the node - LetizeNode(); - - //pass 2: - // - //2. print all the let variables and their counterpart expressions - //2. as follows (LET var1 = expr1, var2 = expr2, ... - // - //3. Then print the Node itself, replacing every occurence of - //3. expr1 with var1, expr2 with var2, ... - //os << "("; - if(0 < bm.NodeLetVarMap.size()) { - //ASTNodeMap::iterator it=bm.NodeLetVarMap.begin(); - //ASTNodeMap::iterator itend=bm.NodeLetVarMap.end(); - std::vector >::iterator it = bm.NodeLetVarVec.begin(); - std::vector >::iterator itend = bm.NodeLetVarVec.end(); - - os << "(LET "; - //print the let var first - it->first.PL_Print1(os,indentation,false); - os << " = "; - //print the expr - it->second.PL_Print1(os,indentation,false); - - //update the second map for proper printing of LET - bm.NodeLetVarMap1[it->second] = it->first; - - for(it++;it!=itend;it++) { - os << "," << endl; - //print the let var first - it->first.PL_Print1(os,indentation,false); - os << " = "; - //print the expr - it->second.PL_Print1(os,indentation,false); - - //update the second map for proper printing of LET - bm.NodeLetVarMap1[it->second] = it->first; - } - - os << " IN " << endl; - PL_Print1(os,indentation, true); - os << ") "; - } - else - PL_Print1(os,indentation, false); - //os << " )"; - os << " "; - return os; - } //end of PL_Print() - - //traverse "*this", and construct "let variables" for terms that - //occur more than once in "*this". - void ASTNode::LetizeNode(void) const { - Kind kind = this->GetKind(); - - if(kind == SYMBOL || - kind == BVCONST || - kind == FALSE || - kind == TRUE) - return; - - //FIXME: this is ugly. - BeevMgr& bm = GetBeevMgr(); - const ASTVec &c = this->GetChildren(); - for(ASTVec::const_iterator it=c.begin(),itend=c.end();it!=itend;it++){ - ASTNode ccc = *it; - if(bm.PLPrintNodeSet.find(ccc) == bm.PLPrintNodeSet.end()){ - //If branch: if *it is not in NodeSet then, - // - //1. add it to NodeSet - // - //2. Letize its childNodes - - //FIXME: Fetching BeevMgr is annoying. Can we put this in - //some kind of a printer class - bm.PLPrintNodeSet.insert(ccc); - //debugging - //cerr << ccc; - ccc.LetizeNode(); - } - else{ - Kind k = ccc.GetKind(); - if(k == SYMBOL || - k == BVCONST || - k == FALSE || - k == TRUE) - continue; - - //0. Else branch: Node has been seen before + + //**************************************** + // print + //**************************************** + printf("[%10d]", 0); + for (int i = 0; i < prefix; i++) + { + printf(" "); + } + cout << GetKind(); + printf("\n"); + + //**************************************** + // recurse + //**************************************** + + const ASTVec &children = GetChildren(); + ASTVec::const_iterator it = children.begin(); + for (; it != children.end(); it++) + { + it->NFASTPrint(l + 1, max, prefix + 1); + } +} + +// Print in lisp format +ostream &ASTNode::LispPrint(ostream &os, int indentation) const +{ + // Clear the PrintMap + BeevMgr& bm = GetBeevMgr(); + bm.AlreadyPrintedSet.clear(); + LispPrint_indent(os, indentation); + printf("\n"); + return os; +} + +// Print newline and indentation, then print the thing. +ostream &ASTNode::LispPrint_indent(ostream &os, int indentation) const +{ + os << endl << spaces(indentation); + LispPrint1(os, indentation); + return os; +} + +/** Internal function to print in lisp format. Assume newline + and indentation printed already before first line. Recursive + calls will have newline & indent, though */ +ostream &ASTNode::LispPrint1(ostream &os, int indentation) const +{ + if (!IsDefined()) + { + os << ""; + return os; + } + Kind kind = GetKind(); + // FIXME: figure out how to avoid symbols with same names as kinds. + // if (kind == READ) { + // const ASTVec &children = GetChildren(); + // children[0].LispPrint1(os, indentation); + // os << "[" << children[1] << "]"; + // } else + if (kind == BVGETBIT) + { + const ASTVec &children = GetChildren(); + // child 0 is a symbol. Print without the NodeNum. + os << GetNodeNum() << ":"; + + children[0]._int_node_ptr->nodeprint(os); + //os << "{" << children[1].GetBVConst() << "}"; + os << "{"; + children[1]._int_node_ptr->nodeprint(os); + os << "}"; + } + else if (kind == NOT) + { + const ASTVec &children = GetChildren(); + os << GetNodeNum() << ":"; + os << "(NOT "; + children[0].LispPrint1(os, indentation); + os << ")"; + } + else if (Degree() == 0) + { + // Symbol or a kind with no children print as index:NAME if shared, + // even if they have been printed before. + os << GetNodeNum() << ":"; + _int_node_ptr->nodeprint(os); + // os << "(" << _int_node_ptr->_ref_count << ")"; + // os << "{" << GetValueWidth() << "}"; + } + else if (IsAlreadyPrinted()) + { + // print non-symbols as "[index]" if seen before. + os << "[" << GetNodeNum() << "]"; + // << "(" << _int_node_ptr->_ref_count << ")"; + } + else + { + MarkAlreadyPrinted(); + const ASTVec &children = GetChildren(); + os << GetNodeNum() << ":" + //<< "(" << _int_node_ptr->_ref_count << ")" + << "(" << kind << " "; + // os << "{" << GetValueWidth() << "}"; + ASTVec::const_iterator iend = children.end(); + for (ASTVec::const_iterator i = children.begin(); i != iend; i++) + { + i->LispPrint_indent(os, indentation + 2); + } + os << ")"; + } + return os; +} + +//print in PRESENTATION LANGUAGE +// +//two pass algorithm: +// +//1. In the first pass, letize this Node, N: i.e. if a node +//1. appears more than once in N, then record this fact. +// +//2. In the second pass print a "global let" and then print N +//2. as follows: Every occurence of a node occuring more than +//2. once is replaced with the corresponding let variable. +ostream& ASTNode::PL_Print(ostream &os, int indentation) const +{ + // Clear the PrintMap + BeevMgr& bm = GetBeevMgr(); + bm.PLPrintNodeSet.clear(); + bm.NodeLetVarMap.clear(); + bm.NodeLetVarVec.clear(); + bm.NodeLetVarMap1.clear(); + + //pass 1: letize the node + LetizeNode(); + + //pass 2: // - //1. Check if the node has a corresponding letvar in the - //1. NodeLetVarMap. + //2. print all the let variables and their counterpart expressions + //2. as follows (LET var1 = expr1, var2 = expr2, ... // - //2. if no, then create a new var and add it to the - //2. NodeLetVarMap - if(bm.NodeLetVarMap.find(ccc) == bm.NodeLetVarMap.end()) { - //Create a new symbol. Get some name. if it conflicts with a - //declared name, too bad. - int sz = bm.NodeLetVarMap.size(); - ostringstream oss; - oss << "let_k_" << sz; - - ASTNode CurrentSymbol = bm.CreateSymbol(oss.str().c_str()); - CurrentSymbol.SetValueWidth(this->GetValueWidth()); - CurrentSymbol.SetIndexWidth(this->GetIndexWidth()); - /* If for some reason the variable being created here is - * already declared by the user then the printed output will - * not be a legal input to the system. too bad. I refuse to - * check for this. [Vijay is the author of this comment.] - */ - - bm.NodeLetVarMap[ccc] = CurrentSymbol; - std::pair node_letvar_pair(CurrentSymbol,ccc); - bm.NodeLetVarVec.push_back(node_letvar_pair); + //3. Then print the Node itself, replacing every occurence of + //3. expr1 with var1, expr2 with var2, ... + //os << "("; + if (0 < bm.NodeLetVarMap.size()) + { + //ASTNodeMap::iterator it=bm.NodeLetVarMap.begin(); + //ASTNodeMap::iterator itend=bm.NodeLetVarMap.end(); + std::vector >::iterator it = bm.NodeLetVarVec.begin(); + std::vector >::iterator itend = bm.NodeLetVarVec.end(); + + os << "(LET "; + //print the let var first + it->first.PL_Print1(os, indentation, false); + os << " = "; + //print the expr + it->second.PL_Print1(os, indentation, false); + + //update the second map for proper printing of LET + bm.NodeLetVarMap1[it->second] = it->first; + + for (it++; it != itend; it++) + { + os << "," << endl; + //print the let var first + it->first.PL_Print1(os, indentation, false); + os << " = "; + //print the expr + it->second.PL_Print1(os, indentation, false); + + //update the second map for proper printing of LET + bm.NodeLetVarMap1[it->second] = it->first; + } + + os << " IN " << endl; + PL_Print1(os, indentation, true); + os << ") "; + } + else + PL_Print1(os, indentation, false); + //os << " )"; + os << " "; + return os; +} //end of PL_Print() + +//traverse "*this", and construct "let variables" for terms that +//occur more than once in "*this". +void ASTNode::LetizeNode(void) const +{ + Kind kind = this->GetKind(); + + if (kind == SYMBOL || kind == BVCONST || kind == FALSE || kind == TRUE) + return; + + //FIXME: this is ugly. + BeevMgr& bm = GetBeevMgr(); + const ASTVec &c = this->GetChildren(); + for (ASTVec::const_iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + ASTNode ccc = *it; + if (bm.PLPrintNodeSet.find(ccc) == bm.PLPrintNodeSet.end()) + { + //If branch: if *it is not in NodeSet then, + // + //1. add it to NodeSet + // + //2. Letize its childNodes + + //FIXME: Fetching BeevMgr is annoying. Can we put this in + //some kind of a printer class + bm.PLPrintNodeSet.insert(ccc); + //debugging + //cerr << ccc; + ccc.LetizeNode(); + } + else + { + Kind k = ccc.GetKind(); + if (k == SYMBOL || k == BVCONST || k == FALSE || k == TRUE) + continue; + + //0. Else branch: Node has been seen before + // + //1. Check if the node has a corresponding letvar in the + //1. NodeLetVarMap. + // + //2. if no, then create a new var and add it to the + //2. NodeLetVarMap + if (bm.NodeLetVarMap.find(ccc) == bm.NodeLetVarMap.end()) + { + //Create a new symbol. Get some name. if it conflicts with a + //declared name, too bad. + int sz = bm.NodeLetVarMap.size(); + ostringstream oss; + oss << "let_k_" << sz; + + ASTNode CurrentSymbol = bm.CreateSymbol(oss.str().c_str()); + CurrentSymbol.SetValueWidth(this->GetValueWidth()); + CurrentSymbol.SetIndexWidth(this->GetIndexWidth()); + /* If for some reason the variable being created here is + * already declared by the user then the printed output will + * not be a legal input to the system. too bad. I refuse to + * check for this. [Vijay is the author of this comment.] + */ + + bm.NodeLetVarMap[ccc] = CurrentSymbol; + std::pair node_letvar_pair(CurrentSymbol, ccc); + bm.NodeLetVarVec.push_back(node_letvar_pair); + } + } + } +} //end of LetizeNode() + +void ASTNode::PL_Print1(ostream& os, int indentation, bool letize) const +{ + //os << spaces(indentation); + //os << endl << spaces(indentation); + if (!IsDefined()) + { + os << ""; + return; + } + + //if this node is present in the letvar Map, then print the letvar + BeevMgr &bm = GetBeevMgr(); + + //this is to print letvars for shared subterms inside the printing + //of "(LET v0 = term1, v1=term1@term2,... + if ((bm.NodeLetVarMap1.find(*this) != bm.NodeLetVarMap1.end()) && !letize) + { + (bm.NodeLetVarMap1[*this]).PL_Print1(os, indentation, letize); + return; } - } - } - } //end of LetizeNode() - - void ASTNode::PL_Print1(ostream& os, - int indentation, - bool letize) const { - //os << spaces(indentation); - //os << endl << spaces(indentation); - if (!IsDefined()) { - os << ""; - return; - } - - //if this node is present in the letvar Map, then print the letvar - BeevMgr &bm = GetBeevMgr(); - - //this is to print letvars for shared subterms inside the printing - //of "(LET v0 = term1, v1=term1@term2,... - if((bm.NodeLetVarMap1.find(*this) != bm.NodeLetVarMap1.end()) && !letize) { - (bm.NodeLetVarMap1[*this]).PL_Print1(os,indentation,letize); - return; - } - - //this is to print letvars for shared subterms inside the actual - //term to be printed - if((bm.NodeLetVarMap.find(*this) != bm.NodeLetVarMap.end()) && letize) { - (bm.NodeLetVarMap[*this]).PL_Print1(os,indentation,letize); - return; - } - - //otherwise print it normally - Kind kind = GetKind(); - const ASTVec &c = GetChildren(); - switch(kind) { - case BVGETBIT: - c[0].PL_Print1(os,indentation,letize); - os << "{"; - c[1].PL_Print1(os,indentation,letize); - os << "}"; - break; - case BITVECTOR: - os << "BITVECTOR("; - unsigned char * str; - str = CONSTANTBV::BitVector_to_Hex(c[0].GetBVConst()); - os << str << ")"; - CONSTANTBV::BitVector_Dispose(str); - break; - case BOOLEAN: - os << "BOOLEAN"; - break; - case FALSE: - case TRUE: - os << kind; - break; - case BVCONST: - case SYMBOL: - _int_node_ptr->nodeprint(os); - break; - case READ: - c[0].PL_Print1(os, indentation,letize); - os << "["; - c[1].PL_Print1(os,indentation,letize); - os << "]"; - break; - case WRITE: - os << "("; - c[0].PL_Print1(os,indentation,letize); - os << " WITH ["; - c[1].PL_Print1(os,indentation,letize); - os << "] := "; - c[2].PL_Print1(os,indentation,letize); - os << ")"; - os << endl; - break; - case BVUMINUS: - os << kind << "( "; - c[0].PL_Print1(os,indentation,letize); - os << ")"; - break; - case NOT: - os << "NOT("; - c[0].PL_Print1(os,indentation,letize); - os << ") " << endl; - break; - case BVNEG: - os << " ~("; - c[0].PL_Print1(os,indentation,letize); - os << ")"; - break; - case BVCONCAT: - os << "("; - c[0].PL_Print1(os,indentation,letize); - os << " @ "; - c[1].PL_Print1(os,indentation,letize); - os << ")" << endl; - break; - case BVOR: - os << "("; - c[0].PL_Print1(os,indentation,letize); - os << " | "; - c[1].PL_Print1(os,indentation,letize); - os << ")"; - break; - case BVAND: - os << "("; - c[0].PL_Print1(os,indentation,letize); - os << " & "; - c[1].PL_Print1(os,indentation,letize); - os << ")"; - break; - case BVEXTRACT: - c[0].PL_Print1(os,indentation,letize); - os << "["; - os << GetUnsignedConst(c[1]); - os << ":"; - os << GetUnsignedConst(c[2]); - os << "]"; - break; - case BVLEFTSHIFT: - os << "("; - c[0].PL_Print1(os,indentation,letize); - os << " << "; - os << GetUnsignedConst(c[1]); - os << ")"; - break; - case BVRIGHTSHIFT: - os << "("; - c[0].PL_Print1(os,indentation,letize); - os << " >> "; - os << GetUnsignedConst(c[1]); - os << ")"; - break; - case BVMULT: - case BVSUB: - case BVPLUS: - case SBVDIV: - case SBVREM: - case BVDIV: - case BVMOD: - os << kind << "("; - os << this->GetValueWidth(); - for(ASTVec::const_iterator it=c.begin(),itend=c.end();it!=itend;it++) { - os << ", " << endl; - it->PL_Print1(os,indentation,letize); - } - os << ")" << endl; - break; - case ITE: - os << "IF("; - c[0].PL_Print1(os,indentation,letize); - os << ")" << endl; - os << "THEN "; - c[1].PL_Print1(os,indentation,letize); - os << endl << "ELSE "; - c[2].PL_Print1(os,indentation,letize); - os << endl << "ENDIF"; - break; - case BVLT: - case BVLE: - case BVGT: - case BVGE: - case BVXOR: - case BVNAND: - case BVNOR: - case BVXNOR: - os << kind << "("; - c[0].PL_Print1(os,indentation,letize); - os << ","; - c[1].PL_Print1(os,indentation,letize); - os << ")" << endl; - break; - case BVSLT: - os << "SBVLT" << "("; - c[0].PL_Print1(os,indentation,letize); - os << ","; - c[1].PL_Print1(os,indentation,letize); - os << ")" << endl; - break; - case BVSLE: - os << "SBVLE" << "("; - c[0].PL_Print1(os,indentation,letize); - os << ","; - c[1].PL_Print1(os,indentation,letize); - os << ")" << endl; - break; - case BVSGT: - os << "SBVGT" << "("; - c[0].PL_Print1(os,indentation,letize); - os << ","; - c[1].PL_Print1(os,indentation,letize); - os << ")" << endl; - break; - case BVSGE: - os << "SBVGE" << "("; - c[0].PL_Print1(os,indentation,letize); - os << ","; - c[1].PL_Print1(os,indentation,letize); - os << ")" << endl; - break; - case EQ: - c[0].PL_Print1(os,indentation,letize); - os << " = "; - c[1].PL_Print1(os,indentation,letize); - os << endl; - break; - case NEQ: - c[0].PL_Print1(os,indentation,letize); - os << " /= "; - c[1].PL_Print1(os,indentation,letize); - os << endl; - break; - case AND: - case OR: - case NAND: - case NOR: - case XOR: { - os << "("; - c[0].PL_Print1(os,indentation,letize); - ASTVec::const_iterator it=c.begin(); - ASTVec::const_iterator itend=c.end(); - - it++; - for(;it!=itend;it++) { - os << " " << kind << " "; - it->PL_Print1(os,indentation,letize); - os << endl; - } - os << ")"; - break; - } - case IFF: - os << "("; - os << "("; - c[0].PL_Print1(os,indentation,letize); - os << ")"; - os << " <=> "; - os << "("; - c[1].PL_Print1(os,indentation,letize); - os << ")"; - os << ")"; - os << endl; - break; - case IMPLIES: - os << "("; - os << "("; - c[0].PL_Print1(os,indentation,letize); - os << ")"; - os << " => "; - os << "("; - c[1].PL_Print1(os,indentation,letize); - os << ")"; - os << ")"; - os << endl; - break; - case BVSX: - case BVZX: - os << kind << "("; - c[0].PL_Print1(os,indentation,letize); - os << ","; - os << this->GetValueWidth(); - os << ")" << endl; - break; - default: - //remember to use LispPrinter here. Otherwise this function will - //go into an infinite loop. Recall that "<<" is overloaded to - //the lisp printer. FatalError uses lispprinter - FatalError("PL_Print1: printing not implemented for this kind: ",*this); - break; - } - } //end of PL_Print1() - - //////////////////////////////////////////////////////////////// - // BeevMgr members - //////////////////////////////////////////////////////////////// - ASTNode BeevMgr::CreateNode(Kind kind, const ASTVec & back_children) { - // create a new node. Children will be modified. - ASTInterior *n_ptr = new ASTInterior(kind, *this); - - // insert all of children at end of new_children. - ASTNode n(CreateInteriorNode(kind, n_ptr, back_children)); - return n; - } - - ASTNode BeevMgr::CreateNode(Kind kind, - const ASTNode& child0, - const ASTVec & back_children) { - - ASTInterior *n_ptr = new ASTInterior(kind, *this); - ASTVec &front_children = n_ptr->_children; - front_children.push_back(child0); - ASTNode n(CreateInteriorNode(kind, n_ptr, back_children)); - return n; - } - - ASTNode BeevMgr::CreateNode(Kind kind, - const ASTNode& child0, - const ASTNode& child1, - const ASTVec & back_children) { - - ASTInterior *n_ptr = new ASTInterior(kind, *this); - ASTVec &front_children = n_ptr->_children; - front_children.push_back(child0); - front_children.push_back(child1); - ASTNode n(CreateInteriorNode(kind, n_ptr, back_children)); - return n; - } - - - ASTNode BeevMgr::CreateNode(Kind kind, - const ASTNode& child0, - const ASTNode& child1, - const ASTNode& child2, - const ASTVec & back_children) { - ASTInterior *n_ptr = new ASTInterior(kind, *this); - ASTVec &front_children = n_ptr->_children; - front_children.push_back(child0); - front_children.push_back(child1); - front_children.push_back(child2); - ASTNode n(CreateInteriorNode(kind, n_ptr, back_children)); - return n; - } - - - ASTInterior *BeevMgr::CreateInteriorNode(Kind kind, - // children array of this node will be modified. - ASTInterior *n_ptr, - const ASTVec & back_children) { - - // insert back_children at end of front_children - ASTVec &front_children = n_ptr->_children; - - front_children.insert(front_children.end(), back_children.begin(), back_children.end()); - - // check for undefined nodes. - ASTVec::const_iterator it_end = front_children.end(); - for (ASTVec::const_iterator it = front_children.begin(); it != it_end; it++) { - if (it->IsNull()) - FatalError("CreateInteriorNode: Undefined childnode in CreateInteriorNode: ", ASTUndefined); - } - - return LookupOrCreateInterior(n_ptr); - } - - /** Trivial but virtual destructor */ - ASTSymbol::~ASTSymbol() {} - - ostream &operator<<(ostream &os, const ASTNodeMap &nmap) - { - ASTNodeMap::const_iterator iend = nmap.end(); - for (ASTNodeMap::const_iterator i = nmap.begin(); i!=iend; i++) { - os << "Key: " << i->first << endl; - os << "Value: " << i->second << endl; - } - return os; - } - - //////////////////////////////////////////////////////////////// - // BeevMgr member functions to create ASTSymbol and ASTBVConst - //////////////////////////////////////////////////////////////// - ASTNode BeevMgr::CreateSymbol(const char * const name) - { - ASTSymbol temp_sym(name, *this); - ASTNode n(LookupOrCreateSymbol(temp_sym)); - return n; - } + + //this is to print letvars for shared subterms inside the actual + //term to be printed + if ((bm.NodeLetVarMap.find(*this) != bm.NodeLetVarMap.end()) && letize) + { + (bm.NodeLetVarMap[*this]).PL_Print1(os, indentation, letize); + return; + } + + //otherwise print it normally + Kind kind = GetKind(); + const ASTVec &c = GetChildren(); + switch (kind) + { + case BVGETBIT: + c[0].PL_Print1(os, indentation, letize); + os << "{"; + c[1].PL_Print1(os, indentation, letize); + os << "}"; + break; + case BITVECTOR: + os << "BITVECTOR("; + unsigned char * str; + str = CONSTANTBV::BitVector_to_Hex(c[0].GetBVConst()); + os << str << ")"; + CONSTANTBV::BitVector_Dispose(str); + break; + case BOOLEAN: + os << "BOOLEAN"; + break; + case FALSE: + case TRUE: + os << kind; + break; + case BVCONST: + case SYMBOL: + _int_node_ptr->nodeprint(os); + break; + case READ: + c[0].PL_Print1(os, indentation, letize); + os << "["; + c[1].PL_Print1(os, indentation, letize); + os << "]"; + break; + case WRITE: + os << "("; + c[0].PL_Print1(os, indentation, letize); + os << " WITH ["; + c[1].PL_Print1(os, indentation, letize); + os << "] := "; + c[2].PL_Print1(os, indentation, letize); + os << ")"; + os << endl; + break; + case BVUMINUS: + os << kind << "( "; + c[0].PL_Print1(os, indentation, letize); + os << ")"; + break; + case NOT: + os << "NOT("; + c[0].PL_Print1(os, indentation, letize); + os << ") " << endl; + break; + case BVNEG: + os << " ~("; + c[0].PL_Print1(os, indentation, letize); + os << ")"; + break; + case BVCONCAT: + os << "("; + c[0].PL_Print1(os, indentation, letize); + os << " @ "; + c[1].PL_Print1(os, indentation, letize); + os << ")" << endl; + break; + case BVOR: + os << "("; + c[0].PL_Print1(os, indentation, letize); + os << " | "; + c[1].PL_Print1(os, indentation, letize); + os << ")"; + break; + case BVAND: + os << "("; + c[0].PL_Print1(os, indentation, letize); + os << " & "; + c[1].PL_Print1(os, indentation, letize); + os << ")"; + break; + case BVEXTRACT: + c[0].PL_Print1(os, indentation, letize); + os << "["; + os << GetUnsignedConst(c[1]); + os << ":"; + os << GetUnsignedConst(c[2]); + os << "]"; + break; + case BVLEFTSHIFT: + os << "("; + c[0].PL_Print1(os, indentation, letize); + os << " << "; + os << GetUnsignedConst(c[1]); + os << ")"; + break; + case BVRIGHTSHIFT: + os << "("; + c[0].PL_Print1(os, indentation, letize); + os << " >> "; + os << GetUnsignedConst(c[1]); + os << ")"; + break; + case BVMULT: + case BVSUB: + case BVPLUS: + case SBVDIV: + case SBVREM: + case BVDIV: + case BVMOD: + os << kind << "("; + os << this->GetValueWidth(); + for (ASTVec::const_iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + os << ", " << endl; + it->PL_Print1(os, indentation, letize); + } + os << ")" << endl; + break; + case ITE: + os << "IF("; + c[0].PL_Print1(os, indentation, letize); + os << ")" << endl; + os << "THEN "; + c[1].PL_Print1(os, indentation, letize); + os << endl << "ELSE "; + c[2].PL_Print1(os, indentation, letize); + os << endl << "ENDIF"; + break; + case BVLT: + case BVLE: + case BVGT: + case BVGE: + case BVXOR: + case BVNAND: + case BVNOR: + case BVXNOR: + os << kind << "("; + c[0].PL_Print1(os, indentation, letize); + os << ","; + c[1].PL_Print1(os, indentation, letize); + os << ")" << endl; + break; + case BVSLT: + os << "SBVLT" << "("; + c[0].PL_Print1(os, indentation, letize); + os << ","; + c[1].PL_Print1(os, indentation, letize); + os << ")" << endl; + break; + case BVSLE: + os << "SBVLE" << "("; + c[0].PL_Print1(os, indentation, letize); + os << ","; + c[1].PL_Print1(os, indentation, letize); + os << ")" << endl; + break; + case BVSGT: + os << "SBVGT" << "("; + c[0].PL_Print1(os, indentation, letize); + os << ","; + c[1].PL_Print1(os, indentation, letize); + os << ")" << endl; + break; + case BVSGE: + os << "SBVGE" << "("; + c[0].PL_Print1(os, indentation, letize); + os << ","; + c[1].PL_Print1(os, indentation, letize); + os << ")" << endl; + break; + case EQ: + c[0].PL_Print1(os, indentation, letize); + os << " = "; + c[1].PL_Print1(os, indentation, letize); + os << endl; + break; + case NEQ: + c[0].PL_Print1(os, indentation, letize); + os << " /= "; + c[1].PL_Print1(os, indentation, letize); + os << endl; + break; + case AND: + case OR: + case NAND: + case NOR: + case XOR: + { + os << "("; + c[0].PL_Print1(os, indentation, letize); + ASTVec::const_iterator it = c.begin(); + ASTVec::const_iterator itend = c.end(); + + it++; + for (; it != itend; it++) + { + os << " " << kind << " "; + it->PL_Print1(os, indentation, letize); + os << endl; + } + os << ")"; + break; + } + case IFF: + os << "("; + os << "("; + c[0].PL_Print1(os, indentation, letize); + os << ")"; + os << " <=> "; + os << "("; + c[1].PL_Print1(os, indentation, letize); + os << ")"; + os << ")"; + os << endl; + break; + case IMPLIES: + os << "("; + os << "("; + c[0].PL_Print1(os, indentation, letize); + os << ")"; + os << " => "; + os << "("; + c[1].PL_Print1(os, indentation, letize); + os << ")"; + os << ")"; + os << endl; + break; + case BVSX: + case BVZX: + os << kind << "("; + c[0].PL_Print1(os, indentation, letize); + os << ","; + os << this->GetValueWidth(); + os << ")" << endl; + break; + default: + //remember to use LispPrinter here. Otherwise this function will + //go into an infinite loop. Recall that "<<" is overloaded to + //the lisp printer. FatalError uses lispprinter + FatalError("PL_Print1: printing not implemented for this kind: ", *this); + break; + } +} //end of PL_Print1() + +//////////////////////////////////////////////////////////////// +// BeevMgr members +//////////////////////////////////////////////////////////////// +ASTNode BeevMgr::CreateNode(Kind kind, const ASTVec & back_children) +{ + // create a new node. Children will be modified. + ASTInterior *n_ptr = new ASTInterior(kind, *this); + + // insert all of children at end of new_children. + ASTNode n(CreateInteriorNode(kind, n_ptr, back_children)); + return n; +} + +ASTNode BeevMgr::CreateNode(Kind kind, const ASTNode& child0, const ASTVec & back_children) +{ + + ASTInterior *n_ptr = new ASTInterior(kind, *this); + ASTVec &front_children = n_ptr->_children; + front_children.push_back(child0); + ASTNode n(CreateInteriorNode(kind, n_ptr, back_children)); + return n; +} + +ASTNode BeevMgr::CreateNode(Kind kind, const ASTNode& child0, const ASTNode& child1, const ASTVec & back_children) +{ + + ASTInterior *n_ptr = new ASTInterior(kind, *this); + ASTVec &front_children = n_ptr->_children; + front_children.push_back(child0); + front_children.push_back(child1); + ASTNode n(CreateInteriorNode(kind, n_ptr, back_children)); + return n; +} + +ASTNode BeevMgr::CreateNode(Kind kind, const ASTNode& child0, const ASTNode& child1, const ASTNode& child2, const ASTVec & back_children) +{ + ASTInterior *n_ptr = new ASTInterior(kind, *this); + ASTVec &front_children = n_ptr->_children; + front_children.push_back(child0); + front_children.push_back(child1); + front_children.push_back(child2); + ASTNode n(CreateInteriorNode(kind, n_ptr, back_children)); + return n; +} + +ASTInterior *BeevMgr::CreateInteriorNode(Kind kind, +// children array of this node will be modified. + ASTInterior *n_ptr, + const ASTVec & back_children) +{ + + // insert back_children at end of front_children + ASTVec &front_children = n_ptr->_children; + + front_children.insert(front_children.end(), back_children.begin(), back_children.end()); + + // check for undefined nodes. + ASTVec::const_iterator it_end = front_children.end(); + for (ASTVec::const_iterator it = front_children.begin(); it != it_end; it++) + { + if (it->IsNull()) + FatalError("CreateInteriorNode: Undefined childnode in CreateInteriorNode: ", ASTUndefined); + } + + return LookupOrCreateInterior(n_ptr); +} + +/** Trivial but virtual destructor */ +ASTSymbol::~ASTSymbol() +{ +} + +ostream &operator<<(ostream &os, const ASTNodeMap &nmap) +{ + ASTNodeMap::const_iterator iend = nmap.end(); + for (ASTNodeMap::const_iterator i = nmap.begin(); i != iend; i++) + { + os << "Key: " << i->first << endl; + os << "Value: " << i->second << endl; + } + return os; +} + +//////////////////////////////////////////////////////////////// +// BeevMgr member functions to create ASTSymbol and ASTBVConst +//////////////////////////////////////////////////////////////// +ASTNode BeevMgr::CreateSymbol(const char * const name) +{ + ASTSymbol temp_sym(name, *this); + ASTNode n(LookupOrCreateSymbol(temp_sym)); + return n; +} #ifndef NATIVE_C_ARITH - //Create a ASTBVConst node - ASTNode BeevMgr::CreateBVConst(unsigned int width, - unsigned long long int bvconst){ - if(width > (sizeof(unsigned long long int)<<3) || width <= 0) - FatalError("CreateBVConst: trying to create a bvconst of width: ", ASTUndefined, width); - - - CBV bv = CONSTANTBV::BitVector_Create(width, true); - unsigned long c_val = (~((unsigned long)0)) & bvconst; - unsigned int copied = 0; - - // sizeof(unsigned long) returns the number of bytes in unsigned - // long. In order to convert it to bits, we need to shift left by - // 3. Hence, sizeof(unsigned long) << 3 - - //The algo below works as follows: It starts by copying the - //lower-order bits of the input "bvconst" in chunks of size = - //number of bits in unsigned long. The variable "copied" keeps - //track of the number of chunks copied so far - - while(copied + (sizeof(unsigned long)<<3) < width){ - CONSTANTBV::BitVector_Chunk_Store(bv, sizeof(unsigned long)<<3,copied,c_val); - bvconst = bvconst >> (sizeof(unsigned long) << 3); - c_val = (~((unsigned long)0)) & bvconst; - copied += sizeof(unsigned long) << 3; - } - CONSTANTBV::BitVector_Chunk_Store(bv,width - copied,copied,c_val); - return CreateBVConst(bv,width); - } - - ASTNode BeevMgr::CreateBVConst(string*& strval, int base, int bit_width) { - - if(!(2 == base || 10 == base || 16 == base)) - { - FatalError("CreateBVConst: unsupported base: ",ASTUndefined,base); - } - - //checking if the input is in the correct format - CBV bv = CONSTANTBV::BitVector_Create(bit_width,true); - CONSTANTBV::ErrCode e; - if(2 == base){ - e = CONSTANTBV::BitVector_from_Bin(bv, (unsigned char*) strval->c_str()); - }else if(10 == base){ - e = CONSTANTBV::BitVector_from_Dec(bv, (unsigned char*) strval->c_str()); - }else if(16 == base){ - e = CONSTANTBV::BitVector_from_Hex(bv, (unsigned char*) strval->c_str()); - }else{ - e = CONSTANTBV::ErrCode_Pars; - } - - if(0 != e) { - cerr << "CreateBVConst: " << BitVector_Error(e); - FatalError("",ASTUndefined); - } - - return CreateBVConst(bv, bit_width); - } - - - - //Create a ASTBVConst node from std::string - ASTNode BeevMgr::CreateBVConst(const char* const strval, int base) { - size_t width = strlen((const char *)strval); - if(!(2 == base || 10 == base || 16 == base)){ - FatalError("CreateBVConst: unsupported base: ",ASTUndefined,base); - } - //FIXME Tim: Earlier versions of the code assume that the length of - //binary strings is 32 bits. - if(10 == base) width = 32; - if(16 == base) width = width * 4; - - //checking if the input is in the correct format - CBV bv = CONSTANTBV::BitVector_Create(width,true); - CONSTANTBV::ErrCode e; - if(2 == base){ - e = CONSTANTBV::BitVector_from_Bin(bv, (unsigned char*)strval); - }else if(10 == base){ - e = CONSTANTBV::BitVector_from_Dec(bv, (unsigned char*)strval); - }else if(16 == base){ - e = CONSTANTBV::BitVector_from_Hex(bv, (unsigned char*)strval); - }else{ - e = CONSTANTBV::ErrCode_Pars; - } - - if(0 != e) { - cerr << "CreateBVConst: " << BitVector_Error(e); - FatalError("",ASTUndefined); - } - - //FIXME - return CreateBVConst(bv, width); - } - - - //FIXME Code currently assumes that it will destroy the bitvector passed to it - ASTNode BeevMgr::CreateBVConst(CBV bv, unsigned width){ - ASTBVConst temp_bvconst(bv, width, *this); - ASTNode n(LookupOrCreateBVConst(temp_bvconst)); - - CONSTANTBV::BitVector_Destroy(bv); - - return n; - } - - ASTNode BeevMgr::CreateZeroConst(unsigned width) { - CBV z = CONSTANTBV::BitVector_Create(width, true); - return CreateBVConst(z, width); - } - - ASTNode BeevMgr::CreateOneConst(unsigned width) { - CBV o = CONSTANTBV::BitVector_Create(width, true); - CONSTANTBV::BitVector_increment(o); - - return CreateBVConst(o,width); - } - - ASTNode BeevMgr::CreateTwoConst(unsigned width) { - CBV two = CONSTANTBV::BitVector_Create(width, true); - CONSTANTBV::BitVector_increment(two); - CONSTANTBV::BitVector_increment(two); - - return CreateBVConst(two,width); - } - - ASTNode BeevMgr::CreateMaxConst(unsigned width) { - CBV max = CONSTANTBV::BitVector_Create(width, false); - CONSTANTBV::BitVector_Fill(max); - - return CreateBVConst(max,width); - } - - //To ensure unique BVConst nodes, lookup the node in unique-table - //before creating a new one. - ASTBVConst *BeevMgr::LookupOrCreateBVConst(ASTBVConst &s) { - ASTBVConst *s_ptr = &s; // it's a temporary key. - - // Do an explicit lookup to see if we need to create a copy of the string. - ASTBVConstSet::const_iterator it; - if ((it = _bvconst_unique_table.find(s_ptr)) == _bvconst_unique_table.end()) { - // Make a new ASTBVConst with duplicated string (can't assign - // _name because it's const). Can cast the iterator to - // non-const -- carefully. - - ASTBVConst * s_copy = new ASTBVConst(s); - s_copy->SetNodeNum(NewNodeNum()); - - pair p = _bvconst_unique_table.insert(s_copy); - return *p.first; - } - else{ - // return symbol found in table. - return *it; - } - } - - // Inline because we need to wait until unique_table is defined - void ASTBVConst::CleanUp() { - // cout << "Deleting node " << this->GetNodeNum() << endl; - _bm._bvconst_unique_table.erase(this); - delete this; - } - - // Get the value of bvconst from a bvconst. It's an error if kind != BVCONST - CBV const ASTNode::GetBVConst() const { - if(GetKind() != BVCONST) - FatalError("GetBVConst: non bitvector-constant: ",*this); - return ((ASTBVConst *) _int_node_ptr)->GetBVConst(); - } +//Create a ASTBVConst node +ASTNode BeevMgr::CreateBVConst(unsigned int width, unsigned long long int bvconst) +{ + if (width > (sizeof(unsigned long long int) << 3) || width <= 0) + FatalError("CreateBVConst: trying to create a bvconst of width: ", ASTUndefined, width); + + CBV bv = CONSTANTBV::BitVector_Create(width, true); + unsigned long c_val = (~((unsigned long) 0)) & bvconst; + unsigned int copied = 0; + + // sizeof(unsigned long) returns the number of bytes in unsigned + // long. In order to convert it to bits, we need to shift left by + // 3. Hence, sizeof(unsigned long) << 3 + + //The algo below works as follows: It starts by copying the + //lower-order bits of the input "bvconst" in chunks of size = + //number of bits in unsigned long. The variable "copied" keeps + //track of the number of chunks copied so far + + while (copied + (sizeof(unsigned long) << 3) < width) + { + CONSTANTBV::BitVector_Chunk_Store(bv, sizeof(unsigned long) << 3, copied, c_val); + bvconst = bvconst >> (sizeof(unsigned long) << 3); + c_val = (~((unsigned long) 0)) & bvconst; + copied += sizeof(unsigned long) << 3; + } + CONSTANTBV::BitVector_Chunk_Store(bv, width - copied, copied, c_val); + return CreateBVConst(bv, width); +} + +ASTNode BeevMgr::CreateBVConst(string*& strval, int base, int bit_width) +{ + + if (!(2 == base || 10 == base || 16 == base)) + { + FatalError("CreateBVConst: unsupported base: ", ASTUndefined, base); + } + + //checking if the input is in the correct format + CBV bv = CONSTANTBV::BitVector_Create(bit_width, true); + CONSTANTBV::ErrCode e; + if (2 == base) + { + e = CONSTANTBV::BitVector_from_Bin(bv, (unsigned char*) strval->c_str()); + } + else if (10 == base) + { + e = CONSTANTBV::BitVector_from_Dec(bv, (unsigned char*) strval->c_str()); + } + else if (16 == base) + { + e = CONSTANTBV::BitVector_from_Hex(bv, (unsigned char*) strval->c_str()); + } + else + { + e = CONSTANTBV::ErrCode_Pars; + } + + if (0 != e) + { + cerr << "CreateBVConst: " << BitVector_Error(e); + FatalError("", ASTUndefined); + } + + return CreateBVConst(bv, bit_width); +} + +//Create a ASTBVConst node from std::string +ASTNode BeevMgr::CreateBVConst(const char* const strval, int base) +{ + size_t width = strlen((const char *) strval); + if (!(2 == base || 10 == base || 16 == base)) + { + FatalError("CreateBVConst: unsupported base: ", ASTUndefined, base); + } + //FIXME Tim: Earlier versions of the code assume that the length of + //binary strings is 32 bits. + if (10 == base) + width = 32; + if (16 == base) + width = width * 4; + + //checking if the input is in the correct format + CBV bv = CONSTANTBV::BitVector_Create(width, true); + CONSTANTBV::ErrCode e; + if (2 == base) + { + e = CONSTANTBV::BitVector_from_Bin(bv, (unsigned char*) strval); + } + else if (10 == base) + { + e = CONSTANTBV::BitVector_from_Dec(bv, (unsigned char*) strval); + } + else if (16 == base) + { + e = CONSTANTBV::BitVector_from_Hex(bv, (unsigned char*) strval); + } + else + { + e = CONSTANTBV::ErrCode_Pars; + } + + if (0 != e) + { + cerr << "CreateBVConst: " << BitVector_Error(e); + FatalError("", ASTUndefined); + } + + //FIXME + return CreateBVConst(bv, width); +} + +//FIXME Code currently assumes that it will destroy the bitvector passed to it +ASTNode BeevMgr::CreateBVConst(CBV bv, unsigned width) +{ + ASTBVConst temp_bvconst(bv, width, *this); + ASTNode n(LookupOrCreateBVConst(temp_bvconst)); + + CONSTANTBV::BitVector_Destroy(bv); + + return n; +} + +ASTNode BeevMgr::CreateZeroConst(unsigned width) +{ + CBV z = CONSTANTBV::BitVector_Create(width, true); + return CreateBVConst(z, width); +} + +ASTNode BeevMgr::CreateOneConst(unsigned width) +{ + CBV o = CONSTANTBV::BitVector_Create(width, true); + CONSTANTBV::BitVector_increment(o); + + return CreateBVConst(o, width); +} + +ASTNode BeevMgr::CreateTwoConst(unsigned width) +{ + CBV two = CONSTANTBV::BitVector_Create(width, true); + CONSTANTBV::BitVector_increment(two); + CONSTANTBV::BitVector_increment(two); + + return CreateBVConst(two, width); +} + +ASTNode BeevMgr::CreateMaxConst(unsigned width) +{ + CBV max = CONSTANTBV::BitVector_Create(width, false); + CONSTANTBV::BitVector_Fill(max); + + return CreateBVConst(max, width); +} + +//To ensure unique BVConst nodes, lookup the node in unique-table +//before creating a new one. +ASTBVConst *BeevMgr::LookupOrCreateBVConst(ASTBVConst &s) +{ + ASTBVConst *s_ptr = &s; // it's a temporary key. + + // Do an explicit lookup to see if we need to create a copy of the string. + ASTBVConstSet::const_iterator it; + if ((it = _bvconst_unique_table.find(s_ptr)) == _bvconst_unique_table.end()) + { + // Make a new ASTBVConst with duplicated string (can't assign + // _name because it's const). Can cast the iterator to + // non-const -- carefully. + + ASTBVConst * s_copy = new ASTBVConst(s); + s_copy->SetNodeNum(NewNodeNum()); + + pair p = _bvconst_unique_table.insert(s_copy); + return *p.first; + } + else + { + // return symbol found in table. + return *it; + } +} + +// Inline because we need to wait until unique_table is defined +void ASTBVConst::CleanUp() +{ + // cout << "Deleting node " << this->GetNodeNum() << endl; + _bm._bvconst_unique_table.erase(this); + delete this; +} + +// Get the value of bvconst from a bvconst. It's an error if kind != BVCONST +CBV const ASTNode::GetBVConst() const +{ + if (GetKind() != BVCONST) + FatalError("GetBVConst: non bitvector-constant: ", *this); + return ((ASTBVConst *) _int_node_ptr)->GetBVConst(); +} #else - //Create a ASTBVConst node - ASTNode BeevMgr::CreateBVConst(const unsigned int width, - const unsigned long long int bvconst) { - if(width > 64 || width <= 0) - FatalError("Fatal Error: CreateBVConst: trying to create a bvconst of width:", ASTUndefined, width); - - //64 bit mask - unsigned long long int mask = 0xffffffffffffffffLL; - mask = mask >> (64 - width); - - unsigned long long int bv = bvconst; - bv = bv & mask; - - ASTBVConst temp_bvconst(bv, *this); - temp_bvconst._value_width = width; - ASTNode n(LookupOrCreateBVConst(temp_bvconst)); - n.SetValueWidth(width); - n.SetIndexWidth(0); - return n; - } - //Create a ASTBVConst node from std::string - ASTNode BeevMgr::CreateBVConst(const char* strval, int base) { - if(!(base == 2 || base == 16 || base == 10)) - FatalError("CreateBVConst: This base is not supported: ", ASTUndefined, base); - - if(10 != base) { - unsigned int width = (base == 2) ? strlen(strval) : strlen(strval)*4; - unsigned long long int val = strtoull(strval, NULL, base); - ASTNode bvcon = CreateBVConst(width, val); - return bvcon; - } - else { - //this is an ugly hack to accomodate SMTLIB format - //restrictions. SMTLIB format represents bitvector constants in - //base 10 (what a terrible idea, but i have no choice but to - //support it), and make an implicit assumption that the length - //is 32 (another terrible idea). - unsigned width = 32; - unsigned long long int val = strtoull(strval, NULL, base); - ASTNode bvcon = CreateBVConst(width, val); - return bvcon; - } - } - - //To ensure unique BVConst nodes, lookup the node in unique-table - //before creating a new one. - ASTBVConst *BeevMgr::LookupOrCreateBVConst(ASTBVConst &s) { - ASTBVConst *s_ptr = &s; // it's a temporary key. - - // Do an explicit lookup to see if we need to create a copy of the - // string. - ASTBVConstSet::const_iterator it; - if ((it = _bvconst_unique_table.find(s_ptr)) == _bvconst_unique_table.end()) { - // Make a new ASTBVConst. Can cast the iterator to non-const -- - // carefully. - unsigned int width = s_ptr->_value_width; - ASTBVConst * s_ptr1 = new ASTBVConst(s_ptr->GetBVConst(), *this); - s_ptr1->SetNodeNum(NewNodeNum()); - s_ptr1->_value_width = width; - pair p = _bvconst_unique_table.insert(s_ptr1); - return *p.first; - } - else - // return BVConst found in table. - return *it; - } - - // Inline because we need to wait until unique_table is defined - void ASTBVConst::CleanUp() { - // cout << "Deleting node " << this->GetNodeNum() << endl; - _bm._bvconst_unique_table.erase(this); - delete this; - } - - // Get the value of bvconst from a bvconst. It's an error if kind - // != BVCONST - unsigned long long int ASTNode::GetBVConst() const { - if(GetKind() != BVCONST) - FatalError("GetBVConst: non bitvector-constant: ", *this); - return ((ASTBVConstTmp *) _int_node_ptr)->GetBVConst(); - } - - ASTNode BeevMgr::CreateZeroConst(unsigned width) { - return CreateBVConst(width,0); - } - - ASTNode BeevMgr::CreateOneConst(unsigned width) { - return CreateBVConst(width,1); - } - - ASTNode BeevMgr::CreateTwoConst(unsigned width) { - return CreateBVConst(width,2); - } - - ASTNode BeevMgr::CreateMaxConst(unsigned width) { - std::string s; - s.insert(s.end(),width,'1'); - return CreateBVConst(s.c_str(),2); - } - -#endif - - // FIXME: _name is now a constant field, and this assigns to it - // because it tries not to copy the string unless it needs to. How - // do I avoid copying children in ASTInterior? Perhaps I don't! - - // Note: There seems to be a limitation of hash_set, in that insert - // returns a const iterator to the value. That prevents us from - // modifying the name (in a hash-preserving way) after the symbol is - // inserted. FIXME: Is there a way to do this with insert? Need a - // function to make a new object in the middle of insert. Read STL - // documentation. - - ASTSymbol *BeevMgr::LookupOrCreateSymbol(ASTSymbol& s) { - ASTSymbol *s_ptr = &s; // it's a temporary key. - - // Do an explicit lookup to see if we need to create a copy of the string. - ASTSymbolSet::const_iterator it; - if ((it = _symbol_unique_table.find(s_ptr)) == _symbol_unique_table.end()) { - // Make a new ASTSymbol with duplicated string (can't assign - // _name because it's const). Can cast the iterator to - // non-const -- carefully. - //std::string strname(s_ptr->GetName()); - ASTSymbol * s_ptr1 = new ASTSymbol(strdup(s_ptr->GetName()), *this); - s_ptr1->SetNodeNum(NewNodeNum()); - s_ptr1->_value_width = s_ptr->_value_width; - pair p = _symbol_unique_table.insert(s_ptr1); - return *p.first; - } - else - // return symbol found in table. - return *it; - } - - bool BeevMgr::LookupSymbol(ASTSymbol& s) { - ASTSymbol* s_ptr = &s; // it's a temporary key. - - if(_symbol_unique_table.find(s_ptr) == _symbol_unique_table.end()) - return false; - else - return true; - } - - // Inline because we need to wait until unique_table is defined - void ASTSymbol::CleanUp() { - // cout << "Deleting node " << this->GetNodeNum() << endl; - _bm._symbol_unique_table.erase(this); - //FIXME This is a HUGE free to invoke. - //TEST IT! - free((char*) this->_name); - delete this; - } - - //////////////////////////////////////////////////////////////// - // - // IO manipulators for Lisp format printing of AST. - // - //////////////////////////////////////////////////////////////// - - // FIXME: Additional controls - // * Print node numbers (addresses/nums) - // * Printlength limit - // * Printdepth limit - - /** Print a vector of ASTNodes in lisp format */ - ostream &LispPrintVec(ostream &os, const ASTVec &v, int indentation) - { - // Print the children - ASTVec::const_iterator iend = v.end(); - for (ASTVec::const_iterator i = v.begin(); i != iend; i++) { - i->LispPrint_indent(os, indentation); - } - return os; - } - - ostream &LispPrintVecSpecial(ostream &os, const vector &v, int indentation) - { - // Print the children - vector::const_iterator iend = v.end(); - for (vector::const_iterator i = v.begin(); i != iend; i++) { - (*i)->LispPrint_indent(os, indentation); - } - return os; - } - - // FIXME: Made non-ref in the hope that it would work better. - void lp(ASTNode node) - { - cout << lisp(node) << endl; - } - - void lpvec(const ASTVec &vec) - { - vec[0].GetBeevMgr().AlreadyPrintedSet.clear(); - LispPrintVec(cout, vec, 0); - cout << endl; - } - - // Copy constructor. Maintain _ref_count - ASTNode::ASTNode(const ASTNode &n) : _int_node_ptr(n._int_node_ptr) { -#ifndef SMTLIB - if (n._int_node_ptr) { - n._int_node_ptr->IncRef(); - } +//Create a ASTBVConst node +ASTNode BeevMgr::CreateBVConst(const unsigned int width, + const unsigned long long int bvconst) +{ + if(width > 64 || width <= 0) + FatalError("Fatal Error: CreateBVConst: trying to create a bvconst of width:", ASTUndefined, width); + + //64 bit mask + unsigned long long int mask = 0xffffffffffffffffLL; + mask = mask >> (64 - width); + + unsigned long long int bv = bvconst; + bv = bv & mask; + + ASTBVConst temp_bvconst(bv, *this); + temp_bvconst._value_width = width; + ASTNode n(LookupOrCreateBVConst(temp_bvconst)); + n.SetValueWidth(width); + n.SetIndexWidth(0); + return n; +} +//Create a ASTBVConst node from std::string +ASTNode BeevMgr::CreateBVConst(const char* strval, int base) +{ + if(!(base == 2 || base == 16 || base == 10)) + FatalError("CreateBVConst: This base is not supported: ", ASTUndefined, base); + + if(10 != base) + { + unsigned int width = (base == 2) ? strlen(strval) : strlen(strval)*4; + unsigned long long int val = strtoull(strval, NULL, base); + ASTNode bvcon = CreateBVConst(width, val); + return bvcon; + } + else + { + //this is an ugly hack to accomodate SMTLIB format + //restrictions. SMTLIB format represents bitvector constants in + //base 10 (what a terrible idea, but i have no choice but to + //support it), and make an implicit assumption that the length + //is 32 (another terrible idea). + unsigned width = 32; + unsigned long long int val = strtoull(strval, NULL, base); + ASTNode bvcon = CreateBVConst(width, val); + return bvcon; + } +} + +//To ensure unique BVConst nodes, lookup the node in unique-table +//before creating a new one. +ASTBVConst *BeevMgr::LookupOrCreateBVConst(ASTBVConst &s) +{ + ASTBVConst *s_ptr = &s; // it's a temporary key. + + // Do an explicit lookup to see if we need to create a copy of the + // string. + ASTBVConstSet::const_iterator it; + if ((it = _bvconst_unique_table.find(s_ptr)) == _bvconst_unique_table.end()) + { + // Make a new ASTBVConst. Can cast the iterator to non-const -- + // carefully. + unsigned int width = s_ptr->_value_width; + ASTBVConst * s_ptr1 = new ASTBVConst(s_ptr->GetBVConst(), *this); + s_ptr1->SetNodeNum(NewNodeNum()); + s_ptr1->_value_width = width; + pair p = _bvconst_unique_table.insert(s_ptr1); + return *p.first; + } + else + // return BVConst found in table. + return *it; +} + +// Inline because we need to wait until unique_table is defined +void ASTBVConst::CleanUp() +{ + // cout << "Deleting node " << this->GetNodeNum() << endl; + _bm._bvconst_unique_table.erase(this); + delete this; +} + +// Get the value of bvconst from a bvconst. It's an error if kind +// != BVCONST +unsigned long long int ASTNode::GetBVConst() const +{ + if(GetKind() != BVCONST) + FatalError("GetBVConst: non bitvector-constant: ", *this); + return ((ASTBVConstTmp *) _int_node_ptr)->GetBVConst(); +} + +ASTNode BeevMgr::CreateZeroConst(unsigned width) +{ + return CreateBVConst(width,0); +} + +ASTNode BeevMgr::CreateOneConst(unsigned width) +{ + return CreateBVConst(width,1); +} + +ASTNode BeevMgr::CreateTwoConst(unsigned width) +{ + return CreateBVConst(width,2); +} + +ASTNode BeevMgr::CreateMaxConst(unsigned width) +{ + std::string s; + s.insert(s.end(),width,'1'); + return CreateBVConst(s.c_str(),2); +} + +#endif + +// FIXME: _name is now a constant field, and this assigns to it +// because it tries not to copy the string unless it needs to. How +// do I avoid copying children in ASTInterior? Perhaps I don't! + +// Note: There seems to be a limitation of hash_set, in that insert +// returns a const iterator to the value. That prevents us from +// modifying the name (in a hash-preserving way) after the symbol is +// inserted. FIXME: Is there a way to do this with insert? Need a +// function to make a new object in the middle of insert. Read STL +// documentation. + +ASTSymbol *BeevMgr::LookupOrCreateSymbol(ASTSymbol& s) +{ + ASTSymbol *s_ptr = &s; // it's a temporary key. + + // Do an explicit lookup to see if we need to create a copy of the string. + ASTSymbolSet::const_iterator it; + if ((it = _symbol_unique_table.find(s_ptr)) == _symbol_unique_table.end()) + { + // Make a new ASTSymbol with duplicated string (can't assign + // _name because it's const). Can cast the iterator to + // non-const -- carefully. + //std::string strname(s_ptr->GetName()); + ASTSymbol * s_ptr1 = new ASTSymbol(strdup(s_ptr->GetName()), *this); + s_ptr1->SetNodeNum(NewNodeNum()); + s_ptr1->_value_width = s_ptr->_value_width; + pair p = _symbol_unique_table.insert(s_ptr1); + return *p.first; + } + else + // return symbol found in table. + return *it; +} + +bool BeevMgr::LookupSymbol(ASTSymbol& s) +{ + ASTSymbol* s_ptr = &s; // it's a temporary key. + + if (_symbol_unique_table.find(s_ptr) == _symbol_unique_table.end()) + return false; + else + return true; +} + +// Inline because we need to wait until unique_table is defined +void ASTSymbol::CleanUp() +{ + // cout << "Deleting node " << this->GetNodeNum() << endl; + _bm._symbol_unique_table.erase(this); + //FIXME This is a HUGE free to invoke. + //TEST IT! + free((char*) this->_name); + delete this; +} + +//////////////////////////////////////////////////////////////// +// +// IO manipulators for Lisp format printing of AST. +// +//////////////////////////////////////////////////////////////// + +// FIXME: Additional controls +// * Print node numbers (addresses/nums) +// * Printlength limit +// * Printdepth limit + +/** Print a vector of ASTNodes in lisp format */ +ostream &LispPrintVec(ostream &os, const ASTVec &v, int indentation) +{ + // Print the children + ASTVec::const_iterator iend = v.end(); + for (ASTVec::const_iterator i = v.begin(); i != iend; i++) + { + i->LispPrint_indent(os, indentation); + } + return os; +} + +ostream &LispPrintVecSpecial(ostream &os, const vector &v, int indentation) +{ + // Print the children + vector::const_iterator iend = v.end(); + for (vector::const_iterator i = v.begin(); i != iend; i++) + { + (*i)->LispPrint_indent(os, indentation); + } + return os; +} + +// FIXME: Made non-ref in the hope that it would work better. +void lp(ASTNode node) +{ + cout << lisp(node) << endl; +} + +void lpvec(const ASTVec &vec) +{ + vec[0].GetBeevMgr().AlreadyPrintedSet.clear(); + LispPrintVec(cout, vec, 0); + cout << endl; +} + +// Copy constructor. Maintain _ref_count +ASTNode::ASTNode(const ASTNode &n) : + _int_node_ptr(n._int_node_ptr) +{ +#ifndef SMTLIB + if (n._int_node_ptr) + { + n._int_node_ptr->IncRef(); + } #endif - } - - - /* FUNCTION: Typechecker for terms and formulas - * - * TypeChecker: Assumes that the immediate Children of the input - * ASTNode have been typechecked. This function is suitable in - * scenarios like where you are building the ASTNode Tree, and you - * typecheck as you go along. It is not suitable as a general - * typechecker - */ - void BeevMgr::BVTypeCheck(const ASTNode& n) { - Kind k = n.GetKind(); - //The children of bitvector terms are in turn bitvectors. - const ASTVec& v = n.GetChildren(); - if(is_Term_kind(k)) { - switch(k) { - case BVCONST: - if(BITVECTOR_TYPE != n.GetType()) - FatalError("BVTypeCheck: The term t does not typecheck, where t = \n",n); - break; - case SYMBOL: - return; - case ITE: - if (BOOLEAN_TYPE != n[0].GetType() || (n[1].GetType() != n[2].GetType())) - FatalError("BVTypeCheck: The term t does not typecheck, where t = \n",n); - if(n[1].GetValueWidth() != n[2].GetValueWidth()) - FatalError("BVTypeCheck: length of THENbranch != length of ELSEbranch in the term t = \n",n); - if(n[1].GetIndexWidth() != n[2].GetIndexWidth()) - FatalError("BVTypeCheck: length of THENbranch != length of ELSEbranch in the term t = \n",n); - break; - case READ: - if(n[0].GetIndexWidth() != n[1].GetValueWidth()) { - cerr << "Length of indexwidth of array: " << n[0] << " is : " << n[0].GetIndexWidth() << endl; - cerr << "Length of the actual index is: " << n[1] << " is : " << n[1].GetValueWidth() << endl; - FatalError("BVTypeCheck: length of indexwidth of array != length of actual index in the term t = \n",n); +} + +/* FUNCTION: Typechecker for terms and formulas + * + * TypeChecker: Assumes that the immediate Children of the input + * ASTNode have been typechecked. This function is suitable in + * scenarios like where you are building the ASTNode Tree, and you + * typecheck as you go along. It is not suitable as a general + * typechecker + */ +void BeevMgr::BVTypeCheck(const ASTNode& n) +{ + Kind k = n.GetKind(); + //The children of bitvector terms are in turn bitvectors. + const ASTVec& v = n.GetChildren(); + if (is_Term_kind(k)) + { + switch (k) + { + case BVCONST: + if (BITVECTOR_TYPE != n.GetType()) + FatalError("BVTypeCheck: The term t does not typecheck, where t = \n", n); + break; + case SYMBOL: + return; + case ITE: + if (BOOLEAN_TYPE != n[0].GetType() || (n[1].GetType() != n[2].GetType())) + FatalError("BVTypeCheck: The term t does not typecheck, where t = \n", n); + if (n[1].GetValueWidth() != n[2].GetValueWidth()) + FatalError("BVTypeCheck: length of THENbranch != length of ELSEbranch in the term t = \n", n); + if (n[1].GetIndexWidth() != n[2].GetIndexWidth()) + FatalError("BVTypeCheck: length of THENbranch != length of ELSEbranch in the term t = \n", n); + break; + case READ: + if (n[0].GetIndexWidth() != n[1].GetValueWidth()) + { + cerr << "Length of indexwidth of array: " << n[0] << " is : " << n[0].GetIndexWidth() << endl; + cerr << "Length of the actual index is: " << n[1] << " is : " << n[1].GetValueWidth() << endl; + FatalError("BVTypeCheck: length of indexwidth of array != length of actual index in the term t = \n", n); + } + break; + case WRITE: + if (n[0].GetIndexWidth() != n[1].GetValueWidth()) + FatalError("BVTypeCheck: length of indexwidth of array != length of actual index in the term t = \n", n); + if (n[0].GetValueWidth() != n[2].GetValueWidth()) + FatalError("BVTypeCheck: valuewidth of array != length of actual value in the term t = \n", n); + break; + case BVOR: + case BVAND: + case BVXOR: + case BVNOR: + case BVNAND: + case BVXNOR: + case BVPLUS: + case BVMULT: + case BVDIV: + case BVMOD: + case BVSUB: + { + if (!(v.size() >= 2)) + FatalError("BVTypeCheck:bitwise Booleans and BV arith operators must have atleast two arguments\n", n); + unsigned int width = n.GetValueWidth(); + for (ASTVec::const_iterator it = v.begin(), itend = v.end(); it != itend; it++) + { + if (width != it->GetValueWidth()) + { + cerr << "BVTypeCheck:Operands of bitwise-Booleans and BV arith operators must be of equal length\n"; + cerr << n << endl; + cerr << "width of term:" << width << endl; + cerr << "width of offending operand:" << it->GetValueWidth() << endl; + FatalError("BVTypeCheck:Offending operand:\n", *it); + } + if (BITVECTOR_TYPE != it->GetType()) + FatalError("BVTypeCheck: ChildNodes of bitvector-terms must be bitvectors\n", n); + } + break; + } + case BVSX: + //in BVSX(n[0],len), the length of the BVSX term must be + //greater than the length of n[0] + if (n[0].GetValueWidth() > n.GetValueWidth()) + { + FatalError("BVTypeCheck: BVSX(t,bvsx_len) : length of 't' must be <= bvsx_len\n", n); + } + break; + + case BVZX: + //in BVZX(n[0],len), the length of the BVZX term must be + //greater than the length of n[0] + if (n[0].GetValueWidth() > n.GetValueWidth()) + { + FatalError("BVTypeCheck: BVZX(t,bvzx_len) : length of 't' must be <= bvzx_len\n", n); + } + break; + + default: + for (ASTVec::const_iterator it = v.begin(), itend = v.end(); it != itend; it++) + if (BITVECTOR_TYPE != it->GetType()) + { + cerr << "The type is: " << it->GetType() << endl; + FatalError("BVTypeCheck:ChildNodes of bitvector-terms must be bitvectors\n", n); + } + break; + } + + switch (k) + { + case BVCONCAT: + if (n.Degree() != 2) + FatalError("BVTypeCheck: should have exactly 2 args\n", n); + if (n.GetValueWidth() != n[0].GetValueWidth() + n[1].GetValueWidth()) + FatalError("BVTypeCheck:BVCONCAT: lengths do not add up\n", n); + break; + case BVUMINUS: + case BVNEG: + if (n.Degree() != 1) + FatalError("BVTypeCheck: should have exactly 1 args\n", n); + break; + case BVEXTRACT: + if (n.Degree() != 3) + FatalError("BVTypeCheck: should have exactly 3 args\n", n); + if (!(BVCONST == n[1].GetKind() && BVCONST == n[2].GetKind())) + FatalError("BVTypeCheck: indices should be BVCONST\n", n); + if (n.GetValueWidth() != GetUnsignedConst(n[1]) - GetUnsignedConst(n[2]) + 1) + FatalError("BVTypeCheck: length mismatch\n", n); + break; + case BVLEFTSHIFT: + case BVRIGHTSHIFT: + if (n.Degree() != 2) + FatalError("BVTypeCheck: should have exactly 2 args\n", n); + break; + //case BVVARSHIFT: + //case BVSRSHIFT: + break; + default: + break; + } + } + else + { + if (!(is_Form_kind(k) && BOOLEAN_TYPE == n.GetType())) + FatalError("BVTypeCheck: not a formula:", n); + switch (k) + { + case TRUE: + case FALSE: + case SYMBOL: + return; + case EQ: + case NEQ: + if (!(n[0].GetValueWidth() == n[1].GetValueWidth() && n[0].GetIndexWidth() == n[1].GetIndexWidth())) + { + cerr << "valuewidth of lhs of EQ: " << n[0].GetValueWidth() << endl; + cerr << "valuewidth of rhs of EQ: " << n[1].GetValueWidth() << endl; + cerr << "indexwidth of lhs of EQ: " << n[0].GetIndexWidth() << endl; + cerr << "indexwidth of rhs of EQ: " << n[1].GetIndexWidth() << endl; + FatalError("BVTypeCheck: terms in atomic formulas must be of equal length", n); + } + break; + case BVLT: + case BVLE: + case BVGT: + case BVGE: + case BVSLT: + case BVSLE: + case BVSGT: + case BVSGE: + if (BITVECTOR_TYPE != n[0].GetType() && BITVECTOR_TYPE != n[1].GetType()) + FatalError("BVTypeCheck: terms in atomic formulas must be bitvectors", n); + if (n[0].GetValueWidth() != n[1].GetValueWidth()) + FatalError("BVTypeCheck: terms in atomic formulas must be of equal length", n); + if (n[0].GetIndexWidth() != n[1].GetIndexWidth()) + FatalError("BVTypeCheck: terms in atomic formulas must be of equal length", n); + break; + case NOT: + if (1 != n.Degree()) + FatalError("BVTypeCheck: NOT formula can have exactly one childNode", n); + break; + case AND: + case OR: + case XOR: + case NAND: + case NOR: + if (2 > n.Degree()) + FatalError("BVTypeCheck: AND/OR/XOR/NAND/NOR: must have atleast 2 ChildNodes", n); + break; + case IFF: + case IMPLIES: + if (2 != n.Degree()) + FatalError("BVTypeCheck:IFF/IMPLIES must have exactly 2 ChildNodes", n); + break; + case ITE: + if (3 != n.Degree()) + FatalError("BVTypeCheck:ITE must have exactly 3 ChildNodes", n); + break; + default: + FatalError("BVTypeCheck: Unrecognized kind: ", ASTUndefined); + break; + } + } +} //End of TypeCheck function + +//add an assertion to the current logical context +void BeevMgr::AddAssert(const ASTNode& assert) +{ + if (!(is_Form_kind(assert.GetKind()) && BOOLEAN_TYPE == assert.GetType())) + { + FatalError("AddAssert:Trying to assert a non-formula:", assert); + } + + ASTVec * v; + //if the stack of ASTVec is not empty, then take the top ASTVec + //and add the input assert to it + if (!_asserts.empty()) + { + v = _asserts.back(); + //v->push_back(TransformFormula(assert)); + v->push_back(assert); + } + else + { + //else create a logical context, and add it to the top of the + //stack + v = new ASTVec(); + //v->push_back(TransformFormula(assert)); + v->push_back(assert); + _asserts.push_back(v); + } +} + +void BeevMgr::Push(void) +{ + ASTVec * v; + v = new ASTVec(); + _asserts.push_back(v); +} + +void BeevMgr::Pop(void) +{ + if (!_asserts.empty()) + { + ASTVec * c = _asserts.back(); + //by calling the clear function we ensure that the ref count is + //decremented for the ASTNodes stored in c + c->clear(); + delete c; + _asserts.pop_back(); + } +} + +void BeevMgr::AddQuery(const ASTNode& q) +{ + //_current_query = TransformFormula(q); + //cerr << "\nThe current query is: " << q << endl; + _current_query = q; +} + +const ASTNode BeevMgr::PopQuery() +{ + ASTNode q = _current_query; + _current_query = ASTTrue; + return q; +} + +const ASTNode BeevMgr::GetQuery() +{ + return _current_query; +} + +const ASTVec BeevMgr::GetAsserts(void) +{ + vector::iterator it = _asserts.begin(); + vector::iterator itend = _asserts.end(); + + ASTVec v; + for (; it != itend; it++) + { + if (!(*it)->empty()) + v.insert(v.end(), (*it)->begin(), (*it)->end()); + } + return v; +} + +//Create a new variable of ValueWidth 'n' +ASTNode BeevMgr::NewArrayVar(unsigned int index, unsigned int value) +{ + std::string c("v"); + char d[32]; + sprintf(d, "%d", _symbol_count++); + std::string ccc(d); + c += "_writearray_" + ccc; + + ASTNode CurrentSymbol = CreateSymbol(c.c_str()); + CurrentSymbol.SetValueWidth(value); + CurrentSymbol.SetIndexWidth(index); + return CurrentSymbol; +} //end of NewArrayVar() + + +//Create a new variable of ValueWidth 'n' +ASTNode BeevMgr::NewVar(unsigned int value) +{ + std::string c("v"); + char d[32]; + sprintf(d, "%d", _symbol_count++); + std::string ccc(d); + c += "_new_stp_var_" + ccc; + + ASTNode CurrentSymbol = CreateSymbol(c.c_str()); + CurrentSymbol.SetValueWidth(value); + CurrentSymbol.SetIndexWidth(0); + _introduced_symbols.insert(CurrentSymbol); + return CurrentSymbol; +} //end of NewVar() + +//prints statistics for the ASTNode +void BeevMgr::ASTNodeStats(const char * c, const ASTNode& a) +{ + if (!stats) + return; + + StatInfoSet.clear(); + //print node size: + cout << endl << "Printing: " << c; + if (print_nodes) + { + //a.PL_Print(cout,0); + //cout << endl; + cout << a << endl; + } + cout << "Node size is: "; + cout << NodeSize(a) << endl << endl; +} + +unsigned int BeevMgr::NodeSize(const ASTNode& a, bool clearStatInfo) +{ + if (clearStatInfo) + StatInfoSet.clear(); + + ASTNodeSet::iterator it; + if ((it = StatInfoSet.find(a)) != StatInfoSet.end()) + //has already been counted + return 0; + + //record that you have seen this node already + StatInfoSet.insert(a); + + //leaf node has a size of 1 + if (a.Degree() == 0) + return 1; + + unsigned newn = 1; + ASTVec c = a.GetChildren(); + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + newn += NodeSize(*it); + return newn; +} + +void BeevMgr::ClearAllTables(void) +{ + //clear all tables before calling toplevelsat + _ASTNode_to_SATVar.clear(); + _SATVar_to_AST.clear(); + + for (ASTtoBitvectorMap::iterator it = _ASTNode_to_Bitvector.begin(), itend = _ASTNode_to_Bitvector.end(); it != itend; it++) + { + (it->second)->clear(); + delete (it->second); + } + _ASTNode_to_Bitvector.clear(); + + /* OLD Destructor + * for(ASTNodeToVecMap::iterator ivec = BBTermMemo.begin(), + ivec_end=BBTermMemo.end();ivec!=ivec_end;ivec++) { + ivec->second.clear(); + }*/ + + /*What should I do here? For ASTNodes? + * for(ASTNodeMap::iterator ivec = BBTermMemo.begin(), + ivec_end=BBTermMemo.end();ivec!=ivec_end;ivec++) { + ivec->second.clear(); + }*/ + BBTermMemo.clear(); + BBFormMemo.clear(); + NodeLetVarMap.clear(); + NodeLetVarMap1.clear(); + PLPrintNodeSet.clear(); + AlreadyPrintedSet.clear(); + SimplifyMap->clear(); + SimplifyNegMap->clear(); + SolverMap.clear(); + AlwaysTrueFormMap.clear(); + _arrayread_ite.clear(); + _arrayread_symbol.clear(); + _introduced_symbols.clear(); + TransformMap.clear(); + _letid_expr_map->clear(); + CounterExampleMap.clear(); + ComputeFormulaMap.clear(); + StatInfoSet.clear(); + + // for(std::vector::iterator it=_asserts.begin(), + // itend=_asserts.end();it!=itend;it++) { + // (*it)->clear(); + // } + _asserts.clear(); + for (ASTNodeToVecMap::iterator iset = _arrayname_readindices.begin(), iset_end = _arrayname_readindices.end(); iset != iset_end; iset++) + { + iset->second.clear(); + } + + _arrayname_readindices.clear(); + _interior_unique_table.clear(); + _symbol_unique_table.clear(); + _bvconst_unique_table.clear(); +} + +void BeevMgr::ClearAllCaches(void) +{ + //clear all tables before calling toplevelsat + _ASTNode_to_SATVar.clear(); + _SATVar_to_AST.clear(); + + for (ASTtoBitvectorMap::iterator it = _ASTNode_to_Bitvector.begin(), itend = _ASTNode_to_Bitvector.end(); it != itend; it++) + { + (it->second)->clear(); + delete (it->second); + } + _ASTNode_to_Bitvector.clear(); + + /*OLD destructor + * for(ASTNodeToVecMap::iterator ivec = BBTermMemo.begin(), + ivec_end=BBTermMemo.end();ivec!=ivec_end;ivec++) { + ivec->second.clear(); + }*/ + + /*What should I do here? + *for(ASTNodeMap::iterator ivec = BBTermMemo.begin(), + ivec_end=BBTermMemo.end();ivec!=ivec_end;ivec++) { + ivec->second.clear(); + }*/ + BBTermMemo.clear(); + BBFormMemo.clear(); + NodeLetVarMap.clear(); + NodeLetVarMap1.clear(); + PLPrintNodeSet.clear(); + AlreadyPrintedSet.clear(); + SimplifyMap->clear(); + SimplifyNegMap->clear(); + SolverMap.clear(); + AlwaysTrueFormMap.clear(); + _arrayread_ite.clear(); + _arrayread_symbol.clear(); + _introduced_symbols.clear(); + TransformMap.clear(); + _letid_expr_map->clear(); + CounterExampleMap.clear(); + ComputeFormulaMap.clear(); + StatInfoSet.clear(); + + for (ASTNodeToVecMap::iterator iset = _arrayname_readindices.begin(), iset_end = _arrayname_readindices.end(); iset != iset_end; iset++) + { + iset->second.clear(); + } + + _arrayname_readindices.clear(); + //_interior_unique_table.clear(); + //_symbol_unique_table.clear(); + //_bvconst_unique_table.clear(); +} + +void BeevMgr::CopySolverMap_To_CounterExample(void) +{ + if (!SolverMap.empty()) + { + CounterExampleMap.insert(SolverMap.begin(), SolverMap.end()); } - break; - case WRITE: - if(n[0].GetIndexWidth() != n[1].GetValueWidth()) - FatalError("BVTypeCheck: length of indexwidth of array != length of actual index in the term t = \n",n); - if(n[0].GetValueWidth() != n[2].GetValueWidth()) - FatalError("BVTypeCheck: valuewidth of array != length of actual value in the term t = \n",n); - break; - case BVOR: - case BVAND: - case BVXOR: - case BVNOR: - case BVNAND: - case BVXNOR: - case BVPLUS: - case BVMULT: - case BVDIV: - case BVMOD: - case BVSUB: { - if(!(v.size() >= 2)) - FatalError("BVTypeCheck:bitwise Booleans and BV arith operators must have atleast two arguments\n",n); - unsigned int width = n.GetValueWidth(); - for(ASTVec::const_iterator it=v.begin(),itend=v.end();it!=itend;it++){ - if(width != it->GetValueWidth()) { - cerr << "BVTypeCheck:Operands of bitwise-Booleans and BV arith operators must be of equal length\n"; - cerr << n << endl; - cerr << "width of term:" << width << endl; - cerr << "width of offending operand:" << it->GetValueWidth() << endl; - FatalError("BVTypeCheck:Offending operand:\n",*it); - } - if(BITVECTOR_TYPE != it->GetType()) - FatalError("BVTypeCheck: ChildNodes of bitvector-terms must be bitvectors\n",n); +} + +void FatalError(const char * str, const ASTNode& a, int w) +{ + if (a.GetKind() != UNDEFINED) + { + cerr << "Fatal Error: " << str << endl << a << endl; + cerr << w << endl; } - break; - } - case BVSX: - //in BVSX(n[0],len), the length of the BVSX term must be - //greater than the length of n[0] - if(n[0].GetValueWidth() > n.GetValueWidth()) { - FatalError("BVTypeCheck: BVSX(t,bvsx_len) : length of 't' must be <= bvsx_len\n",n); - } - break; - - case BVZX: - //in BVZX(n[0],len), the length of the BVZX term must be - //greater than the length of n[0] - if(n[0].GetValueWidth() > n.GetValueWidth()) { - FatalError("BVTypeCheck: BVZX(t,bvzx_len) : length of 't' must be <= bvzx_len\n",n); + else + { + cerr << "Fatal Error: " << str << endl; + cerr << w << endl; } - break; - - default: - for(ASTVec::const_iterator it=v.begin(),itend=v.end();it!=itend;it++) - if(BITVECTOR_TYPE != it->GetType()) { - cerr << "The type is: " << it->GetType() << endl; - FatalError("BVTypeCheck:ChildNodes of bitvector-terms must be bitvectors\n",n); - } - break; - } - - switch(k) { - case BVCONCAT: - if(n.Degree() != 2) - FatalError("BVTypeCheck: should have exactly 2 args\n",n); - if(n.GetValueWidth() != n[0].GetValueWidth() + n[1].GetValueWidth()) - FatalError("BVTypeCheck:BVCONCAT: lengths do not add up\n",n); - break; - case BVUMINUS: - case BVNEG: - if(n.Degree() != 1) - FatalError("BVTypeCheck: should have exactly 1 args\n",n); - break; - case BVEXTRACT: - if(n.Degree() != 3) - FatalError("BVTypeCheck: should have exactly 3 args\n",n); - if(!(BVCONST == n[1].GetKind() && BVCONST == n[2].GetKind())) - FatalError("BVTypeCheck: indices should be BVCONST\n",n); - if(n.GetValueWidth() != GetUnsignedConst(n[1])- GetUnsignedConst(n[2])+1) - FatalError("BVTypeCheck: length mismatch\n",n); - break; - case BVLEFTSHIFT: - case BVRIGHTSHIFT: - if(n.Degree() != 2) - FatalError("BVTypeCheck: should have exactly 2 args\n",n); - break; - //case BVVARSHIFT: - //case BVSRSHIFT: - break; - default: - break; - } - } - else { - if(!(is_Form_kind(k) && BOOLEAN_TYPE == n.GetType())) - FatalError("BVTypeCheck: not a formula:",n); - switch(k){ - case TRUE: - case FALSE: - case SYMBOL: - return; - case EQ: - case NEQ: - if(!(n[0].GetValueWidth() == n[1].GetValueWidth() && - n[0].GetIndexWidth() == n[1].GetIndexWidth())) { - cerr << "valuewidth of lhs of EQ: " << n[0].GetValueWidth() << endl; - cerr << "valuewidth of rhs of EQ: " << n[1].GetValueWidth() << endl; - cerr << "indexwidth of lhs of EQ: " << n[0].GetIndexWidth() << endl; - cerr << "indexwidth of rhs of EQ: " << n[1].GetIndexWidth() << endl; - FatalError("BVTypeCheck: terms in atomic formulas must be of equal length",n); + if (vc_error_hdlr) + vc_error_hdlr(str); + exit(-1); + //assert(0); +} + +void FatalError(const char * str) +{ + cerr << "Fatal Error: " << str << endl; + if (vc_error_hdlr) + vc_error_hdlr(str); + exit(-1); + //assert(0); +} + +//Variable Order Printer: A global function which converts a MINISAT +//var into a ASTNODE var. It then prints this var along with +//variable order dcisions taken by MINISAT. +void Convert_MINISATVar_To_ASTNode_Print(int minisat_var, int decision_level, int polarity) +{ + BEEV::ASTNode vv = globalBeevMgr_for_parser->_SATVar_to_AST[minisat_var]; + cout << spaces(decision_level); + if (polarity) + { + cout << "!"; } - break; - case BVLT: - case BVLE: - case BVGT: - case BVGE: - case BVSLT: - case BVSLE: - case BVSGT: - case BVSGE: - if(BITVECTOR_TYPE != n[0].GetType() && BITVECTOR_TYPE != n[1].GetType()) - FatalError("BVTypeCheck: terms in atomic formulas must be bitvectors",n); - if(n[0].GetValueWidth() != n[1].GetValueWidth()) - FatalError("BVTypeCheck: terms in atomic formulas must be of equal length",n); - if(n[0].GetIndexWidth() != n[1].GetIndexWidth()) - FatalError("BVTypeCheck: terms in atomic formulas must be of equal length",n); - break; - case NOT: - if(1 != n.Degree()) - FatalError("BVTypeCheck: NOT formula can have exactly one childNode",n); - break; - case AND: - case OR: - case XOR: - case NAND: - case NOR: - if(2 > n.Degree()) - FatalError("BVTypeCheck: AND/OR/XOR/NAND/NOR: must have atleast 2 ChildNodes",n); - break; - case IFF: - case IMPLIES: - if(2 != n.Degree()) - FatalError("BVTypeCheck:IFF/IMPLIES must have exactly 2 ChildNodes",n); - break; - case ITE: - if(3 != n.Degree()) - FatalError("BVTypeCheck:ITE must have exactly 3 ChildNodes",n); - break; - default: - FatalError("BVTypeCheck: Unrecognized kind: ",ASTUndefined); - break; - } - } - } //End of TypeCheck function - - //add an assertion to the current logical context - void BeevMgr::AddAssert(const ASTNode& assert) { - if(!(is_Form_kind(assert.GetKind()) && BOOLEAN_TYPE == assert.GetType())) { - FatalError("AddAssert:Trying to assert a non-formula:",assert); - } - - ASTVec * v; - //if the stack of ASTVec is not empty, then take the top ASTVec - //and add the input assert to it - if(!_asserts.empty()) { - v = _asserts.back(); - //v->push_back(TransformFormula(assert)); - v->push_back(assert); - } - else { - //else create a logical context, and add it to the top of the - //stack - v = new ASTVec(); - //v->push_back(TransformFormula(assert)); - v->push_back(assert); - _asserts.push_back(v); - } - } - - void BeevMgr::Push(void) { - ASTVec * v; - v = new ASTVec(); - _asserts.push_back(v); - } - - void BeevMgr::Pop(void) { - if(!_asserts.empty()) { - ASTVec * c = _asserts.back(); - //by calling the clear function we ensure that the ref count is - //decremented for the ASTNodes stored in c - c->clear(); - delete c; - _asserts.pop_back(); - } - } - - void BeevMgr::AddQuery(const ASTNode& q) { - //_current_query = TransformFormula(q); - //cerr << "\nThe current query is: " << q << endl; - _current_query = q; - } - - const ASTNode BeevMgr::PopQuery() { - ASTNode q = _current_query; - _current_query = ASTTrue; - return q; - } - - const ASTNode BeevMgr::GetQuery() { - return _current_query; - } - - const ASTVec BeevMgr::GetAsserts(void) { - vector::iterator it = _asserts.begin(); - vector::iterator itend = _asserts.end(); - - ASTVec v; - for(;it!=itend;it++) { - if(!(*it)->empty()) - v.insert(v.end(),(*it)->begin(),(*it)->end()); - } - return v; - } - - //Create a new variable of ValueWidth 'n' - ASTNode BeevMgr::NewArrayVar(unsigned int index, unsigned int value) { - std:: string c("v"); - char d[32]; - sprintf(d,"%d",_symbol_count++); - std::string ccc(d); - c += "_writearray_" + ccc; - - ASTNode CurrentSymbol = CreateSymbol(c.c_str()); - CurrentSymbol.SetValueWidth(value); - CurrentSymbol.SetIndexWidth(index); - return CurrentSymbol; - } //end of NewArrayVar() - - - //Create a new variable of ValueWidth 'n' - ASTNode BeevMgr::NewVar(unsigned int value) { - std:: string c("v"); - char d[32]; - sprintf(d,"%d",_symbol_count++); - std::string ccc(d); - c += "_new_stp_var_" + ccc; - - ASTNode CurrentSymbol = CreateSymbol(c.c_str()); - CurrentSymbol.SetValueWidth(value); - CurrentSymbol.SetIndexWidth(0); - _introduced_symbols.insert(CurrentSymbol); - return CurrentSymbol; - } //end of NewVar() - - //prints statistics for the ASTNode - void BeevMgr::ASTNodeStats(const char * c, const ASTNode& a){ - if(!stats) - return; - - StatInfoSet.clear(); - //print node size: - cout << endl << "Printing: " << c; - if(print_nodes) { - //a.PL_Print(cout,0); - //cout << endl; - cout << a << endl; - } - cout << "Node size is: "; - cout << NodeSize(a) << endl << endl; - } - - unsigned int BeevMgr::NodeSize(const ASTNode& a, bool clearStatInfo) { - if(clearStatInfo) - StatInfoSet.clear(); - - ASTNodeSet::iterator it; - if((it = StatInfoSet.find(a)) != StatInfoSet.end()) - //has already been counted - return 0; - - //record that you have seen this node already - StatInfoSet.insert(a); - - //leaf node has a size of 1 - if(a.Degree() == 0) - return 1; - - unsigned newn = 1; - ASTVec c = a.GetChildren(); - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) - newn += NodeSize(*it); - return newn; - } - - void BeevMgr::ClearAllTables(void) { - //clear all tables before calling toplevelsat - _ASTNode_to_SATVar.clear(); - _SATVar_to_AST.clear(); - - for(ASTtoBitvectorMap::iterator it=_ASTNode_to_Bitvector.begin(), - itend=_ASTNode_to_Bitvector.end();it!=itend;it++) { - (it->second)->clear(); - delete (it->second); - } - _ASTNode_to_Bitvector.clear(); - - /* OLD Destructor - * for(ASTNodeToVecMap::iterator ivec = BBTermMemo.begin(), - ivec_end=BBTermMemo.end();ivec!=ivec_end;ivec++) { - ivec->second.clear(); - }*/ - - /*What should I do here? For ASTNodes? - * for(ASTNodeMap::iterator ivec = BBTermMemo.begin(), - ivec_end=BBTermMemo.end();ivec!=ivec_end;ivec++) { - ivec->second.clear(); - }*/ - BBTermMemo.clear(); - BBFormMemo.clear(); - NodeLetVarMap.clear(); - NodeLetVarMap1.clear(); - PLPrintNodeSet.clear(); - AlreadyPrintedSet.clear(); - SimplifyMap->clear(); - SimplifyNegMap->clear(); - SolverMap.clear(); - AlwaysTrueFormMap.clear(); - _arrayread_ite.clear(); - _arrayread_symbol.clear(); - _introduced_symbols.clear(); - TransformMap.clear(); - _letid_expr_map->clear(); - CounterExampleMap.clear(); - ComputeFormulaMap.clear(); - StatInfoSet.clear(); - - // for(std::vector::iterator it=_asserts.begin(), - // itend=_asserts.end();it!=itend;it++) { - // (*it)->clear(); - // } - _asserts.clear(); - for(ASTNodeToVecMap::iterator iset = _arrayname_readindices.begin(), - iset_end = _arrayname_readindices.end(); - iset!=iset_end;iset++) { - iset->second.clear(); - } - - _arrayname_readindices.clear(); - _interior_unique_table.clear(); - _symbol_unique_table.clear(); - _bvconst_unique_table.clear(); - } - - void BeevMgr::ClearAllCaches(void) { - //clear all tables before calling toplevelsat - _ASTNode_to_SATVar.clear(); - _SATVar_to_AST.clear(); - - - for(ASTtoBitvectorMap::iterator it=_ASTNode_to_Bitvector.begin(), - itend=_ASTNode_to_Bitvector.end();it!=itend;it++) { - (it->second)->clear(); - delete (it->second); - } - _ASTNode_to_Bitvector.clear(); - - /*OLD destructor - * for(ASTNodeToVecMap::iterator ivec = BBTermMemo.begin(), - ivec_end=BBTermMemo.end();ivec!=ivec_end;ivec++) { - ivec->second.clear(); - }*/ - - /*What should I do here? - *for(ASTNodeMap::iterator ivec = BBTermMemo.begin(), - ivec_end=BBTermMemo.end();ivec!=ivec_end;ivec++) { - ivec->second.clear(); - }*/ - BBTermMemo.clear(); - BBFormMemo.clear(); - NodeLetVarMap.clear(); - NodeLetVarMap1.clear(); - PLPrintNodeSet.clear(); - AlreadyPrintedSet.clear(); - SimplifyMap->clear(); - SimplifyNegMap->clear(); - SolverMap.clear(); - AlwaysTrueFormMap.clear(); - _arrayread_ite.clear(); - _arrayread_symbol.clear(); - _introduced_symbols.clear(); - TransformMap.clear(); - _letid_expr_map->clear(); - CounterExampleMap.clear(); - ComputeFormulaMap.clear(); - StatInfoSet.clear(); - - for(ASTNodeToVecMap::iterator iset = _arrayname_readindices.begin(), - iset_end = _arrayname_readindices.end(); - iset!=iset_end;iset++) { - iset->second.clear(); - } - - _arrayname_readindices.clear(); - //_interior_unique_table.clear(); - //_symbol_unique_table.clear(); - //_bvconst_unique_table.clear(); - } - - void BeevMgr::CopySolverMap_To_CounterExample(void) { - if(!SolverMap.empty()) { - CounterExampleMap.insert(SolverMap.begin(),SolverMap.end()); - } - } - - void FatalError(const char * str, const ASTNode& a, int w) { - if(a.GetKind() != UNDEFINED) { - cerr << "Fatal Error: " << str << endl << a << endl; - cerr << w << endl; - } - else { - cerr << "Fatal Error: " << str << endl; - cerr << w << endl; - } - if (vc_error_hdlr) - vc_error_hdlr(str); - exit(-1); - //assert(0); - } - - void FatalError(const char * str) { - cerr << "Fatal Error: " << str << endl; - if (vc_error_hdlr) - vc_error_hdlr(str); - exit(-1); - //assert(0); - } - - //Variable Order Printer: A global function which converts a MINISAT - //var into a ASTNODE var. It then prints this var along with - //variable order dcisions taken by MINISAT. - void Convert_MINISATVar_To_ASTNode_Print(int minisat_var, - int decision_level, int polarity) { - BEEV::ASTNode vv = globalBeevMgr_for_parser->_SATVar_to_AST[minisat_var]; - cout << spaces(decision_level); - if(polarity) { - cout << "!"; - } - vv.PL_Print(cout,0); - cout << endl; - } - - void SortByExprNum(ASTVec& v) { - sort(v.begin(), v.end(), exprless); - } - - void SortByArith(ASTVec& v) { - sort(v.begin(), v.end(), arithless); - } - - bool isAtomic(Kind kind) { - if(TRUE == kind || - FALSE == kind || - EQ == kind || - NEQ == kind || - BVLT == kind || - BVLE == kind || - BVGT == kind || - BVGE == kind || - BVSLT == kind || - BVSLE == kind || - BVSGT == kind || - BVSGE == kind || - SYMBOL == kind || - BVGETBIT == kind) - return true; - return false; - } - - BeevMgr::~BeevMgr() { - ClearAllTables(); - - delete SimplifyMap; + vv.PL_Print(cout, 0); + cout << endl; +} + +void SortByExprNum(ASTVec& v) +{ + sort(v.begin(), v.end(), exprless); +} + +void SortByArith(ASTVec& v) +{ + sort(v.begin(), v.end(), arithless); +} + +bool isAtomic(Kind kind) +{ + if (TRUE == kind || FALSE == kind || EQ == kind || NEQ == kind || BVLT == kind || BVLE == kind || BVGT == kind || BVGE == kind || BVSLT == kind + || BVSLE == kind || BVSGT == kind || BVSGE == kind || SYMBOL == kind || BVGETBIT == kind) + return true; + return false; +} + +BeevMgr::~BeevMgr() +{ + ClearAllTables(); + + delete SimplifyMap; delete SimplifyNegMap; - delete _letid_expr_map; - } + delete _letid_expr_map; +} -}; // end namespace +} +; // end namespace diff --git a/AST/AST.h b/AST/AST.h index a368d4e..3c487b2 100644 --- a/AST/AST.h +++ b/AST/AST.h @@ -10,7 +10,6 @@ #ifndef AST_H #define AST_H - #include #ifdef EXT_HASH_MAP #include @@ -40,1871 +39,1966 @@ #include "../constantbv/constantbv.h" #endif - - /***************************************************************************** * LIST OF CLASSES DECLARED IN THIS FILE: * - * class BeevMgr; - * class ASTNode; - * class ASTInternal; - * class ASTInterior; + * class BeevMgr; + * class ASTNode; + * class ASTInternal; + * class ASTInterior; * class ASTSymbol; * class ASTBVConst; *****************************************************************************/ -namespace BEEV { - using namespace std; - using namespace MINISAT; +namespace BEEV +{ +using namespace std; +using namespace MINISAT; #ifdef EXT_HASH_MAP - using namespace __gnu_cxx; +using namespace __gnu_cxx; #endif - //return types for the GetType() function in ASTNode class - enum types { - BOOLEAN_TYPE = 0, - BITVECTOR_TYPE, - ARRAY_TYPE, - UNKNOWN_TYPE - }; - - class BeevMgr; - class ASTNode; - class ASTInternal; - class ASTInterior; - class ASTSymbol; - class ASTBVConst; - class BVSolver; - - //Vector of ASTNodes, used for child nodes among other things. - typedef vector ASTVec; - extern ASTVec _empty_ASTVec; - extern BeevMgr * globalBeevMgr_for_parser; - - typedef unsigned int * CBV; - - /***************************************************************************/ - /* Class ASTNode: Smart pointer to actual ASTNode internal datastructure. */ - /***************************************************************************/ - class ASTNode { - friend class BeevMgr; - friend class CNFMgr; - friend class ASTInterior; - friend class vector; - //Print the arguments in lisp format. - friend ostream &LispPrintVec(ostream &os, - const ASTVec &v, int indentation = 0); - friend ostream &LispPrintVecSpecial(ostream &os, - const vector &v, int indentation = 0); - - private: - // FIXME: make this into a reference? - ASTInternal * _int_node_ptr; // The real data. - - // Usual constructor. - ASTNode(ASTInternal *in); - - //Equal iff ASTIntNode pointers are the same. - friend bool operator==(const ASTNode node1, const ASTNode node2){ - return ((size_t) node1._int_node_ptr) == ((size_t) node2._int_node_ptr); - } - - //MKK: This shouldn't be necessary, but for some inexplicable reason I - //cannot get ToSAT.cpp to compile. The differences between the old files - //(AST.h, ToSAT.cpp) and the new files are very minor, mostly Solver -> - //Solver, and so the compiler errors are difficult to understand. - friend bool operator!=(const ASTNode node1, const ASTNode node2){ - return ! (node1 == node2); - //return ((size_t) node1._int_node_ptr) == ((size_t) node2._int_node_ptr); - } - - /* FIXME: Nondeterministic code *** */ - /** questionable pointer comparison function */ - friend bool operator<(const ASTNode node1, const ASTNode node2){ - return ((size_t) node1._int_node_ptr) < ((size_t) node2._int_node_ptr); - } - - public: - //Check if it points to a null node - bool IsNull () const { return _int_node_ptr == NULL; } - - // This is for sorting by expression number (used in Boolean - //optimization). - // With any ordering operation, the properties of the order - // need to be carefully specified. In this case, we just - // need identical exprs to be consecutive, and (NOT x) to - // follow "x" immediately. For some time, this function was - // "arithless" (below), which separates x and (NOT x) in some - // cases. - // DO NOT MODIFY WITHOUT CHECKING WITH DAVID DILL FIRST! - friend bool exprless(const ASTNode n1, const ASTNode n2) { - return (n1.GetNodeNum() < n2.GetNodeNum()); - } // end of exprless - - // This is for sorting by arithmetic expressions (for - // combining like terms, etc.) - friend bool arithless(const ASTNode n1, const ASTNode n2) { - Kind k1 = n1.GetKind(); - Kind k2 = n2.GetKind(); - - if (n1 == n2) { - // necessary for "strict weak ordering" - return false; - } - else if (BVCONST == k1 && BVCONST != k2) { - // put consts first - return true; - } - else if (BVCONST != k1 && BVCONST == k2) { - // put consts first - return false; - } - else if (SYMBOL == k1 && SYMBOL != k2) { - // put symbols next - return true; - } - else if (SYMBOL != k1 && SYMBOL == k2) { - // put symbols next - return false; - } - else { - // otherwise, sort by exprnum (descendents will appear - // before ancestors). - return (n1.GetNodeNum() < n2.GetNodeNum()); - } - } //end of arithless - - // Internal lisp-form printer that does not clear _node_print_table - ostream &LispPrint1(ostream &os, int indentation) const; - - ostream &LispPrint_indent(ostream &os, int indentation) const; - - // For lisp DAG printing. Has it been printed already, so we can - // just print the node number? - bool IsAlreadyPrinted() const; - void MarkAlreadyPrinted() const; - - // delegates to the ASTInternal node. - void nodeprint(ostream& os, bool c_friendly = false) const; - - - public: - // Default constructor. This gets used when declaring an ASTVec - // of a given size, in the hash table, etc. For faster - // refcounting, create a symbol node for NULL. Give it a big - // initial refcount. Never free it. also check, for ref-count - // overflow? - ASTNode() : _int_node_ptr(NULL) { }; - - // Copy constructor - ASTNode(const ASTNode &n); - - // Destructor - ~ASTNode(); - - // Assignment (for ref counting) - ASTNode& operator=(const ASTNode& n); - - BeevMgr &GetBeevMgr() const; - - // Access node number - int GetNodeNum() const; - - // Access kind. Inlined later because of declaration ordering problems. - Kind GetKind() const; - - // access Children - const ASTVec &GetChildren() const; - - // Return the number of child nodes - size_t Degree() const{ - return GetChildren().size(); - }; - - // Get indexth childNode. - const ASTNode operator[](size_t index) const { - return GetChildren()[index]; - }; - - // Get begin() iterator for child nodes - ASTVec::const_iterator begin() const{ - return GetChildren().begin(); - }; - - // Get end() iterator for child nodes - ASTVec::const_iterator end() const{ - return GetChildren().end(); - }; - - //Get back() element for child nodes - const ASTNode back() const{ - return GetChildren().back(); - }; - - // Get the name from a symbol (char *). It's an error if kind != SYMBOL - const char * const GetName() const; - - //Get the BVCONST value +//return types for the GetType() function in ASTNode class +enum types +{ + BOOLEAN_TYPE = 0, BITVECTOR_TYPE, ARRAY_TYPE, UNKNOWN_TYPE +}; + +class BeevMgr; +class ASTNode; +class ASTInternal; +class ASTInterior; +class ASTSymbol; +class ASTBVConst; +class BVSolver; + +//Vector of ASTNodes, used for child nodes among other things. +typedef vector ASTVec; +extern ASTVec _empty_ASTVec; +extern BeevMgr * globalBeevMgr_for_parser; + +typedef unsigned int * CBV; + +/***************************************************************************/ +/* Class ASTNode: Smart pointer to actual ASTNode internal datastructure. */ +/***************************************************************************/ +class ASTNode +{ + friend class BeevMgr; + friend class CNFMgr; + friend class ASTInterior; + friend class vector ; + //Print the arguments in lisp format. + friend ostream &LispPrintVec(ostream &os, const ASTVec &v, int indentation = 0); + friend ostream &LispPrintVecSpecial(ostream &os, const vector &v, int indentation = 0); + +private: + // FIXME: make this into a reference? + ASTInternal * _int_node_ptr; // The real data. + + // Usual constructor. + ASTNode(ASTInternal *in); + + //Equal iff ASTIntNode pointers are the same. + friend bool operator==(const ASTNode node1, const ASTNode node2) + { + return ((size_t) node1._int_node_ptr) == ((size_t) node2._int_node_ptr); + } + + //MKK: This shouldn't be necessary, but for some inexplicable reason I + //cannot get ToSAT.cpp to compile. The differences between the old files + //(AST.h, ToSAT.cpp) and the new files are very minor, mostly Solver -> + //Solver, and so the compiler errors are difficult to understand. + friend bool operator!=(const ASTNode node1, const ASTNode node2) + { + return !(node1 == node2); + //return ((size_t) node1._int_node_ptr) == ((size_t) node2._int_node_ptr); + } + + /* FIXME: Nondeterministic code *** */ + /** questionable pointer comparison function */ + friend bool operator<(const ASTNode node1, const ASTNode node2) + { + return ((size_t) node1._int_node_ptr) < ((size_t) node2._int_node_ptr); + } + +public: + //Check if it points to a null node + bool IsNull() const + { + return _int_node_ptr == NULL; + } + + // This is for sorting by expression number (used in Boolean + //optimization). + // With any ordering operation, the properties of the order + // need to be carefully specified. In this case, we just + // need identical exprs to be consecutive, and (NOT x) to + // follow "x" immediately. For some time, this function was + // "arithless" (below), which separates x and (NOT x) in some + // cases. + // DO NOT MODIFY WITHOUT CHECKING WITH DAVID DILL FIRST! + friend bool exprless(const ASTNode n1, const ASTNode n2) + { + return (n1.GetNodeNum() < n2.GetNodeNum()); + } // end of exprless + + // This is for sorting by arithmetic expressions (for + // combining like terms, etc.) + friend bool arithless(const ASTNode n1, const ASTNode n2) + { + Kind k1 = n1.GetKind(); + Kind k2 = n2.GetKind(); + + if (n1 == n2) + { + // necessary for "strict weak ordering" + return false; + } + else if (BVCONST == k1 && BVCONST != k2) + { + // put consts first + return true; + } + else if (BVCONST != k1 && BVCONST == k2) + { + // put consts first + return false; + } + else if (SYMBOL == k1 && SYMBOL != k2) + { + // put symbols next + return true; + } + else if (SYMBOL != k1 && SYMBOL == k2) + { + // put symbols next + return false; + } + else + { + // otherwise, sort by exprnum (descendents will appear + // before ancestors). + return (n1.GetNodeNum() < n2.GetNodeNum()); + } + } //end of arithless + + // Internal lisp-form printer that does not clear _node_print_table + ostream &LispPrint1(ostream &os, int indentation) const; + + ostream &LispPrint_indent(ostream &os, int indentation) const; + + // For lisp DAG printing. Has it been printed already, so we can + // just print the node number? + bool IsAlreadyPrinted() const; + void MarkAlreadyPrinted() const; + + // delegates to the ASTInternal node. + void nodeprint(ostream& os, bool c_friendly = false) const; + +public: + // Default constructor. This gets used when declaring an ASTVec + // of a given size, in the hash table, etc. For faster + // refcounting, create a symbol node for NULL. Give it a big + // initial refcount. Never free it. also check, for ref-count + // overflow? + ASTNode() : + _int_node_ptr(NULL) + { + } + ; + + // Copy constructor + ASTNode(const ASTNode &n); + + // Destructor + ~ASTNode(); + + // Assignment (for ref counting) + ASTNode& operator=(const ASTNode& n); + + BeevMgr &GetBeevMgr() const; + + // Access node number + int GetNodeNum() const; + + // Access kind. Inlined later because of declaration ordering problems. + Kind GetKind() const; + + // access Children + const ASTVec &GetChildren() const; + + // Return the number of child nodes + size_t Degree() const + { + return GetChildren().size(); + } + ; + + // Get indexth childNode. + const ASTNode operator[](size_t index) const + { + return GetChildren()[index]; + } + ; + + // Get begin() iterator for child nodes + ASTVec::const_iterator begin() const + { + return GetChildren().begin(); + } + ; + + // Get end() iterator for child nodes + ASTVec::const_iterator end() const + { + return GetChildren().end(); + } + ; + + //Get back() element for child nodes + const ASTNode back() const + { + return GetChildren().back(); + } + ; + + // Get the name from a symbol (char *). It's an error if kind != SYMBOL + const char * const GetName() const; + + //Get the BVCONST value #ifndef NATIVE_C_ARITH - const CBV GetBVConst() const; + const CBV GetBVConst() const; #else - unsigned long long int GetBVConst() const; + unsigned long long int GetBVConst() const; #endif - /*ASTNode is of type BV <==> ((indexwidth=0)&&(valuewidth>0)) - * - *ASTNode is of type ARRAY <==> ((indexwidth>0)&&(valuewidth>0)) - * - *ASTNode is of type BOOLEAN <==> ((indexwidth=0)&&(valuewidth=0)) - * - *both indexwidth and valuewidth should never be less than 0 - */ - unsigned int GetIndexWidth () const; - - // FIXME: This function is dangerous. Try to eliminate it's use. - void SetIndexWidth (unsigned int iw) const; - - unsigned int GetValueWidth () const; - - // FIXME: This function is dangerous. Try to eliminate it's use. - void SetValueWidth (unsigned int vw) const; - - //return the type of the ASTNode - //0 iff BOOLEAN - //1 iff BITVECTOR - //2 iff ARRAY - - /*ASTNode is of type BV <==> ((indexwidth=0)&&(valuewidth>0)) - * - *ASTNode is of type ARRAY <==> ((indexwidth>0)&&(valuewidth>0)) - * - *ASTNode is of type BOOLEAN <==> ((indexwidth=0)&&(valuewidth=0)) - * - *both indexwidth and valuewidth should never be less than 0 - */ - types GetType(void) const; - - // Hash is pointer value of _int_node_ptr. - const size_t Hash() const{ - return (size_t) _int_node_ptr; - //return GetNodeNum(); - } - - void NFASTPrint(int l, int max, int prefix) const; - - // lisp-form printer - ostream& LispPrint(ostream &os, int indentation = 0) const; - - //Presentation Language Printer - ostream& PL_Print(ostream &os, int indentation = 0) const; - - void PL_Print1(ostream &os, int indentation = 0, bool b = false) const; - - //Construct let variables for shared subterms - void LetizeNode(void) const; - - // Attempt to define something that will work in the gdb - friend void lp(ASTNode &node); - friend void lpvec(const ASTVec &vec); - - friend ostream &operator<<(ostream &os, const ASTNode &node) { - node.LispPrint(os, 0); - return os; - }; - - // Check whether the ASTNode points to anything. Undefined nodes - // are created by the default constructor. In binding table (for - // lambda args, etc.), undefined nodes are used to represent - // deleted entries. - bool IsDefined() const { return _int_node_ptr != NULL; } - - /* Hasher class for STL hash_maps and hash_sets that use ASTNodes - * as keys. Needs to be public so people can define hash tables - * (and use ASTNodeMap class)*/ - class ASTNodeHasher { - public: - size_t operator() (const ASTNode& n) const{ - return (size_t) n._int_node_ptr; - //return (size_t)n.GetNodeNum(); - }; - }; //End of ASTNodeHasher - - /* Equality for ASTNode hash_set and hash_map. Returns true iff - * internal pointers are the same. Needs to be public so people - * can define hash tables (and use ASTNodeSet class)*/ - class ASTNodeEqual { - public: - bool operator()(const ASTNode& n1, const ASTNode& n2) const{ - return (n1._int_node_ptr == n2._int_node_ptr); - } - }; //End of ASTNodeEqual - }; //End of Class ASTNode - - void FatalError(const char * str, const ASTNode& a, int w = 0); - void FatalError(const char * str); - void SortByExprNum(ASTVec& c); - void SortByArith(ASTVec& c); - bool exprless(const ASTNode n1, const ASTNode n2); - bool arithless(const ASTNode n1, const ASTNode n2); - bool isAtomic(Kind k); - - /***************************************************************************/ - /* Class ASTInternal:Abstract base class for internal node representation.*/ - /* Requires Kind and ChildNodes so same traversal works */ - /* on all nodes. */ - /***************************************************************************/ - class ASTInternal { - - friend class ASTNode; - friend class CNFMgr; - - protected: - - // reference count. - int _ref_count; - - // Kind. It's a type tag and the operator. - Kind _kind; - - // The vector of children (*** should this be in ASTInterior? ***) - ASTVec _children; - - // Manager object. Having this backpointer means it's easy to - // find the manager when we need it. - BeevMgr &_bm; - - //Nodenum is a unique positive integer for the node. The nodenum - //of a node should always be greater than its descendents (which - //is easily achieved by incrementing the number each time a new - //node is created). - int _node_num; - - // Length of bitvector type for array index. The term is an - // array iff this is positive. Otherwise, the term is a bitvector - // or a bit. - unsigned int _index_width; - - // Length of bitvector type for scalar value or array element. - // If this is one, the term represents a single bit (same as a bitvector - // of length 1). It must be 1 or greater. - unsigned int _value_width; - - // Increment refcount. + /*ASTNode is of type BV <==> ((indexwidth=0)&&(valuewidth>0)) + * + *ASTNode is of type ARRAY <==> ((indexwidth>0)&&(valuewidth>0)) + * + *ASTNode is of type BOOLEAN <==> ((indexwidth=0)&&(valuewidth=0)) + * + *both indexwidth and valuewidth should never be less than 0 + */ + unsigned int GetIndexWidth() const; + + // FIXME: This function is dangerous. Try to eliminate it's use. + void SetIndexWidth(unsigned int iw) const; + + unsigned int GetValueWidth() const; + + // FIXME: This function is dangerous. Try to eliminate it's use. + void SetValueWidth(unsigned int vw) const; + + //return the type of the ASTNode + //0 iff BOOLEAN + //1 iff BITVECTOR + //2 iff ARRAY + + /*ASTNode is of type BV <==> ((indexwidth=0)&&(valuewidth>0)) + * + *ASTNode is of type ARRAY <==> ((indexwidth>0)&&(valuewidth>0)) + * + *ASTNode is of type BOOLEAN <==> ((indexwidth=0)&&(valuewidth=0)) + * + *both indexwidth and valuewidth should never be less than 0 + */ + types GetType(void) const; + + // Hash is pointer value of _int_node_ptr. + const size_t Hash() const + { + return (size_t) _int_node_ptr; + //return GetNodeNum(); + } + + void NFASTPrint(int l, int max, int prefix) const; + + // lisp-form printer + ostream& LispPrint(ostream &os, int indentation = 0) const; + + //Presentation Language Printer + ostream& PL_Print(ostream &os, int indentation = 0) const; + + void PL_Print1(ostream &os, int indentation = 0, bool b = false) const; + + //Construct let variables for shared subterms + void LetizeNode(void) const; + + // Attempt to define something that will work in the gdb + friend void lp(ASTNode &node); + friend void lpvec(const ASTVec &vec); + + friend ostream &operator<<(ostream &os, const ASTNode &node) + { + node.LispPrint(os, 0); + return os; + } + ; + + // Check whether the ASTNode points to anything. Undefined nodes + // are created by the default constructor. In binding table (for + // lambda args, etc.), undefined nodes are used to represent + // deleted entries. + bool IsDefined() const + { + return _int_node_ptr != NULL; + } + + /* Hasher class for STL hash_maps and hash_sets that use ASTNodes + * as keys. Needs to be public so people can define hash tables + * (and use ASTNodeMap class)*/ + class ASTNodeHasher + { + public: + size_t operator()(const ASTNode& n) const + { + return (size_t) n._int_node_ptr; + //return (size_t)n.GetNodeNum(); + } + ; + }; //End of ASTNodeHasher + + /* Equality for ASTNode hash_set and hash_map. Returns true iff + * internal pointers are the same. Needs to be public so people + * can define hash tables (and use ASTNodeSet class)*/ + class ASTNodeEqual + { + public: + bool operator()(const ASTNode& n1, const ASTNode& n2) const + { + return (n1._int_node_ptr == n2._int_node_ptr); + } + }; //End of ASTNodeEqual +}; //End of Class ASTNode + +void FatalError(const char * str, const ASTNode& a, int w = 0); +void FatalError(const char * str); +void SortByExprNum(ASTVec& c); +void SortByArith(ASTVec& c); +bool exprless(const ASTNode n1, const ASTNode n2); +bool arithless(const ASTNode n1, const ASTNode n2); +bool isAtomic(Kind k); + +/***************************************************************************/ +/* Class ASTInternal:Abstract base class for internal node representation.*/ +/* Requires Kind and ChildNodes so same traversal works */ +/* on all nodes. */ +/***************************************************************************/ +class ASTInternal +{ + + friend class ASTNode; + friend class CNFMgr; + +protected: + + // reference count. + int _ref_count; + + // Kind. It's a type tag and the operator. + Kind _kind; + + // The vector of children (*** should this be in ASTInterior? ***) + ASTVec _children; + + // Manager object. Having this backpointer means it's easy to + // find the manager when we need it. + BeevMgr &_bm; + + //Nodenum is a unique positive integer for the node. The nodenum + //of a node should always be greater than its descendents (which + //is easily achieved by incrementing the number each time a new + //node is created). + int _node_num; + + // Length of bitvector type for array index. The term is an + // array iff this is positive. Otherwise, the term is a bitvector + // or a bit. + unsigned int _index_width; + + // Length of bitvector type for scalar value or array element. + // If this is one, the term represents a single bit (same as a bitvector + // of length 1). It must be 1 or greater. + unsigned int _value_width; + + // Increment refcount. #ifndef SMTLIB - void IncRef() { - ++_ref_count; - } + void IncRef() + { + ++_ref_count; + } #else - void IncRef() { } + void IncRef() + {} #endif - // DecRef is a potentially expensive, because it has to delete - // the node from the unique table, in addition to freeing it. - // FIXME: Consider putting in a backpointer (iterator) to the hash - // table entry so it can be deleted without looking it up again. - void DecRef(); - - virtual const Kind GetKind() const { return _kind; } - - virtual ASTVec const &GetChildren() const { return _children; } - - int GetNodeNum() const { return _node_num; } - - void SetNodeNum(int nn) { _node_num = nn; }; - - // Constructor (bm only) - ASTInternal(BeevMgr &bm, int nodenum = 0) : - _ref_count(0), - _kind(UNDEFINED), - _bm(bm), - _node_num(nodenum), - _index_width(0), - _value_width(0) { } - - // Constructor (kind only, empty children, int nodenum) - ASTInternal(Kind kind, BeevMgr &bm, int nodenum = 0) : - _ref_count(0), - _kind(kind), - _bm(bm), - _node_num(nodenum), - _index_width(0), - _value_width(0) { } - - // Constructor (kind and children). This copies the contents of - // the child nodes. - // FIXME: is there a way to avoid repeating these? - ASTInternal(Kind kind, const ASTVec &children, BeevMgr &bm, int nodenum = 0) : - _ref_count(0), - _kind(kind), - _children(children), - _bm(bm), - _node_num(nodenum), - _index_width(0), - _value_width(0) { } - - // Copy constructor. This copies the contents of the child nodes - // array, along with everything else. Assigning the smart pointer, - // ASTNode, does NOT invoke this; This should only be used for - // temporary hash keys before uniquefication. - // FIXME: I don't think children need to be copied. - ASTInternal(const ASTInternal &int_node, int nodenum = 0) : - _ref_count(0), - _kind(int_node._kind), - _children(int_node._children), - _bm(int_node._bm), - _node_num(int_node._node_num), - _index_width(int_node._index_width), - _value_width(int_node._value_width) { } - - // Copying assign operator. Also copies contents of children. - ASTInternal& operator=(const ASTInternal &int_node); - - // Cleanup function for removing from hash table - virtual void CleanUp() = 0; - - // Destructor (does nothing, but is declared virtual here. - virtual ~ASTInternal(); - - // Abstract virtual print function for internal node. - // (c_friendly is for printing hex. numbers that C compilers will accept) - virtual void nodeprint(ostream& os, bool c_friendly = false) { os << "*"; }; - }; //End of Class ASTInternal - - // FIXME: Should children be only in interior node type? - /*************************************************************************** - Class ASTInterior: Internal representation of an interior - ASTNode. Generally, these nodes should have at least one - child - ***************************************************************************/ - class ASTInterior : public ASTInternal { - - friend class BeevMgr; - friend class ASTNodeHasher; - friend class ASTNodeEqual; - - private: - - // Hasher for ASTInterior pointer nodes - class ASTInteriorHasher { - public: - size_t operator()(const ASTInterior *int_node_ptr) const; - }; - - // Equality for ASTInterior nodes - class ASTInteriorEqual { - public: - bool operator()(const ASTInterior *int_node_ptr1, - const ASTInterior *int_node_ptr2) const{ - return (*int_node_ptr1 == *int_node_ptr2); - } - }; - - // Used in Equality class for hash tables - friend bool operator==(const ASTInterior &int_node1, - const ASTInterior &int_node2){ - return (int_node1._kind == int_node2._kind) && - (int_node1._children == int_node2._children); - } - - // Call this when deleting a node that has been stored in the - // the unique table - virtual void CleanUp(); - - // Returns kinds. "lispprinter" handles printing of parenthesis - // and childnodes. - // (c_friendly is for printing hex. numbers that C compilers will accept) - virtual void nodeprint(ostream& os, bool c_friendly = false) { - os << _kind_names[_kind]; - } - public: - - // FIXME: This should not be public, but has to be because the - // ASTInterior hash table insists on it. I can't seem to make the - // private destructor visible to hash_set. It does not even work - // to put "friend class hash_set" in here. - - // Basic constructors - ASTInterior(Kind kind, BeevMgr &bm) : - ASTInternal(kind, bm) { } - - ASTInterior(Kind kind, ASTVec &children, BeevMgr &bm) : - ASTInternal(kind, children, bm) { } - - //Copy constructor. This copies the contents of the child nodes - //array, along with everything else. Assigning the smart pointer, - //ASTNode, does NOT invoke this. - ASTInterior(const ASTInterior &int_node) : ASTInternal(int_node) { } - - // Destructor (does nothing, but is declared virtual here. - virtual ~ASTInterior(); - - }; //End of ASTNodeInterior - - - /***************************************************************************/ - /* Class ASTSymbol: Class to represent internals of Symbol node. */ - /***************************************************************************/ - class ASTSymbol : public ASTInternal{ - friend class BeevMgr; - friend class ASTNode; - friend class ASTNodeHasher; - friend class ASTNodeEqual; - - private: - // The name of the symbol - const char * const _name; - - class ASTSymbolHasher{ - public: - size_t operator() (const ASTSymbol *sym_ptr) const{ + // DecRef is a potentially expensive, because it has to delete + // the node from the unique table, in addition to freeing it. + // FIXME: Consider putting in a backpointer (iterator) to the hash + // table entry so it can be deleted without looking it up again. + void DecRef(); + + virtual const Kind GetKind() const + { + return _kind; + } + + virtual ASTVec const &GetChildren() const + { + return _children; + } + + int GetNodeNum() const + { + return _node_num; + } + + void SetNodeNum(int nn) + { + _node_num = nn; + } + ; + + // Constructor (bm only) + ASTInternal(BeevMgr &bm, int nodenum = 0) : + _ref_count(0), _kind(UNDEFINED), _bm(bm), _node_num(nodenum), _index_width(0), _value_width(0) + { + } + + // Constructor (kind only, empty children, int nodenum) + ASTInternal(Kind kind, BeevMgr &bm, int nodenum = 0) : + _ref_count(0), _kind(kind), _bm(bm), _node_num(nodenum), _index_width(0), _value_width(0) + { + } + + // Constructor (kind and children). This copies the contents of + // the child nodes. + // FIXME: is there a way to avoid repeating these? + ASTInternal(Kind kind, const ASTVec &children, BeevMgr &bm, int nodenum = 0) : + _ref_count(0), _kind(kind), _children(children), _bm(bm), _node_num(nodenum), _index_width(0), _value_width(0) + { + } + + // Copy constructor. This copies the contents of the child nodes + // array, along with everything else. Assigning the smart pointer, + // ASTNode, does NOT invoke this; This should only be used for + // temporary hash keys before uniquefication. + // FIXME: I don't think children need to be copied. + ASTInternal(const ASTInternal &int_node, int nodenum = 0) : + _ref_count(0), _kind(int_node._kind), _children(int_node._children), _bm(int_node._bm), _node_num(int_node._node_num), _index_width( + int_node._index_width), _value_width(int_node._value_width) + { + } + + // Copying assign operator. Also copies contents of children. + ASTInternal& operator=(const ASTInternal &int_node); + + // Cleanup function for removing from hash table + virtual void CleanUp() = 0; + + // Destructor (does nothing, but is declared virtual here. + virtual ~ASTInternal(); + + // Abstract virtual print function for internal node. + // (c_friendly is for printing hex. numbers that C compilers will accept) + virtual void nodeprint(ostream& os, bool c_friendly = false) + { + os << "*"; + } + ; +}; //End of Class ASTInternal + +// FIXME: Should children be only in interior node type? +/*************************************************************************** + Class ASTInterior: Internal representation of an interior + ASTNode. Generally, these nodes should have at least one + child + ***************************************************************************/ +class ASTInterior: public ASTInternal +{ + + friend class BeevMgr; + friend class ASTNodeHasher; + friend class ASTNodeEqual; + +private: + + // Hasher for ASTInterior pointer nodes + class ASTInteriorHasher + { + public: + size_t operator()(const ASTInterior *int_node_ptr) const; + }; + + // Equality for ASTInterior nodes + class ASTInteriorEqual + { + public: + bool operator()(const ASTInterior *int_node_ptr1, const ASTInterior *int_node_ptr2) const + { + return (*int_node_ptr1 == *int_node_ptr2); + } + }; + + // Used in Equality class for hash tables + friend bool operator==(const ASTInterior &int_node1, const ASTInterior &int_node2) + { + return (int_node1._kind == int_node2._kind) && (int_node1._children == int_node2._children); + } + + // Call this when deleting a node that has been stored in the + // the unique table + virtual void CleanUp(); + + // Returns kinds. "lispprinter" handles printing of parenthesis + // and childnodes. + // (c_friendly is for printing hex. numbers that C compilers will accept) + virtual void nodeprint(ostream& os, bool c_friendly = false) + { + os << _kind_names[_kind]; + } +public: + + // FIXME: This should not be public, but has to be because the + // ASTInterior hash table insists on it. I can't seem to make the + // private destructor visible to hash_set. It does not even work + // to put "friend class hash_set" in here. + + // Basic constructors + ASTInterior(Kind kind, BeevMgr &bm) : + ASTInternal(kind, bm) + { + } + + ASTInterior(Kind kind, ASTVec &children, BeevMgr &bm) : + ASTInternal(kind, children, bm) + { + } + + //Copy constructor. This copies the contents of the child nodes + //array, along with everything else. Assigning the smart pointer, + //ASTNode, does NOT invoke this. + ASTInterior(const ASTInterior &int_node) : + ASTInternal(int_node) + { + } + + // Destructor (does nothing, but is declared virtual here. + virtual ~ASTInterior(); + +}; //End of ASTNodeInterior + + +/***************************************************************************/ +/* Class ASTSymbol: Class to represent internals of Symbol node. */ +/***************************************************************************/ +class ASTSymbol: public ASTInternal +{ + friend class BeevMgr; + friend class ASTNode; + friend class ASTNodeHasher; + friend class ASTNodeEqual; + +private: + // The name of the symbol + const char * const _name; + + class ASTSymbolHasher + { + public: + size_t operator()(const ASTSymbol *sym_ptr) const + { #ifdef TR1_UNORDERED_MAP - tr1::hash h; + tr1::hash h; #else - hash h; + hash h; #endif - return h(sym_ptr->_name); - }; - }; - - // Equality for ASTInternal nodes - class ASTSymbolEqual{ - public: - bool operator()(const ASTSymbol *sym_ptr1, const ASTSymbol *sym_ptr2) const{ - return (*sym_ptr1 == *sym_ptr2); - } - }; - - friend bool operator==(const ASTSymbol &sym1, const ASTSymbol &sym2){ - return (strcmp(sym1._name, sym2._name) == 0); - } - - const char * const GetName() const{return _name;} - - // Print function for symbol -- return name */ - // (c_friendly is for printing hex. numbers that C compilers will accept) - virtual void nodeprint(ostream& os, bool c_friendly = false) { os << _name;} - - // Call this when deleting a node that has been stored in the - // the unique table - virtual void CleanUp(); - - public: - - // Default constructor - ASTSymbol(BeevMgr &bm) : ASTInternal(bm), _name(NULL) { } - - // Constructor. This does NOT copy its argument. - ASTSymbol(const char * const name, BeevMgr &bm) : ASTInternal(SYMBOL, bm), - _name(name) { } - - // Destructor (does nothing, but is declared virtual here. - virtual ~ASTSymbol(); - - // Copy constructor - // FIXME: seems to be calling default constructor for astinternal - ASTSymbol(const ASTSymbol &sym) : - ASTInternal(sym._kind, sym._children, sym._bm), - _name(sym._name) { } - }; //End of ASTSymbol - - - /***************************************************************************/ - /* Class ASTBVConst: Class to represent internals of a bitvectorconst */ - /***************************************************************************/ + return h(sym_ptr->_name); + } + ; + }; + + // Equality for ASTInternal nodes + class ASTSymbolEqual + { + public: + bool operator()(const ASTSymbol *sym_ptr1, const ASTSymbol *sym_ptr2) const + { + return (*sym_ptr1 == *sym_ptr2); + } + }; + + friend bool operator==(const ASTSymbol &sym1, const ASTSymbol &sym2) + { + return (strcmp(sym1._name, sym2._name) == 0); + } + + const char * const GetName() const + { + return _name; + } + + // Print function for symbol -- return name */ + // (c_friendly is for printing hex. numbers that C compilers will accept) + virtual void nodeprint(ostream& os, bool c_friendly = false) + { + os << _name; + } + + // Call this when deleting a node that has been stored in the + // the unique table + virtual void CleanUp(); + +public: + + // Default constructor + ASTSymbol(BeevMgr &bm) : + ASTInternal(bm), _name(NULL) + { + } + + // Constructor. This does NOT copy its argument. + ASTSymbol(const char * const name, BeevMgr &bm) : + ASTInternal(SYMBOL, bm), _name(name) + { + } + + // Destructor (does nothing, but is declared virtual here. + virtual ~ASTSymbol(); + + // Copy constructor + // FIXME: seems to be calling default constructor for astinternal + ASTSymbol(const ASTSymbol &sym) : + ASTInternal(sym._kind, sym._children, sym._bm), _name(sym._name) + { + } +}; //End of ASTSymbol + + +/***************************************************************************/ +/* Class ASTBVConst: Class to represent internals of a bitvectorconst */ +/***************************************************************************/ #ifndef NATIVE_C_ARITH - class ASTBVConst : public ASTInternal { - friend class BeevMgr; - friend class ASTNode; - friend class ASTNodeHasher; - friend class ASTNodeEqual; - - private: - //This is the private copy of a bvconst currently - //This should not be changed at any point - CBV _bvconst; - - class ASTBVConstHasher{ - public: - size_t operator() (const ASTBVConst * bvc) const { - return CONSTANTBV::BitVector_Hash(bvc->_bvconst); - }; - }; - - class ASTBVConstEqual{ - public: - bool operator()(const ASTBVConst * bvc1, const ASTBVConst * bvc2) const { - if( bvc1->_value_width != bvc2->_value_width){ - return false; - } - return (0==CONSTANTBV::BitVector_Compare(bvc1->_bvconst,bvc2->_bvconst)); - } - }; - - //FIXME Keep an eye on this function - ASTBVConst(CBV bv, unsigned int width, BeevMgr &bm) : - ASTInternal(BVCONST, bm) - { - _bvconst = CONSTANTBV::BitVector_Clone(bv); - _value_width = width; - } - - friend bool operator==(const ASTBVConst &bvc1, const ASTBVConst &bvc2){ - if(bvc1._value_width != bvc2._value_width) - return false; - return (0==CONSTANTBV::BitVector_Compare(bvc1._bvconst,bvc2._bvconst)); - } - // Call this when deleting a node that has been stored in the - // the unique table - virtual void CleanUp(); - - // Print function for bvconst -- return _bvconst value in bin format - // (c_friendly is for printing hex. numbers that C compilers will accept) - virtual void nodeprint(ostream& os, bool c_friendly = false) { - unsigned char *res; - const char *prefix; - - if (_value_width%4 == 0) { - res = CONSTANTBV::BitVector_to_Hex(_bvconst); - if (c_friendly) { - prefix = "0x"; - } - else { - prefix = "0hex"; - } - } else { - res = CONSTANTBV::BitVector_to_Bin(_bvconst); - if (c_friendly) { - prefix = "0b"; - } - else { - prefix = "0bin"; - } - } - if (NULL == res) { - os << "nodeprint: BVCONST : could not convert to string" << _bvconst; - FatalError(""); - } - os << prefix << res; - CONSTANTBV::BitVector_Dispose(res); - } - - // Copy constructor. - ASTBVConst(const ASTBVConst &sym) : - ASTInternal(sym._kind, sym._children, sym._bm) - { - _bvconst = CONSTANTBV::BitVector_Clone(sym._bvconst); - _value_width = sym._value_width; - } - - public: - virtual ~ASTBVConst(){ - CONSTANTBV::BitVector_Destroy(_bvconst); - } - - CBV GetBVConst() const {return _bvconst;} - }; //End of ASTBVConst - - - //FIXME This function is DEPRECATED - //Do not use in the future - inline unsigned int GetUnsignedConst(const ASTNode n) - { - if(sizeof(unsigned int) * 8 <= n.GetValueWidth()) - { - // It may only contain a small value in a bit type, which fits nicely into an unsigned int. - // This is common for functions like: bvshl(bv1[128], bv1[128]) - // where both operands have the same type. - signed long maxBit = CONSTANTBV::Set_Max(n.GetBVConst()); - if (maxBit >= ((signed long) sizeof(unsigned int)) * 8 ) - { - n.LispPrint(cerr); //print the node so they can find it. - FatalError("GetUnsignedConst: cannot convert bvconst of length greater than 32 to unsigned int"); - } - } - return (unsigned int) *((unsigned int *)n.GetBVConst()); - } +class ASTBVConst: public ASTInternal +{ + friend class BeevMgr; + friend class ASTNode; + friend class ASTNodeHasher; + friend class ASTNodeEqual; + +private: + //This is the private copy of a bvconst currently + //This should not be changed at any point + CBV _bvconst; + + class ASTBVConstHasher + { + public: + size_t operator()(const ASTBVConst * bvc) const + { + return CONSTANTBV::BitVector_Hash(bvc->_bvconst); + } + ; + }; + + class ASTBVConstEqual + { + public: + bool operator()(const ASTBVConst * bvc1, const ASTBVConst * bvc2) const + { + if (bvc1->_value_width != bvc2->_value_width) + { + return false; + } + return (0 == CONSTANTBV::BitVector_Compare(bvc1->_bvconst, bvc2->_bvconst)); + } + }; + + //FIXME Keep an eye on this function + ASTBVConst(CBV bv, unsigned int width, BeevMgr &bm) : + ASTInternal(BVCONST, bm) + { + _bvconst = CONSTANTBV::BitVector_Clone(bv); + _value_width = width; + } + + friend bool operator==(const ASTBVConst &bvc1, const ASTBVConst &bvc2) + { + if (bvc1._value_width != bvc2._value_width) + return false; + return (0 == CONSTANTBV::BitVector_Compare(bvc1._bvconst, bvc2._bvconst)); + } + // Call this when deleting a node that has been stored in the + // the unique table + virtual void CleanUp(); + + // Print function for bvconst -- return _bvconst value in bin format + // (c_friendly is for printing hex. numbers that C compilers will accept) + virtual void nodeprint(ostream& os, bool c_friendly = false) + { + unsigned char *res; + const char *prefix; + + if (_value_width % 4 == 0) + { + res = CONSTANTBV::BitVector_to_Hex(_bvconst); + if (c_friendly) + { + prefix = "0x"; + } + else + { + prefix = "0hex"; + } + } + else + { + res = CONSTANTBV::BitVector_to_Bin(_bvconst); + if (c_friendly) + { + prefix = "0b"; + } + else + { + prefix = "0bin"; + } + } + if (NULL == res) + { + os << "nodeprint: BVCONST : could not convert to string" << _bvconst; + FatalError(""); + } + os << prefix << res; + CONSTANTBV::BitVector_Dispose(res); + } + + // Copy constructor. + ASTBVConst(const ASTBVConst &sym) : + ASTInternal(sym._kind, sym._children, sym._bm) + { + _bvconst = CONSTANTBV::BitVector_Clone(sym._bvconst); + _value_width = sym._value_width; + } + +public: + virtual ~ASTBVConst() + { + CONSTANTBV::BitVector_Destroy(_bvconst); + } + + CBV GetBVConst() const + { + return _bvconst; + } +}; //End of ASTBVConst + + +//FIXME This function is DEPRECATED +//Do not use in the future +inline unsigned int GetUnsignedConst(const ASTNode n) +{ + if (sizeof(unsigned int) * 8 <= n.GetValueWidth()) + { + // It may only contain a small value in a bit type, which fits nicely into an unsigned int. + // This is common for functions like: bvshl(bv1[128], bv1[128]) + // where both operands have the same type. + signed long maxBit = CONSTANTBV::Set_Max(n.GetBVConst()); + if (maxBit >= ((signed long) sizeof(unsigned int)) * 8) + { + n.LispPrint(cerr); //print the node so they can find it. + FatalError("GetUnsignedConst: cannot convert bvconst of length greater than 32 to unsigned int"); + } + } + return (unsigned int) *((unsigned int *) n.GetBVConst()); +} #else - class ASTBVConst : public ASTInternal { - friend class BeevMgr; - friend class ASTNode; - friend class ASTNodeHasher; - friend class ASTNodeEqual; - - private: - // the bitvector contents. bitvector contents will be in two - // modes. one mode where all bitvectors are NATIVE and in this - // mode we use native unsigned long long int to represent the - // 32/64 bitvectors. The other for arbitrary length bitvector - // operations. - const unsigned long long int _bvconst; - - class ASTBVConstHasher{ - public: - size_t operator() (const ASTBVConst * bvc) const{ - //Thomas Wang's 64 bit Mix Function - unsigned long long int key(bvc->_bvconst); - key += ~(key << 32); - key ^= (key >> 22); - key += ~(key << 13); - key ^= (key >> 8); - key += (key << 3); - key ^= (key >> 15); - key += ~(key << 27); - key ^= (key >> 31); - - size_t return_key = key; - return return_key; - }; - }; - - class ASTBVConstEqual{ - public: - bool operator()(const ASTBVConst * bvc1, const ASTBVConst * bvc2) const { - return ((bvc1->_bvconst == bvc2->_bvconst) - && (bvc1->_value_width == bvc2->_value_width)); - } - }; - - // Call this when deleting a node that has been stored in the - // the unique table - virtual void CleanUp(); - public: - // Default constructor - ASTBVConst(const unsigned long long int bv, BeevMgr &bm) : - ASTInternal(BVCONST, bm), _bvconst(bv) { - } - - // Copy constructor. FIXME: figure out how this is supposed to - // work. - ASTBVConst(const ASTBVConst &sym) : - ASTInternal(sym._kind, sym._children, sym._bm), - _bvconst(sym._bvconst) { - _value_width = sym._value_width; - } - - // Destructor (does nothing, but is declared virtual here) - virtual ~ASTBVConst() { } - - friend bool operator==(const ASTBVConst &sym1, const ASTBVConst &sym2){ - return ((sym1._bvconst == sym2._bvconst) && - (sym1._value_width == sym2._value_width)); - } - - // Print function for bvconst -- return _bvconst value in binary format - virtual void nodeprint(ostream& os, bool c_friendly = false) { - string s = "0bin"; - unsigned long long int bitmask = 0x8000000000000000LL; - bitmask = bitmask >> (64-_value_width); - - for (; bitmask > 0; bitmask >>= 1) - s += (_bvconst & bitmask) ? '1' : '0'; - os << s; - } - - unsigned long long int GetBVConst() const {return _bvconst;} - }; //End of ASTBVConst - - //return value of bvconst - inline unsigned int GetUnsignedConst(const ASTNode n) { - if(32 < n.GetValueWidth()) - FatalError("GetUnsignedConst: cannot convert bvconst of length greater than 32 to unsigned int:"); - return (unsigned int)n.GetBVConst(); - } +class ASTBVConst : public ASTInternal +{ + friend class BeevMgr; + friend class ASTNode; + friend class ASTNodeHasher; + friend class ASTNodeEqual; + +private: + // the bitvector contents. bitvector contents will be in two + // modes. one mode where all bitvectors are NATIVE and in this + // mode we use native unsigned long long int to represent the + // 32/64 bitvectors. The other for arbitrary length bitvector + // operations. + const unsigned long long int _bvconst; + + class ASTBVConstHasher + { + public: + size_t operator() (const ASTBVConst * bvc) const + { + //Thomas Wang's 64 bit Mix Function + unsigned long long int key(bvc->_bvconst); + key += ~(key << 32); + key ^= (key >> 22); + key += ~(key << 13); + key ^= (key >> 8); + key += (key << 3); + key ^= (key >> 15); + key += ~(key << 27); + key ^= (key >> 31); + + size_t return_key = key; + return return_key; + }; + }; + + class ASTBVConstEqual + { + public: + bool operator()(const ASTBVConst * bvc1, const ASTBVConst * bvc2) const + { + return ((bvc1->_bvconst == bvc2->_bvconst) + && (bvc1->_value_width == bvc2->_value_width)); + } + }; + + // Call this when deleting a node that has been stored in the + // the unique table + virtual void CleanUp(); +public: + // Default constructor + ASTBVConst(const unsigned long long int bv, BeevMgr &bm) : + ASTInternal(BVCONST, bm), _bvconst(bv) + { + } + + // Copy constructor. FIXME: figure out how this is supposed to + // work. + ASTBVConst(const ASTBVConst &sym) : + ASTInternal(sym._kind, sym._children, sym._bm), + _bvconst(sym._bvconst) + { + _value_width = sym._value_width; + } + + // Destructor (does nothing, but is declared virtual here) + virtual ~ASTBVConst() + {} + + friend bool operator==(const ASTBVConst &sym1, const ASTBVConst &sym2) + { + return ((sym1._bvconst == sym2._bvconst) && + (sym1._value_width == sym2._value_width)); + } + + // Print function for bvconst -- return _bvconst value in binary format + virtual void nodeprint(ostream& os, bool c_friendly = false) + { + string s = "0bin"; + unsigned long long int bitmask = 0x8000000000000000LL; + bitmask = bitmask >> (64-_value_width); + + for (; bitmask > 0; bitmask >>= 1) + s += (_bvconst & bitmask) ? '1' : '0'; + os << s; + } + + unsigned long long int GetBVConst() const + { return _bvconst;} +}; //End of ASTBVConst + +//return value of bvconst +inline unsigned int GetUnsignedConst(const ASTNode n) +{ + if(32 < n.GetValueWidth()) + FatalError("GetUnsignedConst: cannot convert bvconst of length greater than 32 to unsigned int:"); + return (unsigned int)n.GetBVConst(); +} #endif /* -#else - // the bitvector contents. bitvector contents will be in two - // modes. one mode where all bitvectors are NATIVE and in this mode - // we use native unsigned long long int to represent the 32/64 - // bitvectors. The other for arbitrary length bitvector operations. - - //BVCONST defined for arbitrary length bitvectors - class ASTBVConst : public ASTInternal{ - friend class BeevMgr; - friend class ASTNode; - friend class ASTNodeHasher; - friend class ASTNodeEqual; - - private: - const char * const _bvconst; - - class ASTBVConstHasher{ - public: - size_t operator() (const ASTBVConst * bvc) const{ - hash h; - return h(bvc->_bvconst); - }; - }; - - class ASTBVConstEqual{ - public: - bool operator()(const ASTBVConst * bvc1, const ASTBVConst * bvc2) const { - if(bvc1->_value_width != bvc2->_value_width) - return false; - return (0 == strncmp(bvc1->_bvconst,bvc2->_bvconst,bvc1->_value_width)); - } - }; - - ASTBVConst(const char * bv, BeevMgr &bm) : - ASTInternal(BVCONST, bm), _bvconst(bv) { - //_value_width = strlen(bv); - } - - friend bool operator==(const ASTBVConst &bvc1, const ASTBVConst &bvc2){ - if(bvc1._value_width != bvc2._value_width) - return false; - return (0 == strncmp(bvc1._bvconst,bvc2._bvconst,bvc1._value_width)); - } - - // Call this when deleting a node that has been stored in the - // the unique table - virtual void CleanUp(); - - // Print function for bvconst -- return _bvconst value in binary format - virtual void nodeprint(ostream& os) { - if(_value_width%4 == 0) { - unsigned int * iii = CONSTANTBV::BitVector_Create(_value_width,true); - CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_from_Bin(iii,(unsigned char*)_bvconst); - //error printing - if(0 != e) { - os << "nodeprint: BVCONST : wrong hex value: " << BitVector_Error(e); - FatalError(""); + #else + // the bitvector contents. bitvector contents will be in two + // modes. one mode where all bitvectors are NATIVE and in this mode + // we use native unsigned long long int to represent the 32/64 + // bitvectors. The other for arbitrary length bitvector operations. + + //BVCONST defined for arbitrary length bitvectors + class ASTBVConst : public ASTInternal{ + friend class BeevMgr; + friend class ASTNode; + friend class ASTNodeHasher; + friend class ASTNodeEqual; + + private: + const char * const _bvconst; + + class ASTBVConstHasher{ + public: + size_t operator() (const ASTBVConst * bvc) const{ + hash h; + return h(bvc->_bvconst); + }; + }; + + class ASTBVConstEqual{ + public: + bool operator()(const ASTBVConst * bvc1, const ASTBVConst * bvc2) const { + if(bvc1->_value_width != bvc2->_value_width) + return false; + return (0 == strncmp(bvc1->_bvconst,bvc2->_bvconst,bvc1->_value_width)); + } + }; + + ASTBVConst(const char * bv, BeevMgr &bm) : + ASTInternal(BVCONST, bm), _bvconst(bv) { + //_value_width = strlen(bv); + } + + friend bool operator==(const ASTBVConst &bvc1, const ASTBVConst &bvc2){ + if(bvc1._value_width != bvc2._value_width) + return false; + return (0 == strncmp(bvc1._bvconst,bvc2._bvconst,bvc1._value_width)); + } + + // Call this when deleting a node that has been stored in the + // the unique table + virtual void CleanUp(); + + // Print function for bvconst -- return _bvconst value in binary format + virtual void nodeprint(ostream& os) { + if(_value_width%4 == 0) { + unsigned int * iii = CONSTANTBV::BitVector_Create(_value_width,true); + CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_from_Bin(iii,(unsigned char*)_bvconst); + //error printing + if(0 != e) { + os << "nodeprint: BVCONST : wrong hex value: " << BitVector_Error(e); + FatalError(""); + } + unsigned char * ccc = CONSTANTBV::BitVector_to_Hex(iii); + os << "0hex" << ccc; + CONSTANTBV::BitVector_Destroy(iii); + } + else { + std::string s(_bvconst,_value_width); + s = "0bin" + s; + os << s; + } + } + + // Copy constructor. + ASTBVConst(const ASTBVConst &sym) : ASTInternal(sym._kind, sym._children, sym._bm),_bvconst(sym._bvconst) { + //checking if the input is in the correct format + for(unsigned int jj=0;jj ASTNodeMap; + +// Function to dump contents of ASTNodeMap +ostream &operator<<(ostream &os, const ASTNodeMap &nmap); + +/*************************************************************************** + Typedef ASTNodeSet: This is a hash set of ASTNodes. Very useful + for representing things like "visited nodes" + ***************************************************************************/ +typedef hash_set ASTNodeSet; + +typedef hash_multiset ASTNodeMultiSet; + +//external parser table for declared symbols. +//FIXME: move to a more appropriate place +extern ASTNodeSet _parser_symbol_table; + +/*************************************************************************** + Class LispPrinter: iomanipulator for printing ASTNode or ASTVec + ***************************************************************************/ +class LispPrinter +{ + +public: + ASTNode _node; + + // number of spaces to print before first real character of + // object. + int _indentation; + + // FIXME: pass ASTNode by reference + // Constructor to build the LispPrinter object + LispPrinter(ASTNode node, int indentation) : + _node(node), _indentation(indentation) + { } - unsigned char * ccc = CONSTANTBV::BitVector_to_Hex(iii); - os << "0hex" << ccc; - CONSTANTBV::BitVector_Destroy(iii); - } - else { - std::string s(_bvconst,_value_width); - s = "0bin" + s; - os << s; - } - } - - // Copy constructor. - ASTBVConst(const ASTBVConst &sym) : ASTInternal(sym._kind, sym._children, sym._bm),_bvconst(sym._bvconst) { - //checking if the input is in the correct format - for(unsigned int jj=0;jj ASTNodeMap; - - // Function to dump contents of ASTNodeMap - ostream &operator<<(ostream &os, const ASTNodeMap &nmap); - - /*************************************************************************** - Typedef ASTNodeSet: This is a hash set of ASTNodes. Very useful - for representing things like "visited nodes" - ***************************************************************************/ - typedef hash_set ASTNodeSet; - - typedef hash_multiset ASTNodeMultiSet; - - //external parser table for declared symbols. - //FIXME: move to a more appropriate place - extern ASTNodeSet _parser_symbol_table; - - /*************************************************************************** - Class LispPrinter: iomanipulator for printing ASTNode or ASTVec - ***************************************************************************/ - class LispPrinter { - - public: - ASTNode _node; - - // number of spaces to print before first real character of - // object. - int _indentation; - - // FIXME: pass ASTNode by reference - // Constructor to build the LispPrinter object - LispPrinter(ASTNode node, int indentation): _node(node), _indentation(indentation) { } - - friend ostream &operator<<(ostream &os, const LispPrinter &lp){ - return lp._node.LispPrint(os, lp._indentation); - }; - - }; //End of ListPrinter - - //This is the IO manipulator. It builds an object of class - //"LispPrinter" that has a special overloaded "<<" operator. - inline LispPrinter lisp(const ASTNode &node, int indentation = 0){ - LispPrinter lp(node, indentation); - return lp; - } - - /***************************************************************************/ - /* Class LispVecPrinter:iomanipulator for printing vector of ASTNodes */ - /***************************************************************************/ - class LispVecPrinter { - - public: - const ASTVec * _vec; - // number of spaces to print before first real - // character of object. - int _indentation; - - // Constructor to build the LispPrinter object - LispVecPrinter(const ASTVec &vec, int indentation){ - _vec = &vec; _indentation = indentation; - } - - friend ostream &operator<<(ostream &os, const LispVecPrinter &lvp){ - LispPrintVec(os, *lvp._vec, lvp._indentation); - return os; - }; - }; //End of Class ListVecPrinter - - //iomanipulator. builds an object of class "LisPrinter" that has a - //special overloaded "<<" operator. - inline LispVecPrinter lisp(const ASTVec &vec, int indentation = 0){ - LispVecPrinter lvp(vec, indentation); - return lvp; - } - - - /***************************************************************** - * INLINE METHODS from various classed, declared here because of - * dependencies on classes that are declared later. - *****************************************************************/ - // ASTNode accessor function. - inline Kind ASTNode::GetKind() const { - //cout << "GetKind: " << _int_node_ptr; - return _int_node_ptr->GetKind(); - } - - // FIXME: should be const ASTVec const? - // Declared here because of same ordering problem as GetKind. - inline const ASTVec &ASTNode::GetChildren() const { - return _int_node_ptr->GetChildren(); - } - - // Access node number - inline int ASTNode::GetNodeNum() const { - return _int_node_ptr->_node_num; - } - - inline unsigned int ASTNode::GetIndexWidth () const { - return _int_node_ptr->_index_width; - } - - inline void ASTNode::SetIndexWidth (unsigned int iw) const { - _int_node_ptr->_index_width = iw; - } - - inline unsigned int ASTNode::GetValueWidth () const { - return _int_node_ptr->_value_width; - } - - inline void ASTNode::SetValueWidth (unsigned int vw) const { - _int_node_ptr->_value_width = vw; - } - - //return the type of the ASTNode: 0 iff BOOLEAN; 1 iff BITVECTOR; 2 - //iff ARRAY; 3 iff UNKNOWN; - inline types ASTNode::GetType() const { - if((GetIndexWidth() == 0) && (GetValueWidth() == 0)) //BOOLEAN - return BOOLEAN_TYPE; - if((GetIndexWidth() == 0) && (GetValueWidth() > 0)) //BITVECTOR - return BITVECTOR_TYPE; - if((GetIndexWidth() > 0) && (GetValueWidth() > 0)) //ARRAY - return ARRAY_TYPE; - return UNKNOWN_TYPE; - } - - // Constructor; creates a new pointer, increments refcount of - // pointed-to object. + ; + +}; //End of ListPrinter + +//This is the IO manipulator. It builds an object of class +//"LispPrinter" that has a special overloaded "<<" operator. +inline LispPrinter lisp(const ASTNode &node, int indentation = 0) +{ + LispPrinter lp(node, indentation); + return lp; +} + +/***************************************************************************/ +/* Class LispVecPrinter:iomanipulator for printing vector of ASTNodes */ +/***************************************************************************/ +class LispVecPrinter +{ + +public: + const ASTVec * _vec; + // number of spaces to print before first real + // character of object. + int _indentation; + + // Constructor to build the LispPrinter object + LispVecPrinter(const ASTVec &vec, int indentation) + { + _vec = &vec; + _indentation = indentation; + } + + friend ostream &operator<<(ostream &os, const LispVecPrinter &lvp) + { + LispPrintVec(os, *lvp._vec, lvp._indentation); + return os; + } + ; +}; //End of Class ListVecPrinter + +//iomanipulator. builds an object of class "LisPrinter" that has a +//special overloaded "<<" operator. +inline LispVecPrinter lisp(const ASTVec &vec, int indentation = 0) +{ + LispVecPrinter lvp(vec, indentation); + return lvp; +} + +/***************************************************************** + * INLINE METHODS from various classed, declared here because of + * dependencies on classes that are declared later. + *****************************************************************/ +// ASTNode accessor function. +inline Kind ASTNode::GetKind() const +{ + //cout << "GetKind: " << _int_node_ptr; + return _int_node_ptr->GetKind(); +} + +// FIXME: should be const ASTVec const? +// Declared here because of same ordering problem as GetKind. +inline const ASTVec &ASTNode::GetChildren() const +{ + return _int_node_ptr->GetChildren(); +} + +// Access node number +inline int ASTNode::GetNodeNum() const +{ + return _int_node_ptr->_node_num; +} + +inline unsigned int ASTNode::GetIndexWidth() const +{ + return _int_node_ptr->_index_width; +} + +inline void ASTNode::SetIndexWidth(unsigned int iw) const +{ + _int_node_ptr->_index_width = iw; +} + +inline unsigned int ASTNode::GetValueWidth() const +{ + return _int_node_ptr->_value_width; +} + +inline void ASTNode::SetValueWidth(unsigned int vw) const +{ + _int_node_ptr->_value_width = vw; +} + +//return the type of the ASTNode: 0 iff BOOLEAN; 1 iff BITVECTOR; 2 +//iff ARRAY; 3 iff UNKNOWN; +inline types ASTNode::GetType() const +{ + if ((GetIndexWidth() == 0) && (GetValueWidth() == 0)) //BOOLEAN + return BOOLEAN_TYPE; + if ((GetIndexWidth() == 0) && (GetValueWidth() > 0)) //BITVECTOR + return BITVECTOR_TYPE; + if ((GetIndexWidth() > 0) && (GetValueWidth() > 0)) //ARRAY + return ARRAY_TYPE; + return UNKNOWN_TYPE; +} + +// Constructor; creates a new pointer, increments refcount of +// pointed-to object. #ifndef SMTLIB - inline ASTNode::ASTNode(ASTInternal *in) : _int_node_ptr(in) { - if (in) in->IncRef(); - } +inline ASTNode::ASTNode(ASTInternal *in) : + _int_node_ptr(in) +{ + if (in) + in->IncRef(); +} #else - inline ASTNode::ASTNode(ASTInternal *in) : _int_node_ptr(in) { }; +inline ASTNode::ASTNode(ASTInternal *in) : _int_node_ptr(in) +{}; #endif - // Assignment. Increment refcount of new value, decrement refcount - // of old value and destroy if this was the last pointer. FIXME: - // accelerate this by creating an intnode with a ref counter instead - // of pointing to NULL. Need a special check in CleanUp to make - // sure the null node never gets freed. +// Assignment. Increment refcount of new value, decrement refcount +// of old value and destroy if this was the last pointer. FIXME: +// accelerate this by creating an intnode with a ref counter instead +// of pointing to NULL. Need a special check in CleanUp to make +// sure the null node never gets freed. #ifndef SMTLIB - inline ASTNode& ASTNode::operator=(const ASTNode& n) { - if (n._int_node_ptr) { - n._int_node_ptr->IncRef(); - } - if (_int_node_ptr) { - _int_node_ptr->DecRef(); - } - _int_node_ptr = n._int_node_ptr; - return *this; - } +inline ASTNode& ASTNode::operator=(const ASTNode& n) +{ + if (n._int_node_ptr) + { + n._int_node_ptr->IncRef(); + } + if (_int_node_ptr) + { + _int_node_ptr->DecRef(); + } + _int_node_ptr = n._int_node_ptr; + return *this; +} #else - inline ASTNode& ASTNode::operator=(const ASTNode& n) { - _int_node_ptr = n._int_node_ptr; - return *this; - } +inline ASTNode& ASTNode::operator=(const ASTNode& n) +{ + _int_node_ptr = n._int_node_ptr; + return *this; +} #endif #ifndef SMTLIB - inline void ASTInternal::DecRef() - { - if (--_ref_count == 0) { - // Delete node from unique table and kill it. - CleanUp(); - } - } - - // Destructor - inline ASTNode::~ASTNode() - { - if (_int_node_ptr) { - _int_node_ptr->DecRef(); - } - }; +inline void ASTInternal::DecRef() +{ + if (--_ref_count == 0) + { + // Delete node from unique table and kill it. + CleanUp(); + } +} + +// Destructor +inline ASTNode::~ASTNode() +{ + if (_int_node_ptr) + { + _int_node_ptr->DecRef(); + } +} +; #else - // No refcounting - inline void ASTInternal::DecRef() - { - } - - // Destructor - inline ASTNode::~ASTNode() - { - }; +// No refcounting +inline void ASTInternal::DecRef() +{ +} + +// Destructor +inline ASTNode::~ASTNode() +{ +}; #endif - inline BeevMgr& ASTNode::GetBeevMgr() const { return _int_node_ptr->_bm; } - - /*************************************************************************** - * Class BeevMgr. This holds all "global" variables for the system, such as - * unique tables for the various kinds of nodes. - ***************************************************************************/ - class BeevMgr { - friend class ASTNode; // ASTNode modifies AlreadyPrintedSet - // in BeevMgr - friend class ASTInterior; - friend class ASTBVConst; - friend class ASTSymbol; - - // FIXME: The values appear to be the same regardless of the value of SMTLIB - // initial hash table sizes, to save time on resizing. +inline BeevMgr& ASTNode::GetBeevMgr() const +{ + return _int_node_ptr->_bm; +} + +/*************************************************************************** + * Class BeevMgr. This holds all "global" variables for the system, such as + * unique tables for the various kinds of nodes. + ***************************************************************************/ +class BeevMgr +{ + friend class ASTNode; // ASTNode modifies AlreadyPrintedSet + // in BeevMgr + friend class ASTInterior; + friend class ASTBVConst; + friend class ASTSymbol; + + // FIXME: The values appear to be the same regardless of the value of SMTLIB + // initial hash table sizes, to save time on resizing. #ifdef SMTLIB - static const int INITIAL_INTERIOR_UNIQUE_TABLE_SIZE = 100; - static const int INITIAL_SYMBOL_UNIQUE_TABLE_SIZE = 100; - static const int INITIAL_BVCONST_UNIQUE_TABLE_SIZE = 100; - static const int INITIAL_BBTERM_MEMO_TABLE_SIZE = 100; - static const int INITIAL_BBFORM_MEMO_TABLE_SIZE = 100; - - static const int INITIAL_SIMPLIFY_MAP_SIZE = 100; - static const int INITIAL_SOLVER_MAP_SIZE = 100; - static const int INITIAL_ARRAYREAD_SYMBOL_SIZE = 100; - static const int INITIAL_INTRODUCED_SYMBOLS_SIZE = 100; + static const int INITIAL_INTERIOR_UNIQUE_TABLE_SIZE = 100; + static const int INITIAL_SYMBOL_UNIQUE_TABLE_SIZE = 100; + static const int INITIAL_BVCONST_UNIQUE_TABLE_SIZE = 100; + static const int INITIAL_BBTERM_MEMO_TABLE_SIZE = 100; + static const int INITIAL_BBFORM_MEMO_TABLE_SIZE = 100; + + static const int INITIAL_SIMPLIFY_MAP_SIZE = 100; + static const int INITIAL_SOLVER_MAP_SIZE = 100; + static const int INITIAL_ARRAYREAD_SYMBOL_SIZE = 100; + static const int INITIAL_INTRODUCED_SYMBOLS_SIZE = 100; #else - // these are the STL defaults - static const int INITIAL_INTERIOR_UNIQUE_TABLE_SIZE = 100; - static const int INITIAL_SYMBOL_UNIQUE_TABLE_SIZE = 100; - static const int INITIAL_BVCONST_UNIQUE_TABLE_SIZE = 100; - static const int INITIAL_BBTERM_MEMO_TABLE_SIZE = 100; - static const int INITIAL_BBFORM_MEMO_TABLE_SIZE = 100; - - static const int INITIAL_SIMPLIFY_MAP_SIZE = 100; - static const int INITIAL_SOLVER_MAP_SIZE = 100; - static const int INITIAL_ARRAYREAD_SYMBOL_SIZE = 100; - static const int INITIAL_INTRODUCED_SYMBOLS_SIZE = 100; + // these are the STL defaults + static const int INITIAL_INTERIOR_UNIQUE_TABLE_SIZE = 100; + static const int INITIAL_SYMBOL_UNIQUE_TABLE_SIZE = 100; + static const int INITIAL_BVCONST_UNIQUE_TABLE_SIZE = 100; + static const int INITIAL_BBTERM_MEMO_TABLE_SIZE = 100; + static const int INITIAL_BBFORM_MEMO_TABLE_SIZE = 100; + + static const int INITIAL_SIMPLIFY_MAP_SIZE = 100; + static const int INITIAL_SOLVER_MAP_SIZE = 100; + static const int INITIAL_ARRAYREAD_SYMBOL_SIZE = 100; + static const int INITIAL_INTRODUCED_SYMBOLS_SIZE = 100; #endif - private: - // Typedef for unique Interior node table. - typedef hash_set ASTInteriorSet; - - // Typedef for unique Symbol node (leaf) table. - typedef hash_set ASTSymbolSet; - - // Unique tables to share nodes whenever possible. - ASTInteriorSet _interior_unique_table; - //The _symbol_unique_table is also the symbol table to be used - //during parsing/semantic analysis - ASTSymbolSet _symbol_unique_table; - - //Typedef for unique BVConst node (leaf) table. - typedef hash_set ASTBVConstSet; - - //table to uniquefy bvconst - ASTBVConstSet _bvconst_unique_table; - - // type of memo table. - typedef hash_map ASTNodeToVecMap; - - typedef hash_map ASTNodeToSetMap; - - // Memo table for bit blasted terms. If a node has already been - // bitblasted, it is mapped to a vector of Boolean formulas for - // the bits. - - //OLD: ASTNodeToVecMap BBTermMemo; - ASTNodeMap BBTermMemo; - - // Memo table for bit blasted formulas. If a node has already - // been bitblasted, it is mapped to a node representing the - // bitblasted equivalent - ASTNodeMap BBFormMemo; - - //public: - // Get vector of Boolean formulas for sum of two - // vectors of Boolean formulas - void BBPlus2(ASTVec& sum, const ASTVec& y, ASTNode cin); - // Increment - ASTVec BBInc(ASTVec& x); - // Add one bit to a vector of bits. - ASTVec BBAddOneBit(ASTVec& x, ASTNode cin); - // Bitwise complement - ASTVec BBNeg(const ASTVec& x); - // Unary minus - ASTVec BBUminus(const ASTVec& x); - // Multiply. - ASTVec BBMult(const ASTVec& x, const ASTVec& y); - // AND each bit of vector y with single bit b and return the result. - // (used in BBMult) - ASTVec BBAndBit(const ASTVec& y, ASTNode b); - // Returns ASTVec for result - y. This destroys "result". - void BBSub(ASTVec& result, const ASTVec& y); - // build ITE's (ITE cond then[i] else[i]) for each i. - ASTVec BBITE(const ASTNode& cond, - const ASTVec& thn, const ASTVec& els); - // Build a vector of zeros. - ASTVec BBfill(unsigned int width, ASTNode fillval); - // build an EQ formula - ASTNode BBEQ(const ASTVec& left, const ASTVec& right); - - // This implements a variant of binary long division. - // q and r are "out" parameters. rwidth puts a bound on the - // recursion depth. Unsigned only, for now. - void BBDivMod(const ASTVec &y, - const ASTVec &x, - ASTVec &q, - ASTVec &r, - unsigned int rwidth); - - // Return formula for majority function of three formulas. - ASTNode Majority(const ASTNode& a, const ASTNode& b, const ASTNode& c); - - // Internal bit blasting routines. - ASTNode BBBVLE(const ASTVec& x, const ASTVec& y, bool is_signed); - - // Return bit-blasted form for BVLE, BVGE, BVGT, SBLE, etc. - ASTNode BBcompare(const ASTNode& form); - - // Left and right shift one. Writes into x. - void BBLShift(ASTVec& x); - void BBRShift(ASTVec& x); - - void BBLShift(ASTVec& x, unsigned int shift); - void BBRShift(ASTVec& x, unsigned int shift); - - public: - // Simplifying create functions - ASTNode CreateSimpForm(Kind kind, ASTVec &children); - ASTNode CreateSimpForm(Kind kind, const ASTNode& child0); - ASTNode CreateSimpForm(Kind kind, - const ASTNode& child0, - const ASTNode& child1); - ASTNode CreateSimpForm(Kind kind, - const ASTNode& child0, - const ASTNode& child1, - const ASTNode& child2); - - ASTNode CreateSimpNot(const ASTNode& form); - - // These are for internal use only. - // FIXME: Find a way to make this local to SimpBool, so they're - // not in AST.h - ASTNode CreateSimpXor(const ASTNode& form1, - const ASTNode& form2); - ASTNode CreateSimpXor(ASTVec &children); - ASTNode CreateSimpAndOr(bool isAnd, - const ASTNode& form1, - const ASTNode& form2); - ASTNode CreateSimpAndOr(bool IsAnd, ASTVec &children); - ASTNode CreateSimpFormITE(const ASTNode& child0, - const ASTNode& child1, - const ASTNode& child2); - - - // Declarations of BitBlaster functions (BitBlast.cpp) - public: - // Adds or removes a NOT as necessary to negate a literal. - ASTNode Negate(const ASTNode& form); - - // Bit blast a bitvector term. The term must have a kind for a - // bitvector term. Result is a ref to a vector of formula nodes - // representing the boolean formula. - const ASTNode BBTerm(const ASTNode& term); - - const ASTNode BBForm(const ASTNode& formula); - - // Declarations of CNF conversion (ToCNF.cpp) - public: - // ToCNF converts a bit-blasted Boolean formula to Conjunctive - // Normal Form, suitable for many SAT solvers. Our CNF representation - // is an STL vector of STL vectors, for independence from any particular - // SAT solver's representation. There needs to be a separate driver to - // convert our clauselist to the representation used by the SAT solver. - // Currently, there is only one such solver and its driver is "ToSAT" - - // Datatype for clauses - typedef vector* ClausePtr; - - // Datatype for Clauselists - typedef vector ClauseList; - - // Convert a Boolean formula to an equisatisfiable CNF formula. - ClauseList *ToCNF(const ASTNode& form); - - // Print function for debugging - void PrintClauseList(ostream& os, ClauseList& cll); - - // Free the clause list and all its clauses. - void DeleteClauseList(BeevMgr::ClauseList *cllp); - - // Map from formulas to representative literals, for debugging. - ASTNodeMap RepLitMap; - - private: - // Global for assigning new node numbers. - int _max_node_num; - - const ASTNode ASTFalse, ASTTrue, ASTUndefined; - - // I just did this so I could put it in as a fake return value in - // methods that return a ASTNode &, to make -Wall shut up. - ASTNode dummy_node; - - //BeevMgr Constructor, Destructor and other misc. functions - public: - - int NewNodeNum() { _max_node_num += 2; return _max_node_num; } - - // Table for DAG printing. - ASTNodeSet AlreadyPrintedSet; - - //Tables for Presentation language printing - - //Nodes seen so far - ASTNodeSet PLPrintNodeSet; - - //Map from ASTNodes to LetVars - ASTNodeMap NodeLetVarMap; - - //This is a vector which stores the Node to LetVars pairs. It - //allows for sorted printing, as opposed to NodeLetVarMap - std::vector > NodeLetVarVec; - - //a partial Map from ASTNodes to LetVars. Needed in order to - //correctly print shared subterms inside the LET itself - ASTNodeMap NodeLetVarMap1; - - //functions to lookup nodes from the memo tables. these should be - //private. - private: - //Destructively appends back_child nodes to front_child nodes. - //If back_child nodes is NULL, no appending is done. back_child - //nodes are not modified. Then it returns the hashed copy of the - //node, which is created if necessary. - ASTInterior *CreateInteriorNode(Kind kind, - ASTInterior *new_node, - // this is destructively modified. - const ASTVec & back_children = _empty_ASTVec); - - // Create unique ASTInterior node. - ASTInterior *LookupOrCreateInterior(ASTInterior *n); - - // Create unique ASTSymbol node. - ASTSymbol *LookupOrCreateSymbol(ASTSymbol& s); - - // Called whenever we want to make sure that the Symbol is - // declared during semantic analysis - bool LookupSymbol(ASTSymbol& s); - - // Called by ASTNode constructors to uniqueify ASTBVConst - ASTBVConst *LookupOrCreateBVConst(ASTBVConst& s); - - //Public functions for CreateNodes and Createterms - public: - // Create and return an ASTNode for a symbol - ASTNode CreateSymbol(const char * const name); - - // Create and return an ASTNode for a symbol - // Width is number of bits. - ASTNode CreateBVConst(string*& strval, int base, int bit_width); - ASTNode CreateBVConst(unsigned int width, unsigned long long int bvconst); - ASTNode CreateZeroConst(unsigned int width); - ASTNode CreateOneConst(unsigned int width); - ASTNode CreateTwoConst(unsigned int width); - ASTNode CreateMaxConst(unsigned int width); - - - // Create and return an ASTNode for a symbol - // Optional base was a problem because 0 could be an int or char *, - // so CreateBVConst was ambiguous. - ASTNode CreateBVConst(const char *strval, int base); - - //FIXME This is a dangerous function - ASTNode CreateBVConst(CBV bv, unsigned width); - - // Create and return an interior ASTNode - ASTNode CreateNode(Kind kind, const ASTVec &children = _empty_ASTVec); - - ASTNode CreateNode(Kind kind, - const ASTNode& child0, - const ASTVec &children = _empty_ASTVec); - - ASTNode CreateNode(Kind kind, - const ASTNode& child0, - const ASTNode& child1, - const ASTVec &children = _empty_ASTVec); - - ASTNode CreateNode(Kind kind, - const ASTNode& child0, - const ASTNode& child1, - const ASTNode& child2, - const ASTVec &children = _empty_ASTVec); - - // Create and return an ASTNode for a term - inline ASTNode CreateTerm(Kind kind, - unsigned int width, - const ASTVec &children = _empty_ASTVec) { - if(!is_Term_kind(kind)) - FatalError("CreateTerm: Illegal kind to CreateTerm:",ASTUndefined, kind); - ASTNode n = CreateNode(kind, children); - n.SetValueWidth(width); - - //by default we assume that the term is a Bitvector. If - //necessary the indexwidth can be changed later - n.SetIndexWidth(0); - return n; - } - - inline ASTNode CreateTerm(Kind kind, - unsigned int width, - const ASTNode& child0, - const ASTVec &children = _empty_ASTVec) { - if(!is_Term_kind(kind)) - FatalError("CreateTerm: Illegal kind to CreateTerm:",ASTUndefined, kind); - ASTNode n = CreateNode(kind, child0, children); - n.SetValueWidth(width); - return n; - } - - inline ASTNode CreateTerm(Kind kind, - unsigned int width, - const ASTNode& child0, - const ASTNode& child1, - const ASTVec &children = _empty_ASTVec) { - if(!is_Term_kind(kind)) - FatalError("CreateTerm: Illegal kind to CreateTerm:",ASTUndefined, kind); - ASTNode n = CreateNode(kind, child0, child1, children); - n.SetValueWidth(width); - return n; - } - - inline ASTNode CreateTerm(Kind kind, - unsigned int width, - const ASTNode& child0, - const ASTNode& child1, - const ASTNode& child2, - const ASTVec &children = _empty_ASTVec) { - if(!is_Term_kind(kind)) - FatalError("CreateTerm: Illegal kind to CreateTerm:",ASTUndefined, kind); - ASTNode n = CreateNode(kind, child0, child1, child2, children); - n.SetValueWidth(width); - return n; - } - - ASTNode SimplifyFormula_NoRemoveWrites(const ASTNode& a, bool pushNeg); - ASTNode SimplifyFormula_TopLevel(const ASTNode& a, bool pushNeg); - ASTNode SimplifyFormula(const ASTNode& a, bool pushNeg); - ASTNode SimplifyTerm_TopLevel(const ASTNode& b); - ASTNode SimplifyTerm(const ASTNode& a); - ASTNode SimplifyTermAux(const ASTNode& a); - void CheckSimplifyInvariant(const ASTNode& a, const ASTNode& output); - private: - //memo table for simplifcation - ASTNodeMap *SimplifyMap; - ASTNodeMap *SimplifyNegMap; - ASTNodeMap SolverMap; - ASTNodeSet AlwaysTrueFormMap; - ASTNodeMap MultInverseMap; - - public: - ASTNode SimplifyAtomicFormula(const ASTNode& a, bool pushNeg); - ASTNode CreateSimplifiedEQ(const ASTNode& t1, const ASTNode& t2); - ASTNode ITEOpt_InEqs(const ASTNode& in1); - ASTNode CreateSimplifiedTermITE(const ASTNode& t1, const ASTNode& t2, const ASTNode& t3); - ASTNode CreateSimplifiedFormulaITE(const ASTNode& in0, const ASTNode& in1, const ASTNode& in2); - ASTNode CreateSimplifiedINEQ(Kind k, const ASTNode& a0, const ASTNode& a1, bool pushNeg); - ASTNode SimplifyNotFormula(const ASTNode& a, bool pushNeg); - ASTNode SimplifyAndOrFormula(const ASTNode& a, bool pushNeg); - ASTNode SimplifyXorFormula(const ASTNode& a, bool pushNeg); - ASTNode SimplifyNandFormula(const ASTNode& a, bool pushNeg); - ASTNode SimplifyNorFormula(const ASTNode& a, bool pushNeg); - ASTNode SimplifyImpliesFormula(const ASTNode& a, bool pushNeg); - ASTNode SimplifyIffFormula(const ASTNode& a, bool pushNeg); - ASTNode SimplifyIteFormula(const ASTNode& a, bool pushNeg); - ASTNode FlattenOneLevel(const ASTNode& a); - ASTNode FlattenAndOr(const ASTNode& a); - ASTNode CombineLikeTerms(const ASTNode& a); - ASTNode LhsMinusRhs(const ASTNode& eq); - ASTNode DistributeMultOverPlus(const ASTNode& a, - bool startdistribution=false); - ASTNode ConvertBVSXToITE(const ASTNode& a); - //checks if the input constant is odd or not - bool BVConstIsOdd(const ASTNode& c); - //computes the multiplicatve inverse of the input - ASTNode MultiplicativeInverse(const ASTNode& c); - - void ClearAllTables(void); - void ClearAllCaches(void); - int BeforeSAT_ResultCheck(const ASTNode& q); - int CallSAT_ResultCheck(MINISAT::Solver& newS, - const ASTNode& q, const ASTNode& orig_input); - int SATBased_ArrayReadRefinement(MINISAT::Solver& newS, - const ASTNode& q, const ASTNode& orig_input); - int SATBased_ArrayWriteRefinement(MINISAT::Solver& newS, const ASTNode& orig_input); - //creates array write axiom only for the input term or formula, if - //necessary. If there are no axioms to produce then it simply - //generates TRUE - ASTNode Create_ArrayWriteAxioms(const ASTNode& array_readoverwrite_term, const ASTNode& array_newname); - ASTVec ArrayWrite_RemainingAxioms; - //variable indicates that counterexample will now be checked by - //the counterexample checker, and hence simplifyterm must switch - //off certain optimizations. In particular, array write - //optimizations - bool start_abstracting; - bool Begin_RemoveWrites; - bool SimplifyWrites_InPlace_Flag; - - void CopySolverMap_To_CounterExample(void); - //int LinearSearch(const ASTNode& orig_input); - //Datastructures and functions needed for counterexample - //generation, and interface with MINISAT - private: - /* MAP: This is a map from ASTNodes to MINISAT::Vars. - * - * The map is populated while ASTclauses are read from the AST - * ClauseList returned by CNF converter. For every new boolean - * variable in ASTClause a new MINISAT::Var is created (these vars - * typedefs for ints) - */ - typedef hash_map ASTtoSATMap; - ASTtoSATMap _ASTNode_to_SATVar; - - - public: - //converts the clause to SAT and calls SAT solver - bool toSATandSolve(MINISAT::Solver& S, ClauseList& cll); - - ///print SAT solver statistics - void PrintStats(MINISAT::Solver& stats); - - //from v8 - int TopLevelSATAux(const ASTNode& query); - - //################################################## - //################################################## - - //accepts query and returns the answer. if query is valid, return - //true, else return false. Automatically constructs counterexample - //for invalid queries, and prints them upon request. - int TopLevelSAT(const ASTNode& query, const ASTNode& asserts); - - // Debugging function to find problems in BitBlast and ToCNF. - // See body in ToSAT.cpp for more explanation. - ASTNode CheckBBandCNF(MINISAT::Solver& newS, ASTNode form); - - // Internal recursive body of above. - ASTNode CheckBBandCNF_int(MINISAT::Solver& newS, ASTNode form); - - // Helper function for CheckBBandCNF - ASTNode SymbolTruthValue(MINISAT::Solver &newS, ASTNode form); - - //looksup a MINISAT var from the minisat-var memo-table. if none - //exists, then creates one. - const MINISAT::Var LookupOrCreateSATVar(MINISAT::Solver& S, const ASTNode& n); - - // Memo table for CheckBBandCNF debugging function - ASTNodeMap CheckBBandCNFMemo; - - - //Data structures for Array Read Transformations - private: - /* MAP: This is a map from Array Names to list of array-read - * indices in the input. This map is used by the TransformArray() - * function - * - * This map is useful in converting array reads into nested ITE - * constructs. Suppose there are two array reads in the input - * Read(A,i) and Read(A,j). Then Read(A,i) is replaced with a - * symbolic constant, say v1, and Read(A,j) is replaced with the - * following ITE: - * - * ITE(i=j,v1,v2) - */ - //CAUTION: I tried using a set instead of vector for - //readindicies. for some odd reason the performance went down - //considerably. this is totally inexplicable. - ASTNodeToVecMap _arrayname_readindices; - - /* MAP: This is a map from Array Names to nested ITE constructs, - * which are built as described below. This map is used by the - * TransformArray() function - * - * This map is useful in converting array reads into nested ITE - * constructs. Suppose there are two array reads in the input - * Read(A,i) and Read(A,j). Then Read(A,i) is replaced with a - * symbolic constant, say v1, and Read(A,j) is replaced with the - * following ITE: - * - * ITE(i=j,v1,v2) - */ - ASTNodeMap _arrayread_ite; - - /*MAP: This is a map from array-reads to symbolic constants. This - *map is used by the TransformArray() - */ - ASTNodeMap _arrayread_symbol; - - ASTNodeSet _introduced_symbols; - - /*Memoization map for TransformFormula/TransformTerm/TransformArray function - */ - ASTNodeMap TransformMap; - - //count to keep track of new symbolic constants introduced - //corresponding to Array Reads - unsigned int _symbol_count; - - //Formula/Term Transformers. Let Expr Manager, Type Checker - public: - //Functions that Transform ASTNodes - ASTNode TransformFormula(const ASTNode& query); - ASTNode TransformTerm(const ASTNode& term); - ASTNode TransformArray(const ASTNode& term); - ASTNode TranslateSignedDivMod(const ASTNode& term); - - //LET Management - private: - // MAP: This map is from bound IDs that occur in LETs to - // expression. The map is useful in checking replacing the IDs - // with the corresponding expressions. - ASTNodeMap *_letid_expr_map; - public: - - ASTNode ResolveID(const ASTNode& var); - - //Functions that are used to manage LET expressions - void LetExprMgr(const ASTNode& var, const ASTNode& letExpr); - - //Delete Letid Map - void CleanupLetIDMap(void); - - //Allocate LetID map - void InitializeLetIDMap(void); - - //Substitute Let-vars with LetExprs - ASTNode SubstituteLetExpr(ASTNode inExpr); - - /* MAP: This is a map from MINISAT::Vars to ASTNodes - * - * This is a reverse map, useful in constructing - * counterexamples. MINISAT returns a model in terms of MINISAT - * Vars, and this map helps us convert it to a model over ASTNode - * variables. - */ - vector _SATVar_to_AST; - - private: - /* MAP: This is a map from ASTNodes to vectors of bits - * - * This map is used in constructing and printing - * counterexamples. MINISAT returns values for each bit (a - * BVGETBIT Node), and this maps allows us to assemble the bits - * into bitvectors. - */ - typedef hash_map *, - ASTNode::ASTNodeHasher, - ASTNode::ASTNodeEqual> ASTtoBitvectorMap; - ASTtoBitvectorMap _ASTNode_to_Bitvector; - - //Data structure that holds the counter-model - ASTNodeMap CounterExampleMap; - - //Checks if the counter_example is ok. In order for the - //counter_example to be ok, Every assert must evaluate to true - //w.r.t couner_example and the query must evaluate to - //false. Otherwise the counter_example is bogus. - void CheckCounterExample(bool t); - - //Converts a vector of bools to a BVConst - ASTNode BoolVectoBVConst(hash_map * w, unsigned int l); - - //accepts a term and turns it into a constant-term w.r.t counter_example - ASTNode TermToConstTermUsingModel(const ASTNode& term, bool ArrayReadFlag = true); - ASTNode Expand_ReadOverWrite_UsingModel(const ASTNode& term, bool ArrayReadFlag = true); - //Computes the truth value of a formula w.r.t counter_example - ASTNode ComputeFormulaUsingModel(const ASTNode& form); - - //Replaces WRITE(Arr,i,val) with ITE(j=i, val, READ(Arr,j)) - ASTNode RemoveWrites_TopLevel(const ASTNode& term); - ASTNode RemoveWrites(const ASTNode& term); - ASTNode SimplifyWrites_InPlace(const ASTNode& term); - ASTNode ReadOverWrite_To_ITE(const ASTNode& term); - - ASTNode NewArrayVar(unsigned int index, unsigned int value); - ASTNode NewVar(unsigned int valuewidth); - //For ArrayWrite Abstraction: map from read-over-write term to - //newname. - ASTNodeMap ReadOverWrite_NewName_Map; - //For ArrayWrite Refinement: Map new arraynames to Read-Over-Write - //terms - ASTNodeMap NewName_ReadOverWrite_Map; - - public: - //print the STP solver output - void PrintOutput(bool true_iff_valid); - - //Converts MINISAT counterexample into an AST memotable (i.e. the - //function populates the datastructure CounterExampleMap) - void ConstructCounterExample(MINISAT::Solver& S); - - //Prints the counterexample to stdout - void PrintCounterExample(bool t,std::ostream& os=cout); - - //Prints the counterexample to stdout - void PrintCounterExample_InOrder(bool t); - - //queries the counterexample, and returns the value corresponding - //to e - ASTNode GetCounterExample(bool t, const ASTNode& e); - - int CounterExampleSize(void) const {return CounterExampleMap.size();} - - //FIXME: This is bloody dangerous function. Hack attack to take - //care of requests from users who want to store complete - //counter-examples in their own data structures. - ASTNodeMap GetCompleteCounterExample() {return CounterExampleMap;} - - // prints MINISAT assigment one bit at a time, for debugging. - void PrintSATModel(MINISAT::Solver& S); - - //accepts constant input and normalizes it. - ASTNode BVConstEvaluator(const ASTNode& t); - - //FUNCTION TypeChecker: Assumes that the immediate Children of the - //input ASTNode have been typechecked. This function is suitable - //in scenarios like where you are building the ASTNode Tree, and - //you typecheck as you go along. It is not suitable as a general - //typechecker - void BVTypeCheck(const ASTNode& n); - - private: - //stack of Logical Context. each entry in the stack is a logical - //context. A logical context is a vector of assertions. The - //logical context is represented by a ptr to a vector of - //assertions in that logical context. Logical contexts are created - //by PUSH/POP - std::vector _asserts; - //The query for the current logical context. - ASTNode _current_query; - - //this flag, when true, indicates that counterexample is being - //checked by the counterexample checker - bool counterexample_checking_during_refinement; - - //this flag indicates as to whether the input has been determined to - //be valid or not by this tool - bool ValidFlag; - - //this flag, when true, indicates that a BVDIV divide by zero - //exception occured. However, the program must not exit with a - //fatalerror. Instead, it should evaluate the whole formula (which - //contains the BVDIV term) to be FALSE. - bool bvdiv_exception_occured; - - public: - //set of functions that manipulate Logical Contexts. - // - //add an assertion to the current logical context - void AddAssert(const ASTNode& assert); - void Push(void); - void Pop(void); - void AddQuery(const ASTNode& q); - const ASTNode PopQuery(); - const ASTNode GetQuery(); - const ASTVec GetAsserts(void); - - //reports node size. Second arg is "clearstatinfo", whatever that is. - unsigned int NodeSize(const ASTNode& a, bool t = false); - - private: - //This memo map is used by the ComputeFormulaUsingModel() - ASTNodeMap ComputeFormulaMap; - //Map for statiscal purposes - ASTNodeSet StatInfoSet; - - - ASTNodeMap TermsAlreadySeenMap; - ASTNode CreateSubstitutionMap(const ASTNode& a); - public: - //prints statistics for the ASTNode. can add a prefix string c - void ASTNodeStats(const char * c, const ASTNode& a); - - //substitution - bool CheckSubstitutionMap(const ASTNode& a, ASTNode& output); - bool CheckSubstitutionMap(const ASTNode& a); - bool UpdateSubstitutionMap(const ASTNode& e0, const ASTNode& e1); - //if (a > b) in the termorder, then return 1 - //elseif (a < b) in the termorder, then return -1 - //else return 0 - int TermOrder(const ASTNode& a, const ASTNode& b); - //fill the arrayname_readindices vector if e0 is a READ(Arr,index) - //and index is a BVCONST - void FillUp_ArrReadIndex_Vec(const ASTNode& e0, const ASTNode& e1); - bool VarSeenInTerm(const ASTNode& var, const ASTNode& term); - - //functions for checking and updating simplifcation map - bool CheckSimplifyMap(const ASTNode& key, ASTNode& output, bool pushNeg); - void UpdateSimplifyMap(const ASTNode& key, const ASTNode& value, bool pushNeg); - void ResetSimplifyMaps(); - bool CheckAlwaysTrueFormMap(const ASTNode& key); - void UpdateAlwaysTrueFormMap(const ASTNode& val); - bool CheckMultInverseMap(const ASTNode& key, ASTNode& output); - void UpdateMultInverseMap(const ASTNode& key, const ASTNode& value); - - //Map for solved variables - bool CheckSolverMap(const ASTNode& a, ASTNode& output); - bool CheckSolverMap(const ASTNode& a); - bool UpdateSolverMap(const ASTNode& e0, const ASTNode& e1); - - public: - //FIXME: HACK_ATTACK. this vector was hacked into the code to - //support a special request by Dawson' group. They want the - //counterexample to be printed in the order of variables declared. - //TO BE COMMENTED LATER (say by 1st week of march,2006) - ASTVec _special_print_set; - - - //prints the initial activity levels of variables - //void PrintActivityLevels_Of_SATVars(char * init_msg, MINISAT::Solver& newS); - - //this function biases the activity levels of MINISAT variables. - //void ChangeActivityLevels_Of_SATVars(MINISAT::Solver& n); - - // Constructor - BeevMgr() : _interior_unique_table(INITIAL_INTERIOR_UNIQUE_TABLE_SIZE), - _symbol_unique_table(INITIAL_SYMBOL_UNIQUE_TABLE_SIZE), - _bvconst_unique_table(INITIAL_BVCONST_UNIQUE_TABLE_SIZE), - BBTermMemo(INITIAL_BBTERM_MEMO_TABLE_SIZE), - BBFormMemo(INITIAL_BBFORM_MEMO_TABLE_SIZE), - _max_node_num(0), - ASTFalse(CreateNode(FALSE)), - ASTTrue(CreateNode(TRUE)), - ASTUndefined(CreateNode(UNDEFINED)), - SolverMap(INITIAL_SOLVER_MAP_SIZE), - _arrayread_symbol(INITIAL_ARRAYREAD_SYMBOL_SIZE), - _introduced_symbols(INITIAL_INTRODUCED_SYMBOLS_SIZE), - _symbol_count(0) { - _current_query = ASTUndefined; - ValidFlag = false; - bvdiv_exception_occured = false; - counterexample_checking_during_refinement = false; - start_abstracting = false; - Begin_RemoveWrites = false; - SimplifyWrites_InPlace_Flag = false; - SimplifyMap = new ASTNodeMap(INITIAL_SIMPLIFY_MAP_SIZE); - SimplifyNegMap = new ASTNodeMap(INITIAL_SIMPLIFY_MAP_SIZE); - _letid_expr_map = new ASTNodeMap(INITIAL_INTRODUCED_SYMBOLS_SIZE); - }; - - //destructor - ~BeevMgr(); - }; //End of Class BeevMgr - - - class CompleteCounterExample { - ASTNodeMap counterexample; - BeevMgr * bv; - public: - CompleteCounterExample(ASTNodeMap a, BeevMgr* beev) : counterexample(a), bv(beev){} - ASTNode GetCounterExample(ASTNode e) { - if(BOOLEAN_TYPE == e.GetType() && SYMBOL != e.GetKind()) { - FatalError("You must input a term or propositional variables\n",e); - } - if(counterexample.find(e) != counterexample.end()) { - return counterexample[e]; - } - else { - if(SYMBOL == e.GetKind() && BOOLEAN_TYPE == e.GetType()) { - return bv->CreateNode(BEEV::FALSE); +private: + // Typedef for unique Interior node table. + typedef hash_set ASTInteriorSet; + + // Typedef for unique Symbol node (leaf) table. + typedef hash_set ASTSymbolSet; + + // Unique tables to share nodes whenever possible. + ASTInteriorSet _interior_unique_table; + //The _symbol_unique_table is also the symbol table to be used + //during parsing/semantic analysis + ASTSymbolSet _symbol_unique_table; + + //Typedef for unique BVConst node (leaf) table. + typedef hash_set ASTBVConstSet; + + //table to uniquefy bvconst + ASTBVConstSet _bvconst_unique_table; + + // type of memo table. + typedef hash_map ASTNodeToVecMap; + + typedef hash_map ASTNodeToSetMap; + + // Memo table for bit blasted terms. If a node has already been + // bitblasted, it is mapped to a vector of Boolean formulas for + // the bits. + + //OLD: ASTNodeToVecMap BBTermMemo; + ASTNodeMap BBTermMemo; + + // Memo table for bit blasted formulas. If a node has already + // been bitblasted, it is mapped to a node representing the + // bitblasted equivalent + ASTNodeMap BBFormMemo; + + //public: + // Get vector of Boolean formulas for sum of two + // vectors of Boolean formulas + void BBPlus2(ASTVec& sum, const ASTVec& y, ASTNode cin); + // Increment + ASTVec BBInc(ASTVec& x); + // Add one bit to a vector of bits. + ASTVec BBAddOneBit(ASTVec& x, ASTNode cin); + // Bitwise complement + ASTVec BBNeg(const ASTVec& x); + // Unary minus + ASTVec BBUminus(const ASTVec& x); + // Multiply. + ASTVec BBMult(const ASTVec& x, const ASTVec& y); + // AND each bit of vector y with single bit b and return the result. + // (used in BBMult) + ASTVec BBAndBit(const ASTVec& y, ASTNode b); + // Returns ASTVec for result - y. This destroys "result". + void BBSub(ASTVec& result, const ASTVec& y); + // build ITE's (ITE cond then[i] else[i]) for each i. + ASTVec BBITE(const ASTNode& cond, const ASTVec& thn, const ASTVec& els); + // Build a vector of zeros. + ASTVec BBfill(unsigned int width, ASTNode fillval); + // build an EQ formula + ASTNode BBEQ(const ASTVec& left, const ASTVec& right); + + // This implements a variant of binary long division. + // q and r are "out" parameters. rwidth puts a bound on the + // recursion depth. Unsigned only, for now. + void BBDivMod(const ASTVec &y, const ASTVec &x, ASTVec &q, ASTVec &r, unsigned int rwidth); + + // Return formula for majority function of three formulas. + ASTNode Majority(const ASTNode& a, const ASTNode& b, const ASTNode& c); + + // Internal bit blasting routines. + ASTNode BBBVLE(const ASTVec& x, const ASTVec& y, bool is_signed); + + // Return bit-blasted form for BVLE, BVGE, BVGT, SBLE, etc. + ASTNode BBcompare(const ASTNode& form); + + // Left and right shift one. Writes into x. + void BBLShift(ASTVec& x); + void BBRShift(ASTVec& x); + + void BBLShift(ASTVec& x, unsigned int shift); + void BBRShift(ASTVec& x, unsigned int shift); + +public: + // Simplifying create functions + ASTNode CreateSimpForm(Kind kind, ASTVec &children); + ASTNode CreateSimpForm(Kind kind, const ASTNode& child0); + ASTNode CreateSimpForm(Kind kind, const ASTNode& child0, const ASTNode& child1); + ASTNode CreateSimpForm(Kind kind, const ASTNode& child0, const ASTNode& child1, const ASTNode& child2); + + ASTNode CreateSimpNot(const ASTNode& form); + + // These are for internal use only. + // FIXME: Find a way to make this local to SimpBool, so they're + // not in AST.h + ASTNode CreateSimpXor(const ASTNode& form1, const ASTNode& form2); + ASTNode CreateSimpXor(ASTVec &children); + ASTNode CreateSimpAndOr(bool isAnd, const ASTNode& form1, const ASTNode& form2); + ASTNode CreateSimpAndOr(bool IsAnd, ASTVec &children); + ASTNode CreateSimpFormITE(const ASTNode& child0, const ASTNode& child1, const ASTNode& child2); + + // Declarations of BitBlaster functions (BitBlast.cpp) +public: + // Adds or removes a NOT as necessary to negate a literal. + ASTNode Negate(const ASTNode& form); + + // Bit blast a bitvector term. The term must have a kind for a + // bitvector term. Result is a ref to a vector of formula nodes + // representing the boolean formula. + const ASTNode BBTerm(const ASTNode& term); + + const ASTNode BBForm(const ASTNode& formula); + + // Declarations of CNF conversion (ToCNF.cpp) +public: + // ToCNF converts a bit-blasted Boolean formula to Conjunctive + // Normal Form, suitable for many SAT solvers. Our CNF representation + // is an STL vector of STL vectors, for independence from any particular + // SAT solver's representation. There needs to be a separate driver to + // convert our clauselist to the representation used by the SAT solver. + // Currently, there is only one such solver and its driver is "ToSAT" + + // Datatype for clauses + typedef vector* ClausePtr; + + // Datatype for Clauselists + typedef vector ClauseList; + + // Convert a Boolean formula to an equisatisfiable CNF formula. + ClauseList *ToCNF(const ASTNode& form); + + // Print function for debugging + void PrintClauseList(ostream& os, ClauseList& cll); + + // Free the clause list and all its clauses. + void DeleteClauseList(BeevMgr::ClauseList *cllp); + + // Map from formulas to representative literals, for debugging. + ASTNodeMap RepLitMap; + +private: + // Global for assigning new node numbers. + int _max_node_num; + + const ASTNode ASTFalse, ASTTrue, ASTUndefined; + + // I just did this so I could put it in as a fake return value in + // methods that return a ASTNode &, to make -Wall shut up. + ASTNode dummy_node; + + //BeevMgr Constructor, Destructor and other misc. functions +public: + + int NewNodeNum() + { + _max_node_num += 2; + return _max_node_num; } - if(SYMBOL == e.GetKind()) { - ASTNode z = bv->CreateZeroConst(e.GetValueWidth()); - return z; + // Table for DAG printing. + ASTNodeSet AlreadyPrintedSet; + + //Tables for Presentation language printing + + //Nodes seen so far + ASTNodeSet PLPrintNodeSet; + + //Map from ASTNodes to LetVars + ASTNodeMap NodeLetVarMap; + + //This is a vector which stores the Node to LetVars pairs. It + //allows for sorted printing, as opposed to NodeLetVarMap + std::vector > NodeLetVarVec; + + //a partial Map from ASTNodes to LetVars. Needed in order to + //correctly print shared subterms inside the LET itself + ASTNodeMap NodeLetVarMap1; + + //functions to lookup nodes from the memo tables. these should be + //private. +private: + //Destructively appends back_child nodes to front_child nodes. + //If back_child nodes is NULL, no appending is done. back_child + //nodes are not modified. Then it returns the hashed copy of the + //node, which is created if necessary. + ASTInterior *CreateInteriorNode(Kind kind, ASTInterior *new_node, + // this is destructively modified. + const ASTVec & back_children = _empty_ASTVec); + + // Create unique ASTInterior node. + ASTInterior *LookupOrCreateInterior(ASTInterior *n); + + // Create unique ASTSymbol node. + ASTSymbol *LookupOrCreateSymbol(ASTSymbol& s); + + // Called whenever we want to make sure that the Symbol is + // declared during semantic analysis + bool LookupSymbol(ASTSymbol& s); + + // Called by ASTNode constructors to uniqueify ASTBVConst + ASTBVConst *LookupOrCreateBVConst(ASTBVConst& s); + + //Public functions for CreateNodes and Createterms +public: + // Create and return an ASTNode for a symbol + ASTNode CreateSymbol(const char * const name); + + // Create and return an ASTNode for a symbol + // Width is number of bits. + ASTNode CreateBVConst(string*& strval, int base, int bit_width); + ASTNode CreateBVConst(unsigned int width, unsigned long long int bvconst); + ASTNode CreateZeroConst(unsigned int width); + ASTNode CreateOneConst(unsigned int width); + ASTNode CreateTwoConst(unsigned int width); + ASTNode CreateMaxConst(unsigned int width); + + // Create and return an ASTNode for a symbol + // Optional base was a problem because 0 could be an int or char *, + // so CreateBVConst was ambiguous. + ASTNode CreateBVConst(const char *strval, int base); + + //FIXME This is a dangerous function + ASTNode CreateBVConst(CBV bv, unsigned width); + + // Create and return an interior ASTNode + ASTNode CreateNode(Kind kind, const ASTVec &children = _empty_ASTVec); + + ASTNode CreateNode(Kind kind, const ASTNode& child0, const ASTVec &children = _empty_ASTVec); + + ASTNode CreateNode(Kind kind, const ASTNode& child0, const ASTNode& child1, const ASTVec &children = _empty_ASTVec); + + ASTNode CreateNode(Kind kind, const ASTNode& child0, const ASTNode& child1, const ASTNode& child2, const ASTVec &children = _empty_ASTVec); + + // Create and return an ASTNode for a term + inline ASTNode CreateTerm(Kind kind, unsigned int width, const ASTVec &children = _empty_ASTVec) + { + if (!is_Term_kind(kind)) + FatalError("CreateTerm: Illegal kind to CreateTerm:", ASTUndefined, kind); + ASTNode n = CreateNode(kind, children); + n.SetValueWidth(width); + + //by default we assume that the term is a Bitvector. If + //necessary the indexwidth can be changed later + n.SetIndexWidth(0); + return n; + } + + inline ASTNode CreateTerm(Kind kind, unsigned int width, const ASTNode& child0, const ASTVec &children = _empty_ASTVec) + { + if (!is_Term_kind(kind)) + FatalError("CreateTerm: Illegal kind to CreateTerm:", ASTUndefined, kind); + ASTNode n = CreateNode(kind, child0, children); + n.SetValueWidth(width); + return n; + } + + inline ASTNode CreateTerm(Kind kind, unsigned int width, const ASTNode& child0, const ASTNode& child1, const ASTVec &children = _empty_ASTVec) + { + if (!is_Term_kind(kind)) + FatalError("CreateTerm: Illegal kind to CreateTerm:", ASTUndefined, kind); + ASTNode n = CreateNode(kind, child0, child1, children); + n.SetValueWidth(width); + return n; + } + + inline ASTNode CreateTerm(Kind kind, + unsigned int width, + const ASTNode& child0, + const ASTNode& child1, + const ASTNode& child2, + const ASTVec &children = _empty_ASTVec) + { + if (!is_Term_kind(kind)) + FatalError("CreateTerm: Illegal kind to CreateTerm:", ASTUndefined, kind); + ASTNode n = CreateNode(kind, child0, child1, child2, children); + n.SetValueWidth(width); + return n; } - return e; - } - } - }; + ASTNode SimplifyFormula_NoRemoveWrites(const ASTNode& a, bool pushNeg); + ASTNode SimplifyFormula_TopLevel(const ASTNode& a, bool pushNeg); + ASTNode SimplifyFormula(const ASTNode& a, bool pushNeg); + ASTNode SimplifyTerm_TopLevel(const ASTNode& b); + ASTNode SimplifyTerm(const ASTNode& a); + ASTNode SimplifyTermAux(const ASTNode& a); + void CheckSimplifyInvariant(const ASTNode& a, const ASTNode& output); +private: + //memo table for simplifcation + ASTNodeMap *SimplifyMap; + ASTNodeMap *SimplifyNegMap; + ASTNodeMap SolverMap; + ASTNodeSet AlwaysTrueFormMap; + ASTNodeMap MultInverseMap; + +public: + ASTNode SimplifyAtomicFormula(const ASTNode& a, bool pushNeg); + ASTNode CreateSimplifiedEQ(const ASTNode& t1, const ASTNode& t2); + ASTNode ITEOpt_InEqs(const ASTNode& in1); + ASTNode CreateSimplifiedTermITE(const ASTNode& t1, const ASTNode& t2, const ASTNode& t3); + ASTNode CreateSimplifiedFormulaITE(const ASTNode& in0, const ASTNode& in1, const ASTNode& in2); + ASTNode CreateSimplifiedINEQ(Kind k, const ASTNode& a0, const ASTNode& a1, bool pushNeg); + ASTNode SimplifyNotFormula(const ASTNode& a, bool pushNeg); + ASTNode SimplifyAndOrFormula(const ASTNode& a, bool pushNeg); + ASTNode SimplifyXorFormula(const ASTNode& a, bool pushNeg); + ASTNode SimplifyNandFormula(const ASTNode& a, bool pushNeg); + ASTNode SimplifyNorFormula(const ASTNode& a, bool pushNeg); + ASTNode SimplifyImpliesFormula(const ASTNode& a, bool pushNeg); + ASTNode SimplifyIffFormula(const ASTNode& a, bool pushNeg); + ASTNode SimplifyIteFormula(const ASTNode& a, bool pushNeg); + ASTNode FlattenOneLevel(const ASTNode& a); + ASTNode FlattenAndOr(const ASTNode& a); + ASTNode CombineLikeTerms(const ASTNode& a); + ASTNode LhsMinusRhs(const ASTNode& eq); + ASTNode DistributeMultOverPlus(const ASTNode& a, bool startdistribution = false); + ASTNode ConvertBVSXToITE(const ASTNode& a); + //checks if the input constant is odd or not + bool BVConstIsOdd(const ASTNode& c); + //computes the multiplicatve inverse of the input + ASTNode MultiplicativeInverse(const ASTNode& c); + + void ClearAllTables(void); + void ClearAllCaches(void); + int BeforeSAT_ResultCheck(const ASTNode& q); + int CallSAT_ResultCheck(MINISAT::Solver& newS, const ASTNode& q, const ASTNode& orig_input); + int SATBased_ArrayReadRefinement(MINISAT::Solver& newS, const ASTNode& q, const ASTNode& orig_input); + int SATBased_ArrayWriteRefinement(MINISAT::Solver& newS, const ASTNode& orig_input); + //creates array write axiom only for the input term or formula, if + //necessary. If there are no axioms to produce then it simply + //generates TRUE + ASTNode Create_ArrayWriteAxioms(const ASTNode& array_readoverwrite_term, const ASTNode& array_newname); + ASTVec ArrayWrite_RemainingAxioms; + //variable indicates that counterexample will now be checked by + //the counterexample checker, and hence simplifyterm must switch + //off certain optimizations. In particular, array write + //optimizations + bool start_abstracting; + bool Begin_RemoveWrites; + bool SimplifyWrites_InPlace_Flag; + + void CopySolverMap_To_CounterExample(void); + //int LinearSearch(const ASTNode& orig_input); + //Datastructures and functions needed for counterexample + //generation, and interface with MINISAT +private: + /* MAP: This is a map from ASTNodes to MINISAT::Vars. + * + * The map is populated while ASTclauses are read from the AST + * ClauseList returned by CNF converter. For every new boolean + * variable in ASTClause a new MINISAT::Var is created (these vars + * typedefs for ints) + */ + typedef hash_map ASTtoSATMap; + ASTtoSATMap _ASTNode_to_SATVar; + +public: + //converts the clause to SAT and calls SAT solver + bool toSATandSolve(MINISAT::Solver& S, ClauseList& cll); + + ///print SAT solver statistics + void PrintStats(MINISAT::Solver& stats); + + //from v8 + int TopLevelSATAux(const ASTNode& query); + + //################################################## + //################################################## + + //accepts query and returns the answer. if query is valid, return + //true, else return false. Automatically constructs counterexample + //for invalid queries, and prints them upon request. + int TopLevelSAT(const ASTNode& query, const ASTNode& asserts); + + // Debugging function to find problems in BitBlast and ToCNF. + // See body in ToSAT.cpp for more explanation. + ASTNode CheckBBandCNF(MINISAT::Solver& newS, ASTNode form); + + // Internal recursive body of above. + ASTNode CheckBBandCNF_int(MINISAT::Solver& newS, ASTNode form); + + // Helper function for CheckBBandCNF + ASTNode SymbolTruthValue(MINISAT::Solver &newS, ASTNode form); + + //looksup a MINISAT var from the minisat-var memo-table. if none + //exists, then creates one. + const MINISAT::Var LookupOrCreateSATVar(MINISAT::Solver& S, const ASTNode& n); + + // Memo table for CheckBBandCNF debugging function + ASTNodeMap CheckBBandCNFMemo; + + //Data structures for Array Read Transformations +private: + /* MAP: This is a map from Array Names to list of array-read + * indices in the input. This map is used by the TransformArray() + * function + * + * This map is useful in converting array reads into nested ITE + * constructs. Suppose there are two array reads in the input + * Read(A,i) and Read(A,j). Then Read(A,i) is replaced with a + * symbolic constant, say v1, and Read(A,j) is replaced with the + * following ITE: + * + * ITE(i=j,v1,v2) + */ + //CAUTION: I tried using a set instead of vector for + //readindicies. for some odd reason the performance went down + //considerably. this is totally inexplicable. + ASTNodeToVecMap _arrayname_readindices; + + /* MAP: This is a map from Array Names to nested ITE constructs, + * which are built as described below. This map is used by the + * TransformArray() function + * + * This map is useful in converting array reads into nested ITE + * constructs. Suppose there are two array reads in the input + * Read(A,i) and Read(A,j). Then Read(A,i) is replaced with a + * symbolic constant, say v1, and Read(A,j) is replaced with the + * following ITE: + * + * ITE(i=j,v1,v2) + */ + ASTNodeMap _arrayread_ite; + + /*MAP: This is a map from array-reads to symbolic constants. This + *map is used by the TransformArray() + */ + ASTNodeMap _arrayread_symbol; + + ASTNodeSet _introduced_symbols; + + /*Memoization map for TransformFormula/TransformTerm/TransformArray function + */ + ASTNodeMap TransformMap; + + //count to keep track of new symbolic constants introduced + //corresponding to Array Reads + unsigned int _symbol_count; + + //Formula/Term Transformers. Let Expr Manager, Type Checker +public: + //Functions that Transform ASTNodes + ASTNode TransformFormula(const ASTNode& query); + ASTNode TransformTerm(const ASTNode& term); + ASTNode TransformArray(const ASTNode& term); + ASTNode TranslateSignedDivMod(const ASTNode& term); + + //LET Management +private: + // MAP: This map is from bound IDs that occur in LETs to + // expression. The map is useful in checking replacing the IDs + // with the corresponding expressions. + ASTNodeMap *_letid_expr_map; +public: + + ASTNode ResolveID(const ASTNode& var); + + //Functions that are used to manage LET expressions + void LetExprMgr(const ASTNode& var, const ASTNode& letExpr); + + //Delete Letid Map + void CleanupLetIDMap(void); + + //Allocate LetID map + void InitializeLetIDMap(void); + + //Substitute Let-vars with LetExprs + ASTNode SubstituteLetExpr(ASTNode inExpr); + + /* MAP: This is a map from MINISAT::Vars to ASTNodes + * + * This is a reverse map, useful in constructing + * counterexamples. MINISAT returns a model in terms of MINISAT + * Vars, and this map helps us convert it to a model over ASTNode + * variables. + */ + vector _SATVar_to_AST; + +private: + /* MAP: This is a map from ASTNodes to vectors of bits + * + * This map is used in constructing and printing + * counterexamples. MINISAT returns values for each bit (a + * BVGETBIT Node), and this maps allows us to assemble the bits + * into bitvectors. + */ + typedef hash_map *, ASTNode::ASTNodeHasher, ASTNode::ASTNodeEqual> ASTtoBitvectorMap; + ASTtoBitvectorMap _ASTNode_to_Bitvector; + + //Data structure that holds the counter-model + ASTNodeMap CounterExampleMap; + + //Checks if the counter_example is ok. In order for the + //counter_example to be ok, Every assert must evaluate to true + //w.r.t couner_example and the query must evaluate to + //false. Otherwise the counter_example is bogus. + void CheckCounterExample(bool t); + + //Converts a vector of bools to a BVConst + ASTNode BoolVectoBVConst(hash_map * w, unsigned int l); + + //accepts a term and turns it into a constant-term w.r.t counter_example + ASTNode TermToConstTermUsingModel(const ASTNode& term, bool ArrayReadFlag = true); + ASTNode Expand_ReadOverWrite_UsingModel(const ASTNode& term, bool ArrayReadFlag = true); + //Computes the truth value of a formula w.r.t counter_example + ASTNode ComputeFormulaUsingModel(const ASTNode& form); + + //Replaces WRITE(Arr,i,val) with ITE(j=i, val, READ(Arr,j)) + ASTNode RemoveWrites_TopLevel(const ASTNode& term); + ASTNode RemoveWrites(const ASTNode& term); + ASTNode SimplifyWrites_InPlace(const ASTNode& term); + ASTNode ReadOverWrite_To_ITE(const ASTNode& term); + + ASTNode NewArrayVar(unsigned int index, unsigned int value); + ASTNode NewVar(unsigned int valuewidth); + //For ArrayWrite Abstraction: map from read-over-write term to + //newname. + ASTNodeMap ReadOverWrite_NewName_Map; + //For ArrayWrite Refinement: Map new arraynames to Read-Over-Write + //terms + ASTNodeMap NewName_ReadOverWrite_Map; + +public: + //print the STP solver output + void PrintOutput(bool true_iff_valid); + + //Converts MINISAT counterexample into an AST memotable (i.e. the + //function populates the datastructure CounterExampleMap) + void ConstructCounterExample(MINISAT::Solver& S); + + //Prints the counterexample to stdout + void PrintCounterExample(bool t, std::ostream& os = cout); + + //Prints the counterexample to stdout + void PrintCounterExample_InOrder(bool t); + + //queries the counterexample, and returns the value corresponding + //to e + ASTNode GetCounterExample(bool t, const ASTNode& e); + + int CounterExampleSize(void) const + { + return CounterExampleMap.size(); + } + + //FIXME: This is bloody dangerous function. Hack attack to take + //care of requests from users who want to store complete + //counter-examples in their own data structures. + ASTNodeMap GetCompleteCounterExample() + { + return CounterExampleMap; + } + + // prints MINISAT assigment one bit at a time, for debugging. + void PrintSATModel(MINISAT::Solver& S); + + //accepts constant input and normalizes it. + ASTNode BVConstEvaluator(const ASTNode& t); + + //FUNCTION TypeChecker: Assumes that the immediate Children of the + //input ASTNode have been typechecked. This function is suitable + //in scenarios like where you are building the ASTNode Tree, and + //you typecheck as you go along. It is not suitable as a general + //typechecker + void BVTypeCheck(const ASTNode& n); + +private: + //stack of Logical Context. each entry in the stack is a logical + //context. A logical context is a vector of assertions. The + //logical context is represented by a ptr to a vector of + //assertions in that logical context. Logical contexts are created + //by PUSH/POP + std::vector _asserts; + //The query for the current logical context. + ASTNode _current_query; + + //this flag, when true, indicates that counterexample is being + //checked by the counterexample checker + bool counterexample_checking_during_refinement; + + //this flag indicates as to whether the input has been determined to + //be valid or not by this tool + bool ValidFlag; + + //this flag, when true, indicates that a BVDIV divide by zero + //exception occured. However, the program must not exit with a + //fatalerror. Instead, it should evaluate the whole formula (which + //contains the BVDIV term) to be FALSE. + bool bvdiv_exception_occured; + +public: + //set of functions that manipulate Logical Contexts. + // + //add an assertion to the current logical context + void AddAssert(const ASTNode& assert); + void Push(void); + void Pop(void); + void AddQuery(const ASTNode& q); + const ASTNode PopQuery(); + const ASTNode GetQuery(); + const ASTVec GetAsserts(void); + + //reports node size. Second arg is "clearstatinfo", whatever that is. + unsigned int NodeSize(const ASTNode& a, bool t = false); + +private: + //This memo map is used by the ComputeFormulaUsingModel() + ASTNodeMap ComputeFormulaMap; + //Map for statiscal purposes + ASTNodeSet StatInfoSet; + + ASTNodeMap TermsAlreadySeenMap; + ASTNode CreateSubstitutionMap(const ASTNode& a); +public: + //prints statistics for the ASTNode. can add a prefix string c + void ASTNodeStats(const char * c, const ASTNode& a); + + //substitution + bool CheckSubstitutionMap(const ASTNode& a, ASTNode& output); + bool CheckSubstitutionMap(const ASTNode& a); + bool UpdateSubstitutionMap(const ASTNode& e0, const ASTNode& e1); + //if (a > b) in the termorder, then return 1 + //elseif (a < b) in the termorder, then return -1 + //else return 0 + int TermOrder(const ASTNode& a, const ASTNode& b); + //fill the arrayname_readindices vector if e0 is a READ(Arr,index) + //and index is a BVCONST + void FillUp_ArrReadIndex_Vec(const ASTNode& e0, const ASTNode& e1); + bool VarSeenInTerm(const ASTNode& var, const ASTNode& term); + + //functions for checking and updating simplifcation map + bool CheckSimplifyMap(const ASTNode& key, ASTNode& output, bool pushNeg); + void UpdateSimplifyMap(const ASTNode& key, const ASTNode& value, bool pushNeg); + void ResetSimplifyMaps(); + bool CheckAlwaysTrueFormMap(const ASTNode& key); + void UpdateAlwaysTrueFormMap(const ASTNode& val); + bool CheckMultInverseMap(const ASTNode& key, ASTNode& output); + void UpdateMultInverseMap(const ASTNode& key, const ASTNode& value); + + //Map for solved variables + bool CheckSolverMap(const ASTNode& a, ASTNode& output); + bool CheckSolverMap(const ASTNode& a); + bool UpdateSolverMap(const ASTNode& e0, const ASTNode& e1); + +public: + //FIXME: HACK_ATTACK. this vector was hacked into the code to + //support a special request by Dawson' group. They want the + //counterexample to be printed in the order of variables declared. + //TO BE COMMENTED LATER (say by 1st week of march,2006) + ASTVec _special_print_set; + + //prints the initial activity levels of variables + //void PrintActivityLevels_Of_SATVars(char * init_msg, MINISAT::Solver& newS); + + //this function biases the activity levels of MINISAT variables. + //void ChangeActivityLevels_Of_SATVars(MINISAT::Solver& n); + + // Constructor + BeevMgr() : + _interior_unique_table(INITIAL_INTERIOR_UNIQUE_TABLE_SIZE), _symbol_unique_table(INITIAL_SYMBOL_UNIQUE_TABLE_SIZE), _bvconst_unique_table( + INITIAL_BVCONST_UNIQUE_TABLE_SIZE), BBTermMemo(INITIAL_BBTERM_MEMO_TABLE_SIZE), BBFormMemo(INITIAL_BBFORM_MEMO_TABLE_SIZE), + _max_node_num(0), ASTFalse(CreateNode(FALSE)), ASTTrue(CreateNode(TRUE)), ASTUndefined(CreateNode(UNDEFINED)), SolverMap( + INITIAL_SOLVER_MAP_SIZE), _arrayread_symbol(INITIAL_ARRAYREAD_SYMBOL_SIZE), _introduced_symbols( + INITIAL_INTRODUCED_SYMBOLS_SIZE), _symbol_count(0) + { + _current_query = ASTUndefined; + ValidFlag = false; + bvdiv_exception_occured = false; + counterexample_checking_during_refinement = false; + start_abstracting = false; + Begin_RemoveWrites = false; + SimplifyWrites_InPlace_Flag = false; + SimplifyMap = new ASTNodeMap(INITIAL_SIMPLIFY_MAP_SIZE); + SimplifyNegMap = new ASTNodeMap(INITIAL_SIMPLIFY_MAP_SIZE); + _letid_expr_map = new ASTNodeMap(INITIAL_INTRODUCED_SYMBOLS_SIZE); + } + ; + + //destructor + ~BeevMgr(); +}; //End of Class BeevMgr + + +class CompleteCounterExample +{ + ASTNodeMap counterexample; + BeevMgr * bv; +public: + CompleteCounterExample(ASTNodeMap a, BeevMgr* beev) : + counterexample(a), bv(beev) + { + } + ASTNode GetCounterExample(ASTNode e) + { + if (BOOLEAN_TYPE == e.GetType() && SYMBOL != e.GetKind()) + { + FatalError("You must input a term or propositional variables\n", e); + } + if (counterexample.find(e) != counterexample.end()) + { + return counterexample[e]; + } + else + { + if (SYMBOL == e.GetKind() && BOOLEAN_TYPE == e.GetType()) + { + return bv->CreateNode(BEEV::FALSE); + } + + if (SYMBOL == e.GetKind()) + { + ASTNode z = bv->CreateZeroConst(e.GetValueWidth()); + return z; + } + + return e; + } + } +}; -}; // end namespace BEEV +} +; // end namespace BEEV #endif diff --git a/AST/ASTUtil.cpp b/AST/ASTUtil.cpp index c14d175..d7a3b2b 100644 --- a/AST/ASTUtil.cpp +++ b/AST/ASTUtil.cpp @@ -8,38 +8,44 @@ // -*- c++ -*- #include "ASTUtil.h" -namespace BEEV { - ostream &operator<<(ostream &os, const Spacer &sp) { - // Instead of wrapping lines with hundreds of spaces, prints - // a "+" at the beginning of the line for each wrap-around. - // so lines print like: +14+ (XOR ... - int blanks = sp._spaces % 60; - int wraps = sp._spaces / 60; - if (wraps > 0) { - os << "+" << wraps; - } - for (int i = 0; i < blanks; i++) - os << " "; - return os; - } - - //this function accepts the name of a function (as a char *), and - //records some stats about it. if the input is "print_func_stats", - //the function will then print the stats that it has collected. - void CountersAndStats(const char * functionname) { - static function_counters s; +namespace BEEV +{ +ostream &operator<<(ostream &os, const Spacer &sp) +{ + // Instead of wrapping lines with hundreds of spaces, prints + // a "+" at the beginning of the line for each wrap-around. + // so lines print like: +14+ (XOR ... + int blanks = sp._spaces % 60; + int wraps = sp._spaces / 60; + if (wraps > 0) + { + os << "+" << wraps; + } + for (int i = 0; i < blanks; i++) + os << " "; + return os; +} - if (stats) { +//this function accepts the name of a function (as a char *), and +//records some stats about it. if the input is "print_func_stats", +//the function will then print the stats that it has collected. +void CountersAndStats(const char * functionname) +{ + static function_counters s; - if(!strcmp(functionname,"print_func_stats")) { - cout << endl; - for(function_counters::iterator it=s.begin(),itend=s.end(); - it!=itend;it++) - cout << "Number of times the function: " << it->first << ": is called: " << it->second << endl; - return; - } - s[functionname] += 1; + if (stats) + { - } - } -};// end of namespace + if (!strcmp(functionname, "print_func_stats")) + { + cout << endl; + for (function_counters::iterator it = s.begin(), itend = s.end(); it != itend; it++) + cout << "Number of times the function: " << it->first << ": is called: " << it->second << endl; + return; + } + s[functionname] += 1; + + } +} +} +;// end of namespace diff --git a/AST/BitBlast.cpp b/AST/BitBlast.cpp index c9f5023..8f50ccf 100644 --- a/AST/BitBlast.cpp +++ b/AST/BitBlast.cpp @@ -19,8 +19,9 @@ // The 0th element of the vector corresponds to bit 0 -- the low-order bit. #include "AST.h" -namespace BEEV { - // extern void lpvec(ASTVec &vec); +namespace BEEV +{ +// extern void lpvec(ASTVec &vec); // FIXME: Assert no zero-length bit vectors!!! // FIXME: Need top-level functions that create and destroy the memo tables. @@ -33,510 +34,542 @@ namespace BEEV { ASTNode ASTJunk; -const ASTNode BeevMgr::BBTerm(const ASTNode& term) { - - - //CHANGED TermMemo is now an ASTNodeMap. Based on BBFormMemo - ASTNodeMap::iterator it = BBTermMemo.find(term); - if (it != BBTermMemo.end()) { - // already there. Just return it. - return it->second; - } - -// ASTNode& result = ASTJunk; - ASTNode result; - - /* - bool weregood = false; - if(term.GetNodeNum() == 17408){ - weregood = true; - } - */ - - - Kind k = term.GetKind(); - if (!is_Term_kind(k)) - FatalError("BBTerm: Illegal kind to BBTerm",term); - - ASTVec::const_iterator kids_end = term.end(); - unsigned int num_bits = term.GetValueWidth(); - switch (k) { - case BVNEG: { - // bitwise complement - // bitblast the child. - //FIXME Uses a tempory const ASTNode - const ASTNode& bbkids = BBTerm(term[0]); - result = CreateNode(BOOLVEC, BBNeg(bbkids.GetChildren())); - break; - } - - case BVLEFTSHIFT: - { - if (BVCONST == term[1].GetKind()) - { - // Constant shifts should be removed during simplification. - unsigned int shift = GetUnsignedConst(term[1]); - - ASTNode term0 = BBTerm(term[0]); - ASTVec children(term0.GetChildren()); // mutable copy of the children. - BBLShift(children, shift); - - result = CreateNode(BOOLVEC, children); - } - else - { - // Barrel shifter - const ASTVec& bbarg1 = BBTerm(term[0]).GetChildren(); - const ASTVec& bbarg2 = BBTerm(term[1]).GetChildren(); - - ASTVec temp_result(bbarg1); - - for (unsigned int i =0; i < bbarg2.size(); i++) +const ASTNode BeevMgr::BBTerm(const ASTNode& term) +{ + + //CHANGED TermMemo is now an ASTNodeMap. Based on BBFormMemo + ASTNodeMap::iterator it = BBTermMemo.find(term); + if (it != BBTermMemo.end()) + { + // already there. Just return it. + return it->second; + } + + // ASTNode& result = ASTJunk; + ASTNode result; + + /* + bool weregood = false; + if(term.GetNodeNum() == 17408){ + weregood = true; + } + */ + + Kind k = term.GetKind(); + if (!is_Term_kind(k)) + FatalError("BBTerm: Illegal kind to BBTerm", term); + + ASTVec::const_iterator kids_end = term.end(); + unsigned int num_bits = term.GetValueWidth(); + switch (k) + { + case BVNEG: { - if (bbarg2[i] == ASTFalse) - continue; // Not shifting by anything. - - unsigned int shift_amount = 1 << i; - - bool done = false; - - for (unsigned int j=temp_result.size()-1; !done; j--) + // bitwise complement + // bitblast the child. + //FIXME Uses a tempory const ASTNode + const ASTNode& bbkids = BBTerm(term[0]); + result = CreateNode(BOOLVEC, BBNeg(bbkids.GetChildren())); + break; + } + + case BVLEFTSHIFT: + { + if (BVCONST == term[1].GetKind()) + { + // Constant shifts should be removed during simplification. + unsigned int shift = GetUnsignedConst(term[1]); + + ASTNode term0 = BBTerm(term[0]); + ASTVec children(term0.GetChildren()); // mutable copy of the children. + BBLShift(children, shift); + + result = CreateNode(BOOLVEC, children); + } + else { - if (j < shift_amount) - temp_result[j] = CreateSimpForm(ITE, bbarg2[i],ASTFalse,temp_result[j]); - else - temp_result[j] = CreateSimpForm(ITE, bbarg2[i],temp_result[j-shift_amount],temp_result[j]); - - // want the loop to finish after j=0, but when j=0, j-1 == MAX_INT. Hence this weird idiom. - if (j ==0) - done = true; + // Barrel shifter + const ASTVec& bbarg1 = BBTerm(term[0]).GetChildren(); + const ASTVec& bbarg2 = BBTerm(term[1]).GetChildren(); + + ASTVec temp_result(bbarg1); + + for (unsigned int i = 0; i < bbarg2.size(); i++) + { + if (bbarg2[i] == ASTFalse) + continue; // Not shifting by anything. + + unsigned int shift_amount = 1 << i; + + bool done = false; + + for (unsigned int j = temp_result.size() - 1; !done; j--) + { + if (j < shift_amount) + temp_result[j] = CreateSimpForm(ITE, bbarg2[i], ASTFalse, temp_result[j]); + else + temp_result[j] = CreateSimpForm(ITE, bbarg2[i], temp_result[j - shift_amount], temp_result[j]); + + // want the loop to finish after j=0, but when j=0, j-1 == MAX_INT. Hence this weird idiom. + if (j == 0) + done = true; + } + } + + result = CreateNode(BOOLVEC, temp_result); } + break; } - result = CreateNode(BOOLVEC, temp_result); - } - break; - } - - case BVRIGHTSHIFT: - { - if (BVCONST == term[1].GetKind()) - { - // Constant shifts should be removed during simplification. - - unsigned int shift = GetUnsignedConst(term[1]); - - ASTNode term0 = BBTerm(term[0]); - ASTVec children(term0.GetChildren()); // mutable copy of the children. - BBRShift(children, shift); - - result = CreateNode(BOOLVEC, children); - } - else - { - // Barrel shifter - const ASTVec& bbarg1 = BBTerm(term[0]).GetChildren(); - const ASTVec& bbarg2 = BBTerm(term[1]).GetChildren(); - - ASTVec temp_result(bbarg1); - - for (unsigned int i =0; i < bbarg2.size(); i++) - { - if (bbarg2[i] == ASTFalse) - continue; // Not shifting by anything. - - unsigned int shift_amount = 1 << i; - - bool done = false; - - for (unsigned int j=0; j < temp_result.size(); j++) - { - if (j + shift_amount >= temp_result.size()) - temp_result[j] = CreateSimpForm(ITE, bbarg2[i],ASTFalse,temp_result[j]); - else - temp_result[j] = CreateSimpForm(ITE, bbarg2[i],temp_result[j+shift_amount],temp_result[j]); - - if (j ==0) - done = true; - } - } - - - result = CreateNode(BOOLVEC, temp_result); - - /* cerr << result << endl; - cerr << term[0] << endl; - cerr << term[1] << endl; - cerr << "right shift. Node size is:" << NodeSize(result) << endl; - cerr << "input size: " << NodeSize(term[0]) << " " << NodeSize(term[1]) << endl; - */ - } - } - break; - - - - case BVSRSHIFT: - case BVVARSHIFT: - FatalError("BBTerm: These kinds have not been implemented in the BitBlaster: ", term); - break; - case ITE: { - // Term version of ITE. - - // Blast the args - // FIXME Uses temporary const ASTNodes and an ASTVec& - //const ASTNode& cond = BBForm(term[0]); - const ASTNode& cond = BBForm(term[0]); - const ASTNode& thn = BBTerm(term[1]); - const ASTNode& els = BBTerm(term[2]); - result = - CreateNode(BOOLVEC, BBITE(cond, thn.GetChildren(), els.GetChildren())); - break; - } - - - case BVSX: { - // Replicate high-order bit as many times as necessary. - // Arg 0 is expression to be sign extended. - const ASTNode& arg = term[0]; - unsigned long result_width = term.GetValueWidth(); - unsigned long arg_width = arg.GetValueWidth(); - //FIXME Uses a temporary const ASTNode reference - const ASTNode& bbarg = BBTerm(arg); - - if (result_width == arg_width) { - //nothing to sign extend - break; - } - else { - //we need to sign extend - const ASTNode& msbX = bbarg.back(); - //const ASTNode& msb1 = msbX; - - ASTVec ccc = msbX.GetChildren(); - const ASTNode& msb = CreateSimpForm(msbX.GetKind(),ccc); - - // Old version - // ASTNode msb = bbarg.back(); - // const ASTNode msb1 = msb; - - // ASTVec ccc = msb.GetChildren(); - // msb = CreateSimpForm(msb.GetKind(),ccc); - - // DD 1/14/07 Simplify silently drops all but first two args of XOR. - // I expanded XOR to N args with flattening optimization. - // This bug took 2 days to track down! - - // msb = SimplifyFormula(msb,false); - - // cout << "!!!!!!!!!!!!!!!!" << endl - // << "Simplify msb:" << msb2 << endl - // << "Simplify result:" << msb << endl; - - //FIXME Dynamically allocate the result vector? - //Is this doing multiple copies? - //ASTVec& tmp_res = *(new ASTVec(result_width)); - ASTVec tmp_res(result_width); - - //FIXME Should these be gotten from result? - ASTVec::const_iterator bb_it = bbarg.begin(); - ASTVec::iterator res_it = tmp_res.begin(); - ASTVec::iterator res_ext = res_it+arg_width; // first bit of extended part - ASTVec::iterator res_end = tmp_res.end(); - // copy LSBs directly from bbvec - for( ; res_it < res_ext; (res_it++, bb_it++)) { - *res_it = *bb_it; - } - // repeat MSB to fill up rest of result. - for( ; res_it < res_end; (res_it++)) { - *res_it = msb; - } - - //Temporary debugging code - // cout << "Sign extending:" << endl - // << " Vec "; - // lpvec( bbarg.GetChildren() ); - // cout << " Extended to "; - // lp(result); - // cout << endl; - - result = CreateNode(BOOLVEC, tmp_res); - - break; - } - } - - case BVZX: { - // Fill the high-order bits with as many zeroes as needed. - // Arg 0 is expression to be sign extended. - const ASTNode& arg = term[0]; - unsigned long result_width = term.GetValueWidth(); - unsigned long arg_width = arg.GetValueWidth(); - - //FIXME Uses a temporary const ASTNode reference - const ASTNode& bbarg = BBTerm(arg); - ASTVec tmp_res(result_width); - - //FIXME Should these be gotten from result? - ASTVec::const_iterator bb_it = bbarg.begin(); - ASTVec::iterator res_it = tmp_res.begin(); - ASTVec::iterator res_ext = res_it+arg_width; // first bit of extended part - ASTVec::iterator res_end = tmp_res.end(); - // copy LSBs directly from bbvec - for( ; res_it < res_ext; (res_it++, bb_it++)) { - *res_it = *bb_it; - } - // repeat zero to fill up rest of result. - for( ; res_it < res_end; (res_it++)) { - *res_it = ASTFalse; - } - - // Temporary debugging code - // cout << "Zero extending:" << endl - // << " Vec "; - // lpvec( bbarg.GetChildren() ); - // cout << " Extended to "; - // cout << result; - // cout << endl; - - result = CreateNode(BOOLVEC, tmp_res); - - break; - } - - - - - case BVEXTRACT: { - // bitblast the child, then extract the relevant bits. - // Note: This could be optimized by not bitblasting the bits - // that aren't fetched. But that would be tricky, especially - // with memo-ization. - - //FIXME Using const ASTNode w/out reference - /* - if(weregood){ - printf("spot01\n"); - term[0].LispPrint(cout, 0); - } - */ - const ASTNode& bbkids = BBTerm(term[0]); - /* - if(weregood){ - printf("spot02, kids:\n"); - bbkids.LispPrint(cout, 0); - } - */ - unsigned int high = GetUnsignedConst(term[1]); - /* - if(weregood){ - printf("spot03, high: %d\n", high); - } - */ - unsigned int low = GetUnsignedConst(term[2]); - /* - if(weregood){ - printf("spot04, low: %d\n", low); - } - */ - - ASTVec::const_iterator bbkfit = bbkids.begin(); - // I should have used pointers to ASTVec, to avoid this crock - - //FIXME Creates a new local ASTVec and does the CreateNode from that - result = CreateNode(BOOLVEC, ASTVec(bbkfit+low, bbkfit+high+1)); - /* - if(weregood){ - printf("spot05\n"); - } - */ - break; - } - case BVCONCAT: { - //FIXME Using temporary const ASTNodes - const ASTNode& vec1 = BBTerm(term[0]); - const ASTNode& vec2 = BBTerm(term[1]); - - //FIXME This has to be an unnessecary copy and a memory leak - //Leaking ASTVec tmp_res = *(new ASTVec(vec2.GetChildren())); - ASTVec tmp_res(vec2.GetChildren()); - tmp_res.insert(tmp_res.end(), vec1.begin(), vec1.end()); - result = CreateNode(BOOLVEC, tmp_res); - break; - } - case BVPLUS: { - // ASSERT: at least one child. - // ASSERT: all children and result are the same size. - // Previous phase must make sure this is true. - // Add children pairwise and accumulate in BBsum - - // FIXME: Unnecessary array copies. - ASTVec::const_iterator it = term.begin(); - ASTVec tmp_res = BBTerm(*it).GetChildren(); - for (++it; it < kids_end; it++) { - const ASTVec& tmp = BBTerm(*it).GetChildren(); - BBPlus2(tmp_res, tmp, ASTFalse); - } - - result = CreateNode(BOOLVEC, tmp_res); - break; - } - case BVUMINUS: { - //FIXME Using const ASTNode reference - const ASTNode& bbkid = BBTerm(term[0]); - result = CreateNode(BOOLVEC, BBUminus(bbkid.GetChildren())); - break; - } - case BVSUB: { - // complement of subtrahend - // copy, since BBSub writes into it. - - //FIXME: Unnecessary array copies? - ASTVec tmp_res = BBTerm(term[0]).GetChildren(); - - const ASTVec& bbkid1 = BBTerm(term[1]).GetChildren(); - BBSub(tmp_res, bbkid1); - result = CreateNode(BOOLVEC, tmp_res); - break; - } - case BVMULT: { - // ASSERT 2 arguments, same length, result is same length. - - const ASTNode& t0 = term[0]; - const ASTNode& t1 = term[1]; - - const ASTNode& mpcd1 = BBTerm(t0); - const ASTNode& mpcd2 = BBTerm(t1); - //Reverese the order of the nodes w/out the need for temporaries - //This is needed because t0 an t1 must be const - if ((BVCONST != t0.GetKind()) && (BVCONST == t1.GetKind())) { - result = CreateNode(BOOLVEC, - BBMult(mpcd2.GetChildren(), mpcd1.GetChildren()) ); - }else{ - result = CreateNode(BOOLVEC, - BBMult(mpcd1.GetChildren(), mpcd2.GetChildren()) ); - } - break; - } - case BVDIV: - case BVMOD: { - const ASTNode& dvdd = BBTerm(term[0]); - const ASTNode& dvsr = BBTerm(term[1]); - unsigned int width = dvdd.Degree(); - ASTVec q(width); - ASTVec r(width); - BBDivMod(dvdd.GetChildren(), dvsr.GetChildren(), q, r, width); - if (k == BVDIV) - result = CreateNode(BOOLVEC, q); - else - result = CreateNode(BOOLVEC, r); - break; - } - // n-ary bitwise operators. - case BVXOR: - case BVXNOR: - case BVAND: - case BVOR: - case BVNOR: - case BVNAND: { - // Add children pairwise and accumulate in BBsum - ASTVec::const_iterator it = term.begin(); - Kind bk = UNDEFINED; // Kind of individual bit op. - switch (k) { - case BVXOR: bk = XOR; break; - case BVXNOR: bk = IFF; break; - case BVAND: bk = AND; break; - case BVOR: bk = OR; break; - case BVNOR: bk = NOR; break; - case BVNAND: bk = NAND; break; - default: - FatalError("BBTerm: Illegal kind to BBTerm",term); - break; - } - - // Sum is destructively modified in the loop, so make a copy of value - // returned by BBTerm. - ASTNode temp = BBTerm(*it); - ASTVec sum(temp.GetChildren()); // First operand. - - // Iterate over remaining bitvector term operands - for (++it; it < kids_end; it++) { - //FIXME FIXME FIXME: Why does using a temp. var change the behavior? - temp = BBTerm(*it); - const ASTVec& y = temp.GetChildren(); - - // Iterate over bits - // FIXME: Why is this not using an iterator??? - int n = y.size(); - for (int i = 0; i < n; i++) { - sum[i] = CreateSimpForm(bk, sum[i], y[i]); - } - } - result = CreateNode(BOOLVEC, sum); - break; - } - case SYMBOL: { - // ASSERT: IndexWidth = 0? Semantic analysis should check. - //Leaking ASTVec& bbvec = *(new ASTVec); - - //FIXME Why is isn't this ASTVEC bbvec(num_bits) ? - ASTVec bbvec; - /* - if(term.GetNodeNum() == 17132){ - weregood = true; - } - */ - - /* - if(weregood){ - printf("number of bits for node 17132: %d\n", num_bits); - } - */ - for (unsigned int i = 0; i < num_bits; i++) { - ASTNode bit_node = - CreateNode(BVGETBIT, term, CreateBVConst(32,i)); - bbvec.push_back(bit_node); - } - result = CreateNode(BOOLVEC, bbvec); - /* - if(weregood){ - printf("done\n"); - } - */ - break; - } - case BVCONST: { - ASTVec tmp_res(num_bits); + case BVRIGHTSHIFT: + { + if (BVCONST == term[1].GetKind()) + { + // Constant shifts should be removed during simplification. + + unsigned int shift = GetUnsignedConst(term[1]); + + ASTNode term0 = BBTerm(term[0]); + ASTVec children(term0.GetChildren()); // mutable copy of the children. + BBRShift(children, shift); + + result = CreateNode(BOOLVEC, children); + } + else + { + // Barrel shifter + const ASTVec& bbarg1 = BBTerm(term[0]).GetChildren(); + const ASTVec& bbarg2 = BBTerm(term[1]).GetChildren(); + + ASTVec temp_result(bbarg1); + + for (unsigned int i = 0; i < bbarg2.size(); i++) + { + if (bbarg2[i] == ASTFalse) + continue; // Not shifting by anything. + + unsigned int shift_amount = 1 << i; + + bool done = false; + + for (unsigned int j = 0; j < temp_result.size(); j++) + { + if (j + shift_amount >= temp_result.size()) + temp_result[j] = CreateSimpForm(ITE, bbarg2[i], ASTFalse, temp_result[j]); + else + temp_result[j] = CreateSimpForm(ITE, bbarg2[i], temp_result[j + shift_amount], temp_result[j]); + + if (j == 0) + done = true; + } + } + + result = CreateNode(BOOLVEC, temp_result); + + /* cerr << result << endl; + cerr << term[0] << endl; + cerr << term[1] << endl; + cerr << "right shift. Node size is:" << NodeSize(result) << endl; + cerr << "input size: " << NodeSize(term[0]) << " " << NodeSize(term[1]) << endl; + */ + } + } + break; + + case BVSRSHIFT: + case BVVARSHIFT: + FatalError("BBTerm: These kinds have not been implemented in the BitBlaster: ", term); + break; + case ITE: + { + // Term version of ITE. + + // Blast the args + // FIXME Uses temporary const ASTNodes and an ASTVec& + //const ASTNode& cond = BBForm(term[0]); + const ASTNode& cond = BBForm(term[0]); + const ASTNode& thn = BBTerm(term[1]); + const ASTNode& els = BBTerm(term[2]); + result = CreateNode(BOOLVEC, BBITE(cond, thn.GetChildren(), els.GetChildren())); + break; + } + + case BVSX: + { + // Replicate high-order bit as many times as necessary. + // Arg 0 is expression to be sign extended. + const ASTNode& arg = term[0]; + unsigned long result_width = term.GetValueWidth(); + unsigned long arg_width = arg.GetValueWidth(); + //FIXME Uses a temporary const ASTNode reference + const ASTNode& bbarg = BBTerm(arg); + + if (result_width == arg_width) + { + //nothing to sign extend + break; + } + else + { + //we need to sign extend + const ASTNode& msbX = bbarg.back(); + //const ASTNode& msb1 = msbX; + + ASTVec ccc = msbX.GetChildren(); + const ASTNode& msb = CreateSimpForm(msbX.GetKind(), ccc); + + // Old version + // ASTNode msb = bbarg.back(); + // const ASTNode msb1 = msb; + + // ASTVec ccc = msb.GetChildren(); + // msb = CreateSimpForm(msb.GetKind(),ccc); + + // DD 1/14/07 Simplify silently drops all but first two args of XOR. + // I expanded XOR to N args with flattening optimization. + // This bug took 2 days to track down! + + // msb = SimplifyFormula(msb,false); + + // cout << "!!!!!!!!!!!!!!!!" << endl + // << "Simplify msb:" << msb2 << endl + // << "Simplify result:" << msb << endl; + + //FIXME Dynamically allocate the result vector? + //Is this doing multiple copies? + //ASTVec& tmp_res = *(new ASTVec(result_width)); + ASTVec tmp_res(result_width); + + //FIXME Should these be gotten from result? + ASTVec::const_iterator bb_it = bbarg.begin(); + ASTVec::iterator res_it = tmp_res.begin(); + ASTVec::iterator res_ext = res_it + arg_width; // first bit of extended part + ASTVec::iterator res_end = tmp_res.end(); + // copy LSBs directly from bbvec + for (; res_it < res_ext; (res_it++, bb_it++)) + { + *res_it = *bb_it; + } + // repeat MSB to fill up rest of result. + for (; res_it < res_end; (res_it++)) + { + *res_it = msb; + } + + //Temporary debugging code + // cout << "Sign extending:" << endl + // << " Vec "; + // lpvec( bbarg.GetChildren() ); + // cout << " Extended to "; + // lp(result); + // cout << endl; + + result = CreateNode(BOOLVEC, tmp_res); + + break; + } + } + + case BVZX: + { + // Fill the high-order bits with as many zeroes as needed. + // Arg 0 is expression to be sign extended. + const ASTNode& arg = term[0]; + unsigned long result_width = term.GetValueWidth(); + unsigned long arg_width = arg.GetValueWidth(); + + //FIXME Uses a temporary const ASTNode reference + const ASTNode& bbarg = BBTerm(arg); + ASTVec tmp_res(result_width); + + //FIXME Should these be gotten from result? + ASTVec::const_iterator bb_it = bbarg.begin(); + ASTVec::iterator res_it = tmp_res.begin(); + ASTVec::iterator res_ext = res_it + arg_width; // first bit of extended part + ASTVec::iterator res_end = tmp_res.end(); + // copy LSBs directly from bbvec + for (; res_it < res_ext; (res_it++, bb_it++)) + { + *res_it = *bb_it; + } + // repeat zero to fill up rest of result. + for (; res_it < res_end; (res_it++)) + { + *res_it = ASTFalse; + } + + // Temporary debugging code + // cout << "Zero extending:" << endl + // << " Vec "; + // lpvec( bbarg.GetChildren() ); + // cout << " Extended to "; + // cout << result; + // cout << endl; + + result = CreateNode(BOOLVEC, tmp_res); + + break; + } + + case BVEXTRACT: + { + // bitblast the child, then extract the relevant bits. + // Note: This could be optimized by not bitblasting the bits + // that aren't fetched. But that would be tricky, especially + // with memo-ization. + + //FIXME Using const ASTNode w/out reference + /* + if(weregood){ + printf("spot01\n"); + term[0].LispPrint(cout, 0); + } + */ + const ASTNode& bbkids = BBTerm(term[0]); + /* + if(weregood){ + printf("spot02, kids:\n"); + bbkids.LispPrint(cout, 0); + } + */ + unsigned int high = GetUnsignedConst(term[1]); + /* + if(weregood){ + printf("spot03, high: %d\n", high); + } + */ + unsigned int low = GetUnsignedConst(term[2]); + /* + if(weregood){ + printf("spot04, low: %d\n", low); + } + */ + + ASTVec::const_iterator bbkfit = bbkids.begin(); + // I should have used pointers to ASTVec, to avoid this crock + + //FIXME Creates a new local ASTVec and does the CreateNode from that + result = CreateNode(BOOLVEC, ASTVec(bbkfit + low, bbkfit + high + 1)); + /* + if(weregood){ + printf("spot05\n"); + } + */ + break; + } + case BVCONCAT: + { + //FIXME Using temporary const ASTNodes + const ASTNode& vec1 = BBTerm(term[0]); + const ASTNode& vec2 = BBTerm(term[1]); + + //FIXME This has to be an unnessecary copy and a memory leak + //Leaking ASTVec tmp_res = *(new ASTVec(vec2.GetChildren())); + ASTVec tmp_res(vec2.GetChildren()); + tmp_res.insert(tmp_res.end(), vec1.begin(), vec1.end()); + result = CreateNode(BOOLVEC, tmp_res); + break; + } + case BVPLUS: + { + // ASSERT: at least one child. + // ASSERT: all children and result are the same size. + // Previous phase must make sure this is true. + // Add children pairwise and accumulate in BBsum + + // FIXME: Unnecessary array copies. + ASTVec::const_iterator it = term.begin(); + ASTVec tmp_res = BBTerm(*it).GetChildren(); + for (++it; it < kids_end; it++) + { + const ASTVec& tmp = BBTerm(*it).GetChildren(); + BBPlus2(tmp_res, tmp, ASTFalse); + } + + result = CreateNode(BOOLVEC, tmp_res); + break; + } + case BVUMINUS: + { + //FIXME Using const ASTNode reference + const ASTNode& bbkid = BBTerm(term[0]); + result = CreateNode(BOOLVEC, BBUminus(bbkid.GetChildren())); + break; + } + case BVSUB: + { + // complement of subtrahend + // copy, since BBSub writes into it. + + //FIXME: Unnecessary array copies? + ASTVec tmp_res = BBTerm(term[0]).GetChildren(); + + const ASTVec& bbkid1 = BBTerm(term[1]).GetChildren(); + BBSub(tmp_res, bbkid1); + result = CreateNode(BOOLVEC, tmp_res); + break; + } + case BVMULT: + { + // ASSERT 2 arguments, same length, result is same length. + + const ASTNode& t0 = term[0]; + const ASTNode& t1 = term[1]; + + const ASTNode& mpcd1 = BBTerm(t0); + const ASTNode& mpcd2 = BBTerm(t1); + //Reverese the order of the nodes w/out the need for temporaries + //This is needed because t0 an t1 must be const + if ((BVCONST != t0.GetKind()) && (BVCONST == t1.GetKind())) + { + result = CreateNode(BOOLVEC, BBMult(mpcd2.GetChildren(), mpcd1.GetChildren())); + } + else + { + result = CreateNode(BOOLVEC, BBMult(mpcd1.GetChildren(), mpcd2.GetChildren())); + } + break; + } + case BVDIV: + case BVMOD: + { + const ASTNode& dvdd = BBTerm(term[0]); + const ASTNode& dvsr = BBTerm(term[1]); + unsigned int width = dvdd.Degree(); + ASTVec q(width); + ASTVec r(width); + BBDivMod(dvdd.GetChildren(), dvsr.GetChildren(), q, r, width); + if (k == BVDIV) + result = CreateNode(BOOLVEC, q); + else + result = CreateNode(BOOLVEC, r); + break; + } + // n-ary bitwise operators. + case BVXOR: + case BVXNOR: + case BVAND: + case BVOR: + case BVNOR: + case BVNAND: + { + // Add children pairwise and accumulate in BBsum + ASTVec::const_iterator it = term.begin(); + Kind bk = UNDEFINED; // Kind of individual bit op. + switch (k) + { + case BVXOR: + bk = XOR; + break; + case BVXNOR: + bk = IFF; + break; + case BVAND: + bk = AND; + break; + case BVOR: + bk = OR; + break; + case BVNOR: + bk = NOR; + break; + case BVNAND: + bk = NAND; + break; + default: + FatalError("BBTerm: Illegal kind to BBTerm", term); + break; + } + + // Sum is destructively modified in the loop, so make a copy of value + // returned by BBTerm. + ASTNode temp = BBTerm(*it); + ASTVec sum(temp.GetChildren()); // First operand. + + // Iterate over remaining bitvector term operands + for (++it; it < kids_end; it++) + { + //FIXME FIXME FIXME: Why does using a temp. var change the behavior? + temp = BBTerm(*it); + const ASTVec& y = temp.GetChildren(); + + // Iterate over bits + // FIXME: Why is this not using an iterator??? + int n = y.size(); + for (int i = 0; i < n; i++) + { + sum[i] = CreateSimpForm(bk, sum[i], y[i]); + } + } + result = CreateNode(BOOLVEC, sum); + break; + } + case SYMBOL: + { + // ASSERT: IndexWidth = 0? Semantic analysis should check. + //Leaking ASTVec& bbvec = *(new ASTVec); + + //FIXME Why is isn't this ASTVEC bbvec(num_bits) ? + ASTVec bbvec; + /* + if(term.GetNodeNum() == 17132){ + weregood = true; + } + */ + + /* + if(weregood){ + printf("number of bits for node 17132: %d\n", num_bits); + } + */ + for (unsigned int i = 0; i < num_bits; i++) + { + ASTNode bit_node = CreateNode(BVGETBIT, term, CreateBVConst(32, i)); + bbvec.push_back(bit_node); + } + result = CreateNode(BOOLVEC, bbvec); + /* + if(weregood){ + printf("done\n"); + } + */ + break; + } + case BVCONST: + { + ASTVec tmp_res(num_bits); #ifndef NATIVE_C_ARITH - CBV bv = term.GetBVConst(); - for(unsigned int i = 0; i < num_bits; i++){ - tmp_res[i] = CONSTANTBV::BitVector_bit_test(bv,i) ? ASTTrue : ASTFalse; - } + CBV bv = term.GetBVConst(); + for (unsigned int i = 0; i < num_bits; i++) + { + tmp_res[i] = CONSTANTBV::BitVector_bit_test(bv, i) ? ASTTrue : ASTFalse; + } #else - const unsigned long long int c = term.GetBVConst(); - unsigned long long int bitmask = 0x00000000000000001LL; - for (unsigned int i = 0; i < num_bits; i++, bitmask <<= 1) - tmp_res[i] = ((c & (bitmask)) ? ASTTrue : ASTFalse); + const unsigned long long int c = term.GetBVConst(); + unsigned long long int bitmask = 0x00000000000000001LL; + for (unsigned int i = 0; i < num_bits; i++, bitmask <<= 1) + tmp_res[i] = ((c & (bitmask)) ? ASTTrue : ASTFalse); #endif - result = CreateNode(BOOLVEC, tmp_res); - break; - } - case BOOLVEC: { - cerr << "Hit a boolvec! what to do?" << endl; - break; - } - default: - FatalError("BBTerm: Illegal kind to BBTerm",term); - } - - //if(result == ASTJunk) - // cout<<"result does not change"<second; - } - - ASTNode result = ASTUndefined; - - Kind k = form.GetKind(); - if (!is_Form_kind(k)) { - FatalError("BBForm: Illegal kind: ",form); - } - - // Not returning until end, and memoizing everything, makes it easier - // to trace coherently. - - // Various special cases - switch (k) { - case TRUE: - case FALSE: { - result = form; - break; - } - - case SYMBOL: - //printf("bit-blasting SYMBOL\n"); - if (form.GetType() != BOOLEAN_TYPE) { - FatalError("BBForm: Symbol represents more than one bit", form); - } - - result = form; - break; - - case BVGETBIT: { - // exactly two children - const ASTNode bbchild = BBTerm(form[0]); - unsigned int index = GetUnsignedConst(form[1]); - result = bbchild[index]; - break; - } - - case NOT: - result = CreateSimpNot(BBForm(form[0])); - break; - - case ITE: - // FIXME: SHould this be CreateSimpITE? - result = CreateNode(ITE, BBForm(form[0]), BBForm(form[1]), BBForm(form[2])); - break; - - case AND: - case OR: - case NAND: - case NOR: - case IFF: - case XOR: - case IMPLIES: { - //printf("bit-blasting AND or OR\n"); - ASTVec bbkids; // bit-blasted children (formulas) - - // FIXME: Put in fast exits for AND/OR/NAND/NOR/IMPLIES - ASTVec::const_iterator kids_end = form.end(); - for (ASTVec::const_iterator it = form.begin(); it != kids_end; it++) { - bbkids.push_back(BBForm(*it)); - } - result = CreateSimpForm(k, bbkids); - break; - } - - case NEQ: { - ASTNode bbkid = BBForm(CreateNode(EQ, form.GetChildren())); - result = CreateSimpNot(bbkid); - break; - } - - case EQ: { - //printf("bit-blasting EQ\n"); - //form.LispPrint(cout, 0); - // Common code for binary operations - // FIXME: This ought to be in a semantic analysis phase. - //printf("spot01\n"); - const ASTNode left = BBTerm(form[0]); - //printf("spot02\n"); - const ASTNode right = BBTerm(form[1]); - //printf("spot03\n"); - if (left.Degree() != right.Degree()) { - cerr << "BBForm: Size mismatch" << endl << form[0] << endl << form[1] << endl; - FatalError("",ASTUndefined); - } - result = BBEQ(left.GetChildren(), right.GetChildren()); - //printf("spot04\n"); - break; - } - - case BVLE: - case BVGE: - case BVGT: - case BVLT: - case BVSLE: - case BVSGE: - case BVSGT: - case BVSLT: { - result = BBcompare(form); - break; - } - default: - FatalError("BBForm: Illegal kind: ", form); - break; - } - - // cout << "================" << endl - // << "BBForm: " << form << endl - // << "----------------" << endl - // << "BBForm Result: " << result << endl; - - return (BBFormMemo[form] = result); + ASTNodeMap::iterator it = BBFormMemo.find(form); + if (it != BBFormMemo.end()) + { + // already there. Just return it. + return it->second; + } + + ASTNode result = ASTUndefined; + + Kind k = form.GetKind(); + if (!is_Form_kind(k)) + { + FatalError("BBForm: Illegal kind: ", form); + } + + // Not returning until end, and memoizing everything, makes it easier + // to trace coherently. + + // Various special cases + switch (k) + { + case TRUE: + case FALSE: + { + result = form; + break; + } + + case SYMBOL: + //printf("bit-blasting SYMBOL\n"); + if (form.GetType() != BOOLEAN_TYPE) + { + FatalError("BBForm: Symbol represents more than one bit", form); + } + + result = form; + break; + + case BVGETBIT: + { + // exactly two children + const ASTNode bbchild = BBTerm(form[0]); + unsigned int index = GetUnsignedConst(form[1]); + result = bbchild[index]; + break; + } + + case NOT: + result = CreateSimpNot(BBForm(form[0])); + break; + + case ITE: + // FIXME: SHould this be CreateSimpITE? + result = CreateNode(ITE, BBForm(form[0]), BBForm(form[1]), BBForm(form[2])); + break; + + case AND: + case OR: + case NAND: + case NOR: + case IFF: + case XOR: + case IMPLIES: + { + //printf("bit-blasting AND or OR\n"); + ASTVec bbkids; // bit-blasted children (formulas) + + // FIXME: Put in fast exits for AND/OR/NAND/NOR/IMPLIES + ASTVec::const_iterator kids_end = form.end(); + for (ASTVec::const_iterator it = form.begin(); it != kids_end; it++) + { + bbkids.push_back(BBForm(*it)); + } + result = CreateSimpForm(k, bbkids); + break; + } + + case NEQ: + { + ASTNode bbkid = BBForm(CreateNode(EQ, form.GetChildren())); + result = CreateSimpNot(bbkid); + break; + } + + case EQ: + { + //printf("bit-blasting EQ\n"); + //form.LispPrint(cout, 0); + // Common code for binary operations + // FIXME: This ought to be in a semantic analysis phase. + //printf("spot01\n"); + const ASTNode left = BBTerm(form[0]); + //printf("spot02\n"); + const ASTNode right = BBTerm(form[1]); + //printf("spot03\n"); + if (left.Degree() != right.Degree()) + { + cerr << "BBForm: Size mismatch" << endl << form[0] << endl << form[1] << endl; + FatalError("", ASTUndefined); + } + result = BBEQ(left.GetChildren(), right.GetChildren()); + //printf("spot04\n"); + break; + } + + case BVLE: + case BVGE: + case BVGT: + case BVLT: + case BVSLE: + case BVSGE: + case BVSGT: + case BVSLT: + { + result = BBcompare(form); + break; + } + default: + FatalError("BBForm: Illegal kind: ", form); + break; + } + + // cout << "================" << endl + // << "BBForm: " << form << endl + // << "----------------" << endl + // << "BBForm Result: " << result << endl; + + return (BBFormMemo[form] = result); } - + // Bit blast a sum of two equal length BVs. // Update sum vector destructively with new sum. void BeevMgr::BBPlus2(ASTVec& sum, const ASTVec& y, ASTNode cin) { -// cout << "Bitblasting plus. Operand 1: " << endl; -// lpvec(sum); -// cout << endl << " operand 2: " << endl; -// lpvec(y); -// cout << endl << "carry: " << endl << cin << endl; - - - int n = sum.size(); - // ASSERT: y.size() == x.size() - // FIXME: Don't bother computing i+1 carry, which is discarded. - for (int i = 0; i < n; i++) { - ASTNode nextcin = Majority(sum[i], y[i], cin); - sum[i] = CreateSimpForm(XOR, CreateSimpForm(XOR, sum[i], y[i]), cin); - cin = nextcin; - } - -// cout << "----------------" << endl << "Result: " << endl; -// lpvec(sum); -// cout << endl; + // cout << "Bitblasting plus. Operand 1: " << endl; + // lpvec(sum); + // cout << endl << " operand 2: " << endl; + // lpvec(y); + // cout << endl << "carry: " << endl << cin << endl; + + + int n = sum.size(); + // ASSERT: y.size() == x.size() + // FIXME: Don't bother computing i+1 carry, which is discarded. + for (int i = 0; i < n; i++) + { + ASTNode nextcin = Majority(sum[i], y[i], cin); + sum[i] = CreateSimpForm(XOR, CreateSimpForm(XOR, sum[i], y[i]), cin); + cin = nextcin; + } + + // cout << "----------------" << endl << "Result: " << endl; + // lpvec(sum); + // cout << endl; } // Stores result - x in result, destructively void BeevMgr::BBSub(ASTVec& result, const ASTVec& y) { - ASTVec compsubtrahend = BBNeg(y); - BBPlus2(result, compsubtrahend, ASTTrue); + ASTVec compsubtrahend = BBNeg(y); + BBPlus2(result, compsubtrahend, ASTTrue); } // Add one bit ASTVec BeevMgr::BBAddOneBit(ASTVec& x, ASTNode cin) { - ASTVec result = ASTVec(0); - ASTVec::const_iterator itend = x.end(); - for (ASTVec::const_iterator it = x.begin(); it < itend; it++) { - ASTNode nextcin = CreateSimpForm(AND, *it, cin); - result.push_back(CreateSimpForm(XOR, *it, cin)); - cin = nextcin; - } - // FIXME: unnecessary array copy on return? - return result; + ASTVec result = ASTVec(0); + ASTVec::const_iterator itend = x.end(); + for (ASTVec::const_iterator it = x.begin(); it < itend; it++) + { + ASTNode nextcin = CreateSimpForm(AND, *it, cin); + result.push_back(CreateSimpForm(XOR, *it, cin)); + cin = nextcin; + } + // FIXME: unnecessary array copy on return? + return result; } // Increment bit-blasted vector and return result. ASTVec BeevMgr::BBInc(ASTVec& x) { - return BBAddOneBit(x, ASTTrue); + return BBAddOneBit(x, ASTTrue); } // Return formula for majority function of three bits. // Pass arguments by reference to reduce refcounting. -ASTNode BeevMgr::Majority(const ASTNode& a, const ASTNode& b,const ASTNode& c) +ASTNode BeevMgr::Majority(const ASTNode& a, const ASTNode& b, const ASTNode& c) { - // Checking explicitly for constant a, b and c could - // be more efficient, because they are repeated in the logic. - if (ASTTrue == a) { - return CreateSimpForm(OR, b, c); - } - else if (ASTFalse == a) { - return CreateSimpForm(AND, b, c); - } - else if (ASTTrue == b) { - return CreateSimpForm(OR, a, c); - } - else if (ASTFalse == b) { - return CreateSimpForm(AND, a, c); - } - else if (ASTTrue == c) { - return CreateSimpForm(OR, a, b); - } - else if (ASTFalse == c) { - return CreateSimpForm(AND, a, b); - } - // there are lots more simplifications, but I'm not sure they're - // worth doing explicitly (e.g., a = b, a = ~b, etc.) - else { - return - CreateSimpForm(OR, - CreateSimpForm(AND, a, b), - CreateSimpForm(AND, b, c), - CreateSimpForm(AND, a, c)); - } + // Checking explicitly for constant a, b and c could + // be more efficient, because they are repeated in the logic. + if (ASTTrue == a) + { + return CreateSimpForm(OR, b, c); + } + else if (ASTFalse == a) + { + return CreateSimpForm(AND, b, c); + } + else if (ASTTrue == b) + { + return CreateSimpForm(OR, a, c); + } + else if (ASTFalse == b) + { + return CreateSimpForm(AND, a, c); + } + else if (ASTTrue == c) + { + return CreateSimpForm(OR, a, b); + } + else if (ASTFalse == c) + { + return CreateSimpForm(AND, a, b); + } + // there are lots more simplifications, but I'm not sure they're + // worth doing explicitly (e.g., a = b, a = ~b, etc.) + else + { + return CreateSimpForm(OR, CreateSimpForm(AND, a, b), CreateSimpForm(AND, b, c), CreateSimpForm(AND, a, c)); + } } - // Bitwise complement ASTVec BeevMgr::BBNeg(const ASTVec& x) { - ASTVec result = ASTVec(0); // FIXME: faster to preallocate n entries? - // Negate each bit. - ASTVec::const_iterator xend = x.end(); - for (ASTVec::const_iterator it = x.begin(); it < xend; it++) { - result.push_back(CreateSimpNot(*it)); - } - // FIXME: unecessary array copy when it returns? - return result; + ASTVec result = ASTVec(0); // FIXME: faster to preallocate n entries? + // Negate each bit. + ASTVec::const_iterator xend = x.end(); + for (ASTVec::const_iterator it = x.begin(); it < xend; it++) + { + result.push_back(CreateSimpNot(*it)); + } + // FIXME: unecessary array copy when it returns? + return result; } // Compute unary minus ASTVec BeevMgr::BBUminus(const ASTVec& x) { - ASTVec xneg = BBNeg(x); - return BBInc(xneg); + ASTVec xneg = BBNeg(x); + return BBInc(xneg); } // Multiply two bitblasted numbers ASTVec BeevMgr::BBMult(const ASTVec& x, const ASTVec& y) { - ASTVec ycopy(y); - ASTVec::const_iterator xend = x.end(); - ASTVec::const_iterator xit = x.begin(); - // start prod with first partial product. - // FIXME: This is unnecessary. Clean it up. - ASTVec prod = ASTVec(BBAndBit(y, *xit)); - // start loop at next bit. - for(xit++; xit < xend; xit++) { - // shift first - BBLShift(ycopy); - - if (ASTFalse == *xit) { - // If this bit is zero, the partial product will - // be zero. No reason to add that in. - continue; - } - - ASTVec pprod = BBAndBit(ycopy, *xit); - // accumulate in the product. - BBPlus2(prod, pprod, ASTFalse); - } - return prod; + ASTVec ycopy(y); + ASTVec::const_iterator xend = x.end(); + ASTVec::const_iterator xit = x.begin(); + // start prod with first partial product. + // FIXME: This is unnecessary. Clean it up. + ASTVec prod = ASTVec(BBAndBit(y, *xit)); + // start loop at next bit. + for (xit++; xit < xend; xit++) + { + // shift first + BBLShift(ycopy); + + if (ASTFalse == *xit) + { + // If this bit is zero, the partial product will + // be zero. No reason to add that in. + continue; + } + + ASTVec pprod = BBAndBit(ycopy, *xit); + // accumulate in the product. + BBPlus2(prod, pprod, ASTFalse); + } + return prod; } // This implements a variant of binary long division. @@ -805,86 +857,92 @@ ASTVec BeevMgr::BBMult(const ASTVec& x, const ASTVec& y) // recursion depth. void BeevMgr::BBDivMod(const ASTVec &y, const ASTVec &x, ASTVec &q, ASTVec &r, unsigned int rwidth) { - unsigned int width = y.size(); - if (rwidth == 0) { - // When we have shifted the entire width, y is guaranteed to be 0. - q = BBfill(width, ASTFalse); - r = BBfill(width, ASTFalse); - } - else { - ASTVec q1, r1; - ASTVec yrshift1(y); - BBRShift(yrshift1); - - // recursively divide y/2 by x. - BBDivMod(yrshift1, x, q1, r1, rwidth-1); - - ASTVec q1lshift1(q1); - BBLShift(q1lshift1); - - ASTVec r1lshift1(r1); - BBLShift(r1lshift1); - - ASTVec r1lshift1plusyodd = BBAddOneBit(r1lshift1, y[0]); - ASTVec rminusx(r1lshift1plusyodd); - BBSub(rminusx, x); - - // Adjusted q, r values when when r is too large. - ASTNode rtoolarge = BBBVLE(x, r1lshift1plusyodd, false); - ASTVec ygtrxqval = BBITE(rtoolarge, BBInc(q1lshift1), q1lshift1); - ASTVec ygtrxrval = BBITE(rtoolarge, rminusx, r1lshift1plusyodd); - - // q & r values when y >= x - ASTNode yeqx = BBEQ(y, x); - // *** Problem: the bbfill for qval is wrong. Should be 1, not -1. - ASTVec one = BBfill(width, ASTFalse); - one[0] = ASTTrue; - ASTVec notylessxqval = BBITE(yeqx, one, ygtrxqval); - ASTVec notylessxrval = BBITE(yeqx, BBfill(width, ASTFalse), ygtrxrval); - // y < x <=> not x >= y. - ASTNode ylessx = CreateSimpNot(BBBVLE(x, y, false)); - // final values of q and r - q = BBITE(ylessx, BBfill(width, ASTFalse), notylessxqval); - r = BBITE(ylessx, y, notylessxrval); - } + unsigned int width = y.size(); + if (rwidth == 0) + { + // When we have shifted the entire width, y is guaranteed to be 0. + q = BBfill(width, ASTFalse); + r = BBfill(width, ASTFalse); + } + else + { + ASTVec q1, r1; + ASTVec yrshift1(y); + BBRShift(yrshift1); + + // recursively divide y/2 by x. + BBDivMod(yrshift1, x, q1, r1, rwidth - 1); + + ASTVec q1lshift1(q1); + BBLShift(q1lshift1); + + ASTVec r1lshift1(r1); + BBLShift(r1lshift1); + + ASTVec r1lshift1plusyodd = BBAddOneBit(r1lshift1, y[0]); + ASTVec rminusx(r1lshift1plusyodd); + BBSub(rminusx, x); + + // Adjusted q, r values when when r is too large. + ASTNode rtoolarge = BBBVLE(x, r1lshift1plusyodd, false); + ASTVec ygtrxqval = BBITE(rtoolarge, BBInc(q1lshift1), q1lshift1); + ASTVec ygtrxrval = BBITE(rtoolarge, rminusx, r1lshift1plusyodd); + + // q & r values when y >= x + ASTNode yeqx = BBEQ(y, x); + // *** Problem: the bbfill for qval is wrong. Should be 1, not -1. + ASTVec one = BBfill(width, ASTFalse); + one[0] = ASTTrue; + ASTVec notylessxqval = BBITE(yeqx, one, ygtrxqval); + ASTVec notylessxrval = BBITE(yeqx, BBfill(width, ASTFalse), ygtrxrval); + // y < x <=> not x >= y. + ASTNode ylessx = CreateSimpNot(BBBVLE(x, y, false)); + // final values of q and r + q = BBITE(ylessx, BBfill(width, ASTFalse), notylessxqval); + r = BBITE(ylessx, y, notylessxrval); + } } // build ITE's (ITE cond then[i] else[i]) for each i. ASTVec BeevMgr::BBITE(const ASTNode& cond, const ASTVec& thn, const ASTVec& els) { - // Fast exits. - if (ASTTrue == cond) { - return thn; - } - else if (ASTFalse == cond) { - return els; - } - - ASTVec result(0); - ASTVec::const_iterator th_it_end = thn.end(); - ASTVec::const_iterator el_it = els.begin(); - for (ASTVec::const_iterator th_it = thn.begin(); th_it < th_it_end; th_it++, el_it++) { - result.push_back(CreateSimpForm(ITE, cond, *th_it, *el_it)); - } - return result; + // Fast exits. + if (ASTTrue == cond) + { + return thn; + } + else if (ASTFalse == cond) + { + return els; + } + + ASTVec result(0); + ASTVec::const_iterator th_it_end = thn.end(); + ASTVec::const_iterator el_it = els.begin(); + for (ASTVec::const_iterator th_it = thn.begin(); th_it < th_it_end; th_it++, el_it++) + { + result.push_back(CreateSimpForm(ITE, cond, *th_it, *el_it)); + } + return result; } // AND each bit of vector y with single bit b and return the result. ASTVec BeevMgr::BBAndBit(const ASTVec& y, ASTNode b) { - ASTVec result(0); - - if (ASTTrue == b) { - return y; - } - // FIXME: put in fast exits when b is constant 0. - - ASTVec::const_iterator yend = y.end(); - for(ASTVec::const_iterator yit = y.begin(); yit < yend; yit++) { - result.push_back(CreateSimpForm(AND, *yit, b)); - } - return result; -} + ASTVec result(0); + + if (ASTTrue == b) + { + return y; + } + // FIXME: put in fast exits when b is constant 0. + ASTVec::const_iterator yend = y.end(); + for (ASTVec::const_iterator yit = y.begin(); yit < yend; yit++) + { + result.push_back(CreateSimpForm(AND, *yit, b)); + } + return result; +} // Workhorse for comparison routines. This does a signed BVLE if is_signed // is true, else it's unsigned. All other comparison operators can be reduced @@ -894,44 +952,40 @@ ASTVec BeevMgr::BBAndBit(const ASTVec& y, ASTNode b) // of the bits. ASTNode BeevMgr::BBBVLE(const ASTVec& left, const ASTVec& right, bool is_signed) { - // "thisbit" represents BVLE of the suffixes of the BVs - // from that position . if R < L, return TRUE, else if L < R - // return FALSE, else return BVLE of lower-order bits. MSB is - // treated separately, because signed comparison is done by - // complementing the MSB of each BV, then doing an unsigned - // comparison. - ASTVec::const_iterator lit = left.begin(); - ASTVec::const_iterator litend = left.end(); - ASTVec::const_iterator rit = right.begin(); - ASTNode prevbit = ASTTrue; - for ( ; lit < litend-1; lit++, rit++) { - ASTNode neglit = CreateSimpNot(*lit); - ASTNode thisbit = - CreateSimpForm(OR, - CreateSimpForm(AND,neglit,*rit), // TRUE if l < r - CreateSimpForm(AND, - CreateSimpForm(OR, neglit, *rit), // false if not equal - prevbit)); // else prevbit - prevbit = thisbit; - } - - // Handle MSB -- negate MSBs if signed comparison - // FIXME: make into refs after it's debugged. - ASTNode lmsb = *lit; - ASTNode rmsb = *rit; - if (is_signed) { - lmsb = CreateSimpNot(*lit); - rmsb = CreateSimpNot(*rit); - } - - ASTNode neglmsb = CreateSimpNot(lmsb); - ASTNode msb = - CreateSimpForm(OR, - CreateSimpForm(AND,neglmsb, rmsb), // TRUE if l < r - CreateSimpForm(AND, - CreateSimpForm(OR, neglmsb, rmsb), // false if not equal - prevbit)); // else prevbit - return msb; + // "thisbit" represents BVLE of the suffixes of the BVs + // from that position . if R < L, return TRUE, else if L < R + // return FALSE, else return BVLE of lower-order bits. MSB is + // treated separately, because signed comparison is done by + // complementing the MSB of each BV, then doing an unsigned + // comparison. + ASTVec::const_iterator lit = left.begin(); + ASTVec::const_iterator litend = left.end(); + ASTVec::const_iterator rit = right.begin(); + ASTNode prevbit = ASTTrue; + for (; lit < litend - 1; lit++, rit++) + { + ASTNode neglit = CreateSimpNot(*lit); + ASTNode thisbit = CreateSimpForm(OR, CreateSimpForm(AND, neglit, *rit), // TRUE if l < r + CreateSimpForm(AND, CreateSimpForm(OR, neglit, *rit), // false if not equal + prevbit)); // else prevbit + prevbit = thisbit; + } + + // Handle MSB -- negate MSBs if signed comparison + // FIXME: make into refs after it's debugged. + ASTNode lmsb = *lit; + ASTNode rmsb = *rit; + if (is_signed) + { + lmsb = CreateSimpNot(*lit); + rmsb = CreateSimpNot(*rit); + } + + ASTNode neglmsb = CreateSimpNot(lmsb); + ASTNode msb = CreateSimpForm(OR, CreateSimpForm(AND, neglmsb, rmsb), // TRUE if l < r + CreateSimpForm(AND, CreateSimpForm(OR, neglmsb, rmsb), // false if not equal + prevbit)); // else prevbit + return msb; } // Left shift by 1 within fixed field inserting zeros at LSB. @@ -939,121 +993,159 @@ ASTNode BeevMgr::BBBVLE(const ASTVec& left, const ASTVec& right, bool is_signed) // Fixme: generalize to n bits void BeevMgr::BBLShift(ASTVec& x) { - // left shift x (destructively) within width. - // loop backwards so that copy to self works correctly. (DON'T use STL insert!) - ASTVec::iterator xbeg = x.begin(); - for(ASTVec::iterator xit = x.end()-1; xit > xbeg; xit--) { - *xit = *(xit-1); - } - *xbeg = ASTFalse; // new LSB is zero. - // cout << "Shifted result" << endl; - // lpvec(x); + // left shift x (destructively) within width. + // loop backwards so that copy to self works correctly. (DON'T use STL insert!) + ASTVec::iterator xbeg = x.begin(); + for (ASTVec::iterator xit = x.end() - 1; xit > xbeg; xit--) + { + *xit = *(xit - 1); + } + *xbeg = ASTFalse; // new LSB is zero. + // cout << "Shifted result" << endl; + // lpvec(x); } // Left shift within fixed field inserting zeros at LSB. // Writes result into first argument. - void BeevMgr::BBLShift(ASTVec& x, unsigned int shift) +void BeevMgr::BBLShift(ASTVec& x, unsigned int shift) { - // left shift x (destructively) within width. - // loop backwards so that copy to self works correctly. (DON'T use STL insert!) - ASTVec::iterator xbeg = x.begin(); - ASTVec::iterator xit = x.end()-1; - for(; xit >= xbeg; xit--) { - if (xit-shift >= xbeg) - *xit = *(xit-shift); - else - *xit= ASTFalse; // new LSB is zero. - } + // left shift x (destructively) within width. + // loop backwards so that copy to self works correctly. (DON'T use STL insert!) + ASTVec::iterator xbeg = x.begin(); + ASTVec::iterator xit = x.end() - 1; + for (; xit >= xbeg; xit--) + { + if (xit - shift >= xbeg) + *xit = *(xit - shift); + else + *xit = ASTFalse; // new LSB is zero. + } } // Right shift within fixed field inserting zeros at MSB. // Writes result into first argument. - void BeevMgr::BBRShift(ASTVec& x, unsigned int shift) +void BeevMgr::BBRShift(ASTVec& x, unsigned int shift) { - // right shift x (destructively) within width. - ASTVec::iterator xend = x.end(); - ASTVec::iterator xit = x.begin(); - for(; xit < xend; xit++) { - if (xit+shift < xend) - *xit = *(xit+shift); - else - *xit= ASTFalse; // new MSB is zero. - } + // right shift x (destructively) within width. + ASTVec::iterator xend = x.end(); + ASTVec::iterator xit = x.begin(); + for (; xit < xend; xit++) + { + if (xit + shift < xend) + *xit = *(xit + shift); + else + *xit = ASTFalse; // new MSB is zero. + } } - - - // Right shift by 1 within fixed field, inserting new zeros at MSB. // Writes result into first argument. // Fixme: generalize to n bits. void BeevMgr::BBRShift(ASTVec& x) { - ASTVec::iterator xend = x.end() - 1; - ASTVec::iterator xit = x.begin(); - for( ; xit < xend; xit++) { - *xit = *(xit+1); - } - *xit = ASTFalse; // new MSB is zero. + ASTVec::iterator xend = x.end() - 1; + ASTVec::iterator xit = x.begin(); + for (; xit < xend; xit++) + { + *xit = *(xit + 1); + } + *xit = ASTFalse; // new MSB is zero. } -// Return bit-blasted form for BVLE, BVGE, BVGT, SBLE, etc. -ASTNode BeevMgr::BBcompare(const ASTNode& form) { - const ASTNode lnode = BBTerm(form[0]); - const ASTNode rnode = BBTerm(form[1]); - const ASTVec& left = lnode.GetChildren(); - const ASTVec& right = rnode.GetChildren(); - - //const ASTVec& left = BBTerm(form[0]).GetChildren(); - //const ASTVec& right = BBTerm(form[1]).GetChildren(); - - Kind k = form.GetKind(); - switch(k) { - case BVLE: { return BBBVLE(left, right, false); break; } - case BVGE: { return BBBVLE(right, left, false); break; } - case BVGT: { return CreateSimpNot(BBBVLE(left, right, false)); break; } - case BVLT: { return CreateSimpNot(BBBVLE(right, left, false)); break; } - case BVSLE: { return BBBVLE(left, right, true); break; } - case BVSGE: { return BBBVLE(right, left, true); break; } - case BVSGT: { return CreateSimpNot(BBBVLE(left, right, true)); break; } - case BVSLT: { return CreateSimpNot(BBBVLE(right, left, true)); break; } - default: - cerr << "BBCompare: Illegal kind" << form << endl; - FatalError("",ASTUndefined); - } - return ASTUndefined; +// Return bit-blasted form for BVLE, BVGE, BVGT, SBLE, etc. +ASTNode BeevMgr::BBcompare(const ASTNode& form) +{ + const ASTNode lnode = BBTerm(form[0]); + const ASTNode rnode = BBTerm(form[1]); + const ASTVec& left = lnode.GetChildren(); + const ASTVec& right = rnode.GetChildren(); + + //const ASTVec& left = BBTerm(form[0]).GetChildren(); + //const ASTVec& right = BBTerm(form[1]).GetChildren(); + + Kind k = form.GetKind(); + switch (k) + { + case BVLE: + { + return BBBVLE(left, right, false); + break; + } + case BVGE: + { + return BBBVLE(right, left, false); + break; + } + case BVGT: + { + return CreateSimpNot(BBBVLE(left, right, false)); + break; + } + case BVLT: + { + return CreateSimpNot(BBBVLE(right, left, false)); + break; + } + case BVSLE: + { + return BBBVLE(left, right, true); + break; + } + case BVSGE: + { + return BBBVLE(right, left, true); + break; + } + case BVSGT: + { + return CreateSimpNot(BBBVLE(left, right, true)); + break; + } + case BVSLT: + { + return CreateSimpNot(BBBVLE(right, left, true)); + break; + } + default: + cerr << "BBCompare: Illegal kind" << form << endl; + FatalError("", ASTUndefined); + } + return ASTUndefined; } - // return a vector with n copies of fillval ASTVec BeevMgr::BBfill(unsigned int width, ASTNode fillval) { - ASTVec zvec(width, fillval); - return zvec; + ASTVec zvec(width, fillval); + return zvec; } ASTNode BeevMgr::BBEQ(const ASTVec& left, const ASTVec& right) { - ASTVec andvec; - ASTVec::const_iterator lit = left.begin(); - ASTVec::const_iterator litend = left.end(); - ASTVec::const_iterator rit = right.begin(); - - if(left.size() > 1) { - for(; lit != litend; lit++, rit++) { - ASTNode biteq = CreateSimpForm(IFF, *lit, *rit); - // fast path exit - if (biteq == ASTFalse) { - return ASTFalse; - } - else { - andvec.push_back(biteq); - } - } - ASTNode n = CreateSimpForm(AND, andvec); - return n; - } - else - return CreateSimpForm(IFF,*lit,*rit); + ASTVec andvec; + ASTVec::const_iterator lit = left.begin(); + ASTVec::const_iterator litend = left.end(); + ASTVec::const_iterator rit = right.begin(); + + if (left.size() > 1) + { + for (; lit != litend; lit++, rit++) + { + ASTNode biteq = CreateSimpForm(IFF, *lit, *rit); + // fast path exit + if (biteq == ASTFalse) + { + return ASTFalse; + } + else + { + andvec.push_back(biteq); + } + } + ASTNode n = CreateSimpForm(AND, andvec); + return n; + } + else + return CreateSimpForm(IFF, *lit, *rit); } } // BEEV namespace diff --git a/AST/SimpBool.cpp b/AST/SimpBool.cpp index 7dc24ef..85e1916 100644 --- a/AST/SimpBool.cpp +++ b/AST/SimpBool.cpp @@ -24,400 +24,483 @@ static bool _disable_simpbool = 0; // children to reduce growing of vectors. //BEEV::ASTVec child_stack; -namespace BEEV { - - ASTNode BeevMgr::CreateSimpForm(Kind kind, ASTVec &children = _empty_ASTVec) { - if (_disable_simpbool) { - return CreateNode(kind, children); - } - else { - switch (kind) { - case NOT: return CreateSimpNot(children[0]); break; - case AND: return CreateSimpAndOr(1, children); break; - case OR: return CreateSimpAndOr(0, children); break; - case NAND: return CreateSimpNot(CreateSimpAndOr(1, children)); break; - case NOR: return CreateSimpNot(CreateSimpAndOr(0, children)); break; - case IFF: { - // Not sure children can ever be empty, but what the heck. - // if (children.size() == 0) { - // return ASTTrue; - // } - // Convert IFF to XOR ASAP to simplify flattening. - children[0] = CreateSimpNot(children[0]); - return CreateSimpXor(children); break; - } - case XOR: - return CreateSimpXor(children); break; - // FIXME: Earlier, check that this only has two arguments - case IMPLIES: return CreateSimpAndOr(0, CreateSimpNot(children[0]), children[1]); break; - case ITE: return CreateSimpFormITE(children[0], children[1], children[2]); - default: return CreateNode(kind, children); - } - } - } - - // specialized versions - - ASTNode BeevMgr::CreateSimpForm(Kind kind, - const ASTNode& child0) { - ASTVec children; - //child_stack.clear(); // could just reset top pointer. - children.push_back(child0); - //child_stack.push_back(child0); - return CreateSimpForm(kind, children); - //return CreateSimpForm(kind, child_stack); - } - - ASTNode BeevMgr::CreateSimpForm(Kind kind, - const ASTNode& child0, - const ASTNode& child1) { - ASTVec children; - //child_stack.clear(); // could just reset top pointer. - children.push_back(child0); - //child_stack.push_back(child0); - children.push_back(child1); - //child_stack.push_back(child1); - return CreateSimpForm(kind, children); - //return CreateSimpForm(kind, child_stack); - } - - - ASTNode BeevMgr::CreateSimpForm(Kind kind, - const ASTNode& child0, - const ASTNode& child1, - const ASTNode& child2) { - ASTVec children; - //child_stack.clear(); // could just reset top pointer. - children.push_back(child0); - //child_stack.push_back(child0); - children.push_back(child1); - //child_stack.push_back(child1); - children.push_back(child2); - //child_stack.push_back(child2); - return CreateSimpForm(kind, children); - //return CreateSimpForm(kind, child_stack); - } - - ASTNode BeevMgr::CreateSimpNot(const ASTNode& form) { - Kind k = form.GetKind(); - switch (k) { - case FALSE: { return ASTTrue; } - case TRUE: { return ASTFalse; } - case NOT: { return form[0]; } // NOT NOT cancellation - case XOR: { - // Push negation down in this case. - // FIXME: Separate pre-pass to push negation down? - // CreateSimp should be local, and this isn't. - // It isn't memoized. Arg. - ASTVec children = form.GetChildren(); - children[0] = CreateSimpNot(children[0]); - return CreateSimpXor(children); - } - default: { return CreateNode(NOT, form); } - } - } - - // I don't think this is even called, since it called - // CreateSimpAndOr instead of CreateSimpXor until 1/9/07 with no - // ill effects. Calls seem to go to the version that takes a vector - // of children. - ASTNode BeevMgr::CreateSimpXor(const ASTNode& form1, const ASTNode& form2) { - ASTVec children; - children.push_back(form1); - children.push_back(form2); - return CreateSimpXor(children); - } - - // Flatten (k ... (k ci cj) ...) to (k ... ci cj ...) - // This is local to this file. - ASTVec FlattenKind(Kind k, ASTVec &children) { - - ASTVec flat_children; - - ASTVec::const_iterator ch_end = children.end(); - - bool fflag = 0; // ***Temp debugging - - // Experimental flattening code. - - for(ASTVec::iterator it = children.begin(); it != ch_end; it++) { - Kind ck = it->GetKind(); - const ASTVec &gchildren = it->GetChildren(); - if (k == ck) { - fflag = 1; // For selective debug printing (below). - // append grandchildren to children - flat_children.insert(flat_children.end(), gchildren.begin(), gchildren.end()); - } - else { - flat_children.push_back(*it); - } - } - - if (_trace_simpbool && fflag) { - cout << "========" << endl; - cout << "Flattening " << k << ":" << endl; - lpvec(children); - - cout << "--------" << endl; - cout << "Flattening result: " << endl; - lpvec(flat_children); - } - - // FIXME: This unnecessarily copies the array. - return flat_children; - } - - ASTNode BeevMgr::CreateSimpAndOr(bool IsAnd, const ASTNode& form1, const ASTNode& form2) { - ASTVec children; - children.push_back(form1); - children.push_back(form2); - return CreateSimpAndOr(IsAnd, children); - } - - // FIXME: Could also handle (AND ... (NOT (OR ...) ...) - ASTNode BeevMgr::CreateSimpAndOr(bool IsAnd, ASTVec &children) { - - Kind k = IsAnd ? AND : OR; - - if (_trace_simpbool) { - cout << "========" << endl << "CreateSimpAndOr " << k << " "; - lpvec(children); - cout << endl; - } - - ASTVec new_children; - - ASTVec flat_children; - if (xor_flatten) { - flat_children = FlattenKind(k, children); - } - else { - flat_children = children; - } - - // sort so that identical nodes occur in sequential runs, followed by - // their negations. - SortByExprNum(flat_children); - - ASTNode annihilator = (IsAnd ? ASTFalse : ASTTrue); - ASTNode identity = (IsAnd ? ASTTrue : ASTFalse); - - ASTNode retval; - - ASTVec::const_iterator it_end = flat_children.end(); - ASTVec::const_iterator next_it; - for(ASTVec::const_iterator it = flat_children.begin(); it != it_end; it = next_it) { - next_it = it + 1; - bool nextexists = (next_it < it_end); - - if (*it == annihilator) { - retval = annihilator; - if (_trace_simpbool) { - cout << "returns " << retval << endl; +namespace BEEV +{ + +ASTNode BeevMgr::CreateSimpForm(Kind kind, ASTVec &children = _empty_ASTVec) +{ + if (_disable_simpbool) + { + return CreateNode(kind, children); + } + else + { + switch (kind) + { + case NOT: + return CreateSimpNot(children[0]); + break; + case AND: + return CreateSimpAndOr(1, children); + break; + case OR: + return CreateSimpAndOr(0, children); + break; + case NAND: + return CreateSimpNot(CreateSimpAndOr(1, children)); + break; + case NOR: + return CreateSimpNot(CreateSimpAndOr(0, children)); + break; + case IFF: + { + // Not sure children can ever be empty, but what the heck. + // if (children.size() == 0) { + // return ASTTrue; + // } + // Convert IFF to XOR ASAP to simplify flattening. + children[0] = CreateSimpNot(children[0]); + return CreateSimpXor(children); + break; + } + case XOR: + return CreateSimpXor(children); + break; + // FIXME: Earlier, check that this only has two arguments + case IMPLIES: + return CreateSimpAndOr(0, CreateSimpNot(children[0]), children[1]); + break; + case ITE: + return CreateSimpFormITE(children[0], children[1], children[2]); + default: + return CreateNode(kind, children); + } + } +} + +// specialized versions + +ASTNode BeevMgr::CreateSimpForm(Kind kind, const ASTNode& child0) +{ + ASTVec children; + //child_stack.clear(); // could just reset top pointer. + children.push_back(child0); + //child_stack.push_back(child0); + return CreateSimpForm(kind, children); + //return CreateSimpForm(kind, child_stack); +} + +ASTNode BeevMgr::CreateSimpForm(Kind kind, const ASTNode& child0, const ASTNode& child1) +{ + ASTVec children; + //child_stack.clear(); // could just reset top pointer. + children.push_back(child0); + //child_stack.push_back(child0); + children.push_back(child1); + //child_stack.push_back(child1); + return CreateSimpForm(kind, children); + //return CreateSimpForm(kind, child_stack); +} + +ASTNode BeevMgr::CreateSimpForm(Kind kind, const ASTNode& child0, const ASTNode& child1, const ASTNode& child2) +{ + ASTVec children; + //child_stack.clear(); // could just reset top pointer. + children.push_back(child0); + //child_stack.push_back(child0); + children.push_back(child1); + //child_stack.push_back(child1); + children.push_back(child2); + //child_stack.push_back(child2); + return CreateSimpForm(kind, children); + //return CreateSimpForm(kind, child_stack); +} + +ASTNode BeevMgr::CreateSimpNot(const ASTNode& form) +{ + Kind k = form.GetKind(); + switch (k) + { + case FALSE: + { + return ASTTrue; + } + case TRUE: + { + return ASTFalse; + } + case NOT: + { + return form[0]; + } // NOT NOT cancellation + case XOR: + { + // Push negation down in this case. + // FIXME: Separate pre-pass to push negation down? + // CreateSimp should be local, and this isn't. + // It isn't memoized. Arg. + ASTVec children = form.GetChildren(); + children[0] = CreateSimpNot(children[0]); + return CreateSimpXor(children); + } + default: + { + return CreateNode(NOT, form); + } + } +} + +// I don't think this is even called, since it called +// CreateSimpAndOr instead of CreateSimpXor until 1/9/07 with no +// ill effects. Calls seem to go to the version that takes a vector +// of children. +ASTNode BeevMgr::CreateSimpXor(const ASTNode& form1, const ASTNode& form2) +{ + ASTVec children; + children.push_back(form1); + children.push_back(form2); + return CreateSimpXor(children); +} + +// Flatten (k ... (k ci cj) ...) to (k ... ci cj ...) +// This is local to this file. +ASTVec FlattenKind(Kind k, ASTVec &children) +{ + + ASTVec flat_children; + + ASTVec::const_iterator ch_end = children.end(); + + bool fflag = 0; // ***Temp debugging + + // Experimental flattening code. + + for (ASTVec::iterator it = children.begin(); it != ch_end; it++) + { + Kind ck = it->GetKind(); + const ASTVec &gchildren = it->GetChildren(); + if (k == ck) + { + fflag = 1; // For selective debug printing (below). + // append grandchildren to children + flat_children.insert(flat_children.end(), gchildren.begin(), gchildren.end()); + } + else + { + flat_children.push_back(*it); + } + } + + if (_trace_simpbool && fflag) + { + cout << "========" << endl; + cout << "Flattening " << k << ":" << endl; + lpvec(children); + + cout << "--------" << endl; + cout << "Flattening result: " << endl; + lpvec(flat_children); + } + + // FIXME: This unnecessarily copies the array. + return flat_children; +} + +ASTNode BeevMgr::CreateSimpAndOr(bool IsAnd, const ASTNode& form1, const ASTNode& form2) +{ + ASTVec children; + children.push_back(form1); + children.push_back(form2); + return CreateSimpAndOr(IsAnd, children); +} + +// FIXME: Could also handle (AND ... (NOT (OR ...) ...) +ASTNode BeevMgr::CreateSimpAndOr(bool IsAnd, ASTVec &children) +{ + + Kind k = IsAnd ? AND : OR; + + if (_trace_simpbool) + { + cout << "========" << endl << "CreateSimpAndOr " << k << " "; + lpvec(children); + cout << endl; + } + + ASTVec new_children; + + ASTVec flat_children; + if (xor_flatten) + { + flat_children = FlattenKind(k, children); + } + else + { + flat_children = children; + } + + // sort so that identical nodes occur in sequential runs, followed by + // their negations. + SortByExprNum(flat_children); + + ASTNode annihilator = (IsAnd ? ASTFalse : ASTTrue); + ASTNode identity = (IsAnd ? ASTTrue : ASTFalse); + + ASTNode retval; + + ASTVec::const_iterator it_end = flat_children.end(); + ASTVec::const_iterator next_it; + for (ASTVec::const_iterator it = flat_children.begin(); it != it_end; it = next_it) + { + next_it = it + 1; + bool nextexists = (next_it < it_end); + + if (*it == annihilator) + { + retval = annihilator; + if (_trace_simpbool) + { + cout << "returns " << retval << endl; + } + return retval; + } + else if (*it == identity) + { + // just drop it + } + else if (nextexists && (*next_it == *it)) + { + // drop it + // cout << "Dropping [" << it->GetNodeNum() << "]" << endl; + } + else if (nextexists && (next_it->GetKind() == NOT) && ((*next_it)[0] == *it)) + { + // form and negation -- return FALSE for AND, TRUE for OR. + retval = annihilator; + // cout << "X and/or NOT X" << endl; + if (_trace_simpbool) + { + cout << "returns " << retval << endl; + } + return retval; + } + else + { + // add to children + new_children.push_back(*it); + } + } + + // If we get here, we saw no annihilators, and children should + // be only the non-True nodes. + if (new_children.size() < 2) + { + if (0 == new_children.size()) + { + retval = identity; + } + else + { + // there is just one child + retval = new_children[0]; + } + } + else + { + // 2 or more children. Create a new node. + retval = CreateNode(IsAnd ? AND : OR, new_children); + } + if (_trace_simpbool) + { + cout << "returns " << retval << endl; } return retval; - } - else if (*it == identity) { - // just drop it - } - else if (nextexists && (*next_it == *it)) { - // drop it - // cout << "Dropping [" << it->GetNodeNum() << "]" << endl; - } - else if (nextexists && (next_it->GetKind() == NOT) && ((*next_it)[0] == *it)) { - // form and negation -- return FALSE for AND, TRUE for OR. - retval = annihilator; - // cout << "X and/or NOT X" << endl; - if (_trace_simpbool) { - cout << "returns " << retval << endl; +} + +// Constant children are accumulated in "accumconst". +ASTNode BeevMgr::CreateSimpXor(ASTVec &children) +{ + + if (_trace_simpbool) + { + cout << "========" << endl << "CreateSimpXor "; + lpvec(children); + cout << endl; + } + + ASTVec flat_children; // empty vector + ASTVec::const_iterator it_end = children.end(); + + if (xor_flatten) + { + flat_children = FlattenKind(XOR, children); + } + else + { + flat_children = children; + } + + // sort so that identical nodes occur in sequential runs, followed by + // their negations. + SortByExprNum(flat_children); + + ASTNode retval; + + // This is the C Boolean value of all constant args seen. It is initially + // 0. TRUE children cause it to change value. + bool accumconst = 0; + + ASTVec new_children; + + it_end = flat_children.end(); + ASTVec::iterator next_it; + for (ASTVec::iterator it = flat_children.begin(); it != it_end; it++) + { + next_it = it + 1; + bool nextexists = (next_it < it_end); + + if (ASTTrue == *it) + { + accumconst = !accumconst; + } + else if (ASTFalse == *it) + { + // Ignore it + } + else if (nextexists && (*next_it == *it)) + { + // x XOR x = FALSE. Skip current, write "false" into next_it + // so that it gets tossed, too. + *next_it = ASTFalse; + } + else if (nextexists && (next_it->GetKind() == NOT) && ((*next_it)[0] == *it)) + { + // x XOR NOT x = TRUE. Skip current, write "true" into next_it + // so that it gets tossed, too. + *next_it = ASTTrue; + } + else if (NOT == it->GetKind()) + { + // If child is (NOT alpha), we can flip accumconst and use alpha. + // This is ok because (NOT alpha) == TRUE XOR alpha + accumconst = !accumconst; + // CreateSimpNot just takes child of not. + new_children.push_back(CreateSimpNot(*it)); + } + else + { + new_children.push_back(*it); + } + } + + // Children should be non-constant. + if (new_children.size() < 2) + { + if (0 == new_children.size()) + { + // XOR(TRUE, FALSE) -- accumconst will be 1. + if (accumconst) + { + retval = ASTTrue; + } + else + { + retval = ASTFalse; + } + } + else + { + // there is just one child + // XOR(x, TRUE) -- accumconst will be 1. + if (accumconst) + { + retval = CreateSimpNot(new_children[0]); + } + else + { + retval = new_children[0]; + } + } + } + else + { + // negate first child if accumconst == 1 + if (accumconst) + { + new_children[0] = CreateSimpNot(new_children[0]); + } + retval = CreateNode(XOR, new_children); + } + + if (_trace_simpbool) + { + cout << "returns " << retval << endl; } return retval; - } - else { - // add to children - new_children.push_back(*it); - } - } - - // If we get here, we saw no annihilators, and children should - // be only the non-True nodes. - if (new_children.size() < 2) { - if (0 == new_children.size()) { - retval = identity; - } - else { - // there is just one child - retval = new_children[0]; - } - } - else { - // 2 or more children. Create a new node. - retval = CreateNode(IsAnd ? AND : OR, new_children); - } - if (_trace_simpbool) { - cout << "returns " << retval << endl; - } - return retval; - } - - // Constant children are accumulated in "accumconst". - ASTNode BeevMgr::CreateSimpXor(ASTVec &children) { - - if (_trace_simpbool) { - cout << "========" << endl - << "CreateSimpXor "; - lpvec(children); - cout << endl; - } - - ASTVec flat_children; // empty vector - ASTVec::const_iterator it_end = children.end(); - - if (xor_flatten) { - flat_children = FlattenKind(XOR, children); - } - else { - flat_children = children; - } - - // sort so that identical nodes occur in sequential runs, followed by - // their negations. - SortByExprNum(flat_children); - - ASTNode retval; - - // This is the C Boolean value of all constant args seen. It is initially - // 0. TRUE children cause it to change value. - bool accumconst = 0; - - ASTVec new_children; - - it_end = flat_children.end(); - ASTVec::iterator next_it; - for(ASTVec::iterator it = flat_children.begin(); it != it_end; it++) { - next_it = it + 1; - bool nextexists = (next_it < it_end); - - if (ASTTrue == *it) { - accumconst = !accumconst; - } - else if (ASTFalse == *it) { - // Ignore it - } - else if (nextexists && (*next_it == *it)) { - // x XOR x = FALSE. Skip current, write "false" into next_it - // so that it gets tossed, too. - *next_it = ASTFalse; - } - else if (nextexists && (next_it->GetKind() == NOT) && ((*next_it)[0] == *it)) { - // x XOR NOT x = TRUE. Skip current, write "true" into next_it - // so that it gets tossed, too. - *next_it = ASTTrue; - } - else if (NOT == it->GetKind()) { - // If child is (NOT alpha), we can flip accumconst and use alpha. - // This is ok because (NOT alpha) == TRUE XOR alpha - accumconst = !accumconst; - // CreateSimpNot just takes child of not. - new_children.push_back(CreateSimpNot(*it)); - } - else { - new_children.push_back(*it); - } - } - - // Children should be non-constant. - if (new_children.size() < 2) { - if (0 == new_children.size()) { - // XOR(TRUE, FALSE) -- accumconst will be 1. - if (accumconst) { - retval = ASTTrue; +} + +// FIXME: How do I know whether ITE is a formula or not? +ASTNode BeevMgr::CreateSimpFormITE(const ASTNode& child0, const ASTNode& child1, const ASTNode& child2) +{ + + ASTNode retval; + + if (_trace_simpbool) + { + cout << "========" << endl << "CreateSimpFormITE " << child0 << child1 << child2 << endl; + } + + if (ASTTrue == child0) + { + retval = child1; + } + else if (ASTFalse == child0) + { + retval = child2; + } + else if (child1 == child2) + { + retval = child1; + } + // ITE(x, TRUE, y ) == x OR y + else if (ASTTrue == child1) + { + retval = CreateSimpAndOr(0, child0, child2); } - else { - retval = ASTFalse; + // ITE(x, FALSE, y ) == (!x AND y) + else if (ASTFalse == child1) + { + retval = CreateSimpAndOr(1, CreateSimpNot(child0), child2); } - } - else { - // there is just one child - // XOR(x, TRUE) -- accumconst will be 1. - if (accumconst) { - retval = CreateSimpNot(new_children[0]); + // ITE(x, y, TRUE ) == (!x OR y) + else if (ASTTrue == child2) + { + retval = CreateSimpAndOr(0, CreateSimpNot(child0), child1); } - else { - retval = new_children[0]; + // ITE(x, y, FALSE ) == (x AND y) + else if (ASTFalse == child2) + { + retval = CreateSimpAndOr(1, child0, child1); } - } - } - else { - // negate first child if accumconst == 1 - if (accumconst) { - new_children[0] = CreateSimpNot(new_children[0]); - } - retval = CreateNode(XOR, new_children); - } - - if (_trace_simpbool) { - cout << "returns " << retval << endl; - } - return retval; - } - - // FIXME: How do I know whether ITE is a formula or not? - ASTNode BeevMgr::CreateSimpFormITE(const ASTNode& child0, - const ASTNode& child1, - const ASTNode& child2) { - - ASTNode retval; - - if (_trace_simpbool) { - cout << "========" << endl << "CreateSimpFormITE " - << child0 - << child1 - << child2 << endl; - } - - if (ASTTrue == child0) { - retval = child1; - } - else if (ASTFalse == child0) { - retval = child2; - } - else if (child1 == child2) { - retval = child1; - } - // ITE(x, TRUE, y ) == x OR y - else if (ASTTrue == child1) { - retval = CreateSimpAndOr(0, child0, child2); - } - // ITE(x, FALSE, y ) == (!x AND y) - else if (ASTFalse == child1) { - retval = CreateSimpAndOr(1, CreateSimpNot(child0), child2); - } - // ITE(x, y, TRUE ) == (!x OR y) - else if (ASTTrue == child2) { - retval = CreateSimpAndOr(0, CreateSimpNot(child0), child1); - } - // ITE(x, y, FALSE ) == (x AND y) - else if (ASTFalse == child2) { - retval = CreateSimpAndOr(1, child0, child1); - } - // ITE (x, !y, y) == x XOR y -// else if (NOT == child1.GetKind() && (child1[0] == child2)) { -// retval = CreateSimpXor(child0, child2); -// } -// // ITE (x, y, !y) == x IFF y. I think other cases are covered -// // by XOR/IFF optimizations -// else if (NOT == child2.GetKind() && (child2[0] == child1)) { -// retval = CreateSimpXor(CreateSimpNot(child0), child2); -// } - else { - retval = CreateNode(ITE, child0, child1, child2); - } - - if (_trace_simpbool) { - cout << "returns " << retval << endl; - } - - return retval; - } + // ITE (x, !y, y) == x XOR y + // else if (NOT == child1.GetKind() && (child1[0] == child2)) { + // retval = CreateSimpXor(child0, child2); + // } + // // ITE (x, y, !y) == x IFF y. I think other cases are covered + // // by XOR/IFF optimizations + // else if (NOT == child2.GetKind() && (child2[0] == child1)) { + // retval = CreateSimpXor(CreateSimpNot(child0), child2); + // } + else + { + retval = CreateNode(ITE, child0, child1, child2); + } + + if (_trace_simpbool) + { + cout << "returns " << retval << endl; + } + + return retval; +} } // BEEV namespace diff --git a/AST/ToCNF.cpp b/AST/ToCNF.cpp index d66a7d0..672fd40 100644 --- a/AST/ToCNF.cpp +++ b/AST/ToCNF.cpp @@ -1,1621 +1,1850 @@ #include "AST.h" #include "../simplifier/bvsolver.h" -namespace BEEV { +namespace BEEV +{ -class CNFMgr { +class CNFMgr +{ public: - //######################################## - //######################################## - // constructor + //######################################## + //######################################## + // constructor - CNFMgr(BeevMgr *bmgr){ - bm = bmgr; - } + CNFMgr(BeevMgr *bmgr) + { + bm = bmgr; + } - //######################################## - //######################################## - // destructor + //######################################## + //######################################## + // destructor - ~CNFMgr(){ - ASTNodeToASTNodePtrMap::const_iterator it1 = store.begin(); - for(; it1 != store.end(); it1++){ - delete it1->second; - } + ~CNFMgr() + { + ASTNodeToASTNodePtrMap::const_iterator it1 = store.begin(); + for (; it1 != store.end(); it1++) + { + delete it1->second; + } - store.clear(); + store.clear(); - } + } - //######################################## - //######################################## - // top-level conversion function + //######################################## + //######################################## + // top-level conversion function + + BeevMgr::ClauseList* convertToCNF(const ASTNode& varphi) + { + scanFormula(varphi, true); + ASTNode dummy_true_var = bm->CreateSymbol("*TrueDummy*"); + BeevMgr::ClauseList* defs = SINGLETON(dummy_true_var); + convertFormulaToCNF(varphi, defs); + BeevMgr::ClauseList* top = info[varphi]->clausespos; + defs->insert(defs->begin() + 1, top->begin(), top->end()); + + cleanup(varphi); + return defs; + } - BeevMgr::ClauseList* convertToCNF(const ASTNode& varphi){ - scanFormula(varphi, true); - ASTNode dummy_true_var = bm->CreateSymbol("*TrueDummy*"); - BeevMgr::ClauseList* defs = SINGLETON(dummy_true_var); - convertFormulaToCNF(varphi, defs); - BeevMgr::ClauseList* top = info[varphi]->clausespos; - defs->insert(defs->begin() + 1, top->begin(), top->end()); + void DELETE(BeevMgr::ClauseList* varphi) + { + BeevMgr::ClauseList::const_iterator it = varphi->begin(); + for (; it != varphi->end(); it++) + { + delete *it; + } - cleanup(varphi); - return defs; - } + delete varphi; + } - void DELETE(BeevMgr::ClauseList* varphi){ - BeevMgr::ClauseList::const_iterator it = varphi->begin(); - for(; it != varphi->end(); it++){ - delete *it; - } +private: - delete varphi; - } + //######################################## + //######################################## + // data types + + // for the meaning of control bits, see "utilities for contol bits". + typedef struct + { + int control; + BeevMgr::ClauseList* clausespos; + union + { + BeevMgr::ClauseList* clausesneg; + ASTNode* termforcnf; + }; + } CNFInfo; + + typedef hash_map ASTNodeToCNFInfoMap; + + typedef hash_map ASTNodeToASTNodePtrMap; + + //######################################## + //######################################## + // this is the data + + BeevMgr *bm; + ASTNodeToCNFInfoMap info; + ASTNodeToASTNodePtrMap store; + + //######################################## + //######################################## + // utility predicates + + bool isAtom(const ASTNode& varphi) + { + bool result; + + Kind k = varphi.GetKind(); + switch (k) + { + case TRUE: + { + result = true; + break; + } + case FALSE: + { + result = true; + break; + } + case SYMBOL: + { + result = true; + break; + } + case BVCONST: + { + result = true; + break; + } + default: + { + result = false; + break; + } + } + + return result; + } -private: + bool isPred(const ASTNode& varphi) + { + bool result; + + Kind k = varphi.GetKind(); + switch (k) + { + case BVLT: + { + result = true; + break; + } + case BVLE: + { + result = true; + break; + } + case BVGT: + { + result = true; + break; + } + case BVGE: + { + result = true; + break; + } + case BVSLT: + { + result = true; + break; + } + case BVSLE: + { + result = true; + break; + } + case BVSGT: + { + result = true; + break; + } + case BVSGE: + { + result = true; + break; + } + case EQ: + { + result = true; + break; + } + case NEQ: + { + result = true; + break; + } + default: + { + result = false; + break; + } + } + + return result; + } + + bool isITE(const ASTNode& varphi) + { + bool result; + + Kind k = varphi.GetKind(); + switch (k) + { + case ITE: + { + result = true; + break; + } + default: + { + result = false; + break; + } + } + + return result; + } + + bool onChildDoPos(const ASTNode& varphi, unsigned int idx) + { + bool result = true; + + Kind k = varphi.GetKind(); + switch (k) + { + case NOT: + { + result = false; + break; + } + case NAND: + { + result = false; + break; + } + case NOR: + { + result = false; + break; + } + case IMPLIES: + { + if (idx == 0) + { + result = false; + } + break; + } + default: + { + break; + } + } + + return result; + } + + bool onChildDoNeg(const ASTNode& varphi, unsigned int idx) + { + bool result = false; + + Kind k = varphi.GetKind(); + switch (k) + { + case NOT: + { + result = true; + break; + } + case NAND: + { + result = true; + break; + } + case NOR: + { + result = true; + break; + } + case XOR: + { + result = true; + break; + } + case IFF: + { + result = true; + break; + } + case IMPLIES: + { + if (idx == 0) + { + result = true; + } + break; + } + case ITE: + { + if (idx == 0) + { + result = true; + } + break; + } + default: + { + break; + } + } + + return result; + } + + //######################################## + //######################################## + //utilities for control bits. + + void initializeCNFInfo(CNFInfo& x) + { + x.control = 0; + x.clausespos = NULL; + x.clausesneg = NULL; + } + + void incrementSharesPos(CNFInfo& x) + { + x.control += ((x.control & 3) < 2) ? 1 : 0; + } + + int sharesPos(CNFInfo& x) + { + return (x.control & 3); + } + + void incrementSharesNeg(CNFInfo& x) + { + x.control += ((x.control & 12) < 8) ? 4 : 0; + } + + int sharesNeg(CNFInfo& x) + { + return ((x.control & 12) >> 2); + } + + void setControlBit(CNFInfo& x, unsigned int idx) + { + x.control |= (1 << idx); + } + + bool getControlBit(CNFInfo& x, unsigned int idx) + { + bool result = false; + + if (x.control & (1 << idx)) + { + + result = true; + } + + return result; + } + + void setIsTerm(CNFInfo& x) + { + setControlBit(x, 4); + } + + bool isTerm(CNFInfo& x) + { + return getControlBit(x, 4); + } + + void setDoRenamePos(CNFInfo& x) + { + setControlBit(x, 5); + } + + bool doRenamePos(CNFInfo& x) + { + return getControlBit(x, 5); + } + + void setWasRenamedPos(CNFInfo& x) + { + setControlBit(x, 6); + } + + bool wasRenamedPos(CNFInfo& x) + { + return getControlBit(x, 6); + } + + void setDoRenameNeg(CNFInfo& x) + { + setControlBit(x, 7); + } + + bool doRenameNeg(CNFInfo& x) + { + return getControlBit(x, 7); + } + + void setWasRenamedNeg(CNFInfo& x) + { + setControlBit(x, 8); + } + + bool wasRenamedNeg(CNFInfo& x) + { + return getControlBit(x, 8); + } + + void setDoSibRenamingPos(CNFInfo& x) + { + setControlBit(x, 9); + } + + bool doSibRenamingPos(CNFInfo& x) + { + return getControlBit(x, 9); + } + + void setDoSibRenamingNeg(CNFInfo& x) + { + setControlBit(x, 10); + } + + bool doSibRenamingNeg(CNFInfo& x) + { + return getControlBit(x, 10); + } + + void setWasVisited(CNFInfo& x) + { + setControlBit(x, 11); + } + + bool wasVisited(CNFInfo& x) + { + return getControlBit(x, 11); + } + + //######################################## + //######################################## + //utilities for clause sets + + + BeevMgr::ClauseList* COPY(const BeevMgr::ClauseList& varphi) + { + BeevMgr::ClauseList* psi = new BeevMgr::ClauseList(); + + BeevMgr::ClauseList::const_iterator it = varphi.begin(); + for (; it != varphi.end(); it++) + { + psi->push_back(new vector (**it)); + } + + return psi; + } + + BeevMgr::ClauseList* SINGLETON(const ASTNode& varphi) + { + ASTNode* copy = ASTNodeToASTNodePtr(varphi); + + BeevMgr::ClausePtr clause = new vector (); + clause->push_back(copy); + + BeevMgr::ClauseList* psi = new BeevMgr::ClauseList(); + psi->push_back(clause); + return psi; + } + + BeevMgr::ClauseList* UNION(const BeevMgr::ClauseList& varphi1, const BeevMgr::ClauseList& varphi2) + { + + BeevMgr::ClauseList* psi1 = COPY(varphi1); + BeevMgr::ClauseList* psi2 = COPY(varphi2); + psi1->insert(psi1->end(), psi2->begin(), psi2->end()); + delete psi2; + + return psi1; + + } + + void INPLACE_UNION(BeevMgr::ClauseList* varphi1, const BeevMgr::ClauseList& varphi2) + { + + BeevMgr::ClauseList* psi2 = COPY(varphi2); + varphi1->insert(varphi1->end(), psi2->begin(), psi2->end()); + delete psi2; + } + + void NOCOPY_INPLACE_UNION(BeevMgr::ClauseList* varphi1, BeevMgr::ClauseList* varphi2) + { + + varphi1->insert(varphi1->end(), varphi2->begin(), varphi2->end()); + delete varphi2; + } + + BeevMgr::ClauseList* PRODUCT(const BeevMgr::ClauseList& varphi1, const BeevMgr::ClauseList& varphi2) + { + + BeevMgr::ClauseList* psi = new BeevMgr::ClauseList(); + + BeevMgr::ClauseList::const_iterator it1 = varphi1.begin(); + for (; it1 != varphi1.end(); it1++) + { + BeevMgr::ClausePtr clause1 = *it1; + BeevMgr::ClauseList::const_iterator it2 = varphi2.begin(); + for (; it2 != varphi2.end(); it2++) + { + BeevMgr::ClausePtr clause2 = *it2; + BeevMgr::ClausePtr clause = new vector (); + clause->insert(clause->end(), clause1->begin(), clause1->end()); + clause->insert(clause->end(), clause2->begin(), clause2->end()); + psi->push_back(clause); + } + } + + return psi; + } + + //######################################## + //######################################## + //prep. for cnf conversion + + void scanFormula(const ASTNode& varphi, bool isPos) + { + + CNFInfo* x; + + //######################################## + // step 1, get the info associated with this node + //######################################## + + if (info.find(varphi) == info.end()) + { + x = new CNFInfo(); + initializeCNFInfo(*x); + info[varphi] = x; + } + else + { + x = info[varphi]; + } + + //######################################## + // step 2, we only need to know if shares >= 2 + //######################################## + + if (isPos && sharesPos(*x) == 2) + { + return; + } + + if (!isPos && sharesNeg(*x) == 2) + { + return; + } + + //######################################## + // step 3, set appropriate information fields + //######################################## + + if (isPos) + { + incrementSharesPos(*x); + } + + if (!isPos) + { + incrementSharesNeg(*x); + } + + //######################################## + // step 4, recurse over children + //######################################## + + if (isAtom(varphi)) + { + return; + } + else if (isPred(varphi)) + { + for (unsigned int i = 0; i < varphi.GetChildren().size(); i++) + { + scanTerm(varphi[i]); + } + } + else + { + for (unsigned int i = 0; i < varphi.GetChildren().size(); i++) + { + if (onChildDoPos(varphi, i)) + { + scanFormula(varphi[i], isPos); + } + if (onChildDoNeg(varphi, i)) + { + scanFormula(varphi[i], !isPos); + } + } + } + } + + void scanTerm(const ASTNode& varphi) + { + + CNFInfo* x; + + //######################################## + // step 1, get the info associated with this node + //######################################## + + if (info.find(varphi) == info.end()) + { + x = new CNFInfo(); + initializeCNFInfo(*x); + info[varphi] = x; + } + else + { + x = info[varphi]; + } + + //######################################## + // step 2, need two hits because of term ITEs. + //######################################## + + if (sharesPos(*x) == 2) + { + return; + } + + //######################################## + // step 3, set appropriate data fields, always rename + // term ITEs + //######################################## + + incrementSharesPos(*x); + setIsTerm(*x); + + //######################################## + // step 4, recurse over children + //######################################## + + if (isAtom(varphi)) + { + return; + } + else if (isITE(varphi)) + { + scanFormula(varphi[0], true); + scanFormula(varphi[0], false); + scanTerm(varphi[1]); + scanTerm(varphi[2]); + } + else + { + for (unsigned int i = 0; i < varphi.GetChildren().size(); i++) + { + scanTerm(varphi[i]); + } + } + } + + //######################################## + //######################################## + // main cnf conversion function + + void convertFormulaToCNF(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + + CNFInfo* x = info[varphi]; + + //######################################## + // divert to special case if term (word-level cnf) + + if (isTerm(*x)) + { + convertTermForCNF(varphi, defs); + setWasVisited(*x); + return; + } + + //######################################## + // do work + + if (sharesPos(*x) > 0 && !wasVisited(*x)) + { + convertFormulaToCNFPosCases(varphi, defs); + } + + if (x->clausespos != NULL && x->clausespos->size() > 1) + { + if (doSibRenamingPos(*x) || sharesPos(*x) > 1) + { + doRenamingPos(varphi, defs); + } + } + + if (sharesNeg(*x) > 0 && !wasVisited(*x)) + { + convertFormulaToCNFNegCases(varphi, defs); + } + + if (x->clausesneg != NULL && x->clausesneg->size() > 1) + { + if (doSibRenamingNeg(*x) || sharesNeg(*x) > 1) + { + doRenamingNeg(varphi, defs); + } + } + + //######################################## + //mark that we've already done the hard work + + setWasVisited(*x); + } + + void convertTermForCNF(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + + CNFInfo* x = info[varphi]; + + //######################################## + // step 1, done if we've already visited + //######################################## + + if (x->termforcnf != NULL) + { + return; + } + + //######################################## + // step 2, ITE's always get renamed + //######################################## + + if (isITE(varphi)) + { + x->termforcnf = doRenameITE(varphi, defs); + reduceMemoryFootprintPos(varphi[0]); + reduceMemoryFootprintNeg(varphi[0]); + + } + else if (isAtom(varphi)) + { + x->termforcnf = ASTNodeToASTNodePtr(varphi); + } + else + { + + ASTVec psis; + ASTVec::const_iterator it = varphi.GetChildren().begin(); + for (; it != varphi.GetChildren().end(); it++) + { + convertTermForCNF(*it, defs); + psis.push_back(*(info[*it]->termforcnf)); + } + + ASTNode psi = bm->CreateNode(varphi.GetKind(), psis); + psi.SetValueWidth(varphi.GetValueWidth()); + psi.SetIndexWidth(varphi.GetIndexWidth()); + x->termforcnf = ASTNodeToASTNodePtr(psi); + } + } + + //######################################## + //######################################## + // functions for renaming nodes during cnf conversion + + ASTNode* doRenameITE(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + + ASTNode psi; + + //######################################## + // step 1, old "RepLit" code + //######################################## + + ostringstream oss; + oss << "cnf" << "{" << varphi.GetNodeNum() << "}"; + psi = bm->CreateSymbol(oss.str().c_str()); + + //######################################## + // step 2, set widths appropriately + //######################################## - //######################################## - //######################################## - // data types - - // for the meaning of control bits, see "utilities for contol bits". - typedef struct { - int control; - BeevMgr::ClauseList* clausespos; - union {BeevMgr::ClauseList* clausesneg; ASTNode* termforcnf;}; - } CNFInfo; - - typedef hash_map< ASTNode - , CNFInfo* - , ASTNode::ASTNodeHasher - , ASTNode::ASTNodeEqual - > ASTNodeToCNFInfoMap; - - typedef hash_map< ASTNode - , ASTNode* - , ASTNode::ASTNodeHasher - , ASTNode::ASTNodeEqual - > ASTNodeToASTNodePtrMap; - - - //######################################## - //######################################## - // this is the data - - BeevMgr *bm; - ASTNodeToCNFInfoMap info; - ASTNodeToASTNodePtrMap store; - - //######################################## - //######################################## - // utility predicates - - bool isAtom(const ASTNode& varphi){ - bool result; - - Kind k = varphi.GetKind(); - switch(k){ - case TRUE: { - result = true; - break; - } - case FALSE: { - result = true; - break; - } - case SYMBOL: { - result = true; - break; - } - case BVCONST: { - result = true; - break; - } - default: { - result = false; - break; - } - } - - return result; - } - - bool isPred(const ASTNode& varphi){ - bool result; - - Kind k = varphi.GetKind(); - switch(k){ - case BVLT: { - result = true; - break; - } - case BVLE: { - result = true; - break; - } - case BVGT: { - result = true; - break; - } - case BVGE: { - result = true; - break; - } - case BVSLT: { - result = true; - break; - } - case BVSLE: { - result = true; - break; - } - case BVSGT: { - result = true; - break; - } - case BVSGE: { - result = true; - break; - } - case EQ: { - result = true; - break; - } - case NEQ: { - result = true; - break; - } - default: { - result = false; - break; - } - } - - return result; - } - - bool isITE(const ASTNode& varphi){ - bool result; - - Kind k = varphi.GetKind(); - switch(k){ - case ITE: { - result = true; - break; - } - default: { - result = false; - break; - } - } - - return result; - } - - - bool onChildDoPos(const ASTNode& varphi, unsigned int idx){ - bool result = true; - - Kind k = varphi.GetKind(); - switch(k){ - case NOT: { - result = false; - break; - } - case NAND: { - result = false; - break; - } - case NOR: { - result = false; - break; - } - case IMPLIES: { - if(idx == 0){ - result = false; - } - break; - } - default: { - break; - } - } - - return result; - } - - bool onChildDoNeg(const ASTNode& varphi, unsigned int idx){ - bool result = false; - - Kind k = varphi.GetKind(); - switch(k){ - case NOT: { - result = true; - break; - } - case NAND: { - result = true; - break; - } - case NOR: { - result = true; - break; - } - case XOR: { - result = true; - break; - } - case IFF: { - result = true; - break; - } - case IMPLIES: { - if(idx == 0){ - result = true; - } - break; - } - case ITE: { - if(idx == 0){ - result = true; - } - break; - } - default: { - break; - } - } - - return result; - } - - //######################################## - //######################################## - //utilities for control bits. - - void initializeCNFInfo(CNFInfo& x){ - x.control = 0; - x.clausespos = NULL; - x.clausesneg = NULL; - } - - void incrementSharesPos(CNFInfo& x){ - x.control += ((x.control & 3) < 2) ? 1 : 0; - } - - int sharesPos(CNFInfo& x){ - return (x.control & 3); - } - - void incrementSharesNeg(CNFInfo& x){ - x.control += ((x.control & 12) < 8) ? 4 : 0; - } - - int sharesNeg(CNFInfo& x){ - return ((x.control & 12) >> 2); - } - - void setControlBit(CNFInfo& x, unsigned int idx){ - x.control |= (1 << idx); - } - - bool getControlBit(CNFInfo& x, unsigned int idx){ - bool result = false; - - if(x.control & (1 << idx)){ - - result = true; - } - - return result; - } - - void setIsTerm(CNFInfo& x){ - setControlBit(x, 4); - } - - bool isTerm(CNFInfo& x){ - return getControlBit(x, 4); - } - - void setDoRenamePos(CNFInfo& x){ - setControlBit(x, 5); - } - - bool doRenamePos(CNFInfo& x){ - return getControlBit(x, 5); - } - - void setWasRenamedPos(CNFInfo& x){ - setControlBit(x, 6); - } - - bool wasRenamedPos(CNFInfo& x){ - return getControlBit(x, 6); - } - - void setDoRenameNeg(CNFInfo& x){ - setControlBit(x, 7); - } - - bool doRenameNeg(CNFInfo& x){ - return getControlBit(x, 7); - } - - void setWasRenamedNeg(CNFInfo& x){ - setControlBit(x, 8); - } - - bool wasRenamedNeg(CNFInfo& x){ - return getControlBit(x, 8); - } - - void setDoSibRenamingPos(CNFInfo& x){ - setControlBit(x, 9); - } - - bool doSibRenamingPos(CNFInfo& x){ - return getControlBit(x, 9); - } - - void setDoSibRenamingNeg(CNFInfo& x){ - setControlBit(x, 10); - } + psi.SetValueWidth(varphi.GetValueWidth()); + psi.SetIndexWidth(varphi.GetIndexWidth()); - bool doSibRenamingNeg(CNFInfo& x){ - return getControlBit(x, 10); - } + //######################################## + // step 3, recurse over children + //######################################## - void setWasVisited(CNFInfo& x){ - setControlBit(x, 11); - } + convertFormulaToCNF(varphi[0], defs); + convertTermForCNF(varphi[1], defs); + ASTNode t1 = *(info[varphi[1]]->termforcnf); + convertTermForCNF(varphi[2], defs); + ASTNode t2 = *(info[varphi[2]]->termforcnf); - bool wasVisited(CNFInfo& x){ - return getControlBit(x, 11); - } + //######################################## + // step 4, add def clauses + //######################################## - //######################################## - //######################################## - //utilities for clause sets + BeevMgr::ClauseList* cl1 = SINGLETON(bm->CreateNode(EQ, psi, t1)); + BeevMgr::ClauseList* cl2 = PRODUCT(*(info[varphi[0]]->clausesneg), *cl1); + DELETE(cl1); + defs->insert(defs->end(), cl2->begin(), cl2->end()); + BeevMgr::ClauseList* cl3 = SINGLETON(bm->CreateNode(EQ, psi, t2)); + BeevMgr::ClauseList* cl4 = PRODUCT(*(info[varphi[0]]->clausespos), *cl3); + DELETE(cl3); + defs->insert(defs->end(), cl4->begin(), cl4->end()); - BeevMgr::ClauseList* COPY(const BeevMgr::ClauseList& varphi){ - BeevMgr::ClauseList* psi = new BeevMgr::ClauseList(); + return ASTNodeToASTNodePtr(psi); + } + + void doRenamingPos(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + + CNFInfo* x = info[varphi]; + + //######################################## + // step 1, calc new variable + //######################################## + + ostringstream oss; + oss << "cnf" << "{" << varphi.GetNodeNum() << "}"; + ASTNode psi = bm->CreateSymbol(oss.str().c_str()); + + //######################################## + // step 2, add defs + //######################################## + + BeevMgr::ClauseList* cl1; + cl1 = SINGLETON(bm->CreateNode(NOT, psi)); + BeevMgr::ClauseList* cl2 = PRODUCT(*(info[varphi]->clausespos), *cl1); + defs->insert(defs->end(), cl2->begin(), cl2->end()); + DELETE(info[varphi]->clausespos); + DELETE(cl1); + delete cl2; + + //######################################## + // step 3, update info[varphi] + //######################################## + + x->clausespos = SINGLETON(psi); + setWasRenamedPos(*x); + } + + void doRenamingNeg(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + + CNFInfo* x = info[varphi]; + + //######################################## + // step 2, calc new variable + //######################################## - BeevMgr::ClauseList::const_iterator it = varphi.begin(); - for(; it != varphi.end(); it++){ - psi->push_back(new vector(**it)); - } + ostringstream oss; + oss << "cnf" << "{" << varphi.GetNodeNum() << "}"; + ASTNode psi = bm->CreateSymbol(oss.str().c_str()); - return psi; - } + //######################################## + // step 3, add defs + //######################################## - BeevMgr::ClauseList* SINGLETON(const ASTNode& varphi){ - ASTNode* copy = ASTNodeToASTNodePtr(varphi); + BeevMgr::ClauseList* cl1; + cl1 = SINGLETON(psi); + BeevMgr::ClauseList* cl2 = PRODUCT(*(info[varphi]->clausesneg), *cl1); + defs->insert(defs->end(), cl2->begin(), cl2->end()); + DELETE(info[varphi]->clausesneg); + DELETE(cl1); + delete cl2; - BeevMgr::ClausePtr clause = new vector(); - clause->push_back(copy); + //######################################## + // step 4, update info[varphi] + //######################################## + + x->clausesneg = SINGLETON(bm->CreateNode(NOT, psi)); + setWasRenamedNeg(*x); + + } + + //######################################## + //######################################## + //main switch for individual cnf conversion cases + + void convertFormulaToCNFPosCases(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + + if (isPred(varphi)) + { + convertFormulaToCNFPosPred(varphi, defs); + return; + } + + Kind k = varphi.GetKind(); + switch (k) + { + case FALSE: + { + convertFormulaToCNFPosFALSE(varphi, defs); + break; + } + case TRUE: + { + convertFormulaToCNFPosTRUE(varphi, defs); + break; + } + case BVGETBIT: + { + convertFormulaToCNFPosBVGETBIT(varphi, defs); + break; + } + case SYMBOL: + { + convertFormulaToCNFPosSYMBOL(varphi, defs); + break; + } + case NOT: + { + convertFormulaToCNFPosNOT(varphi, defs); + break; + } + case AND: + { + convertFormulaToCNFPosAND(varphi, defs); + break; + } + case NAND: + { + convertFormulaToCNFPosNAND(varphi, defs); + break; + } + case OR: + { + convertFormulaToCNFPosOR(varphi, defs); + break; + } + case NOR: + { + convertFormulaToCNFPosNOR(varphi, defs); + break; + } + case XOR: + { + convertFormulaToCNFPosXOR(varphi, defs); + break; + } + case IMPLIES: + { + convertFormulaToCNFPosIMPLIES(varphi, defs); + break; + } + case ITE: + { + convertFormulaToCNFPosITE(varphi, defs); + break; + } + default: + { + fprintf(stderr, "convertFormulaToCNFPosCases: doesn't handle kind %d\n", k); + FatalError(""); + } + } + } + + void convertFormulaToCNFNegCases(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + + if (isPred(varphi)) + { + convertFormulaToCNFNegPred(varphi, defs); + return; + } + + Kind k = varphi.GetKind(); + switch (k) + { + case FALSE: + { + convertFormulaToCNFNegFALSE(varphi, defs); + break; + } + case TRUE: + { + convertFormulaToCNFNegTRUE(varphi, defs); + break; + } + case BVGETBIT: + { + convertFormulaToCNFNegBVGETBIT(varphi, defs); + break; + } + case SYMBOL: + { + convertFormulaToCNFNegSYMBOL(varphi, defs); + break; + } + case NOT: + { + convertFormulaToCNFNegNOT(varphi, defs); + break; + } + case AND: + { + convertFormulaToCNFNegAND(varphi, defs); + break; + } + case NAND: + { + convertFormulaToCNFNegNAND(varphi, defs); + break; + } + case OR: + { + convertFormulaToCNFNegOR(varphi, defs); + break; + } + case NOR: + { + convertFormulaToCNFNegNOR(varphi, defs); + break; + } + case XOR: + { + convertFormulaToCNFNegXOR(varphi, defs); + break; + } + case IMPLIES: + { + convertFormulaToCNFNegIMPLIES(varphi, defs); + break; + } + case ITE: + { + convertFormulaToCNFNegITE(varphi, defs); + break; + } + default: + { + fprintf(stderr, "convertFormulaToCNFNegCases: doesn't handle kind %d\n", k); + FatalError(""); + } + } + } + + //######################################## + //######################################## + // individual cnf conversion cases + + void convertFormulaToCNFPosPred(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + + ASTVec psis; + + ASTVec::const_iterator it = varphi.GetChildren().begin(); + for (; it != varphi.GetChildren().end(); it++) + { + convertTermForCNF(*it, defs); + psis.push_back(*(info[*it]->termforcnf)); + } + + info[varphi]->clausespos = SINGLETON(bm->CreateNode(varphi.GetKind(), psis)); + } - BeevMgr::ClauseList* psi = new BeevMgr::ClauseList(); - psi->push_back(clause); - return psi; - } + void convertFormulaToCNFPosFALSE(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + ASTNode dummy_false_var = bm->CreateNode(NOT, bm->CreateSymbol("*TrueDummy*")); + info[varphi]->clausespos = SINGLETON(dummy_false_var); + } + + void convertFormulaToCNFPosTRUE(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + ASTNode dummy_true_var = bm->CreateSymbol("*TrueDummy*"); + info[varphi]->clausespos = SINGLETON(dummy_true_var); + } + + void convertFormulaToCNFPosBVGETBIT(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + info[varphi]->clausespos = SINGLETON(varphi); + } + + void convertFormulaToCNFPosSYMBOL(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + info[varphi]->clausespos = SINGLETON(varphi); + } + + void convertFormulaToCNFPosNOT(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + convertFormulaToCNF(varphi[0], defs); + info[varphi]->clausespos = COPY(*(info[varphi[0]]->clausesneg)); + reduceMemoryFootprintNeg(varphi[0]); + } + + void convertFormulaToCNFPosAND(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + //**************************************** + // (pos) AND ~> UNION + //**************************************** + ASTVec::const_iterator it = varphi.GetChildren().begin(); + convertFormulaToCNF(*it, defs); + BeevMgr::ClauseList* psi = COPY(*(info[*it]->clausespos)); + for (it++; it != varphi.GetChildren().end(); it++) + { + convertFormulaToCNF(*it, defs); + INPLACE_UNION(psi, *(info[*it]->clausespos)); + reduceMemoryFootprintPos(*it); + } + + info[varphi]->clausespos = psi; + } + + void convertFormulaToCNFPosNAND(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + bool renamesibs = false; + BeevMgr::ClauseList* clauses; + BeevMgr::ClauseList* psi; + BeevMgr::ClauseList* oldpsi; + + //**************************************** + // (pos) NAND ~> PRODUCT NOT + //**************************************** + + ASTVec::const_iterator it = varphi.GetChildren().begin(); + convertFormulaToCNF(*it, defs); + clauses = info[*it]->clausesneg; + if (clauses->size() > 1) + { + renamesibs = true; + } + psi = COPY(*clauses); + reduceMemoryFootprintNeg(*it); + + for (it++; it != varphi.GetChildren().end(); it++) + { + if (renamesibs) + { + setDoSibRenamingNeg(*(info[*it])); + } + convertFormulaToCNF(*it, defs); + clauses = info[*it]->clausesneg; + if (clauses->size() > 1) + { + renamesibs = true; + } + oldpsi = psi; + psi = PRODUCT(*psi, *clauses); + reduceMemoryFootprintNeg(*it); + DELETE(oldpsi); + } + + info[varphi]->clausespos = psi; + } + + void convertFormulaToCNFPosOR(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + bool renamesibs = false; + BeevMgr::ClauseList* clauses; + BeevMgr::ClauseList* psi; + BeevMgr::ClauseList* oldpsi; + + //**************************************** + // (pos) OR ~> PRODUCT + //**************************************** + ASTVec::const_iterator it = varphi.GetChildren().begin(); + convertFormulaToCNF(*it, defs); + clauses = info[*it]->clausespos; + if (clauses->size() > 1) + { + renamesibs = true; + } + psi = COPY(*clauses); + reduceMemoryFootprintPos(*it); + + for (it++; it != varphi.GetChildren().end(); it++) + { + if (renamesibs) + { + setDoSibRenamingPos(*(info[*it])); + } + convertFormulaToCNF(*it, defs); + clauses = info[*it]->clausespos; + if (clauses->size() > 1) + { + renamesibs = true; + } + oldpsi = psi; + psi = PRODUCT(*psi, *clauses); + reduceMemoryFootprintPos(*it); + DELETE(oldpsi); + } + + info[varphi]->clausespos = psi; + } + + void convertFormulaToCNFPosNOR(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + //**************************************** + // (pos) NOR ~> UNION NOT + //**************************************** + ASTVec::const_iterator it = varphi.GetChildren().begin(); + convertFormulaToCNF(*it, defs); + BeevMgr::ClauseList* psi = COPY(*(info[*it]->clausesneg)); + reduceMemoryFootprintNeg(*it); + for (it++; it != varphi.GetChildren().end(); it++) + { + convertFormulaToCNF(*it, defs); + INPLACE_UNION(psi, *(info[*it]->clausesneg)); + reduceMemoryFootprintNeg(*it); + } + + info[varphi]->clausespos = psi; + } + + void convertFormulaToCNFPosIMPLIES(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + //**************************************** + // (pos) IMPLIES ~> PRODUCT NOT [0] ; [1] + //**************************************** + CNFInfo* x0 = info[varphi[0]]; + CNFInfo* x1 = info[varphi[1]]; + convertFormulaToCNF(varphi[0], defs); + if (x0->clausesneg->size() > 1) + { + setDoSibRenamingPos(*x1); + } + convertFormulaToCNF(varphi[1], defs); + BeevMgr::ClauseList* psi = PRODUCT(*(x0->clausesneg), *(x1->clausespos)); + reduceMemoryFootprintNeg(varphi[0]); + reduceMemoryFootprintPos(varphi[1]); + info[varphi]->clausespos = psi; + } + + void convertFormulaToCNFPosITE(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + //**************************************** + // (pos) ITE ~> UNION (PRODUCT NOT [0] ; [1]) + // ; (PRODUCT [0] ; [2]) + //**************************************** + CNFInfo* x0 = info[varphi[0]]; + CNFInfo* x1 = info[varphi[1]]; + CNFInfo* x2 = info[varphi[2]]; + convertFormulaToCNF(varphi[0], defs); + if (x0->clausesneg->size() > 1) + { + setDoSibRenamingPos(*x1); + } + convertFormulaToCNF(varphi[1], defs); + if (x0->clausespos->size() > 1) + { + setDoSibRenamingPos(*x2); + } + convertFormulaToCNF(varphi[2], defs); + BeevMgr::ClauseList* psi1 = PRODUCT(*(x0->clausesneg), *(x1->clausespos)); + BeevMgr::ClauseList* psi2 = PRODUCT(*(x0->clausespos), *(x2->clausespos)); + NOCOPY_INPLACE_UNION(psi1, psi2); + reduceMemoryFootprintNeg(varphi[0]); + reduceMemoryFootprintPos(varphi[1]); + reduceMemoryFootprintPos(varphi[0]); + reduceMemoryFootprintPos(varphi[2]); + + info[varphi]->clausespos = psi1; + } + + void convertFormulaToCNFPosXOR(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + BeevMgr::ClauseList* psi = convertFormulaToCNFPosXORAux(varphi, 0, defs); + info[varphi]->clausespos = psi; + } + + BeevMgr::ClauseList* convertFormulaToCNFPosXORAux(const ASTNode& varphi, unsigned int idx, BeevMgr::ClauseList* defs) + { + + bool renamesibs; + BeevMgr::ClauseList* psi; + BeevMgr::ClauseList* psi1; + BeevMgr::ClauseList* psi2; + + if (idx == varphi.GetChildren().size() - 2) + { + //**************************************** + // (pos) XOR ~> UNION + // (PRODUCT [idx] ; [idx+1]) + // ; (PRODUCT NOT [idx] ; NOT [idx+1]) + //**************************************** + convertFormulaToCNF(varphi[idx], defs); + renamesibs = (info[varphi[idx]]->clausespos)->size() > 1 ? true : false; + if (renamesibs) + { + setDoSibRenamingPos(*info[varphi[idx + 1]]); + } + renamesibs = (info[varphi[idx]]->clausesneg)->size() > 1 ? true : false; + if (renamesibs) + { + setDoSibRenamingNeg(*info[varphi[idx + 1]]); + } + convertFormulaToCNF(varphi[idx + 1], defs); + + psi1 = PRODUCT(*(info[varphi[idx]]->clausespos), *(info[varphi[idx + 1]]->clausespos)); + psi2 = PRODUCT(*(info[varphi[idx]]->clausesneg), *(info[varphi[idx + 1]]->clausesneg)); + NOCOPY_INPLACE_UNION(psi1, psi2); + reduceMemoryFootprintPos(varphi[idx]); + reduceMemoryFootprintPos(varphi[idx + 1]); + reduceMemoryFootprintNeg(varphi[idx]); + reduceMemoryFootprintNeg(varphi[idx + 1]); + + psi = psi1; + } + else + { + //**************************************** + // (pos) XOR ~> UNION + // (PRODUCT [idx] ; XOR [idx+1..]) + // ; (PRODUCT NOT [idx] ; NOT XOR [idx+1..]) + //**************************************** + BeevMgr::ClauseList* theta1; + theta1 = convertFormulaToCNFPosXORAux(varphi, idx + 1, defs); + renamesibs = theta1->size() > 1 ? true : false; + if (renamesibs) + { + setDoSibRenamingPos(*info[varphi[idx]]); + } + BeevMgr::ClauseList* theta2; + theta2 = convertFormulaToCNFNegXORAux(varphi, idx + 1, defs); + renamesibs = theta2->size() > 1 ? true : false; + if (renamesibs) + { + setDoSibRenamingNeg(*info[varphi[idx]]); + } + convertFormulaToCNF(varphi[idx], defs); + + psi1 = PRODUCT(*(info[varphi[idx]]->clausespos), *theta1); + psi2 = PRODUCT(*(info[varphi[idx]]->clausesneg), *theta2); + DELETE(theta1); + DELETE(theta2); + NOCOPY_INPLACE_UNION(psi1, psi2); + reduceMemoryFootprintPos(varphi[idx]); + reduceMemoryFootprintNeg(varphi[idx]); + + psi = psi1; + } + + return psi; + } - BeevMgr::ClauseList* UNION(const BeevMgr::ClauseList& varphi1 - , const BeevMgr::ClauseList& varphi2){ - - BeevMgr::ClauseList* psi1 = COPY(varphi1); - BeevMgr::ClauseList* psi2 = COPY(varphi2); - psi1->insert(psi1->end(), psi2->begin(), psi2->end()); - delete psi2; - - return psi1; - - } - - void INPLACE_UNION(BeevMgr::ClauseList* varphi1 - , const BeevMgr::ClauseList& varphi2){ - - BeevMgr::ClauseList* psi2 = COPY(varphi2); - varphi1->insert(varphi1->end(), psi2->begin(), psi2->end()); - delete psi2; - } - - void NOCOPY_INPLACE_UNION(BeevMgr::ClauseList* varphi1 - , BeevMgr::ClauseList* varphi2){ - - varphi1->insert(varphi1->end(), varphi2->begin(), varphi2->end()); - delete varphi2; - } - - BeevMgr::ClauseList* PRODUCT(const BeevMgr::ClauseList& varphi1 - , const BeevMgr::ClauseList& varphi2){ - - BeevMgr::ClauseList* psi = new BeevMgr::ClauseList(); - - BeevMgr::ClauseList::const_iterator it1 = varphi1.begin(); - for(; it1 != varphi1.end(); it1++){ - BeevMgr::ClausePtr clause1 = *it1; - BeevMgr::ClauseList::const_iterator it2 = varphi2.begin(); - for(; it2 != varphi2.end(); it2++){ - BeevMgr::ClausePtr clause2 = *it2; - BeevMgr::ClausePtr clause = new vector(); - clause->insert(clause->end() - , clause1->begin() - , clause1->end() - ); - clause->insert(clause->end() - , clause2->begin() - , clause2->end() - ); - psi->push_back(clause); - } - } - - return psi; - } - - //######################################## - //######################################## - //prep. for cnf conversion - - void scanFormula(const ASTNode& varphi, bool isPos){ - - CNFInfo* x; - - //######################################## - // step 1, get the info associated with this node - //######################################## - - if(info.find(varphi) == info.end()){ - x = new CNFInfo(); - initializeCNFInfo(*x); - info[varphi] = x; - } else { - x = info[varphi]; - } - - //######################################## - // step 2, we only need to know if shares >= 2 - //######################################## - - if(isPos && sharesPos(*x) == 2){ - return; - } - - if(!isPos && sharesNeg(*x) == 2){ - return; - } - - //######################################## - // step 3, set appropriate information fields - //######################################## - - if(isPos){ - incrementSharesPos(*x); - } - - if(!isPos){ - incrementSharesNeg(*x); - } - - //######################################## - // step 4, recurse over children - //######################################## - - if(isAtom(varphi)){ - return; - } else if(isPred(varphi)){ - for(unsigned int i = 0; i < varphi.GetChildren().size(); i++){ - scanTerm(varphi[i]); - } - } else { - for(unsigned int i = 0; i < varphi.GetChildren().size(); i++){ - if(onChildDoPos(varphi, i)){ - scanFormula(varphi[i], isPos); - } - if(onChildDoNeg(varphi, i)){ - scanFormula(varphi[i], !isPos); - } - } - } - } - - void scanTerm(const ASTNode& varphi){ - - CNFInfo* x; - - //######################################## - // step 1, get the info associated with this node - //######################################## - - if(info.find(varphi) == info.end()){ - x = new CNFInfo(); - initializeCNFInfo(*x); - info[varphi] = x; - } else { - x = info[varphi]; - } - - //######################################## - // step 2, need two hits because of term ITEs. - //######################################## - - if(sharesPos(*x) == 2){ - return; - } - - //######################################## - // step 3, set appropriate data fields, always rename - // term ITEs - //######################################## - - incrementSharesPos(*x); - setIsTerm(*x); - - //######################################## - // step 4, recurse over children - //######################################## - - if(isAtom(varphi)){ - return; - } else if(isITE(varphi)){ - scanFormula(varphi[0], true); - scanFormula(varphi[0], false); - scanTerm(varphi[1]); - scanTerm(varphi[2]); - } else { - for(unsigned int i = 0; i < varphi.GetChildren().size(); i++){ - scanTerm(varphi[i]); - } - } - } - - //######################################## - //######################################## - // main cnf conversion function - - void convertFormulaToCNF(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - - CNFInfo* x = info[varphi]; - - //######################################## - // divert to special case if term (word-level cnf) - - if(isTerm(*x)){ - convertTermForCNF(varphi, defs); - setWasVisited(*x); - return; - } - - //######################################## - // do work - - if(sharesPos(*x) > 0 && !wasVisited(*x)){ - convertFormulaToCNFPosCases(varphi, defs); - } - - if(x->clausespos != NULL && x->clausespos->size() > 1){ - if(doSibRenamingPos(*x) || sharesPos(*x) > 1){ - doRenamingPos(varphi, defs); - } - } - - if(sharesNeg(*x) > 0 && !wasVisited(*x)){ - convertFormulaToCNFNegCases(varphi, defs); - } - - if(x->clausesneg != NULL && x->clausesneg->size() > 1){ - if(doSibRenamingNeg(*x) || sharesNeg(*x) > 1){ - doRenamingNeg(varphi, defs); - } - } - - //######################################## - //mark that we've already done the hard work - - setWasVisited(*x); - } - - void convertTermForCNF(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - - CNFInfo* x = info[varphi]; - - //######################################## - // step 1, done if we've already visited - //######################################## - - if(x->termforcnf != NULL){ - return; - } - - //######################################## - // step 2, ITE's always get renamed - //######################################## - - if(isITE(varphi)){ - x->termforcnf = doRenameITE(varphi, defs); - reduceMemoryFootprintPos(varphi[0]); - reduceMemoryFootprintNeg(varphi[0]); - - } else if(isAtom(varphi)){ - x->termforcnf = ASTNodeToASTNodePtr(varphi); - } else { - - ASTVec psis; - ASTVec::const_iterator it = varphi.GetChildren().begin(); - for(; it != varphi.GetChildren().end(); it++){ - convertTermForCNF(*it, defs); - psis.push_back(*(info[*it]->termforcnf)); - } - - ASTNode psi = bm->CreateNode(varphi.GetKind(), psis); - psi.SetValueWidth(varphi.GetValueWidth()); - psi.SetIndexWidth(varphi.GetIndexWidth()); - x->termforcnf = ASTNodeToASTNodePtr(psi); - } - } - - //######################################## - //######################################## - // functions for renaming nodes during cnf conversion - - ASTNode* doRenameITE(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - - ASTNode psi; - - //######################################## - // step 1, old "RepLit" code - //######################################## - - ostringstream oss; - oss << "cnf" << "{" << varphi.GetNodeNum() << "}"; - psi = bm->CreateSymbol(oss.str().c_str()); - - //######################################## - // step 2, set widths appropriately - //######################################## - - psi.SetValueWidth(varphi.GetValueWidth()); - psi.SetIndexWidth(varphi.GetIndexWidth()); - - //######################################## - // step 3, recurse over children - //######################################## - - convertFormulaToCNF(varphi[0], defs); - convertTermForCNF(varphi[1], defs); - ASTNode t1 = *(info[varphi[1]]->termforcnf); - convertTermForCNF(varphi[2], defs); - ASTNode t2 = *(info[varphi[2]]->termforcnf); - - //######################################## - // step 4, add def clauses - //######################################## - - BeevMgr::ClauseList* cl1 = SINGLETON(bm->CreateNode(EQ, psi, t1)); - BeevMgr::ClauseList* cl2 = PRODUCT(*(info[varphi[0]]->clausesneg), *cl1); - DELETE(cl1); - defs->insert(defs->end(), cl2->begin(), cl2->end()); - - BeevMgr::ClauseList* cl3 = SINGLETON(bm->CreateNode(EQ, psi, t2)); - BeevMgr::ClauseList* cl4 = PRODUCT(*(info[varphi[0]]->clausespos), *cl3); - DELETE(cl3); - defs->insert(defs->end(), cl4->begin(), cl4->end()); - - return ASTNodeToASTNodePtr(psi); - } - - void doRenamingPos(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - - CNFInfo* x = info[varphi]; - - //######################################## - // step 1, calc new variable - //######################################## - - ostringstream oss; - oss << "cnf" << "{" << varphi.GetNodeNum() << "}"; - ASTNode psi = bm->CreateSymbol(oss.str().c_str()); - - //######################################## - // step 2, add defs - //######################################## - - BeevMgr::ClauseList* cl1; - cl1 = SINGLETON(bm->CreateNode(NOT, psi)); - BeevMgr::ClauseList* cl2 = PRODUCT(*(info[varphi]->clausespos), *cl1); - defs->insert(defs->end(), cl2->begin(), cl2->end()); - DELETE(info[varphi]->clausespos); - DELETE(cl1); - delete cl2; - - //######################################## - // step 3, update info[varphi] - //######################################## - - x->clausespos = SINGLETON(psi); - setWasRenamedPos(*x); - } - - void doRenamingNeg(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - - CNFInfo* x = info[varphi]; - - //######################################## - // step 2, calc new variable - //######################################## - - ostringstream oss; - oss << "cnf" << "{" << varphi.GetNodeNum() << "}"; - ASTNode psi = bm->CreateSymbol(oss.str().c_str()); - - //######################################## - // step 3, add defs - //######################################## - - BeevMgr::ClauseList* cl1; - cl1 = SINGLETON(psi); - BeevMgr::ClauseList* cl2 = PRODUCT(*(info[varphi]->clausesneg), *cl1); - defs->insert(defs->end(), cl2->begin(), cl2->end()); - DELETE(info[varphi]->clausesneg); - DELETE(cl1); - delete cl2; - - //######################################## - // step 4, update info[varphi] - //######################################## - - x->clausesneg = SINGLETON(bm->CreateNode(NOT, psi)); - setWasRenamedNeg(*x); - - } - - //######################################## - //######################################## - //main switch for individual cnf conversion cases - - void convertFormulaToCNFPosCases(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - - if(isPred(varphi)){ - convertFormulaToCNFPosPred(varphi, defs); - return; - } - - - Kind k = varphi.GetKind(); - switch ( k ){ - case FALSE: { - convertFormulaToCNFPosFALSE(varphi, defs); - break; - } - case TRUE: { - convertFormulaToCNFPosTRUE(varphi, defs); - break; - } - case BVGETBIT: { - convertFormulaToCNFPosBVGETBIT(varphi, defs); - break; - } - case SYMBOL: { - convertFormulaToCNFPosSYMBOL(varphi, defs); - break; - } - case NOT: { - convertFormulaToCNFPosNOT(varphi, defs); - break; - } - case AND: { - convertFormulaToCNFPosAND(varphi, defs); - break; - } - case NAND: { - convertFormulaToCNFPosNAND(varphi, defs); - break; - } - case OR: { - convertFormulaToCNFPosOR(varphi, defs); - break; - } - case NOR: { - convertFormulaToCNFPosNOR(varphi, defs); - break; - } - case XOR: { - convertFormulaToCNFPosXOR(varphi, defs); - break; - } - case IMPLIES: { - convertFormulaToCNFPosIMPLIES(varphi, defs); - break; - } - case ITE: { - convertFormulaToCNFPosITE(varphi, defs); - break; - } - default: { - fprintf(stderr, "convertFormulaToCNFPosCases: doesn't handle kind %d\n", k); - FatalError(""); - } - } - } - - void convertFormulaToCNFNegCases(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - - if(isPred(varphi)){ - convertFormulaToCNFNegPred(varphi, defs); - return; - } - - - Kind k = varphi.GetKind(); - switch ( k ){ - case FALSE: { - convertFormulaToCNFNegFALSE(varphi, defs); - break; - } - case TRUE: { - convertFormulaToCNFNegTRUE(varphi, defs); - break; - } - case BVGETBIT: { - convertFormulaToCNFNegBVGETBIT(varphi, defs); - break; - } - case SYMBOL: { - convertFormulaToCNFNegSYMBOL(varphi, defs); - break; - } - case NOT: { - convertFormulaToCNFNegNOT(varphi, defs); - break; - } - case AND: { - convertFormulaToCNFNegAND(varphi, defs); - break; - } - case NAND: { - convertFormulaToCNFNegNAND(varphi, defs); - break; - } - case OR: { - convertFormulaToCNFNegOR(varphi, defs); - break; - } - case NOR: { - convertFormulaToCNFNegNOR(varphi, defs); - break; - } - case XOR: { - convertFormulaToCNFNegXOR(varphi, defs); - break; - } - case IMPLIES: { - convertFormulaToCNFNegIMPLIES(varphi, defs); - break; - } - case ITE: { - convertFormulaToCNFNegITE(varphi, defs); - break; - } - default: { - fprintf(stderr, "convertFormulaToCNFNegCases: doesn't handle kind %d\n", k); - FatalError(""); - } - } - } - - //######################################## - //######################################## - // individual cnf conversion cases - - void convertFormulaToCNFPosPred(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - - ASTVec psis; - - ASTVec::const_iterator it = varphi.GetChildren().begin(); - for(; it != varphi.GetChildren().end(); it++){ - convertTermForCNF(*it, defs); - psis.push_back(*(info[*it]->termforcnf)); - } - - info[varphi]->clausespos = SINGLETON(bm->CreateNode(varphi.GetKind(), psis)); - } - - void convertFormulaToCNFPosFALSE(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - ASTNode dummy_false_var = bm->CreateNode(NOT, bm->CreateSymbol("*TrueDummy*")); - info[varphi]->clausespos = SINGLETON(dummy_false_var); - } - - void convertFormulaToCNFPosTRUE(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - ASTNode dummy_true_var = bm->CreateSymbol("*TrueDummy*"); - info[varphi]->clausespos = SINGLETON(dummy_true_var); - } - - void convertFormulaToCNFPosBVGETBIT(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - info[varphi]->clausespos = SINGLETON(varphi); - } - - void convertFormulaToCNFPosSYMBOL(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - info[varphi]->clausespos = SINGLETON(varphi); - } - - void convertFormulaToCNFPosNOT(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - convertFormulaToCNF(varphi[0], defs); - info[varphi]->clausespos = COPY(*(info[varphi[0]]->clausesneg)); - reduceMemoryFootprintNeg(varphi[0]); - } - - void convertFormulaToCNFPosAND(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - //**************************************** - // (pos) AND ~> UNION - //**************************************** - ASTVec::const_iterator it = varphi.GetChildren().begin(); - convertFormulaToCNF(*it, defs); - BeevMgr::ClauseList* psi = COPY(*(info[*it]->clausespos)); - for(it++; it != varphi.GetChildren().end(); it++){ - convertFormulaToCNF(*it, defs); - INPLACE_UNION(psi, *(info[*it]->clausespos)); - reduceMemoryFootprintPos(*it); - } - - info[varphi]->clausespos = psi; - } - - void convertFormulaToCNFPosNAND(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - bool renamesibs = false; - BeevMgr::ClauseList* clauses; - BeevMgr::ClauseList* psi; - BeevMgr::ClauseList* oldpsi; - - //**************************************** - // (pos) NAND ~> PRODUCT NOT - //**************************************** - - ASTVec::const_iterator it = varphi.GetChildren().begin(); - convertFormulaToCNF(*it, defs); - clauses = info[*it]->clausesneg; - if(clauses->size() > 1){ - renamesibs = true; - } - psi = COPY(*clauses); - reduceMemoryFootprintNeg(*it); - - for(it++; it != varphi.GetChildren().end(); it++){ - if(renamesibs){ - setDoSibRenamingNeg(*(info[*it])); - } - convertFormulaToCNF(*it, defs); - clauses = info[*it]->clausesneg; - if(clauses->size() > 1){ - renamesibs = true; - } - oldpsi = psi; - psi = PRODUCT(*psi, *clauses); - reduceMemoryFootprintNeg(*it); - DELETE(oldpsi); - } - - info[varphi]->clausespos = psi; - } - - void convertFormulaToCNFPosOR(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - bool renamesibs = false; - BeevMgr::ClauseList* clauses; - BeevMgr::ClauseList* psi; - BeevMgr::ClauseList* oldpsi; - - //**************************************** - // (pos) OR ~> PRODUCT - //**************************************** - ASTVec::const_iterator it = varphi.GetChildren().begin(); - convertFormulaToCNF(*it, defs); - clauses = info[*it]->clausespos; - if(clauses->size() > 1){ - renamesibs = true; - } - psi = COPY(*clauses); - reduceMemoryFootprintPos(*it); - - for(it++; it != varphi.GetChildren().end(); it++){ - if(renamesibs){ - setDoSibRenamingPos(*(info[*it])); - } - convertFormulaToCNF(*it, defs); - clauses = info[*it]->clausespos; - if(clauses->size() > 1){ - renamesibs = true; - } - oldpsi = psi; - psi = PRODUCT(*psi, *clauses); - reduceMemoryFootprintPos(*it); - DELETE(oldpsi); - } - - info[varphi]->clausespos = psi; - } - - void convertFormulaToCNFPosNOR(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - //**************************************** - // (pos) NOR ~> UNION NOT - //**************************************** - ASTVec::const_iterator it = varphi.GetChildren().begin(); - convertFormulaToCNF(*it, defs); - BeevMgr::ClauseList* psi = COPY(*(info[*it]->clausesneg)); - reduceMemoryFootprintNeg(*it); - for(it++; it != varphi.GetChildren().end(); it++){ - convertFormulaToCNF(*it, defs); - INPLACE_UNION(psi, *(info[*it]->clausesneg)); - reduceMemoryFootprintNeg(*it); - } - - info[varphi]->clausespos = psi; - } - - void convertFormulaToCNFPosIMPLIES(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - //**************************************** - // (pos) IMPLIES ~> PRODUCT NOT [0] ; [1] - //**************************************** - CNFInfo* x0 = info[varphi[0]]; - CNFInfo* x1 = info[varphi[1]]; - convertFormulaToCNF(varphi[0], defs); - if(x0->clausesneg->size() > 1){ - setDoSibRenamingPos(*x1); - } - convertFormulaToCNF(varphi[1], defs); - BeevMgr::ClauseList* psi = - PRODUCT(*(x0->clausesneg), *(x1->clausespos)); - reduceMemoryFootprintNeg(varphi[0]); - reduceMemoryFootprintPos(varphi[1]); - info[varphi]->clausespos = psi; - } - - void convertFormulaToCNFPosITE(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - //**************************************** - // (pos) ITE ~> UNION (PRODUCT NOT [0] ; [1]) - // ; (PRODUCT [0] ; [2]) - //**************************************** - CNFInfo* x0 = info[varphi[0]]; - CNFInfo* x1 = info[varphi[1]]; - CNFInfo* x2 = info[varphi[2]]; - convertFormulaToCNF(varphi[0], defs); - if(x0->clausesneg->size() > 1){ - setDoSibRenamingPos(*x1); - } - convertFormulaToCNF(varphi[1], defs); - if(x0->clausespos->size() > 1){ - setDoSibRenamingPos(*x2); - } - convertFormulaToCNF(varphi[2], defs); - BeevMgr::ClauseList* psi1 = PRODUCT(*(x0->clausesneg) - , *(x1->clausespos)); - BeevMgr::ClauseList* psi2 = PRODUCT(*(x0->clausespos) - , *(x2->clausespos)); - NOCOPY_INPLACE_UNION(psi1, psi2); - reduceMemoryFootprintNeg(varphi[0]); - reduceMemoryFootprintPos(varphi[1]); - reduceMemoryFootprintPos(varphi[0]); - reduceMemoryFootprintPos(varphi[2]); - - info[varphi]->clausespos = psi1; - } - - void convertFormulaToCNFPosXOR(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - BeevMgr::ClauseList* psi = convertFormulaToCNFPosXORAux(varphi, 0, defs); - info[varphi]->clausespos = psi; - } - - BeevMgr::ClauseList* convertFormulaToCNFPosXORAux(const ASTNode& varphi - , unsigned int idx, BeevMgr::ClauseList* defs){ - - bool renamesibs; - BeevMgr::ClauseList* psi; - BeevMgr::ClauseList* psi1; - BeevMgr::ClauseList* psi2; - - if(idx == varphi.GetChildren().size() - 2){ - //**************************************** - // (pos) XOR ~> UNION - // (PRODUCT [idx] ; [idx+1]) - // ; (PRODUCT NOT [idx] ; NOT [idx+1]) - //**************************************** - convertFormulaToCNF(varphi[idx], defs); - renamesibs = (info[varphi[idx]]->clausespos)->size() > 1 ? true : false; - if(renamesibs){ - setDoSibRenamingPos(*info[varphi[idx+1]]); - } - renamesibs = (info[varphi[idx]]->clausesneg)->size() > 1 ? true : false; - if(renamesibs){ - setDoSibRenamingNeg(*info[varphi[idx+1]]); - } - convertFormulaToCNF(varphi[idx+1], defs); - - psi1 = PRODUCT(*(info[varphi[idx]]->clausespos), *(info[varphi[idx+1]]->clausespos)); - psi2 = PRODUCT(*(info[varphi[idx]]->clausesneg), *(info[varphi[idx+1]]->clausesneg)); - NOCOPY_INPLACE_UNION(psi1, psi2); - reduceMemoryFootprintPos(varphi[idx]); - reduceMemoryFootprintPos(varphi[idx+1]); - reduceMemoryFootprintNeg(varphi[idx]); - reduceMemoryFootprintNeg(varphi[idx+1]); - - psi = psi1; - } else { - //**************************************** - // (pos) XOR ~> UNION - // (PRODUCT [idx] ; XOR [idx+1..]) - // ; (PRODUCT NOT [idx] ; NOT XOR [idx+1..]) - //**************************************** - BeevMgr::ClauseList* theta1; - theta1 = convertFormulaToCNFPosXORAux(varphi, idx+1, defs); - renamesibs = theta1->size() > 1 ? true : false; - if(renamesibs){ - setDoSibRenamingPos(*info[varphi[idx]]); - } - BeevMgr::ClauseList* theta2; - theta2 = convertFormulaToCNFNegXORAux(varphi, idx+1, defs); - renamesibs = theta2->size() > 1 ? true : false; - if(renamesibs){ - setDoSibRenamingNeg(*info[varphi[idx]]); - } - convertFormulaToCNF(varphi[idx], defs); - - psi1 = PRODUCT(*(info[varphi[idx]]->clausespos), *theta1); - psi2 = PRODUCT(*(info[varphi[idx]]->clausesneg), *theta2); - DELETE(theta1); - DELETE(theta2); - NOCOPY_INPLACE_UNION(psi1, psi2); - reduceMemoryFootprintPos(varphi[idx]); - reduceMemoryFootprintNeg(varphi[idx]); - - psi = psi1; - } - - return psi; - } - - void convertFormulaToCNFNegPred(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - - ASTVec psis; - - ASTVec::const_iterator it = varphi.GetChildren().begin(); - for(; it != varphi.GetChildren().end(); it++){ - convertFormulaToCNF(*it, defs); - psis.push_back(*(info[*it]->termforcnf)); - } - - info[varphi]->clausesneg = SINGLETON(bm->CreateNode(NOT, bm->CreateNode(varphi.GetKind(), psis))); - } - - void convertFormulaToCNFNegFALSE(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - ASTNode dummy_true_var = bm->CreateSymbol("*TrueDummy*"); - info[varphi]->clausesneg = SINGLETON(dummy_true_var); - } - - void convertFormulaToCNFNegTRUE(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - ASTNode dummy_false_var = bm->CreateNode(NOT, bm->CreateSymbol("*TrueDummy*")); - info[varphi]->clausesneg = SINGLETON(dummy_false_var); - } - - void convertFormulaToCNFNegBVGETBIT(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - BeevMgr::ClauseList* psi = SINGLETON(bm->CreateNode(NOT, varphi)); - info[varphi]->clausesneg = psi; - } - - void convertFormulaToCNFNegSYMBOL(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - info[varphi]->clausesneg = SINGLETON(bm->CreateNode(NOT, varphi)); - } - - void convertFormulaToCNFNegNOT(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - convertFormulaToCNF(varphi[0], defs); - info[varphi]->clausesneg = COPY(*(info[varphi[0]]->clausespos)); - reduceMemoryFootprintPos(varphi[0]); - } - - void convertFormulaToCNFNegAND(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - bool renamesibs = false; - BeevMgr::ClauseList* clauses; - BeevMgr::ClauseList* psi; - BeevMgr::ClauseList* oldpsi; - - //**************************************** - // (neg) AND ~> PRODUCT NOT - //**************************************** - - ASTVec::const_iterator it = varphi.GetChildren().begin(); - convertFormulaToCNF(*it, defs); - clauses = info[*it]->clausesneg; - if(clauses->size() > 1){ - renamesibs = true; - } - psi = COPY(*clauses); - reduceMemoryFootprintNeg(*it); - - for(it++; it != varphi.GetChildren().end(); it++){ - if(renamesibs){ - setDoSibRenamingNeg(*(info[*it])); - } - convertFormulaToCNF(*it, defs); - clauses = info[*it]->clausesneg; - if(clauses->size() > 1){ - renamesibs = true; - } - oldpsi = psi; - psi = PRODUCT(*psi, *clauses); - reduceMemoryFootprintNeg(*it); - DELETE(oldpsi); - } - - info[varphi]->clausesneg = psi; - } - - void convertFormulaToCNFNegNAND(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - //**************************************** - // (neg) NAND ~> UNION - //**************************************** - ASTVec::const_iterator it = varphi.GetChildren().begin(); - convertFormulaToCNF(*it, defs); - BeevMgr::ClauseList* psi = COPY(*(info[*it]->clausespos)); - reduceMemoryFootprintPos(*it); - for(it++; it != varphi.GetChildren().end(); it++){ - convertFormulaToCNF(*it, defs); - INPLACE_UNION(psi, *(info[*it]->clausespos)); - reduceMemoryFootprintPos(*it); - } - - info[varphi]->clausespos = psi; - } - - void convertFormulaToCNFNegOR(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - //**************************************** - // (neg) OR ~> UNION NOT - //**************************************** - ASTVec::const_iterator it = varphi.GetChildren().begin(); - convertFormulaToCNF(*it, defs); - BeevMgr::ClauseList* psi = COPY(*(info[*it]->clausesneg)); - reduceMemoryFootprintNeg(*it); - for(it++; it != varphi.GetChildren().end(); it++){ - convertFormulaToCNF(*it, defs); - INPLACE_UNION(psi, *(info[*it]->clausesneg)); - reduceMemoryFootprintNeg(*it); - } - - info[varphi]->clausesneg = psi; - } - - void convertFormulaToCNFNegNOR(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - bool renamesibs = false; - BeevMgr::ClauseList* clauses; - BeevMgr::ClauseList* psi; - BeevMgr::ClauseList* oldpsi; - - //**************************************** - // (neg) NOR ~> PRODUCT - //**************************************** - ASTVec::const_iterator it = varphi.GetChildren().begin(); - convertFormulaToCNF(*it, defs); - clauses = info[*it]->clausespos; - if(clauses->size() > 1){ - renamesibs = true; - } - psi = COPY(*clauses); - reduceMemoryFootprintPos(*it); - - for(it++; it != varphi.GetChildren().end(); it++){ - if(renamesibs){ - setDoSibRenamingPos(*(info[*it])); - } - convertFormulaToCNF(*it, defs); - clauses = info[*it]->clausespos; - if(clauses->size() > 1){ - renamesibs = true; - } - oldpsi = psi; - psi = PRODUCT(*psi, *clauses); - reduceMemoryFootprintPos(*it); - DELETE(oldpsi); - } - - info[varphi]->clausesneg = psi; - } - - void convertFormulaToCNFNegIMPLIES(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - //**************************************** - // (neg) IMPLIES ~> UNION [0] ; NOT [1] - //**************************************** - CNFInfo* x0 = info[varphi[0]]; - CNFInfo* x1 = info[varphi[1]]; - convertFormulaToCNF(varphi[0], defs); - convertFormulaToCNF(varphi[1], defs); - BeevMgr::ClauseList* psi = - UNION(*(x0->clausespos), *(x1->clausesneg)); - info[varphi]->clausesneg = psi; - reduceMemoryFootprintPos(varphi[0]); - reduceMemoryFootprintNeg(varphi[1]); - } - - void convertFormulaToCNFNegITE(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - //**************************************** - // (neg) ITE ~> UNION (PRODUCT NOT [0] ; NOT [1]) - // ; (PRODUCT [0] ; NOT [2]) - //**************************************** - CNFInfo* x0 = info[varphi[0]]; - CNFInfo* x1 = info[varphi[1]]; - CNFInfo* x2 = info[varphi[2]]; - convertFormulaToCNF(varphi[0], defs); - if(x0->clausesneg->size() > 1){ - setDoSibRenamingNeg(*x1); - } - convertFormulaToCNF(varphi[1], defs); - if(x0->clausespos->size() > 1){ - setDoSibRenamingNeg(*x2); - } - convertFormulaToCNF(varphi[2], defs); - BeevMgr::ClauseList* psi1 = PRODUCT(*(x0->clausesneg) - , *(x1->clausesneg)); - BeevMgr::ClauseList* psi2 = PRODUCT(*(x0->clausespos) - , *(x2->clausesneg)); - NOCOPY_INPLACE_UNION(psi1, psi2); - reduceMemoryFootprintNeg(varphi[0]); - reduceMemoryFootprintNeg(varphi[1]); - reduceMemoryFootprintPos(varphi[0]); - reduceMemoryFootprintNeg(varphi[2]); - - info[varphi]->clausesneg = psi1; - } - - void convertFormulaToCNFNegXOR(const ASTNode& varphi, BeevMgr::ClauseList* defs){ - BeevMgr::ClauseList* psi = convertFormulaToCNFNegXORAux(varphi, 0, defs); - info[varphi]->clausesneg = psi; - } - - BeevMgr::ClauseList* convertFormulaToCNFNegXORAux(const ASTNode& varphi - , unsigned int idx, BeevMgr::ClauseList* defs){ - - bool renamesibs; - BeevMgr::ClauseList* psi; - BeevMgr::ClauseList* psi1; - BeevMgr::ClauseList* psi2; - - if(idx == varphi.GetChildren().size() - 2){ - - //**************************************** - // (neg) XOR ~> UNION - // (PRODUCT NOT [idx] ; [idx+1]) - // ; (PRODUCT [idx] ; NOT [idx+1]) - //**************************************** - convertFormulaToCNF(varphi[idx], defs); - renamesibs = (info[varphi[idx]]->clausesneg)->size() > 1 ? true : false; - if(renamesibs){ - setDoSibRenamingPos(*info[varphi[idx+1]]); - } - convertFormulaToCNF(varphi[idx+1], defs); - - - convertFormulaToCNF(varphi[idx], defs); - renamesibs = (info[varphi[idx]]->clausespos)->size() > 1 ? true : false; - if(renamesibs){ - setDoSibRenamingNeg(*info[varphi[idx+1]]); - } - convertFormulaToCNF(varphi[idx+1], defs); - - psi1 = PRODUCT(*(info[varphi[idx]]->clausesneg), *(info[varphi[idx+1]]->clausespos)); - psi2 = PRODUCT(*(info[varphi[idx]]->clausespos), *(info[varphi[idx+1]]->clausesneg)); - NOCOPY_INPLACE_UNION(psi1, psi2); - reduceMemoryFootprintNeg(varphi[idx]); - reduceMemoryFootprintPos(varphi[idx+1]); - reduceMemoryFootprintPos(varphi[idx]); - reduceMemoryFootprintNeg(varphi[idx+1]); - - psi = psi1; - } else { - - //**************************************** - // (neg) XOR ~> UNION - // (PRODUCT NOT [idx] ; XOR [idx+1..]) - // ; (PRODUCT [idx] ; NOT XOR [idx+1..]) - //**************************************** - BeevMgr::ClauseList* theta1; - theta1 = convertFormulaToCNFPosXORAux(varphi, idx+1, defs); - renamesibs = theta1->size() > 1 ? true : false; - if(renamesibs){ - setDoSibRenamingNeg(*info[varphi[idx]]); - } - convertFormulaToCNF(varphi[idx], defs); - - - BeevMgr::ClauseList* theta2; - theta2 = convertFormulaToCNFNegXORAux(varphi, idx+1, defs); - renamesibs = theta2->size() > 1 ? true : false; - if(renamesibs){ - setDoSibRenamingPos(*info[varphi[idx]]); - } - convertFormulaToCNF(varphi[idx], defs); - - psi1 = PRODUCT(*(info[varphi[idx]]->clausesneg), *theta1); - psi2 = PRODUCT(*(info[varphi[idx]]->clausespos), *theta2); - DELETE(theta1); - DELETE(theta2); - NOCOPY_INPLACE_UNION(psi1, psi2); - reduceMemoryFootprintNeg(varphi[idx]); - reduceMemoryFootprintPos(varphi[idx]); - - psi = psi1; - } - - return psi; - } - - //######################################## - //######################################## - // utilities for reclaiming memory. - - void reduceMemoryFootprintPos(const ASTNode& varphi){ - - CNFInfo* x = info[varphi]; - if(sharesPos(*x) == 1){ - DELETE(x->clausespos); - x->clausespos = NULL; - if(x->clausesneg == NULL){ - delete x; - info.erase(varphi); - } - } - } - - void reduceMemoryFootprintNeg(const ASTNode& varphi){ - - CNFInfo* x = info[varphi]; - if(sharesNeg(*x) == 1){ - DELETE(x->clausesneg); - x->clausesneg = NULL; - if(x->clausespos == NULL){ - delete x; - info.erase(varphi); - } - } - } - - //######################################## - //######################################## - - ASTNode* ASTNodeToASTNodePtr(const ASTNode& varphi){ - ASTNode* psi; - - if(store.find(varphi) != store.end()){ - psi = store[varphi]; - } else { - psi = new ASTNode(varphi); - store[varphi] = psi; - } - - return psi; - } - - //######################################## - //######################################## - - void cleanup(const ASTNode& varphi){ - delete info[varphi]->clausespos; - info.erase(varphi); - - ASTNodeToCNFInfoMap::const_iterator it1 = info.begin(); - for(; it1 != info.end(); it1++){ - CNFInfo* x = it1->second; - if(x->clausespos != NULL){ - DELETE(x->clausespos); - } - if(x->clausesneg != NULL){ - if(!isTerm(*x)){ - DELETE(x->clausesneg); - } - } - delete x; - } - - info.clear(); - } + void convertFormulaToCNFNegPred(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + + ASTVec psis; + + ASTVec::const_iterator it = varphi.GetChildren().begin(); + for (; it != varphi.GetChildren().end(); it++) + { + convertFormulaToCNF(*it, defs); + psis.push_back(*(info[*it]->termforcnf)); + } + + info[varphi]->clausesneg = SINGLETON(bm->CreateNode(NOT, bm->CreateNode(varphi.GetKind(), psis))); + } + + void convertFormulaToCNFNegFALSE(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + ASTNode dummy_true_var = bm->CreateSymbol("*TrueDummy*"); + info[varphi]->clausesneg = SINGLETON(dummy_true_var); + } + + void convertFormulaToCNFNegTRUE(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + ASTNode dummy_false_var = bm->CreateNode(NOT, bm->CreateSymbol("*TrueDummy*")); + info[varphi]->clausesneg = SINGLETON(dummy_false_var); + } + + void convertFormulaToCNFNegBVGETBIT(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + BeevMgr::ClauseList* psi = SINGLETON(bm->CreateNode(NOT, varphi)); + info[varphi]->clausesneg = psi; + } + + void convertFormulaToCNFNegSYMBOL(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + info[varphi]->clausesneg = SINGLETON(bm->CreateNode(NOT, varphi)); + } + + void convertFormulaToCNFNegNOT(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + convertFormulaToCNF(varphi[0], defs); + info[varphi]->clausesneg = COPY(*(info[varphi[0]]->clausespos)); + reduceMemoryFootprintPos(varphi[0]); + } + + void convertFormulaToCNFNegAND(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + bool renamesibs = false; + BeevMgr::ClauseList* clauses; + BeevMgr::ClauseList* psi; + BeevMgr::ClauseList* oldpsi; + + //**************************************** + // (neg) AND ~> PRODUCT NOT + //**************************************** + + ASTVec::const_iterator it = varphi.GetChildren().begin(); + convertFormulaToCNF(*it, defs); + clauses = info[*it]->clausesneg; + if (clauses->size() > 1) + { + renamesibs = true; + } + psi = COPY(*clauses); + reduceMemoryFootprintNeg(*it); + + for (it++; it != varphi.GetChildren().end(); it++) + { + if (renamesibs) + { + setDoSibRenamingNeg(*(info[*it])); + } + convertFormulaToCNF(*it, defs); + clauses = info[*it]->clausesneg; + if (clauses->size() > 1) + { + renamesibs = true; + } + oldpsi = psi; + psi = PRODUCT(*psi, *clauses); + reduceMemoryFootprintNeg(*it); + DELETE(oldpsi); + } + + info[varphi]->clausesneg = psi; + } + + void convertFormulaToCNFNegNAND(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + //**************************************** + // (neg) NAND ~> UNION + //**************************************** + ASTVec::const_iterator it = varphi.GetChildren().begin(); + convertFormulaToCNF(*it, defs); + BeevMgr::ClauseList* psi = COPY(*(info[*it]->clausespos)); + reduceMemoryFootprintPos(*it); + for (it++; it != varphi.GetChildren().end(); it++) + { + convertFormulaToCNF(*it, defs); + INPLACE_UNION(psi, *(info[*it]->clausespos)); + reduceMemoryFootprintPos(*it); + } + + info[varphi]->clausespos = psi; + } + + void convertFormulaToCNFNegOR(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + //**************************************** + // (neg) OR ~> UNION NOT + //**************************************** + ASTVec::const_iterator it = varphi.GetChildren().begin(); + convertFormulaToCNF(*it, defs); + BeevMgr::ClauseList* psi = COPY(*(info[*it]->clausesneg)); + reduceMemoryFootprintNeg(*it); + for (it++; it != varphi.GetChildren().end(); it++) + { + convertFormulaToCNF(*it, defs); + INPLACE_UNION(psi, *(info[*it]->clausesneg)); + reduceMemoryFootprintNeg(*it); + } + + info[varphi]->clausesneg = psi; + } + + void convertFormulaToCNFNegNOR(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + bool renamesibs = false; + BeevMgr::ClauseList* clauses; + BeevMgr::ClauseList* psi; + BeevMgr::ClauseList* oldpsi; + + //**************************************** + // (neg) NOR ~> PRODUCT + //**************************************** + ASTVec::const_iterator it = varphi.GetChildren().begin(); + convertFormulaToCNF(*it, defs); + clauses = info[*it]->clausespos; + if (clauses->size() > 1) + { + renamesibs = true; + } + psi = COPY(*clauses); + reduceMemoryFootprintPos(*it); + + for (it++; it != varphi.GetChildren().end(); it++) + { + if (renamesibs) + { + setDoSibRenamingPos(*(info[*it])); + } + convertFormulaToCNF(*it, defs); + clauses = info[*it]->clausespos; + if (clauses->size() > 1) + { + renamesibs = true; + } + oldpsi = psi; + psi = PRODUCT(*psi, *clauses); + reduceMemoryFootprintPos(*it); + DELETE(oldpsi); + } + + info[varphi]->clausesneg = psi; + } + + void convertFormulaToCNFNegIMPLIES(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + //**************************************** + // (neg) IMPLIES ~> UNION [0] ; NOT [1] + //**************************************** + CNFInfo* x0 = info[varphi[0]]; + CNFInfo* x1 = info[varphi[1]]; + convertFormulaToCNF(varphi[0], defs); + convertFormulaToCNF(varphi[1], defs); + BeevMgr::ClauseList* psi = UNION(*(x0->clausespos), *(x1->clausesneg)); + info[varphi]->clausesneg = psi; + reduceMemoryFootprintPos(varphi[0]); + reduceMemoryFootprintNeg(varphi[1]); + } + + void convertFormulaToCNFNegITE(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + //**************************************** + // (neg) ITE ~> UNION (PRODUCT NOT [0] ; NOT [1]) + // ; (PRODUCT [0] ; NOT [2]) + //**************************************** + CNFInfo* x0 = info[varphi[0]]; + CNFInfo* x1 = info[varphi[1]]; + CNFInfo* x2 = info[varphi[2]]; + convertFormulaToCNF(varphi[0], defs); + if (x0->clausesneg->size() > 1) + { + setDoSibRenamingNeg(*x1); + } + convertFormulaToCNF(varphi[1], defs); + if (x0->clausespos->size() > 1) + { + setDoSibRenamingNeg(*x2); + } + convertFormulaToCNF(varphi[2], defs); + BeevMgr::ClauseList* psi1 = PRODUCT(*(x0->clausesneg), *(x1->clausesneg)); + BeevMgr::ClauseList* psi2 = PRODUCT(*(x0->clausespos), *(x2->clausesneg)); + NOCOPY_INPLACE_UNION(psi1, psi2); + reduceMemoryFootprintNeg(varphi[0]); + reduceMemoryFootprintNeg(varphi[1]); + reduceMemoryFootprintPos(varphi[0]); + reduceMemoryFootprintNeg(varphi[2]); + + info[varphi]->clausesneg = psi1; + } + + void convertFormulaToCNFNegXOR(const ASTNode& varphi, BeevMgr::ClauseList* defs) + { + BeevMgr::ClauseList* psi = convertFormulaToCNFNegXORAux(varphi, 0, defs); + info[varphi]->clausesneg = psi; + } + + BeevMgr::ClauseList* convertFormulaToCNFNegXORAux(const ASTNode& varphi, unsigned int idx, BeevMgr::ClauseList* defs) + { + + bool renamesibs; + BeevMgr::ClauseList* psi; + BeevMgr::ClauseList* psi1; + BeevMgr::ClauseList* psi2; + + if (idx == varphi.GetChildren().size() - 2) + { + + //**************************************** + // (neg) XOR ~> UNION + // (PRODUCT NOT [idx] ; [idx+1]) + // ; (PRODUCT [idx] ; NOT [idx+1]) + //**************************************** + convertFormulaToCNF(varphi[idx], defs); + renamesibs = (info[varphi[idx]]->clausesneg)->size() > 1 ? true : false; + if (renamesibs) + { + setDoSibRenamingPos(*info[varphi[idx + 1]]); + } + convertFormulaToCNF(varphi[idx + 1], defs); + + convertFormulaToCNF(varphi[idx], defs); + renamesibs = (info[varphi[idx]]->clausespos)->size() > 1 ? true : false; + if (renamesibs) + { + setDoSibRenamingNeg(*info[varphi[idx + 1]]); + } + convertFormulaToCNF(varphi[idx + 1], defs); + + psi1 = PRODUCT(*(info[varphi[idx]]->clausesneg), *(info[varphi[idx + 1]]->clausespos)); + psi2 = PRODUCT(*(info[varphi[idx]]->clausespos), *(info[varphi[idx + 1]]->clausesneg)); + NOCOPY_INPLACE_UNION(psi1, psi2); + reduceMemoryFootprintNeg(varphi[idx]); + reduceMemoryFootprintPos(varphi[idx + 1]); + reduceMemoryFootprintPos(varphi[idx]); + reduceMemoryFootprintNeg(varphi[idx + 1]); + + psi = psi1; + } + else + { + + //**************************************** + // (neg) XOR ~> UNION + // (PRODUCT NOT [idx] ; XOR [idx+1..]) + // ; (PRODUCT [idx] ; NOT XOR [idx+1..]) + //**************************************** + BeevMgr::ClauseList* theta1; + theta1 = convertFormulaToCNFPosXORAux(varphi, idx + 1, defs); + renamesibs = theta1->size() > 1 ? true : false; + if (renamesibs) + { + setDoSibRenamingNeg(*info[varphi[idx]]); + } + convertFormulaToCNF(varphi[idx], defs); + + BeevMgr::ClauseList* theta2; + theta2 = convertFormulaToCNFNegXORAux(varphi, idx + 1, defs); + renamesibs = theta2->size() > 1 ? true : false; + if (renamesibs) + { + setDoSibRenamingPos(*info[varphi[idx]]); + } + convertFormulaToCNF(varphi[idx], defs); + + psi1 = PRODUCT(*(info[varphi[idx]]->clausesneg), *theta1); + psi2 = PRODUCT(*(info[varphi[idx]]->clausespos), *theta2); + DELETE(theta1); + DELETE(theta2); + NOCOPY_INPLACE_UNION(psi1, psi2); + reduceMemoryFootprintNeg(varphi[idx]); + reduceMemoryFootprintPos(varphi[idx]); + + psi = psi1; + } + + return psi; + } + + //######################################## + //######################################## + // utilities for reclaiming memory. + + void reduceMemoryFootprintPos(const ASTNode& varphi) + { + + CNFInfo* x = info[varphi]; + if (sharesPos(*x) == 1) + { + DELETE(x->clausespos); + x->clausespos = NULL; + if (x->clausesneg == NULL) + { + delete x; + info.erase(varphi); + } + } + } + + void reduceMemoryFootprintNeg(const ASTNode& varphi) + { + + CNFInfo* x = info[varphi]; + if (sharesNeg(*x) == 1) + { + DELETE(x->clausesneg); + x->clausesneg = NULL; + if (x->clausespos == NULL) + { + delete x; + info.erase(varphi); + } + } + } + + //######################################## + //######################################## + + ASTNode* ASTNodeToASTNodePtr(const ASTNode& varphi) + { + ASTNode* psi; + + if (store.find(varphi) != store.end()) + { + psi = store[varphi]; + } + else + { + psi = new ASTNode(varphi); + store[varphi] = psi; + } + + return psi; + } + + //######################################## + //######################################## + + void cleanup(const ASTNode& varphi) + { + delete info[varphi]->clausespos; + info.erase(varphi); + + ASTNodeToCNFInfoMap::const_iterator it1 = info.begin(); + for (; it1 != info.end(); it1++) + { + CNFInfo* x = it1->second; + if (x->clausespos != NULL) + { + DELETE(x->clausespos); + } + if (x->clausesneg != NULL) + { + if (!isTerm(*x)) + { + DELETE(x->clausesneg); + } + } + delete x; + } + + info.clear(); + } }; // end of CNFMgr class - int BeevMgr::TopLevelSAT( const ASTNode& inputasserts, const ASTNode& query) { - - ASTNode q = CreateNode(AND, inputasserts, CreateNode(NOT,query)); - return TopLevelSATAux(q); - } - - //############################################################ - //############################################################ - - - void BeevMgr::PrintClauseList(ostream& os, BeevMgr::ClauseList& cll) - { - int num_clauses = cll.size(); - os << "Clauses: " << endl << "=========================================" << endl; - for(int i=0; i < num_clauses; i++) { - os << "Clause " << i << endl - << "-------------------------------------------" << endl; - LispPrintVecSpecial(os, *cll[i], 0); - os << endl - << "-------------------------------------------" << endl; - } - } - - void BeevMgr::DeleteClauseList(BeevMgr::ClauseList *cllp) - { - BeevMgr::ClauseList::const_iterator iend = cllp->end(); - for (BeevMgr::ClauseList::const_iterator i = cllp->begin(); i < iend; i++) { - delete *i; - } - delete cllp; - } - - int BeevMgr::CallSAT_ResultCheck(MINISAT::Solver& newS, - const ASTNode& q, const ASTNode& orig_input) { - ASTNode BBFormula = BBForm(q); - CNFMgr* cm = new CNFMgr(this); - ClauseList* cl = cm->convertToCNF(BBFormula); - if(stats) - cerr << "Number of clauses:" << cl->size() << endl; - //PrintClauseList(cout, *cl); - bool sat = toSATandSolve(newS,*cl); - cm->DELETE(cl); - delete cm; - - if(!sat) { - PrintOutput(true); - return 1; - } - else if(newS.okay()) { - CounterExampleMap.clear(); - ConstructCounterExample(newS); - if (stats && print_nodes) { - PrintSATModel(newS); - } - //check if the counterexample is good or not - ComputeFormulaMap.clear(); - if(counterexample_checking_during_refinement) - bvdiv_exception_occured = false; - ASTNode orig_result = ComputeFormulaUsingModel(orig_input); - if(!(ASTTrue == orig_result || ASTFalse == orig_result)) - FatalError("TopLevelSat: Original input must compute to true or false against model"); - -// if(!arrayread_refinement && !(ASTTrue == orig_result)) { -// print_counterexample = true; -// PrintCounterExample(true); -// FatalError("counterexample bogus : arrayread_refinement is switched off: " -// "EITHER all LA axioms have not been added OR bitblaster() or ToCNF()" -// "or satsolver() or counterexamplechecker() have a bug"); -// } - - // if the counterexample is indeed a good one, then return - // invalid - if(ASTTrue == orig_result) { - //CheckCounterExample(newS.okay()); - PrintOutput(false); - PrintCounterExample(newS.okay()); - PrintCounterExample_InOrder(newS.okay()); - return 0; - } - // counterexample is bogus: flag it - else { - if(stats && print_nodes) { - cout << "Supposedly bogus one: \n"; - bool tmp = print_counterexample; - print_counterexample = true; - PrintCounterExample(true); - print_counterexample = tmp; - } - - return 2; - } - } - else { - PrintOutput(true); - return -100; - } - } //end of CALLSAT_ResultCheck +int BeevMgr::TopLevelSAT(const ASTNode& inputasserts, const ASTNode& query) +{ + + ASTNode q = CreateNode(AND, inputasserts, CreateNode(NOT, query)); + return TopLevelSATAux(q); +} + +//############################################################ +//############################################################ + + +void BeevMgr::PrintClauseList(ostream& os, BeevMgr::ClauseList& cll) +{ + int num_clauses = cll.size(); + os << "Clauses: " << endl << "=========================================" << endl; + for (int i = 0; i < num_clauses; i++) + { + os << "Clause " << i << endl << "-------------------------------------------" << endl; + LispPrintVecSpecial(os, *cll[i], 0); + os << endl << "-------------------------------------------" << endl; + } +} + +void BeevMgr::DeleteClauseList(BeevMgr::ClauseList *cllp) +{ + BeevMgr::ClauseList::const_iterator iend = cllp->end(); + for (BeevMgr::ClauseList::const_iterator i = cllp->begin(); i < iend; i++) + { + delete *i; + } + delete cllp; +} + +int BeevMgr::CallSAT_ResultCheck(MINISAT::Solver& newS, const ASTNode& q, const ASTNode& orig_input) +{ + ASTNode BBFormula = BBForm(q); + CNFMgr* cm = new CNFMgr(this); + ClauseList* cl = cm->convertToCNF(BBFormula); + if (stats) + cerr << "Number of clauses:" << cl->size() << endl; + //PrintClauseList(cout, *cl); + bool sat = toSATandSolve(newS, *cl); + cm->DELETE(cl); + delete cm; + + if (!sat) + { + PrintOutput(true); + return 1; + } + else if (newS.okay()) + { + CounterExampleMap.clear(); + ConstructCounterExample(newS); + if (stats && print_nodes) + { + PrintSATModel(newS); + } + //check if the counterexample is good or not + ComputeFormulaMap.clear(); + if (counterexample_checking_during_refinement) + bvdiv_exception_occured = false; + ASTNode orig_result = ComputeFormulaUsingModel(orig_input); + if (!(ASTTrue == orig_result || ASTFalse == orig_result)) + FatalError("TopLevelSat: Original input must compute to true or false against model"); + + // if(!arrayread_refinement && !(ASTTrue == orig_result)) { + // print_counterexample = true; + // PrintCounterExample(true); + // FatalError("counterexample bogus : arrayread_refinement is switched off: " + // "EITHER all LA axioms have not been added OR bitblaster() or ToCNF()" + // "or satsolver() or counterexamplechecker() have a bug"); + // } + + // if the counterexample is indeed a good one, then return + // invalid + if (ASTTrue == orig_result) + { + //CheckCounterExample(newS.okay()); + PrintOutput(false); + PrintCounterExample(newS.okay()); + PrintCounterExample_InOrder(newS.okay()); + return 0; + } + // counterexample is bogus: flag it + else + { + if (stats && print_nodes) + { + cout << "Supposedly bogus one: \n"; + bool tmp = print_counterexample; + print_counterexample = true; + PrintCounterExample(true); + print_counterexample = tmp; + } + + return 2; + } + } + else + { + PrintOutput(true); + return -100; + } +} //end of CALLSAT_ResultCheck } // end namespace diff --git a/AST/ToSAT.cpp b/AST/ToSAT.cpp index af3f0b4..f050524 100644 --- a/AST/ToSAT.cpp +++ b/AST/ToSAT.cpp @@ -11,1451 +11,1589 @@ #include "../simplifier/bvsolver.h" #include +namespace BEEV +{ +/* FUNCTION: lookup or create a new MINISAT literal + * lookup or create new MINISAT Vars from the global MAP + * _ASTNode_to_SATVar. + */ +const MINISAT::Var BeevMgr::LookupOrCreateSATVar(MINISAT::Solver& newS, const ASTNode& n) +{ + ASTtoSATMap::iterator it; + MINISAT::Var v; + + //look for the symbol in the global map from ASTNodes to ints. if + //not found, create a S.newVar(), else use the existing one. + if ((it = _ASTNode_to_SATVar.find(n)) == _ASTNode_to_SATVar.end()) + { + v = newS.newVar(); + _ASTNode_to_SATVar[n] = v; + + //ASSUMPTION: I am assuming that the newS.newVar() call increments v + //by 1 each time it is called, and the initial value of a + //MINISAT::Var is 0. + _SATVar_to_AST.push_back(n); + } + else + v = it->second; + return v; +} + +/* FUNCTION: convert ASTClauses to MINISAT clauses and solve. + * Accepts ASTClauses and converts them to MINISAT clauses. Then adds + * the newly minted MINISAT clauses to the local SAT instance, and + * calls solve(). If solve returns unsat, then stop and return + * unsat. else continue. + */ +// FIXME: Still need to deal with TRUE/FALSE in clauses! +//bool BeevMgr::toSATandSolve(MINISAT::Solver& newS, BeevMgr::ClauseList& cll, ASTNodeToIntMap& heuristic) +bool BeevMgr::toSATandSolve(MINISAT::Solver& newS, BeevMgr::ClauseList& cll) +{ + CountersAndStats("SAT Solver"); + + //iterate through the list (conjunction) of ASTclauses cll + BeevMgr::ClauseList::const_iterator i = cll.begin(), iend = cll.end(); + + if (i == iend) + FatalError("toSATandSolve: Nothing to Solve", ASTUndefined); + + //turnOffSubsumption + // MKK: My understanding is that the rougly equivalent effect is had + // through setting the second argument of MINISAT::Solver::solve to + // true + //newS.turnOffSubsumption(); + + // (*i) is an ASTVec-ptr which denotes an ASTclause + //**************************************** + // *i = vector* + //**************************************** + for (; i != iend; i++) + { + //Clause for the SATSolver + MINISAT::vec satSolverClause; + + //now iterate through the internals of the ASTclause itself + vector::const_iterator j = (*i)->begin(), jend = (*i)->end(); + //j is a disjunct in the ASTclause (*i) + for (; j != jend; j++) + { + ASTNode node = **j; + + bool negate = (NOT == node.GetKind()) ? true : false; + ASTNode n = negate ? node[0] : node; + + //Lookup or create the MINISAT::Var corresponding to the Booelan + //ASTNode Variable, and push into sat Solver clause + MINISAT::Var v = LookupOrCreateSATVar(newS, n); + MINISAT::Lit l(v, negate); + satSolverClause.push(l); + } + newS.addClause(satSolverClause); + // clause printing. + // (printClause >)(satSolverClause); + // cout << " 0 "; + // cout << endl; + + if (newS.okay()) + { + continue; + } + else + { + PrintStats(newS); + return false; + } + + if (!newS.simplify()) + { + PrintStats(newS); + return false; + } + } + + // if input is UNSAT return false, else return true + if (!newS.simplify()) + { + PrintStats(newS); + return false; + } + + //PrintActivityLevels_Of_SATVars("Before SAT:",newS); + //ChangeActivityLevels_Of_SATVars(newS); + //PrintActivityLevels_Of_SATVars("Before SAT and after initial bias:",newS); + newS.solve(); + //PrintActivityLevels_Of_SATVars("After SAT",newS); -namespace BEEV { - /* FUNCTION: lookup or create a new MINISAT literal - * lookup or create new MINISAT Vars from the global MAP - * _ASTNode_to_SATVar. - */ - const MINISAT::Var BeevMgr::LookupOrCreateSATVar(MINISAT::Solver& newS, const ASTNode& n) { - ASTtoSATMap::iterator it; - MINISAT::Var v; - - //look for the symbol in the global map from ASTNodes to ints. if - //not found, create a S.newVar(), else use the existing one. - if((it = _ASTNode_to_SATVar.find(n)) == _ASTNode_to_SATVar.end()) { - v = newS.newVar(); - _ASTNode_to_SATVar[n] = v; - - //ASSUMPTION: I am assuming that the newS.newVar() call increments v - //by 1 each time it is called, and the initial value of a - //MINISAT::Var is 0. - _SATVar_to_AST.push_back(n); - } - else - v = it->second; - return v; - } - - /* FUNCTION: convert ASTClauses to MINISAT clauses and solve. - * Accepts ASTClauses and converts them to MINISAT clauses. Then adds - * the newly minted MINISAT clauses to the local SAT instance, and - * calls solve(). If solve returns unsat, then stop and return - * unsat. else continue. - */ - // FIXME: Still need to deal with TRUE/FALSE in clauses! - //bool BeevMgr::toSATandSolve(MINISAT::Solver& newS, BeevMgr::ClauseList& cll, ASTNodeToIntMap& heuristic) - bool BeevMgr::toSATandSolve(MINISAT::Solver& newS, BeevMgr::ClauseList& cll) - { - CountersAndStats("SAT Solver"); - - //iterate through the list (conjunction) of ASTclauses cll - BeevMgr::ClauseList::const_iterator i = cll.begin(), iend = cll.end(); - - if(i == iend) - FatalError("toSATandSolve: Nothing to Solve",ASTUndefined); - - //turnOffSubsumption - // MKK: My understanding is that the rougly equivalent effect is had - // through setting the second argument of MINISAT::Solver::solve to - // true - //newS.turnOffSubsumption(); - - // (*i) is an ASTVec-ptr which denotes an ASTclause - //**************************************** - // *i = vector* - //**************************************** - for(; i!=iend; i++) { - //Clause for the SATSolver - MINISAT::vec satSolverClause; - - //now iterate through the internals of the ASTclause itself - vector::const_iterator j = (*i)->begin(), jend = (*i)->end(); - //j is a disjunct in the ASTclause (*i) - for(;j!=jend;j++) { - ASTNode node = **j; - - bool negate = (NOT == node.GetKind()) ? true : false; - ASTNode n = negate ? node[0] : node; - - //Lookup or create the MINISAT::Var corresponding to the Booelan - //ASTNode Variable, and push into sat Solver clause - MINISAT::Var v = LookupOrCreateSATVar(newS,n); - MINISAT::Lit l(v, negate); - satSolverClause.push(l); - } - newS.addClause(satSolverClause); - // clause printing. - // (printClause >)(satSolverClause); - // cout << " 0 "; - // cout << endl; - - if(newS.okay()) { - continue; - } - else { PrintStats(newS); - return false; - } - - if(!newS.simplify()) { - PrintStats(newS); - return false; - } - } - - // if input is UNSAT return false, else return true - if(!newS.simplify()) { - PrintStats(newS); - return false; - } - - //PrintActivityLevels_Of_SATVars("Before SAT:",newS); - //ChangeActivityLevels_Of_SATVars(newS); - //PrintActivityLevels_Of_SATVars("Before SAT and after initial bias:",newS); - newS.solve(); - //PrintActivityLevels_Of_SATVars("After SAT",newS); - - PrintStats(newS); - if (newS.okay()) - return true; - else - return false; - } - - // GLOBAL FUNCTION: Prints statistics from the MINISAT Solver - void BeevMgr::PrintStats(MINISAT::Solver& s) { - if(!stats) - return; - double cpu_time = MINISAT::cpuTime(); - uint64_t mem_used = MINISAT::memUsed(); - /* - reportf("restarts : %"I64_fmt"\n", s.starts); - reportf("conflicts : %-12"I64_fmt" (%.0f /sec)\n", s.conflicts , s.conflicts /cpu_time); - reportf("decisions : %-12"I64_fmt" (%.0f /sec)\n", s.decisions , s.decisions /cpu_time); - reportf("propagations : %-12"I64_fmt" (%.0f /sec)\n", s.propagations, s.propagations/cpu_time); - reportf("conflict literals : %-12"I64_fmt" (%4.2f %% deleted)\n", - s.tot_literals, - (s.max_literals - s.tot_literals)*100 / (double)s.max_literals); - */ - if (mem_used != 0) reportf("Memory used : %.2f MB\n", mem_used / 1048576.0); - reportf("CPU time : %g s\n", cpu_time); - } - - // Prints Satisfying assignment directly, for debugging. - void BeevMgr::PrintSATModel(MINISAT::Solver& newS) { - if(!newS.okay()) - FatalError("PrintSATModel: NO COUNTEREXAMPLE TO PRINT",ASTUndefined); - // FIXME: Don't put tests like this in the print functions. The print functions - // should print unconditionally. Put a conditional around the call if you don't - // want them to print - if(!(stats && print_nodes)) - return; - - int num_vars = newS.nVars(); - cout << "Satisfying assignment: " << endl; - for (int i = 0; i < num_vars; i++) { - if (newS.model[i] == MINISAT::l_True) { - ASTNode s = _SATVar_to_AST[i]; - cout << s << endl; - } - else if (newS.model[i] == MINISAT::l_False) { - ASTNode s = _SATVar_to_AST[i]; - cout << CreateNode(NOT, s) << endl; - } - } - } - - - // Looks up truth value of ASTNode SYMBOL in MINISAT satisfying assignment. - // Returns ASTTrue if true, ASTFalse if false or undefined. - ASTNode BeevMgr::SymbolTruthValue(MINISAT::Solver &newS, ASTNode form) - { - MINISAT::Var satvar = _ASTNode_to_SATVar[form]; - if (newS.model[satvar] == MINISAT::l_True) { - return ASTTrue; - } - else { - // False or undefined. - return ASTFalse; - } - } - - - // This function is for debugging problems with BitBlast and especially - // ToCNF. It evaluates the bit-blasted formula in the satisfying - // assignment. While doing that, it checks that every subformula has - // the same truth value as its representative literal, if it has one. - // If this condition is violated, it halts immediately (on the leftmost - // lowest term). - // Use CreateSimpForm to evaluate, even though it's expensive, so that - // we can use the partial truth assignment. - ASTNode BeevMgr::CheckBBandCNF(MINISAT::Solver& newS, ASTNode form) - { - // Clear memo table (in case newS has changed). - CheckBBandCNFMemo.clear(); - // Call recursive version that does the work. - return CheckBBandCNF_int(newS, form); - } - - // Recursive body CheckBBandCNF - // FIXME: Modify this to just check if result is true, and print mismatch - // if not. Might have a trace flag for the other stuff. - ASTNode BeevMgr::CheckBBandCNF_int(MINISAT::Solver& newS, ASTNode form) - { - - // cout << "++++++++++++++++" << endl << "CheckBBandCNF_int form = " << - // form << endl; - - ASTNodeMap::iterator memoit = CheckBBandCNFMemo.find(form); - if (memoit != CheckBBandCNFMemo.end()) { - // found it. Return memoized value. - return memoit->second; - } - - ASTNode result; // return value, to memoize. - - Kind k = form.GetKind(); - switch (k) { - case TRUE: - case FALSE: { - return form; - break; - } - case SYMBOL: - case BVGETBIT: { - // Look up the truth value - // ASTNode -> Sat -> Truthvalue -> ASTTrue or ASTFalse; - // FIXME: Could make up a fresh var in undefined case. - - result = SymbolTruthValue(newS, form); - - cout << "================" << endl << "Checking BB formula:" << form << endl; - cout << "----------------" << endl << "Result:" << result << endl; - - break; - } - default: { - // Evaluate the children recursively. - ASTVec eval_children; - ASTVec ch = form.GetChildren(); - ASTVec::iterator itend = ch.end(); - for(ASTVec::iterator it = ch.begin(); it < itend; it++) { - eval_children.push_back(CheckBBandCNF_int(newS, *it)); - } - result = CreateSimpForm(k, eval_children); - - cout << "================" << endl << "Checking BB formula:" << form << endl; - cout << "----------------" << endl << "Result:" << result << endl; - - ASTNode replit_eval; - // Compare with replit, if there is one. - ASTNodeMap::iterator replit_it = RepLitMap.find(form); - if (replit_it != RepLitMap.end()) { - ASTNode replit = RepLitMap[form]; - // Replit is symbol or not symbol. - if (SYMBOL == replit.GetKind()) { - replit_eval = SymbolTruthValue(newS, replit); + if (newS.okay()) + return true; + else + return false; +} + +// GLOBAL FUNCTION: Prints statistics from the MINISAT Solver +void BeevMgr::PrintStats(MINISAT::Solver& s) +{ + if (!stats) + return; + double cpu_time = MINISAT::cpuTime(); + uint64_t mem_used = MINISAT::memUsed(); + /* + reportf("restarts : %"I64_fmt"\n", s.starts); + reportf("conflicts : %-12"I64_fmt" (%.0f /sec)\n", s.conflicts , s.conflicts /cpu_time); + reportf("decisions : %-12"I64_fmt" (%.0f /sec)\n", s.decisions , s.decisions /cpu_time); + reportf("propagations : %-12"I64_fmt" (%.0f /sec)\n", s.propagations, s.propagations/cpu_time); + reportf("conflict literals : %-12"I64_fmt" (%4.2f %% deleted)\n", + s.tot_literals, + (s.max_literals - s.tot_literals)*100 / (double)s.max_literals); + */ + if (mem_used != 0) + reportf("Memory used : %.2f MB\n", mem_used / 1048576.0); + reportf("CPU time : %g s\n", cpu_time); +} + +// Prints Satisfying assignment directly, for debugging. +void BeevMgr::PrintSATModel(MINISAT::Solver& newS) +{ + if (!newS.okay()) + FatalError("PrintSATModel: NO COUNTEREXAMPLE TO PRINT", ASTUndefined); + // FIXME: Don't put tests like this in the print functions. The print functions + // should print unconditionally. Put a conditional around the call if you don't + // want them to print + if (!(stats && print_nodes)) + return; + + int num_vars = newS.nVars(); + cout << "Satisfying assignment: " << endl; + for (int i = 0; i < num_vars; i++) + { + if (newS.model[i] == MINISAT::l_True) + { + ASTNode s = _SATVar_to_AST[i]; + cout << s << endl; + } + else if (newS.model[i] == MINISAT::l_False) + { + ASTNode s = _SATVar_to_AST[i]; + cout << CreateNode(NOT, s) << endl; + } + } +} + +// Looks up truth value of ASTNode SYMBOL in MINISAT satisfying assignment. +// Returns ASTTrue if true, ASTFalse if false or undefined. +ASTNode BeevMgr::SymbolTruthValue(MINISAT::Solver &newS, ASTNode form) +{ + MINISAT::Var satvar = _ASTNode_to_SATVar[form]; + if (newS.model[satvar] == MINISAT::l_True) + { + return ASTTrue; } - else { - // It's (NOT sym). Get value of sym and complement. - replit_eval = CreateSimpNot(SymbolTruthValue(newS, replit[0])); + else + { + // False or undefined. + return ASTFalse; + } +} + +// This function is for debugging problems with BitBlast and especially +// ToCNF. It evaluates the bit-blasted formula in the satisfying +// assignment. While doing that, it checks that every subformula has +// the same truth value as its representative literal, if it has one. +// If this condition is violated, it halts immediately (on the leftmost +// lowest term). +// Use CreateSimpForm to evaluate, even though it's expensive, so that +// we can use the partial truth assignment. +ASTNode BeevMgr::CheckBBandCNF(MINISAT::Solver& newS, ASTNode form) +{ + // Clear memo table (in case newS has changed). + CheckBBandCNFMemo.clear(); + // Call recursive version that does the work. + return CheckBBandCNF_int(newS, form); +} + +// Recursive body CheckBBandCNF +// FIXME: Modify this to just check if result is true, and print mismatch +// if not. Might have a trace flag for the other stuff. +ASTNode BeevMgr::CheckBBandCNF_int(MINISAT::Solver& newS, ASTNode form) +{ + + // cout << "++++++++++++++++" << endl << "CheckBBandCNF_int form = " << + // form << endl; + + ASTNodeMap::iterator memoit = CheckBBandCNFMemo.find(form); + if (memoit != CheckBBandCNFMemo.end()) + { + // found it. Return memoized value. + return memoit->second; } - cout << "----------------" << endl << "Rep lit: " << replit << endl; - cout << "----------------" << endl << "Rep lit value: " << replit_eval << endl; + ASTNode result; // return value, to memoize. + + Kind k = form.GetKind(); + switch (k) + { + case TRUE: + case FALSE: + { + return form; + break; + } + case SYMBOL: + case BVGETBIT: + { + // Look up the truth value + // ASTNode -> Sat -> Truthvalue -> ASTTrue or ASTFalse; + // FIXME: Could make up a fresh var in undefined case. + + result = SymbolTruthValue(newS, form); + + cout << "================" << endl << "Checking BB formula:" << form << endl; + cout << "----------------" << endl << "Result:" << result << endl; - if (result != replit_eval) { - // Hit the panic button. - FatalError("Truth value of BitBlasted formula disagrees with representative literal in CNF."); + break; + } + default: + { + // Evaluate the children recursively. + ASTVec eval_children; + ASTVec ch = form.GetChildren(); + ASTVec::iterator itend = ch.end(); + for (ASTVec::iterator it = ch.begin(); it < itend; it++) + { + eval_children.push_back(CheckBBandCNF_int(newS, *it)); + } + result = CreateSimpForm(k, eval_children); + + cout << "================" << endl << "Checking BB formula:" << form << endl; + cout << "----------------" << endl << "Result:" << result << endl; + + ASTNode replit_eval; + // Compare with replit, if there is one. + ASTNodeMap::iterator replit_it = RepLitMap.find(form); + if (replit_it != RepLitMap.end()) + { + ASTNode replit = RepLitMap[form]; + // Replit is symbol or not symbol. + if (SYMBOL == replit.GetKind()) + { + replit_eval = SymbolTruthValue(newS, replit); + } + else + { + // It's (NOT sym). Get value of sym and complement. + replit_eval = CreateSimpNot(SymbolTruthValue(newS, replit[0])); + } + + cout << "----------------" << endl << "Rep lit: " << replit << endl; + cout << "----------------" << endl << "Rep lit value: " << replit_eval << endl; + + if (result != replit_eval) + { + // Hit the panic button. + FatalError("Truth value of BitBlasted formula disagrees with representative literal in CNF."); + } + } + else + { + cout << "----------------" << endl << "No rep lit" << endl; + } + + } } - } - else { - cout << "----------------" << endl << "No rep lit" << endl; - } - - } - } - - return (CheckBBandCNFMemo[form] = result); - } - - /*FUNCTION: constructs counterexample from MINISAT counterexample - * step1 : iterate through MINISAT counterexample and assemble the - * bits for each AST term. Store it in a map from ASTNode to vector - * of bools (bits). - * - * step2: Iterate over the map from ASTNodes->Vector-of-Bools and - * populate the CounterExampleMap data structure (ASTNode -> BVConst) - */ - void BeevMgr::ConstructCounterExample(MINISAT::Solver& newS) { - //iterate over MINISAT counterexample and construct a map from AST - //terms to vector of bools. We need this iteration step because - //MINISAT might return the various bits of a term out of - //order. Therfore, we need to collect all the bits and assemble - //them properly - - if(!newS.okay()) - return; - if(!construct_counterexample) - return; - - CopySolverMap_To_CounterExample(); - for (int i = 0; i < newS.nVars(); i++) { - //Make sure that the MINISAT::Var is defined - if (newS.model[i] != MINISAT::l_Undef) { - - //mapping from MINISAT::Vars to ASTNodes. We do not need to - //print MINISAT vars or CNF vars. - ASTNode s = _SATVar_to_AST[i]; - - //assemble the counterexample here - if(s.GetKind() == BVGETBIT && s[0].GetKind() == SYMBOL) { - ASTNode symbol = s[0]; - unsigned int symbolWidth = symbol.GetValueWidth(); - - //'v' is the map from bit-index to bit-value - hash_map * v; - if(_ASTNode_to_Bitvector.find(symbol) == _ASTNode_to_Bitvector.end()) - _ASTNode_to_Bitvector[symbol] = new hash_map(symbolWidth); - - //v holds the map from bit-index to bit-value - v = _ASTNode_to_Bitvector[symbol]; - - //kk is the index of BVGETBIT - unsigned int kk = GetUnsignedConst(s[1]); - - //Collect the bits of 'symbol' and store in v. Store in reverse order. - if(newS.model[i]==MINISAT::l_True) - (*v)[(symbolWidth-1) - kk] = true; - else - (*v)[(symbolWidth-1) - kk] = false; + + return (CheckBBandCNFMemo[form] = result); +} + +/*FUNCTION: constructs counterexample from MINISAT counterexample + * step1 : iterate through MINISAT counterexample and assemble the + * bits for each AST term. Store it in a map from ASTNode to vector + * of bools (bits). + * + * step2: Iterate over the map from ASTNodes->Vector-of-Bools and + * populate the CounterExampleMap data structure (ASTNode -> BVConst) + */ +void BeevMgr::ConstructCounterExample(MINISAT::Solver& newS) +{ + //iterate over MINISAT counterexample and construct a map from AST + //terms to vector of bools. We need this iteration step because + //MINISAT might return the various bits of a term out of + //order. Therfore, we need to collect all the bits and assemble + //them properly + + if (!newS.okay()) + return; + if (!construct_counterexample) + return; + + CopySolverMap_To_CounterExample(); + for (int i = 0; i < newS.nVars(); i++) + { + //Make sure that the MINISAT::Var is defined + if (newS.model[i] != MINISAT::l_Undef) + { + + //mapping from MINISAT::Vars to ASTNodes. We do not need to + //print MINISAT vars or CNF vars. + ASTNode s = _SATVar_to_AST[i]; + + //assemble the counterexample here + if (s.GetKind() == BVGETBIT && s[0].GetKind() == SYMBOL) + { + ASTNode symbol = s[0]; + unsigned int symbolWidth = symbol.GetValueWidth(); + + //'v' is the map from bit-index to bit-value + hash_map * v; + if (_ASTNode_to_Bitvector.find(symbol) == _ASTNode_to_Bitvector.end()) + _ASTNode_to_Bitvector[symbol] = new hash_map (symbolWidth); + + //v holds the map from bit-index to bit-value + v = _ASTNode_to_Bitvector[symbol]; + + //kk is the index of BVGETBIT + unsigned int kk = GetUnsignedConst(s[1]); + + //Collect the bits of 'symbol' and store in v. Store in reverse order. + if (newS.model[i] == MINISAT::l_True) + (*v)[(symbolWidth - 1) - kk] = true; + else + (*v)[(symbolWidth - 1) - kk] = false; + } + else + { + if (s.GetKind() == SYMBOL && s.GetType() == BOOLEAN_TYPE) + { + const char * zz = s.GetName(); + //if the variables are not cnf variables then add them to the counterexample + if (0 != strncmp("cnf", zz, 3) && 0 != strcmp("*TrueDummy*", zz)) + { + if (newS.model[i] == MINISAT::l_True) + CounterExampleMap[s] = ASTTrue; + else if (newS.model[i] == MINISAT::l_False) + CounterExampleMap[s] = ASTFalse; + else + { + int seed = 10000; + srand(seed); + CounterExampleMap[s] = (rand() > seed) ? ASTFalse : ASTTrue; + } + } + } + } + } } - else { - if(s.GetKind() == SYMBOL && s.GetType() == BOOLEAN_TYPE) { - const char * zz = s.GetName(); - //if the variables are not cnf variables then add them to the counterexample - if(0 != strncmp("cnf",zz,3) && 0 != strcmp("*TrueDummy*",zz)) { - if(newS.model[i]==MINISAT::l_True) - CounterExampleMap[s] = ASTTrue; - else if(newS.model[i]==MINISAT::l_False) - CounterExampleMap[s] = ASTFalse; - else { - int seed = 10000; - srand(seed); - CounterExampleMap[s] = (rand() > seed) ? ASTFalse : ASTTrue; - } - } - } + + //iterate over the ASTNode_to_Bitvector data-struct and construct + //the the aggregate value of the bitvector, and populate the + //CounterExampleMap datastructure + for (ASTtoBitvectorMap::iterator it = _ASTNode_to_Bitvector.begin(), itend = _ASTNode_to_Bitvector.end(); it != itend; it++) + { + ASTNode var = it->first; + //debugging + //cerr << var; + if (SYMBOL != var.GetKind()) + FatalError("ConstructCounterExample: error while constructing counterexample: not a variable: ", var); + + //construct the bitvector value + hash_map * w = it->second; + ASTNode value = BoolVectoBVConst(w, var.GetValueWidth()); + //debugging + //cerr << value; + + //populate the counterexample datastructure. add only scalars + //variables which were declared in the input and newly + //introduced variables for array reads + CounterExampleMap[var] = value; } - } - } - - //iterate over the ASTNode_to_Bitvector data-struct and construct - //the the aggregate value of the bitvector, and populate the - //CounterExampleMap datastructure - for(ASTtoBitvectorMap::iterator it=_ASTNode_to_Bitvector.begin(),itend=_ASTNode_to_Bitvector.end(); - it!=itend;it++) { - ASTNode var = it->first; - //debugging - //cerr << var; - if(SYMBOL != var.GetKind()) - FatalError("ConstructCounterExample: error while constructing counterexample: not a variable: ",var); - - //construct the bitvector value - hash_map * w = it->second; - ASTNode value = BoolVectoBVConst(w, var.GetValueWidth()); - //debugging - //cerr << value; - - //populate the counterexample datastructure. add only scalars - //variables which were declared in the input and newly - //introduced variables for array reads - CounterExampleMap[var] = value; - } - - //In this loop, we compute the value of each array read, the - //corresponding ITE against the counterexample generated above. - for(ASTNodeMap::iterator it=_arrayread_ite.begin(),itend=_arrayread_ite.end(); - it!=itend;it++){ - //the array read - ASTNode arrayread = it->first; - ASTNode value_ite = _arrayread_ite[arrayread]; - - //convert it to a constant array-read and store it in the - //counter-example. First convert the index into a constant. then - //construct the appropriate array-read and store it in the - //counterexample - ASTNode arrayread_index = TermToConstTermUsingModel(arrayread[1]); - ASTNode key = CreateTerm(READ,arrayread.GetValueWidth(),arrayread[0],arrayread_index); - - //Get the ITE corresponding to the array-read and convert it - //to a constant against the model - ASTNode value = TermToConstTermUsingModel(value_ite); - //save the result in the counter_example - if(!CheckSubstitutionMap(key)) - CounterExampleMap[key] = value; - } - } //End of ConstructCounterExample - - // FUNCTION: accepts a non-constant term, and returns the - // corresponding constant term with respect to a model. - // - // term READ(A,i) is treated as follows: - // - //1. If (the boolean variable 'ArrayReadFlag' is true && ArrayRead - //1. has value in counterexample), then return the value of the - //1. arrayread. - // - //2. If (the boolean variable 'ArrayReadFlag' is true && ArrayRead - //2. doesn't have value in counterexample), then return the - //2. arrayread itself (normalized such that arrayread has a constant - //2. index) - // - //3. If (the boolean variable 'ArrayReadFlag' is false) && ArrayRead - //3. has a value in the counterexample then return the value of the - //3. arrayread. - // - //4. If (the boolean variable 'ArrayReadFlag' is false) && ArrayRead - //4. doesn't have a value in the counterexample then return 0 as the - //4. value of the arrayread. - ASTNode BeevMgr::TermToConstTermUsingModel(const ASTNode& t, bool ArrayReadFlag) { - Begin_RemoveWrites = false; - SimplifyWrites_InPlace_Flag = false; - //ASTNode term = SimplifyTerm(t); - ASTNode term = t; - Kind k = term.GetKind(); - - - //cerr << "Input to TermToConstTermUsingModel: " << term << endl; - if(!is_Term_kind(k)) { - FatalError("TermToConstTermUsingModel: The input is not a term: ",term); - } - if(k == WRITE) { - FatalError("TermToConstTermUsingModel: The input has wrong kind: WRITE : ",term); - } - if(k == SYMBOL && BOOLEAN_TYPE == term.GetType()) { - FatalError("TermToConstTermUsingModel: The input has wrong kind: Propositional variable : ",term); - } - - ASTNodeMap::iterator it1; - if((it1 = CounterExampleMap.find(term)) != CounterExampleMap.end()) { - ASTNode val = it1->second; - if(BVCONST != val.GetKind()) { - //CounterExampleMap has two maps rolled into - //one. SubstitutionMap and SolverMap. - // - //recursion is fine here. There are two maps that are checked - //here. One is the substitutionmap. We garuntee that the value - //of a key in the substitutionmap is always a constant. - // - //in the SolverMap we garuntee that "term" does not occur in - //the value part of the map - if(term == val) { - FatalError("TermToConstTermUsingModel: The input term is stored as-is " - "in the CounterExample: Not ok: ",term); + + //In this loop, we compute the value of each array read, the + //corresponding ITE against the counterexample generated above. + for (ASTNodeMap::iterator it = _arrayread_ite.begin(), itend = _arrayread_ite.end(); it != itend; it++) + { + //the array read + ASTNode arrayread = it->first; + ASTNode value_ite = _arrayread_ite[arrayread]; + + //convert it to a constant array-read and store it in the + //counter-example. First convert the index into a constant. then + //construct the appropriate array-read and store it in the + //counterexample + ASTNode arrayread_index = TermToConstTermUsingModel(arrayread[1]); + ASTNode key = CreateTerm(READ, arrayread.GetValueWidth(), arrayread[0], arrayread_index); + + //Get the ITE corresponding to the array-read and convert it + //to a constant against the model + ASTNode value = TermToConstTermUsingModel(value_ite); + //save the result in the counter_example + if (!CheckSubstitutionMap(key)) + CounterExampleMap[key] = value; + } +} //End of ConstructCounterExample + +// FUNCTION: accepts a non-constant term, and returns the +// corresponding constant term with respect to a model. +// +// term READ(A,i) is treated as follows: +// +//1. If (the boolean variable 'ArrayReadFlag' is true && ArrayRead +//1. has value in counterexample), then return the value of the +//1. arrayread. +// +//2. If (the boolean variable 'ArrayReadFlag' is true && ArrayRead +//2. doesn't have value in counterexample), then return the +//2. arrayread itself (normalized such that arrayread has a constant +//2. index) +// +//3. If (the boolean variable 'ArrayReadFlag' is false) && ArrayRead +//3. has a value in the counterexample then return the value of the +//3. arrayread. +// +//4. If (the boolean variable 'ArrayReadFlag' is false) && ArrayRead +//4. doesn't have a value in the counterexample then return 0 as the +//4. value of the arrayread. +ASTNode BeevMgr::TermToConstTermUsingModel(const ASTNode& t, bool ArrayReadFlag) +{ + Begin_RemoveWrites = false; + SimplifyWrites_InPlace_Flag = false; + //ASTNode term = SimplifyTerm(t); + ASTNode term = t; + Kind k = term.GetKind(); + + //cerr << "Input to TermToConstTermUsingModel: " << term << endl; + if (!is_Term_kind(k)) + { + FatalError("TermToConstTermUsingModel: The input is not a term: ", term); + } + if (k == WRITE) + { + FatalError("TermToConstTermUsingModel: The input has wrong kind: WRITE : ", term); } - return TermToConstTermUsingModel(val,ArrayReadFlag); - } - else { - return val; - } - } - - ASTNode output; - switch(k) { - case BVCONST: - output = term; - break; - case SYMBOL: { - if(term.GetType() == ARRAY_TYPE) { - return term; - } - - //when all else fails set symbol values to some constant by - //default. if the variable is queried the second time then add 1 - //to and return the new value. - ASTNode zero = CreateZeroConst(term.GetValueWidth()); - output = zero; - break; - } - case READ: { - ASTNode arrName = term[0]; - ASTNode index = term[1]; - if(0 == arrName.GetIndexWidth()) { - FatalError("TermToConstTermUsingModel: array has 0 index width: ",arrName); - } - - //READ over a WRITE - if(WRITE == arrName.GetKind()) { - ASTNode wrtterm = Expand_ReadOverWrite_UsingModel(term, ArrayReadFlag); - if(wrtterm == term) { - FatalError("TermToConstTermUsingModel: Read_Over_Write term must be expanded into an ITE", term); + if (k == SYMBOL && BOOLEAN_TYPE == term.GetType()) + { + FatalError("TermToConstTermUsingModel: The input has wrong kind: Propositional variable : ", term); } - ASTNode rtterm = TermToConstTermUsingModel(wrtterm,ArrayReadFlag); - return rtterm; - } - //READ over an ITE - if(ITE == arrName.GetKind()) { - arrName = TermToConstTermUsingModel(arrName,ArrayReadFlag); - } - - ASTNode modelentry; - if(CounterExampleMap.find(index) != CounterExampleMap.end()) { - //index has a const value in the CounterExampleMap - //ASTNode indexVal = CounterExampleMap[index]; - ASTNode indexVal = TermToConstTermUsingModel(CounterExampleMap[index], ArrayReadFlag); - modelentry = CreateTerm(READ, arrName.GetValueWidth(), arrName, indexVal); - } - else { - //index does not have a const value in the CounterExampleMap. compute it. - ASTNode indexconstval = TermToConstTermUsingModel(index,ArrayReadFlag); - //update model with value of the index - //CounterExampleMap[index] = indexconstval; - modelentry = CreateTerm(READ,arrName.GetValueWidth(), arrName,indexconstval); - } - //modelentry is now an arrayread over a constant index - BVTypeCheck(modelentry); - - //if a value exists in the CounterExampleMap then return it - if(CounterExampleMap.find(modelentry) != CounterExampleMap.end()) { - output = TermToConstTermUsingModel(CounterExampleMap[modelentry],ArrayReadFlag); - } - else if(ArrayReadFlag) { - //return the array read over a constantindex - output = modelentry; - } - else { - //when all else fails set symbol values to some constant by - //default. if the variable is queried the second time then add 1 - //to and return the new value. - ASTNode zero = CreateZeroConst(modelentry.GetValueWidth()); - output = zero; - } - break; - } - case ITE: { - ASTNode condcompute = ComputeFormulaUsingModel(term[0]); - if(ASTTrue == condcompute) { - output = TermToConstTermUsingModel(term[1],ArrayReadFlag); - } - else if(ASTFalse == condcompute) { - output = TermToConstTermUsingModel(term[2],ArrayReadFlag); - } - else { - cerr << "TermToConstTermUsingModel: termITE: value of conditional is wrong: " << condcompute << endl; - FatalError(" TermToConstTermUsingModel: termITE: cannot compute ITE conditional against model: ",term); - } - break; - } - default: { - ASTVec c = term.GetChildren(); - ASTVec o; - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - ASTNode ff = TermToConstTermUsingModel(*it,ArrayReadFlag); - o.push_back(ff); - } - output = CreateTerm(k,term.GetValueWidth(),o); - //output is a CONST expression. compute its value and store it - //in the CounterExampleMap - ASTNode oo = BVConstEvaluator(output); - //the return value - output = oo; - break; - } - } - - //when this flag is false, we should compute the arrayread to a - //constant. this constant is stored in the counter_example - //datastructure - if(!ArrayReadFlag) { - CounterExampleMap[term] = output; - } - - //cerr << "Output to TermToConstTermUsingModel: " << output << endl; - return output; - } //End of TermToConstTermUsingModel - - //Expands read-over-write by evaluating (readIndex=writeIndex) for - //every writeindex until, either it evaluates to TRUE or all - //(readIndex=writeIndex) evaluate to FALSE - ASTNode BeevMgr::Expand_ReadOverWrite_UsingModel(const ASTNode& term, bool arrayread_flag) { - if(READ != term.GetKind() && - WRITE != term[0].GetKind()) { - FatalError("RemovesWrites: Input must be a READ over a WRITE",term); - } - - ASTNode output; - ASTNodeMap::iterator it1; - if((it1 = CounterExampleMap.find(term)) != CounterExampleMap.end()) { - ASTNode val = it1->second; - if(BVCONST != val.GetKind()) { - //recursion is fine here. There are two maps that are checked - //here. One is the substitutionmap. We garuntee that the value - //of a key in the substitutionmap is always a constant. - if(term == val) { - FatalError("TermToConstTermUsingModel: The input term is stored as-is " - "in the CounterExample: Not ok: ",term); + + ASTNodeMap::iterator it1; + if ((it1 = CounterExampleMap.find(term)) != CounterExampleMap.end()) + { + ASTNode val = it1->second; + if (BVCONST != val.GetKind()) + { + //CounterExampleMap has two maps rolled into + //one. SubstitutionMap and SolverMap. + // + //recursion is fine here. There are two maps that are checked + //here. One is the substitutionmap. We garuntee that the value + //of a key in the substitutionmap is always a constant. + // + //in the SolverMap we garuntee that "term" does not occur in + //the value part of the map + if (term == val) + { + FatalError("TermToConstTermUsingModel: The input term is stored as-is " + "in the CounterExample: Not ok: ", term); + } + return TermToConstTermUsingModel(val, ArrayReadFlag); + } + else + { + return val; + } + } + + ASTNode output; + switch (k) + { + case BVCONST: + output = term; + break; + case SYMBOL: + { + if (term.GetType() == ARRAY_TYPE) + { + return term; + } + + //when all else fails set symbol values to some constant by + //default. if the variable is queried the second time then add 1 + //to and return the new value. + ASTNode zero = CreateZeroConst(term.GetValueWidth()); + output = zero; + break; + } + case READ: + { + ASTNode arrName = term[0]; + ASTNode index = term[1]; + if (0 == arrName.GetIndexWidth()) + { + FatalError("TermToConstTermUsingModel: array has 0 index width: ", arrName); + } + + //READ over a WRITE + if (WRITE == arrName.GetKind()) + { + ASTNode wrtterm = Expand_ReadOverWrite_UsingModel(term, ArrayReadFlag); + if (wrtterm == term) + { + FatalError("TermToConstTermUsingModel: Read_Over_Write term must be expanded into an ITE", term); + } + ASTNode rtterm = TermToConstTermUsingModel(wrtterm, ArrayReadFlag); + return rtterm; + } + //READ over an ITE + if (ITE == arrName.GetKind()) + { + arrName = TermToConstTermUsingModel(arrName, ArrayReadFlag); + } + + ASTNode modelentry; + if (CounterExampleMap.find(index) != CounterExampleMap.end()) + { + //index has a const value in the CounterExampleMap + //ASTNode indexVal = CounterExampleMap[index]; + ASTNode indexVal = TermToConstTermUsingModel(CounterExampleMap[index], ArrayReadFlag); + modelentry = CreateTerm(READ, arrName.GetValueWidth(), arrName, indexVal); + } + else + { + //index does not have a const value in the CounterExampleMap. compute it. + ASTNode indexconstval = TermToConstTermUsingModel(index, ArrayReadFlag); + //update model with value of the index + //CounterExampleMap[index] = indexconstval; + modelentry = CreateTerm(READ, arrName.GetValueWidth(), arrName, indexconstval); + } + //modelentry is now an arrayread over a constant index + BVTypeCheck(modelentry); + + //if a value exists in the CounterExampleMap then return it + if (CounterExampleMap.find(modelentry) != CounterExampleMap.end()) + { + output = TermToConstTermUsingModel(CounterExampleMap[modelentry], ArrayReadFlag); + } + else if (ArrayReadFlag) + { + //return the array read over a constantindex + output = modelentry; + } + else + { + //when all else fails set symbol values to some constant by + //default. if the variable is queried the second time then add 1 + //to and return the new value. + ASTNode zero = CreateZeroConst(modelentry.GetValueWidth()); + output = zero; + } + break; + } + case ITE: + { + ASTNode condcompute = ComputeFormulaUsingModel(term[0]); + if (ASTTrue == condcompute) + { + output = TermToConstTermUsingModel(term[1], ArrayReadFlag); + } + else if (ASTFalse == condcompute) + { + output = TermToConstTermUsingModel(term[2], ArrayReadFlag); + } + else + { + cerr << "TermToConstTermUsingModel: termITE: value of conditional is wrong: " << condcompute << endl; + FatalError(" TermToConstTermUsingModel: termITE: cannot compute ITE conditional against model: ", term); + } + break; + } + default: + { + ASTVec c = term.GetChildren(); + ASTVec o; + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + ASTNode ff = TermToConstTermUsingModel(*it, ArrayReadFlag); + o.push_back(ff); + } + output = CreateTerm(k, term.GetValueWidth(), o); + //output is a CONST expression. compute its value and store it + //in the CounterExampleMap + ASTNode oo = BVConstEvaluator(output); + //the return value + output = oo; + break; + } } - return TermToConstTermUsingModel(val,arrayread_flag); - } - else { - return val; - } - } - - unsigned int width = term.GetValueWidth(); - ASTNode writeA = ASTTrue; - ASTNode newRead = term; - ASTNode readIndex = TermToConstTermUsingModel(newRead[1],false); - //iteratively expand read-over-write, and evaluate against the - //model at every iteration - do { - ASTNode write = newRead[0]; - writeA = write[0]; - ASTNode writeIndex = TermToConstTermUsingModel(write[1],false); - ASTNode writeVal = TermToConstTermUsingModel(write[2],false); - - ASTNode cond = ComputeFormulaUsingModel(CreateSimplifiedEQ(writeIndex,readIndex)); - if(ASTTrue == cond) { - //found the write-value. return it - output = writeVal; + + //when this flag is false, we should compute the arrayread to a + //constant. this constant is stored in the counter_example + //datastructure + if (!ArrayReadFlag) + { + CounterExampleMap[term] = output; + } + + //cerr << "Output to TermToConstTermUsingModel: " << output << endl; + return output; +} //End of TermToConstTermUsingModel + +//Expands read-over-write by evaluating (readIndex=writeIndex) for +//every writeindex until, either it evaluates to TRUE or all +//(readIndex=writeIndex) evaluate to FALSE +ASTNode BeevMgr::Expand_ReadOverWrite_UsingModel(const ASTNode& term, bool arrayread_flag) +{ + if (READ != term.GetKind() && WRITE != term[0].GetKind()) + { + FatalError("RemovesWrites: Input must be a READ over a WRITE", term); + } + + ASTNode output; + ASTNodeMap::iterator it1; + if ((it1 = CounterExampleMap.find(term)) != CounterExampleMap.end()) + { + ASTNode val = it1->second; + if (BVCONST != val.GetKind()) + { + //recursion is fine here. There are two maps that are checked + //here. One is the substitutionmap. We garuntee that the value + //of a key in the substitutionmap is always a constant. + if (term == val) + { + FatalError("TermToConstTermUsingModel: The input term is stored as-is " + "in the CounterExample: Not ok: ", term); + } + return TermToConstTermUsingModel(val, arrayread_flag); + } + else + { + return val; + } + } + + unsigned int width = term.GetValueWidth(); + ASTNode writeA = ASTTrue; + ASTNode newRead = term; + ASTNode readIndex = TermToConstTermUsingModel(newRead[1], false); + //iteratively expand read-over-write, and evaluate against the + //model at every iteration + do + { + ASTNode write = newRead[0]; + writeA = write[0]; + ASTNode writeIndex = TermToConstTermUsingModel(write[1], false); + ASTNode writeVal = TermToConstTermUsingModel(write[2], false); + + ASTNode cond = ComputeFormulaUsingModel(CreateSimplifiedEQ(writeIndex, readIndex)); + if (ASTTrue == cond) + { + //found the write-value. return it + output = writeVal; + CounterExampleMap[term] = output; + return output; + } + + newRead = CreateTerm(READ, width, writeA, readIndex); + } while (READ == newRead.GetKind() && WRITE == newRead[0].GetKind()); + + output = TermToConstTermUsingModel(newRead, arrayread_flag); + + //memoize CounterExampleMap[term] = output; return output; - } - - newRead = CreateTerm(READ,width,writeA,readIndex); - } while(READ == newRead.GetKind() && WRITE == newRead[0].GetKind()); - - output = TermToConstTermUsingModel(newRead,arrayread_flag); - - //memoize - CounterExampleMap[term] = output; - return output; - } //Exand_ReadOverWrite_To_ITE_UsingModel() - - /* FUNCTION: accepts a non-constant formula, and checks if the - * formula is ASTTrue or ASTFalse w.r.t to a model - */ - ASTNode BeevMgr::ComputeFormulaUsingModel(const ASTNode& form) { - ASTNode in = form; - Kind k = form.GetKind(); - if(!(is_Form_kind(k) && BOOLEAN_TYPE == form.GetType())) { - FatalError(" ComputeConstFormUsingModel: The input is a non-formula: ", form); - } - - //cerr << "Input to ComputeFormulaUsingModel:" << form << endl; - ASTNodeMap::iterator it1; - if((it1 = ComputeFormulaMap.find(form)) != ComputeFormulaMap.end()) { - ASTNode res = it1->second; - if(ASTTrue == res || ASTFalse == res) { - return res; - } - else { - FatalError("ComputeFormulaUsingModel: The value of a formula must be TRUE or FALSE:", form); - } - } - - ASTNode t0,t1; - ASTNode output = ASTFalse; - switch(k) { - case TRUE: - case FALSE: - output = form; - break; - case SYMBOL: - if(BOOLEAN_TYPE != form.GetType()) - FatalError(" ComputeFormulaUsingModel: Non-Boolean variables are not formulas",form); - if(CounterExampleMap.find(form) != CounterExampleMap.end()) { - ASTNode counterexample_val = CounterExampleMap[form]; - if(!VarSeenInTerm(form,counterexample_val)) { - output = ComputeFormulaUsingModel(counterexample_val); +} //Exand_ReadOverWrite_To_ITE_UsingModel() + +/* FUNCTION: accepts a non-constant formula, and checks if the + * formula is ASTTrue or ASTFalse w.r.t to a model + */ +ASTNode BeevMgr::ComputeFormulaUsingModel(const ASTNode& form) +{ + ASTNode in = form; + Kind k = form.GetKind(); + if (!(is_Form_kind(k) && BOOLEAN_TYPE == form.GetType())) + { + FatalError(" ComputeConstFormUsingModel: The input is a non-formula: ", form); + } + + //cerr << "Input to ComputeFormulaUsingModel:" << form << endl; + ASTNodeMap::iterator it1; + if ((it1 = ComputeFormulaMap.find(form)) != ComputeFormulaMap.end()) + { + ASTNode res = it1->second; + if (ASTTrue == res || ASTFalse == res) + { + return res; + } + else + { + FatalError("ComputeFormulaUsingModel: The value of a formula must be TRUE or FALSE:", form); + } + } + + ASTNode t0, t1; + ASTNode output = ASTFalse; + switch (k) + { + case TRUE: + case FALSE: + output = form; + break; + case SYMBOL: + if (BOOLEAN_TYPE != form.GetType()) + FatalError(" ComputeFormulaUsingModel: Non-Boolean variables are not formulas", form); + if (CounterExampleMap.find(form) != CounterExampleMap.end()) + { + ASTNode counterexample_val = CounterExampleMap[form]; + if (!VarSeenInTerm(form, counterexample_val)) + { + output = ComputeFormulaUsingModel(counterexample_val); + } + else + { + output = counterexample_val; + } + } + else + output = ASTFalse; + break; + case EQ: + case NEQ: + case BVLT: + case BVLE: + case BVGT: + case BVGE: + case BVSLT: + case BVSLE: + case BVSGT: + case BVSGE: + //convert form[0] into a constant term + t0 = TermToConstTermUsingModel(form[0], false); + //convert form[0] into a constant term + t1 = TermToConstTermUsingModel(form[1], false); + output = BVConstEvaluator(CreateNode(k, t0, t1)); + + //evaluate formula to false if bvdiv execption occurs while + //counterexample is being checked during refinement. + if (bvdiv_exception_occured && counterexample_checking_during_refinement) + { + output = ASTFalse; + } + break; + case NAND: + { + ASTNode o = ASTTrue; + for (ASTVec::const_iterator it = form.begin(), itend = form.end(); it != itend; it++) + if (ASTFalse == ComputeFormulaUsingModel(*it)) + { + o = ASTFalse; + break; + } + if (o == ASTTrue) + output = ASTFalse; + else + output = ASTTrue; + break; + } + case NOR: + { + ASTNode o = ASTFalse; + for (ASTVec::const_iterator it = form.begin(), itend = form.end(); it != itend; it++) + if (ASTTrue == ComputeFormulaUsingModel(*it)) + { + o = ASTTrue; + break; + } + if (o == ASTTrue) + output = ASTFalse; + else + output = ASTTrue; + break; + } + case NOT: + if (ASTTrue == ComputeFormulaUsingModel(form[0])) + output = ASTFalse; + else + output = ASTTrue; + break; + case OR: + for (ASTVec::const_iterator it = form.begin(), itend = form.end(); it != itend; it++) + if (ASTTrue == ComputeFormulaUsingModel(*it)) + output = ASTTrue; + break; + case AND: + output = ASTTrue; + for (ASTVec::const_iterator it = form.begin(), itend = form.end(); it != itend; it++) + { + if (ASTFalse == ComputeFormulaUsingModel(*it)) + { + output = ASTFalse; + break; + } + } + break; + case XOR: + t0 = ComputeFormulaUsingModel(form[0]); + t1 = ComputeFormulaUsingModel(form[1]); + if ((ASTTrue == t0 && ASTTrue == t1) || (ASTFalse == t0 && ASTFalse == t1)) + output = ASTFalse; + else + output = ASTTrue; + break; + case IFF: + t0 = ComputeFormulaUsingModel(form[0]); + t1 = ComputeFormulaUsingModel(form[1]); + if ((ASTTrue == t0 && ASTTrue == t1) || (ASTFalse == t0 && ASTFalse == t1)) + output = ASTTrue; + else + output = ASTFalse; + break; + case IMPLIES: + t0 = ComputeFormulaUsingModel(form[0]); + t1 = ComputeFormulaUsingModel(form[1]); + if ((ASTFalse == t0) || (ASTTrue == t0 && ASTTrue == t1)) + output = ASTTrue; + else + output = ASTFalse; + break; + case ITE: + t0 = ComputeFormulaUsingModel(form[0]); + if (ASTTrue == t0) + output = ComputeFormulaUsingModel(form[1]); + else if (ASTFalse == t0) + output = ComputeFormulaUsingModel(form[2]); + else + FatalError("ComputeFormulaUsingModel: ITE: something is wrong with the formula: ", form); + break; + default: + FatalError(" ComputeFormulaUsingModel: the kind has not been implemented", ASTUndefined); + break; + } + + //cout << "ComputeFormulaUsingModel output is:" << output << endl; + ComputeFormulaMap[form] = output; + return output; +} + +void BeevMgr::CheckCounterExample(bool t) +{ + // FIXME: Code is more useful if enable flags are check OUTSIDE the method. + // If I want to check a counterexample somewhere, I don't want to have to set + // the flag in order to make it actualy happen! + + printf("checking counterexample\n"); + if (!check_counterexample) + { + return; + } + + //input is valid, no counterexample to check + if (ValidFlag) + return; + + //t is true if SAT solver generated a counterexample, else it is false + if (!t) + FatalError("CheckCounterExample: No CounterExample to check", ASTUndefined); + const ASTVec c = GetAsserts(); + for (ASTVec::const_iterator it = c.begin(), itend = c.end(); it != itend; it++) + if (ASTFalse == ComputeFormulaUsingModel(*it)) + FatalError("CheckCounterExample:counterexample bogus:" + "assert evaluates to FALSE under counterexample: NOT OK", *it); + + if (ASTTrue == ComputeFormulaUsingModel(_current_query)) + FatalError("CheckCounterExample:counterexample bogus:" + "query evaluates to TRUE under counterexample: NOT OK", _current_query); +} + +/* FUNCTION: prints a counterexample for INVALID inputs. iterate + * through the CounterExampleMap data structure and print it to + * stdout + */ +void BeevMgr::PrintCounterExample(bool t, std::ostream& os) +{ + //global command-line option + // FIXME: This should always print the counterexample. If you want + // to turn it off, check the switch at the point of call. + if (!print_counterexample) + { + return; + } + + //input is valid, no counterexample to print + if (ValidFlag) + { + return; + } + + //if this option is true then print the way dawson wants using a + //different printer. do not use this printer. + if (print_arrayval_declaredorder) + { + return; + } + + //t is true if SAT solver generated a counterexample, else it is + //false + if (!t) + { + cerr << "PrintCounterExample: No CounterExample to print: " << endl; + return; + } + + //os << "\nCOUNTEREXAMPLE: \n" << endl; + ASTNodeMap::iterator it = CounterExampleMap.begin(); + ASTNodeMap::iterator itend = CounterExampleMap.end(); + for (; it != itend; it++) + { + ASTNode f = it->first; + ASTNode se = it->second; + + if (ARRAY_TYPE == se.GetType()) + { + FatalError("TermToConstTermUsingModel: entry in counterexample is an arraytype. bogus:", se); + } + + //skip over introduced variables + if (f.GetKind() == SYMBOL && (_introduced_symbols.find(f) != _introduced_symbols.end())) + continue; + if (f.GetKind() == SYMBOL || (f.GetKind() == READ && f[0].GetKind() == SYMBOL && f[1].GetKind() == BVCONST)) + { + os << "ASSERT( "; + f.PL_Print(os, 0); + os << " = "; + if (BITVECTOR_TYPE == se.GetType()) + { + TermToConstTermUsingModel(se, false).PL_Print(os, 0); + } + else + { + se.PL_Print(os, 0); + } + os << " );" << endl; + } } - else { - output = counterexample_val; + //os << "\nEND OF COUNTEREXAMPLE" << endl; +} //End of PrintCounterExample + +/* iterate through the CounterExampleMap data structure and print it + * to stdout. this function prints only the declared array variables + * IN the ORDER in which they were declared. It also assumes that + * the variables are of the form 'varname_number'. otherwise it will + * not print anything. This function was specifically written for + * Dawson Engler's group (bug finding research group at Stanford) + */ +void BeevMgr::PrintCounterExample_InOrder(bool t) +{ + //global command-line option to print counterexample. we do not + //want both counterexample printers to print at the sametime. + // FIXME: This should always print the counterexample. If you want + // to turn it off, check the switch at the point of call. + if (print_counterexample) + return; + + //input is valid, no counterexample to print + if (ValidFlag) + return; + + //print if the commandline option is '-q'. allows printing the + //counterexample in order. + if (!print_arrayval_declaredorder) + return; + + //t is true if SAT solver generated a counterexample, else it is + //false + if (!t) + { + cerr << "PrintCounterExample: No CounterExample to print: " << endl; + return; } - } - else - output = ASTFalse; - break; - case EQ: - case NEQ: - case BVLT: - case BVLE: - case BVGT: - case BVGE: - case BVSLT: - case BVSLE: - case BVSGT: - case BVSGE: - //convert form[0] into a constant term - t0 = TermToConstTermUsingModel(form[0],false); - //convert form[0] into a constant term - t1 = TermToConstTermUsingModel(form[1],false); - output = BVConstEvaluator(CreateNode(k,t0,t1)); - - //evaluate formula to false if bvdiv execption occurs while - //counterexample is being checked during refinement. - if(bvdiv_exception_occured && - counterexample_checking_during_refinement) { - output = ASTFalse; - } - break; - case NAND: { - ASTNode o = ASTTrue; - for(ASTVec::const_iterator it=form.begin(),itend=form.end();it!=itend;it++) - if(ASTFalse == ComputeFormulaUsingModel(*it)) { - o = ASTFalse; - break; - } - if(o == ASTTrue) - output = ASTFalse; - else - output = ASTTrue; - break; - } - case NOR: { - ASTNode o = ASTFalse; - for(ASTVec::const_iterator it=form.begin(),itend=form.end();it!=itend;it++) - if(ASTTrue == ComputeFormulaUsingModel(*it)) { - o = ASTTrue; - break; + + //vector to store the integer values + std::vector out_int; + cout << "% "; + for (ASTVec::iterator it = _special_print_set.begin(), itend = _special_print_set.end(); it != itend; it++) + { + if (ARRAY_TYPE == it->GetType()) + { + //get the name of the variable + const char * c = it->GetName(); + std::string ss(c); + if (!(0 == strncmp(ss.c_str(), "ini_", 4))) + continue; + reverse(ss.begin(), ss.end()); + + //cout << "debugging: " << ss; + size_t pos = ss.find('_', 0); + if (!((0 < pos) && (pos < ss.size()))) + continue; + + //get the associated length + std::string sss = ss.substr(0, pos); + reverse(sss.begin(), sss.end()); + int n = atoi(sss.c_str()); + + it->PL_Print(cout, 2); + for (int j = 0; j < n; j++) + { + ASTNode index = CreateBVConst(it->GetIndexWidth(), j); + ASTNode readexpr = CreateTerm(READ, it->GetValueWidth(), *it, index); + ASTNode val = GetCounterExample(t, readexpr); + //cout << "ASSERT( "; + //cout << " = "; + out_int.push_back(GetUnsignedConst(val)); + //cout << "\n"; + } + } } - if(o == ASTTrue) - output = ASTFalse; - else - output = ASTTrue; - break; - } - case NOT: - if(ASTTrue == ComputeFormulaUsingModel(form[0])) - output = ASTFalse; - else - output = ASTTrue; - break; - case OR: - for(ASTVec::const_iterator it=form.begin(),itend=form.end();it!=itend;it++) - if(ASTTrue == ComputeFormulaUsingModel(*it)) - output = ASTTrue; - break; - case AND: - output = ASTTrue; - for(ASTVec::const_iterator it=form.begin(),itend=form.end();it!=itend;it++) { - if(ASTFalse == ComputeFormulaUsingModel(*it)) { - output = ASTFalse; - break; + cout << endl; + for (unsigned int jj = 0; jj < out_int.size(); jj++) + cout << out_int[jj] << endl; + cout << endl; +} //End of PrintCounterExample_InOrder + +/* FUNCTION: queries the CounterExampleMap object with 'expr' and + * returns the corresponding counterexample value. + */ +ASTNode BeevMgr::GetCounterExample(bool t, const ASTNode& expr) +{ + //input is valid, no counterexample to get + if (ValidFlag) + return ASTUndefined; + + if (BOOLEAN_TYPE == expr.GetType()) + { + return ComputeFormulaUsingModel(expr); } - } - break; - case XOR: - t0 = ComputeFormulaUsingModel(form[0]); - t1 = ComputeFormulaUsingModel(form[1]); - if((ASTTrue == t0 && ASTTrue == t1) || (ASTFalse == t0 && ASTFalse == t1)) - output = ASTFalse; - else - output = ASTTrue; - break; - case IFF: - t0 = ComputeFormulaUsingModel(form[0]); - t1 = ComputeFormulaUsingModel(form[1]); - if((ASTTrue == t0 && ASTTrue == t1) || (ASTFalse == t0 && ASTFalse == t1)) - output = ASTTrue; - else - output = ASTFalse; - break; - case IMPLIES: - t0 = ComputeFormulaUsingModel(form[0]); - t1 = ComputeFormulaUsingModel(form[1]); - if((ASTFalse == t0) || (ASTTrue == t0 && ASTTrue == t1)) - output = ASTTrue; - else - output = ASTFalse; - break; - case ITE: - t0 = ComputeFormulaUsingModel(form[0]); - if(ASTTrue == t0) - output = ComputeFormulaUsingModel(form[1]); - else if(ASTFalse == t0) - output = ComputeFormulaUsingModel(form[2]); - else - FatalError("ComputeFormulaUsingModel: ITE: something is wrong with the formula: ",form); - break; - default: - FatalError(" ComputeFormulaUsingModel: the kind has not been implemented", ASTUndefined); - break; - } - - //cout << "ComputeFormulaUsingModel output is:" << output << endl; - ComputeFormulaMap[form] = output; - return output; - } - - void BeevMgr::CheckCounterExample(bool t) { - // FIXME: Code is more useful if enable flags are check OUTSIDE the method. - // If I want to check a counterexample somewhere, I don't want to have to set - // the flag in order to make it actualy happen! - - printf("checking counterexample\n"); - if(!check_counterexample) { - return; - } - - //input is valid, no counterexample to check - if(ValidFlag) - return; - - //t is true if SAT solver generated a counterexample, else it is false - if(!t) - FatalError("CheckCounterExample: No CounterExample to check", ASTUndefined); - const ASTVec c = GetAsserts(); - for(ASTVec::const_iterator it=c.begin(),itend=c.end();it!=itend;it++) - if(ASTFalse == ComputeFormulaUsingModel(*it)) - FatalError("CheckCounterExample:counterexample bogus:"\ - "assert evaluates to FALSE under counterexample: NOT OK",*it); - - if(ASTTrue == ComputeFormulaUsingModel(_current_query)) - FatalError("CheckCounterExample:counterexample bogus:"\ - "query evaluates to TRUE under counterexample: NOT OK",_current_query); - } - - /* FUNCTION: prints a counterexample for INVALID inputs. iterate - * through the CounterExampleMap data structure and print it to - * stdout - */ - void BeevMgr::PrintCounterExample(bool t, std::ostream& os) { - //global command-line option - // FIXME: This should always print the counterexample. If you want - // to turn it off, check the switch at the point of call. - if(!print_counterexample){ - return; - } - - //input is valid, no counterexample to print - if(ValidFlag){ - return; - } - - //if this option is true then print the way dawson wants using a - //different printer. do not use this printer. - if(print_arrayval_declaredorder){ - return; - } - - //t is true if SAT solver generated a counterexample, else it is - //false - if(!t) { - cerr << "PrintCounterExample: No CounterExample to print: " << endl; - return; - } - - //os << "\nCOUNTEREXAMPLE: \n" << endl; - ASTNodeMap::iterator it = CounterExampleMap.begin(); - ASTNodeMap::iterator itend = CounterExampleMap.end(); - for(;it!=itend;it++) { - ASTNode f = it->first; - ASTNode se = it->second; - - if(ARRAY_TYPE == se.GetType()) { - FatalError("TermToConstTermUsingModel: entry in counterexample is an arraytype. bogus:",se); - } - - //skip over introduced variables - if(f.GetKind() == SYMBOL && (_introduced_symbols.find(f) != _introduced_symbols.end())) - continue; - if(f.GetKind() == SYMBOL || - (f.GetKind() == READ && f[0].GetKind() == SYMBOL && f[1].GetKind() == BVCONST)) { - os << "ASSERT( "; - f.PL_Print(os,0); - os << " = "; - if(BITVECTOR_TYPE == se.GetType()) { - TermToConstTermUsingModel(se,false).PL_Print(os,0); + + if (BVCONST == expr.GetKind()) + { + return expr; } - else { - se.PL_Print(os,0); + + ASTNodeMap::iterator it; + ASTNode output; + if ((it = CounterExampleMap.find(expr)) != CounterExampleMap.end()) + output = TermToConstTermUsingModel(CounterExampleMap[expr], false); + else + output = CreateZeroConst(expr.GetValueWidth()); + return output; +} //End of GetCounterExample + +//################################################## +//################################################## + +// FIXME: Don't use numeric codes. Use an enum type! +//Acceps a query, calls the SAT solver and generates Valid/InValid. +//if returned 0 then input is INVALID +//if returned 1 then input is VALID +//if returned 2 then ERROR +int BeevMgr::TopLevelSATAux(const ASTNode& inputasserts) +{ + ASTNode q = inputasserts; + ASTNode orig_input = q; + ASTNodeStats("input asserts and query: ", q); + + ASTNode newq = q; + //round of substitution, solving, and simplification. ensures that + //DAG is minimized as much as possibly, and ideally should + //garuntee that all liketerms in BVPLUSes have been combined. + BVSolver bvsolver(this); + SimplifyWrites_InPlace_Flag = false; + Begin_RemoveWrites = false; + start_abstracting = false; + TermsAlreadySeenMap.clear(); + do + { + q = newq; + newq = CreateSubstitutionMap(newq); + //printf("##################################################\n"); + //ASTNodeStats("after pure substitution: ", newq); + newq = SimplifyFormula_TopLevel(newq, false); + //ASTNodeStats("after simplification: ", newq); + newq = bvsolver.TopLevelBVSolve(newq); + //ASTNodeStats("after solving: ", newq); + } while (q != newq); + + ASTNodeStats("Before SimplifyWrites_Inplace begins: ", newq); + SimplifyWrites_InPlace_Flag = true; + Begin_RemoveWrites = false; + start_abstracting = false; + TermsAlreadySeenMap.clear(); + do + { + q = newq; + newq = CreateSubstitutionMap(newq); + //ASTNodeStats("after pure substitution: ", newq); + newq = SimplifyFormula_TopLevel(newq, false); + //ASTNodeStats("after simplification: ", newq); + newq = bvsolver.TopLevelBVSolve(newq); + //ASTNodeStats("after solving: ", newq); + } while (q != newq); + ASTNodeStats("After SimplifyWrites_Inplace: ", newq); + + start_abstracting = (arraywrite_refinement) ? true : false; + SimplifyWrites_InPlace_Flag = false; + Begin_RemoveWrites = (start_abstracting) ? false : true; + if (start_abstracting) + { + ASTNodeStats("before abstraction round begins: ", newq); } - os << " );" << endl; - } - } - //os << "\nEND OF COUNTEREXAMPLE" << endl; - } //End of PrintCounterExample - - /* iterate through the CounterExampleMap data structure and print it - * to stdout. this function prints only the declared array variables - * IN the ORDER in which they were declared. It also assumes that - * the variables are of the form 'varname_number'. otherwise it will - * not print anything. This function was specifically written for - * Dawson Engler's group (bug finding research group at Stanford) - */ - void BeevMgr::PrintCounterExample_InOrder(bool t) { - //global command-line option to print counterexample. we do not - //want both counterexample printers to print at the sametime. - // FIXME: This should always print the counterexample. If you want - // to turn it off, check the switch at the point of call. - if(print_counterexample) - return; - - //input is valid, no counterexample to print - if(ValidFlag) - return; - - //print if the commandline option is '-q'. allows printing the - //counterexample in order. - if(!print_arrayval_declaredorder) - return; - - //t is true if SAT solver generated a counterexample, else it is - //false - if(!t) { - cerr << "PrintCounterExample: No CounterExample to print: " << endl; - return; - } - - //vector to store the integer values - std::vector out_int; - cout << "% "; - for(ASTVec::iterator it=_special_print_set.begin(),itend=_special_print_set.end(); - it!=itend;it++) { - if(ARRAY_TYPE == it->GetType()) { - //get the name of the variable - const char * c = it->GetName(); - std::string ss(c); - if(!(0 == strncmp(ss.c_str(),"ini_",4))) - continue; - reverse(ss.begin(),ss.end()); - - //cout << "debugging: " << ss; - size_t pos = ss.find('_',0); - if(!((0 < pos) && (pos < ss.size()))) - continue; - - //get the associated length - std::string sss = ss.substr(0,pos); - reverse(sss.begin(),sss.end()); - int n = atoi(sss.c_str()); - - it->PL_Print(cout,2); - for(int j=0;j < n; j++) { - ASTNode index = CreateBVConst(it->GetIndexWidth(),j); - ASTNode readexpr = CreateTerm(READ,it->GetValueWidth(),*it,index); - ASTNode val = GetCounterExample(t, readexpr); - //cout << "ASSERT( "; - //cout << " = "; - out_int.push_back(GetUnsignedConst(val)); - //cout << "\n"; + + TermsAlreadySeenMap.clear(); + do + { + q = newq; + //newq = CreateSubstitutionMap(newq); + //Begin_RemoveWrites = true; + //ASTNodeStats("after pure substitution: ", newq); + newq = SimplifyFormula_TopLevel(newq, false); + //ASTNodeStats("after simplification: ", newq); + //newq = bvsolver.TopLevelBVSolve(newq); + //ASTNodeStats("after solving: ", newq); + } while (q != newq); + + if (start_abstracting) + { + ASTNodeStats("After abstraction: ", newq); } - } - } - cout << endl; - for(unsigned int jj=0; jj < out_int.size();jj++) - cout << out_int[jj] << endl; - cout << endl; - } //End of PrintCounterExample_InOrder - - /* FUNCTION: queries the CounterExampleMap object with 'expr' and - * returns the corresponding counterexample value. - */ - ASTNode BeevMgr::GetCounterExample(bool t, const ASTNode& expr) { - //input is valid, no counterexample to get - if(ValidFlag) - return ASTUndefined; - - if(BOOLEAN_TYPE == expr.GetType()) { - return ComputeFormulaUsingModel(expr); - } - - if(BVCONST == expr.GetKind()) { - return expr; - } - - ASTNodeMap::iterator it; - ASTNode output; - if((it = CounterExampleMap.find(expr)) != CounterExampleMap.end()) - output = TermToConstTermUsingModel(CounterExampleMap[expr],false); - else - output = CreateZeroConst(expr.GetValueWidth()); - return output; - } //End of GetCounterExample - - //################################################## - //################################################## - - // FIXME: Don't use numeric codes. Use an enum type! - //Acceps a query, calls the SAT solver and generates Valid/InValid. - //if returned 0 then input is INVALID - //if returned 1 then input is VALID - //if returned 2 then ERROR - int BeevMgr::TopLevelSATAux( const ASTNode& inputasserts) { - ASTNode q = inputasserts; - ASTNode orig_input = q; - ASTNodeStats("input asserts and query: ", q); - - ASTNode newq = q; - //round of substitution, solving, and simplification. ensures that - //DAG is minimized as much as possibly, and ideally should - //garuntee that all liketerms in BVPLUSes have been combined. - BVSolver bvsolver(this); - SimplifyWrites_InPlace_Flag = false; - Begin_RemoveWrites = false; - start_abstracting = false; - TermsAlreadySeenMap.clear(); - do { - q = newq; - newq = CreateSubstitutionMap(newq); - //printf("##################################################\n"); - //ASTNodeStats("after pure substitution: ", newq); - newq = SimplifyFormula_TopLevel(newq,false); - //ASTNodeStats("after simplification: ", newq); - newq = bvsolver.TopLevelBVSolve(newq); - //ASTNodeStats("after solving: ", newq); - }while(q!=newq); - - - ASTNodeStats("Before SimplifyWrites_Inplace begins: ", newq); - SimplifyWrites_InPlace_Flag = true; - Begin_RemoveWrites = false; - start_abstracting = false; - TermsAlreadySeenMap.clear(); - do { - q = newq; - newq = CreateSubstitutionMap(newq); - //ASTNodeStats("after pure substitution: ", newq); - newq = SimplifyFormula_TopLevel(newq,false); - //ASTNodeStats("after simplification: ", newq); - newq = bvsolver.TopLevelBVSolve(newq); - //ASTNodeStats("after solving: ", newq); - }while(q!=newq); - ASTNodeStats("After SimplifyWrites_Inplace: ", newq); - - start_abstracting = (arraywrite_refinement) ? true : false; - SimplifyWrites_InPlace_Flag = false; - Begin_RemoveWrites = (start_abstracting) ? false : true; - if(start_abstracting) { - ASTNodeStats("before abstraction round begins: ", newq); - } - - TermsAlreadySeenMap.clear(); - do { - q = newq; - //newq = CreateSubstitutionMap(newq); - //Begin_RemoveWrites = true; - //ASTNodeStats("after pure substitution: ", newq); - newq = SimplifyFormula_TopLevel(newq,false); - //ASTNodeStats("after simplification: ", newq); - //newq = bvsolver.TopLevelBVSolve(newq); - //ASTNodeStats("after solving: ", newq); - }while(q!=newq); - - if(start_abstracting) { - ASTNodeStats("After abstraction: ", newq); - } - start_abstracting = false; - SimplifyWrites_InPlace_Flag = false; - Begin_RemoveWrites = false; - - newq = TransformFormula(newq); - ASTNodeStats("after transformation: ", newq); - TermsAlreadySeenMap.clear(); - - int res; - //solver instantiated here - MINISAT::Solver newS; - if(arrayread_refinement) { - counterexample_checking_during_refinement = true; - } - - res = CallSAT_ResultCheck(newS,newq,orig_input); - if(2 != res) { - CountersAndStats("print_func_stats"); - return res; - } - - res = SATBased_ArrayReadRefinement(newS,newq,orig_input); - if(2 != res) { - CountersAndStats("print_func_stats"); - return res; - } - - res = SATBased_ArrayWriteRefinement(newS,orig_input); - if(2 != res) { - CountersAndStats("print_func_stats"); - return res; - } - - res = SATBased_ArrayReadRefinement(newS,newq,orig_input); - if(2 != res) { - CountersAndStats("print_func_stats"); - return res; - } - - FatalError("TopLevelSAT: reached the end without proper conclusion:" - "either a divide by zero in the input or a bug in STP"); - //bogus return to make the compiler shut up - return 2; - } //End of TopLevelSAT - - //go over the list of indices for each array, and generate Leibnitz - //axioms. Then assert these axioms into the SAT solver. Check if the - //addition of the new constraints has made the bogus counterexample - //go away. if yes, return the correct answer. if no, continue adding - //Leibnitz axioms systematically. - // FIXME: What it really does is, for each array, loop over each index i. - // inside that loop, it finds all the true and false axioms with i as first - // index. When it's got them all, it adds the false axioms to the formula - // and re-solves, and returns if the result is correct. Otherwise, it - // goes on to the next index. - // If it gets through all the indices without a correct result (which I think - // is impossible, but this is pretty confusing), it then solves with all - // the true axioms, too. - // This is not the most obvious way to do it, and I don't know how it - // compares with other approaches (e.g., one false axiom at a time or - // all the false axioms each time). - int BeevMgr::SATBased_ArrayReadRefinement(MINISAT::Solver& newS, - const ASTNode& q, const ASTNode& orig_input) { - //printf("doing array read refinement\n"); - if(!arrayread_refinement) - FatalError("SATBased_ArrayReadRefinement: Control should not reach here"); - - ASTVec FalseAxiomsVec, RemainingAxiomsVec; - RemainingAxiomsVec.push_back(ASTTrue); - FalseAxiomsVec.push_back(ASTTrue); - unsigned int oldFalseAxiomsSize = 0; - - //in these loops we try to construct Leibnitz axioms and add it to - //the solve(). We add only those axioms that are false in the - //current counterexample. we keep adding the axioms until there - //are no more axioms to add - // - //for each array, fetch its list of indices seen so far - for(ASTNodeToVecMap::iterator iset = _arrayname_readindices.begin(), iset_end = _arrayname_readindices.end(); - iset!=iset_end;iset++) { - ASTVec listOfIndices = iset->second; - //loop over the list of indices for the array and create LA, and add to q - for(ASTVec::iterator it=listOfIndices.begin(),itend=listOfIndices.end();it!=itend;it++) { - if(BVCONST == it->GetKind()) { - continue; - } - - ASTNode the_index = *it; - //get the arrayname - ASTNode ArrName = iset->first; - // if(SYMBOL != ArrName.GetKind()) - // FatalError("SATBased_ArrayReadRefinement: arrname is not a SYMBOL",ArrName); - ASTNode arr_read1 = CreateTerm(READ, ArrName.GetValueWidth(), ArrName, the_index); - //get the variable corresponding to the array_read1 - ASTNode arrsym1 = _arrayread_symbol[arr_read1]; - if(!(SYMBOL == arrsym1.GetKind() || BVCONST == arrsym1.GetKind())) - FatalError("TopLevelSAT: refinementloop:term arrsym1 corresponding to READ must be a var", arrsym1); - - //we have nonconst index here. create Leibnitz axiom for it - //w.r.t every index in listOfIndices - for(ASTVec::iterator it1=listOfIndices.begin(),itend1=listOfIndices.end(); - it1!=itend1;it1++) { - ASTNode compare_index = *it1; - //do not compare with yourself - if(the_index == compare_index) - continue; - - //prepare for SAT LOOP - //first construct the antecedent for the LA axiom - ASTNode eqOfIndices = - (exprless(the_index,compare_index)) ? - CreateSimplifiedEQ(the_index,compare_index) : CreateSimplifiedEQ(compare_index,the_index); - - ASTNode arr_read2 = CreateTerm(READ, ArrName.GetValueWidth(), ArrName, compare_index); - //get the variable corresponding to the array_read2 - ASTNode arrsym2 = _arrayread_symbol[arr_read2]; - if(!(SYMBOL == arrsym2.GetKind() || BVCONST == arrsym2.GetKind())) - FatalError("TopLevelSAT: refinement loop:" - "term arrsym2 corresponding to READ must be a var", arrsym2); - - ASTNode eqOfReads = CreateSimplifiedEQ(arrsym1,arrsym2); - //construct appropriate Leibnitz axiom - ASTNode LeibnitzAxiom = CreateNode(IMPLIES, eqOfIndices, eqOfReads); - if(ASTFalse == ComputeFormulaUsingModel(LeibnitzAxiom)) - //FalseAxioms = CreateNode(AND,FalseAxioms,LeibnitzAxiom); - FalseAxiomsVec.push_back(LeibnitzAxiom); - else - //RemainingAxioms = CreateNode(AND,RemainingAxioms,LeibnitzAxiom); - RemainingAxiomsVec.push_back(LeibnitzAxiom); + start_abstracting = false; + SimplifyWrites_InPlace_Flag = false; + Begin_RemoveWrites = false; + + newq = TransformFormula(newq); + ASTNodeStats("after transformation: ", newq); + TermsAlreadySeenMap.clear(); + + int res; + //solver instantiated here + MINISAT::Solver newS; + if (arrayread_refinement) + { + counterexample_checking_during_refinement = true; } - ASTNode FalseAxioms = (FalseAxiomsVec.size()>1) ? CreateNode(AND,FalseAxiomsVec) : FalseAxiomsVec[0]; - ASTNodeStats("adding false readaxioms to SAT: ", FalseAxioms); - //printf("spot 01\n"); - int res2 = 2; - if(FalseAxiomsVec.size() > oldFalseAxiomsSize){ - res2 = CallSAT_ResultCheck(newS,FalseAxioms,orig_input); - oldFalseAxiomsSize = FalseAxiomsVec.size(); - } - //printf("spot 02, res2 = %d\n", res2); - if(2!=res2) { - return res2; - } - } - } - ASTNode RemainingAxioms = (RemainingAxiomsVec.size()>1) ? CreateNode(AND,RemainingAxiomsVec):RemainingAxiomsVec[0]; - ASTNodeStats("adding remaining readaxioms to SAT: ", RemainingAxioms); - return CallSAT_ResultCheck(newS,RemainingAxioms,orig_input); - } //end of SATBased_ArrayReadRefinement - - ASTNode BeevMgr::Create_ArrayWriteAxioms(const ASTNode& term, const ASTNode& newvar) { - if(READ != term.GetKind() && WRITE != term[0].GetKind()) { - FatalError("Create_ArrayWriteAxioms: Input must be a READ over a WRITE",term); - } - - ASTNode lhs = newvar; - ASTNode rhs = term; - ASTNode arraywrite_axiom = CreateSimplifiedEQ(lhs,rhs); - return arraywrite_axiom; - }//end of Create_ArrayWriteAxioms() - - int BeevMgr::SATBased_ArrayWriteRefinement(MINISAT::Solver& newS, const ASTNode& orig_input) { - ASTNode writeAxiom; - ASTNodeMap::iterator it = ReadOverWrite_NewName_Map.begin(); - ASTNodeMap::iterator itend = ReadOverWrite_NewName_Map.end(); - unsigned int oldFalseAxiomsSize = 0; - //int count = 0; - //int num_write_axioms = ReadOverWrite_NewName_Map.size(); - - ASTVec FalseAxioms, RemainingAxioms; - FalseAxioms.push_back(ASTTrue); - RemainingAxioms.push_back(ASTTrue); - for(;it!=itend;it++) { - //Guided refinement starts here - ComputeFormulaMap.clear(); - writeAxiom = Create_ArrayWriteAxioms(it->first,it->second); - if(ASTFalse == ComputeFormulaUsingModel(writeAxiom)) { - writeAxiom = TransformFormula(writeAxiom); - FalseAxioms.push_back(writeAxiom); - } - else { - writeAxiom = TransformFormula(writeAxiom); - RemainingAxioms.push_back(writeAxiom); - } - } - - writeAxiom = (FalseAxioms.size() != 1) ? CreateNode(AND,FalseAxioms) : FalseAxioms[0]; - ASTNodeStats("adding false writeaxiom to SAT: ", writeAxiom); - int res2 = 2; - if(FalseAxioms.size() > oldFalseAxiomsSize){ - res2 = CallSAT_ResultCheck(newS,writeAxiom,orig_input); - oldFalseAxiomsSize = FalseAxioms.size(); - } - if(2!=res2) { - return res2; - } - - writeAxiom = (RemainingAxioms.size() != 1) ? CreateNode(AND,RemainingAxioms) : RemainingAxioms[0]; - ASTNodeStats("adding remaining writeaxiom to SAT: ", writeAxiom); - res2 = CallSAT_ResultCheck(newS,writeAxiom,orig_input); - if(2!=res2) { - return res2; - } - - return 2; - } //end of SATBased_ArrayWriteRefinement -#ifdef PHONY - //Check result after calling SAT FIXME: Document arguments in - //comments, and give them meaningful names. How is anyone supposed - //to know what "q" is? - int BeevMgr::CallSAT_ResultCheck(MINISAT::Solver& newS, - const ASTNode& q, const ASTNode& orig_input) { - //Bitblast, CNF, call SAT now - ASTNode BBFormula = BBForm(q); - //ASTNodeStats("after bitblasting", BBFormula); - //ClauseList *cllp = ToCNF(BBFormula); - // if(stats && print_nodes) { - // cout << "\nClause list" << endl; - // PrintClauseList(cout, *cllp); - // cerr << "\n finished printing clauselist\n"; - // } - - //**************************************** - // TOCNF CONVERSION - //**************************************** - CNFMgr *cm = new CNFMgr(this); - - ClauseList* cllp = new ClauseList(); - cm->NOCOPY_INPLACE_UNION(cllp, cm->SINGLETON(cm->dummy_true_var)); - cm->CountSharesPos(BBFormula); - cm->ToCNFModRenamingPos(BBFormula); - cm->INPLACE_UNION(cllp, *((cm->ClausesPos)[BBFormula])); - cm->AddDefs(cllp); - //**************************************** - // TOCNF CONVERSION - //**************************************** - - bool sat = toSATandSolve(newS,*cllp); - // Temporary debugging call. - // CheckBBandCNF(newS, BBFormula); - - //**************************************** - // TOCNF CLEANUP - //**************************************** - cm->CLEAR(); - cm->DELETE(cllp); - delete cm; - //**************************************** - // TOCNF CLEANUP - //**************************************** - - if(!sat) { - PrintOutput(true); - return 1; - } - else if(newS.okay()) { - CounterExampleMap.clear(); - ConstructCounterExample(newS); - if (stats && print_nodes) { - PrintSATModel(newS); - } - //check if the counterexample is good or not - ComputeFormulaMap.clear(); - if(counterexample_checking_during_refinement) - bvdiv_exception_occured = false; - ASTNode orig_result = ComputeFormulaUsingModel(orig_input); - if(!(ASTTrue == orig_result || ASTFalse == orig_result)) - FatalError("TopLevelSat: Original input must compute to true or false against model"); - -// if(!arrayread_refinement && !(ASTTrue == orig_result)) { -// print_counterexample = true; -// PrintCounterExample(true); -// FatalError("counterexample bogus : arrayread_refinement is switched off: " -// "EITHER all LA axioms have not been added OR bitblaster() or ToCNF()" -// "or satsolver() or counterexamplechecker() have a bug"); -// } - - // if the counterexample is indeed a good one, then return - // invalid - if(ASTTrue == orig_result) { - CheckCounterExample(newS.okay()); - PrintOutput(false); - PrintCounterExample(newS.okay()); - PrintCounterExample_InOrder(newS.okay()); - return 0; - } - // counterexample is bogus: flag it - else { - if(stats && print_nodes) { - cout << "Supposedly bogus one: \n"; - bool tmp = print_counterexample; - print_counterexample = true; - PrintCounterExample(true); - print_counterexample = tmp; + res = CallSAT_ResultCheck(newS, newq, orig_input); + if (2 != res) + { + CountersAndStats("print_func_stats"); + return res; } + res = SATBased_ArrayReadRefinement(newS, newq, orig_input); + if (2 != res) + { + CountersAndStats("print_func_stats"); + return res; + } + + res = SATBased_ArrayWriteRefinement(newS, orig_input); + if (2 != res) + { + CountersAndStats("print_func_stats"); + return res; + } + + res = SATBased_ArrayReadRefinement(newS, newq, orig_input); + if (2 != res) + { + CountersAndStats("print_func_stats"); + return res; + } + + FatalError("TopLevelSAT: reached the end without proper conclusion:" + "either a divide by zero in the input or a bug in STP"); + //bogus return to make the compiler shut up return 2; - } - } - else { - PrintOutput(true); - return -100; - } - } //end of CALLSAT_ResultCheck -#endif +} //End of TopLevelSAT + +//go over the list of indices for each array, and generate Leibnitz +//axioms. Then assert these axioms into the SAT solver. Check if the +//addition of the new constraints has made the bogus counterexample +//go away. if yes, return the correct answer. if no, continue adding +//Leibnitz axioms systematically. +// FIXME: What it really does is, for each array, loop over each index i. +// inside that loop, it finds all the true and false axioms with i as first +// index. When it's got them all, it adds the false axioms to the formula +// and re-solves, and returns if the result is correct. Otherwise, it +// goes on to the next index. +// If it gets through all the indices without a correct result (which I think +// is impossible, but this is pretty confusing), it then solves with all +// the true axioms, too. +// This is not the most obvious way to do it, and I don't know how it +// compares with other approaches (e.g., one false axiom at a time or +// all the false axioms each time). +int BeevMgr::SATBased_ArrayReadRefinement(MINISAT::Solver& newS, const ASTNode& q, const ASTNode& orig_input) +{ + //printf("doing array read refinement\n"); + if (!arrayread_refinement) + FatalError("SATBased_ArrayReadRefinement: Control should not reach here"); + + ASTVec FalseAxiomsVec, RemainingAxiomsVec; + RemainingAxiomsVec.push_back(ASTTrue); + FalseAxiomsVec.push_back(ASTTrue); + unsigned int oldFalseAxiomsSize = 0; + + //in these loops we try to construct Leibnitz axioms and add it to + //the solve(). We add only those axioms that are false in the + //current counterexample. we keep adding the axioms until there + //are no more axioms to add + // + //for each array, fetch its list of indices seen so far + for (ASTNodeToVecMap::iterator iset = _arrayname_readindices.begin(), iset_end = _arrayname_readindices.end(); iset != iset_end; iset++) + { + ASTVec listOfIndices = iset->second; + //loop over the list of indices for the array and create LA, and add to q + for (ASTVec::iterator it = listOfIndices.begin(), itend = listOfIndices.end(); it != itend; it++) + { + if (BVCONST == it->GetKind()) + { + continue; + } + + ASTNode the_index = *it; + //get the arrayname + ASTNode ArrName = iset->first; + // if(SYMBOL != ArrName.GetKind()) + // FatalError("SATBased_ArrayReadRefinement: arrname is not a SYMBOL",ArrName); + ASTNode arr_read1 = CreateTerm(READ, ArrName.GetValueWidth(), ArrName, the_index); + //get the variable corresponding to the array_read1 + ASTNode arrsym1 = _arrayread_symbol[arr_read1]; + if (!(SYMBOL == arrsym1.GetKind() || BVCONST == arrsym1.GetKind())) + FatalError("TopLevelSAT: refinementloop:term arrsym1 corresponding to READ must be a var", arrsym1); + + //we have nonconst index here. create Leibnitz axiom for it + //w.r.t every index in listOfIndices + for (ASTVec::iterator it1 = listOfIndices.begin(), itend1 = listOfIndices.end(); it1 != itend1; it1++) + { + ASTNode compare_index = *it1; + //do not compare with yourself + if (the_index == compare_index) + continue; + + //prepare for SAT LOOP + //first construct the antecedent for the LA axiom + ASTNode eqOfIndices = (exprless(the_index, compare_index)) ? CreateSimplifiedEQ(the_index, compare_index) : CreateSimplifiedEQ( + compare_index, the_index); + + ASTNode arr_read2 = CreateTerm(READ, ArrName.GetValueWidth(), ArrName, compare_index); + //get the variable corresponding to the array_read2 + ASTNode arrsym2 = _arrayread_symbol[arr_read2]; + if (!(SYMBOL == arrsym2.GetKind() || BVCONST == arrsym2.GetKind())) + FatalError("TopLevelSAT: refinement loop:" + "term arrsym2 corresponding to READ must be a var", arrsym2); + + ASTNode eqOfReads = CreateSimplifiedEQ(arrsym1, arrsym2); + //construct appropriate Leibnitz axiom + ASTNode LeibnitzAxiom = CreateNode(IMPLIES, eqOfIndices, eqOfReads); + if (ASTFalse == ComputeFormulaUsingModel(LeibnitzAxiom)) + //FalseAxioms = CreateNode(AND,FalseAxioms,LeibnitzAxiom); + FalseAxiomsVec.push_back(LeibnitzAxiom); + else + //RemainingAxioms = CreateNode(AND,RemainingAxioms,LeibnitzAxiom); + RemainingAxiomsVec.push_back(LeibnitzAxiom); + } + ASTNode FalseAxioms = (FalseAxiomsVec.size() > 1) ? CreateNode(AND, FalseAxiomsVec) : FalseAxiomsVec[0]; + ASTNodeStats("adding false readaxioms to SAT: ", FalseAxioms); + //printf("spot 01\n"); + int res2 = 2; + if (FalseAxiomsVec.size() > oldFalseAxiomsSize) + { + res2 = CallSAT_ResultCheck(newS, FalseAxioms, orig_input); + oldFalseAxiomsSize = FalseAxiomsVec.size(); + } + //printf("spot 02, res2 = %d\n", res2); + if (2 != res2) + { + return res2; + } + } + } + ASTNode RemainingAxioms = (RemainingAxiomsVec.size() > 1) ? CreateNode(AND, RemainingAxiomsVec) : RemainingAxiomsVec[0]; + ASTNodeStats("adding remaining readaxioms to SAT: ", RemainingAxioms); + return CallSAT_ResultCheck(newS, RemainingAxioms, orig_input); +} //end of SATBased_ArrayReadRefinement + +ASTNode BeevMgr::Create_ArrayWriteAxioms(const ASTNode& term, const ASTNode& newvar) +{ + if (READ != term.GetKind() && WRITE != term[0].GetKind()) + { + FatalError("Create_ArrayWriteAxioms: Input must be a READ over a WRITE", term); + } + ASTNode lhs = newvar; + ASTNode rhs = term; + ASTNode arraywrite_axiom = CreateSimplifiedEQ(lhs, rhs); + return arraywrite_axiom; +}//end of Create_ArrayWriteAxioms() + +int BeevMgr::SATBased_ArrayWriteRefinement(MINISAT::Solver& newS, const ASTNode& orig_input) +{ + ASTNode writeAxiom; + ASTNodeMap::iterator it = ReadOverWrite_NewName_Map.begin(); + ASTNodeMap::iterator itend = ReadOverWrite_NewName_Map.end(); + unsigned int oldFalseAxiomsSize = 0; + //int count = 0; + //int num_write_axioms = ReadOverWrite_NewName_Map.size(); + + ASTVec FalseAxioms, RemainingAxioms; + FalseAxioms.push_back(ASTTrue); + RemainingAxioms.push_back(ASTTrue); + for (; it != itend; it++) + { + //Guided refinement starts here + ComputeFormulaMap.clear(); + writeAxiom = Create_ArrayWriteAxioms(it->first, it->second); + if (ASTFalse == ComputeFormulaUsingModel(writeAxiom)) + { + writeAxiom = TransformFormula(writeAxiom); + FalseAxioms.push_back(writeAxiom); + } + else + { + writeAxiom = TransformFormula(writeAxiom); + RemainingAxioms.push_back(writeAxiom); + } + } + + writeAxiom = (FalseAxioms.size() != 1) ? CreateNode(AND, FalseAxioms) : FalseAxioms[0]; + ASTNodeStats("adding false writeaxiom to SAT: ", writeAxiom); + int res2 = 2; + if (FalseAxioms.size() > oldFalseAxiomsSize) + { + res2 = CallSAT_ResultCheck(newS, writeAxiom, orig_input); + oldFalseAxiomsSize = FalseAxioms.size(); + } + if (2 != res2) + { + return res2; + } + + writeAxiom = (RemainingAxioms.size() != 1) ? CreateNode(AND, RemainingAxioms) : RemainingAxioms[0]; + ASTNodeStats("adding remaining writeaxiom to SAT: ", writeAxiom); + res2 = CallSAT_ResultCheck(newS, writeAxiom, orig_input); + if (2 != res2) + { + return res2; + } + + return 2; +} //end of SATBased_ArrayWriteRefinement - //FUNCTION: this function accepts a boolvector and returns a BVConst - ASTNode BeevMgr::BoolVectoBVConst(hash_map * w, unsigned int l) { - unsigned len = w->size(); - if(l < len) - FatalError("BoolVectorBVConst : length of bitvector does not match hash_map size:",ASTUndefined,l); - std::string cc; - for(unsigned int jj = 0; jj < l; jj++) { - if((*w)[jj] == true) - cc += '1'; - else if((*w)[jj] == false) - cc += '0'; - else - cc += '0'; - } - return CreateBVConst(cc.c_str(),2); - } - - /* - void BeevMgr::PrintActivityLevels_Of_SATVars(char * init_msg, MINISAT::Solver& newS) { - if(!print_sat_varorder) - return; - - ASTtoSATMap::iterator itbegin = _ASTNode_to_SATVar.begin(); - ASTtoSATMap::iterator itend = _ASTNode_to_SATVar.end(); - - cout << init_msg; - cout << ": Printing activity levels of variables\n"; - for(ASTtoSATMap::iterator it=itbegin;it!=itend;it++){ - cout << (it->second) << " : "; - (it->first).PL_Print(cout,0); - cout << " : "; - cout << newS.returnActivity(it->second) << endl; - } - } - - //this function biases the activity levels of MINISAT variables. - void BeevMgr::ChangeActivityLevels_Of_SATVars(MINISAT::Solver& newS) { - if(!variable_activity_optimize) - return; - - ASTtoSATMap::iterator itbegin = _ASTNode_to_SATVar.begin(); - ASTtoSATMap::iterator itend = _ASTNode_to_SATVar.end(); - - unsigned int index=1; - double base = 2; - for(ASTtoSATMap::iterator it=itbegin;it!=itend;it++){ - ASTNode n = it->first; - - if(BVGETBIT == n.GetKind() || NOT == n.GetKind()) { - if(BVGETBIT == n.GetKind()) - index = GetUnsignedConst(n[1]); - else if (NOT == n.GetKind() && BVGETBIT == n[0].GetKind()) - index = GetUnsignedConst(n[0][1]); - else - index = 0; - double initial_activity = pow(base,(double)index); - newS.updateInitialActivity(it->second,initial_activity); - } - else { - double initial_activity = pow(base,pow(base,(double)index)); - newS.updateInitialActivity(it->second,initial_activity); - } - } - } - */ - - //This function prints the output of the STP solver - void BeevMgr::PrintOutput(bool true_iff_valid) { - //self-explanatory - if(print_output) { - if(smtlib_parser_enable) - { - if (true_iff_valid && (BEEV::input_status == TO_BE_SATISFIABLE)) - { - cerr << "Warning. Expected satisfiable, FOUND unsatisfiable" << endl; - } - else - if (!true_iff_valid && (BEEV::input_status == TO_BE_UNSATISFIABLE)) +#ifdef PHONY +//Check result after calling SAT FIXME: Document arguments in +//comments, and give them meaningful names. How is anyone supposed +//to know what "q" is? +int BeevMgr::CallSAT_ResultCheck(MINISAT::Solver& newS, + const ASTNode& q, const ASTNode& orig_input) +{ + //Bitblast, CNF, call SAT now + ASTNode BBFormula = BBForm(q); + //ASTNodeStats("after bitblasting", BBFormula); + //ClauseList *cllp = ToCNF(BBFormula); + // if(stats && print_nodes) { + // cout << "\nClause list" << endl; + // PrintClauseList(cout, *cllp); + // cerr << "\n finished printing clauselist\n"; + // } + + //**************************************** + // TOCNF CONVERSION + //**************************************** + CNFMgr *cm = new CNFMgr(this); + + ClauseList* cllp = new ClauseList(); + cm->NOCOPY_INPLACE_UNION(cllp, cm->SINGLETON(cm->dummy_true_var)); + cm->CountSharesPos(BBFormula); + cm->ToCNFModRenamingPos(BBFormula); + cm->INPLACE_UNION(cllp, *((cm->ClausesPos)[BBFormula])); + cm->AddDefs(cllp); + //**************************************** + // TOCNF CONVERSION + //**************************************** + + bool sat = toSATandSolve(newS,*cllp); + // Temporary debugging call. + // CheckBBandCNF(newS, BBFormula); + + //**************************************** + // TOCNF CLEANUP + //**************************************** + cm->CLEAR(); + cm->DELETE(cllp); + delete cm; + //**************************************** + // TOCNF CLEANUP + //**************************************** + + if(!sat) + { + PrintOutput(true); + return 1; + } + else if(newS.okay()) + { + CounterExampleMap.clear(); + ConstructCounterExample(newS); + if (stats && print_nodes) { - cerr << "Warning. Expected unsatisfiable, FOUND satisfiable" << endl; + PrintSATModel(newS); } - } - } - - if(true_iff_valid) { - ValidFlag = true; - if(print_output) { - if(smtlib_parser_enable) - cout << "unsat\n"; + //check if the counterexample is good or not + ComputeFormulaMap.clear(); + if(counterexample_checking_during_refinement) + bvdiv_exception_occured = false; + ASTNode orig_result = ComputeFormulaUsingModel(orig_input); + if(!(ASTTrue == orig_result || ASTFalse == orig_result)) + FatalError("TopLevelSat: Original input must compute to true or false against model"); + + // if(!arrayread_refinement && !(ASTTrue == orig_result)) { + // print_counterexample = true; + // PrintCounterExample(true); + // FatalError("counterexample bogus : arrayread_refinement is switched off: " + // "EITHER all LA axioms have not been added OR bitblaster() or ToCNF()" + // "or satsolver() or counterexamplechecker() have a bug"); + // } + + // if the counterexample is indeed a good one, then return + // invalid + if(ASTTrue == orig_result) + { + CheckCounterExample(newS.okay()); + PrintOutput(false); + PrintCounterExample(newS.okay()); + PrintCounterExample_InOrder(newS.okay()); + return 0; + } + // counterexample is bogus: flag it + + else + { + if(stats && print_nodes) + { + cout << "Supposedly bogus one: \n"; + bool tmp = print_counterexample; + print_counterexample = true; + PrintCounterExample(true); + print_counterexample = tmp; + } + + return 2; + } + } else - cout << "Valid.\n"; - } - } - else { - ValidFlag = false; - if(print_output) { - if(smtlib_parser_enable) - cout << "sat\n"; + { + PrintOutput(true); + return -100; + } +} //end of CALLSAT_ResultCheck +#endif + +//FUNCTION: this function accepts a boolvector and returns a BVConst +ASTNode BeevMgr::BoolVectoBVConst(hash_map * w, unsigned int l) +{ + unsigned len = w->size(); + if (l < len) + FatalError("BoolVectorBVConst : length of bitvector does not match hash_map size:", ASTUndefined, l); + std::string cc; + for (unsigned int jj = 0; jj < l; jj++) + { + if ((*w)[jj] == true) + cc += '1'; + else if ((*w)[jj] == false) + cc += '0'; + else + cc += '0'; + } + return CreateBVConst(cc.c_str(), 2); +} + +/* + void BeevMgr::PrintActivityLevels_Of_SATVars(char * init_msg, MINISAT::Solver& newS) { + if(!print_sat_varorder) + return; + + ASTtoSATMap::iterator itbegin = _ASTNode_to_SATVar.begin(); + ASTtoSATMap::iterator itend = _ASTNode_to_SATVar.end(); + + cout << init_msg; + cout << ": Printing activity levels of variables\n"; + for(ASTtoSATMap::iterator it=itbegin;it!=itend;it++){ + cout << (it->second) << " : "; + (it->first).PL_Print(cout,0); + cout << " : "; + cout << newS.returnActivity(it->second) << endl; + } + } + + //this function biases the activity levels of MINISAT variables. + void BeevMgr::ChangeActivityLevels_Of_SATVars(MINISAT::Solver& newS) { + if(!variable_activity_optimize) + return; + + ASTtoSATMap::iterator itbegin = _ASTNode_to_SATVar.begin(); + ASTtoSATMap::iterator itend = _ASTNode_to_SATVar.end(); + + unsigned int index=1; + double base = 2; + for(ASTtoSATMap::iterator it=itbegin;it!=itend;it++){ + ASTNode n = it->first; + + if(BVGETBIT == n.GetKind() || NOT == n.GetKind()) { + if(BVGETBIT == n.GetKind()) + index = GetUnsignedConst(n[1]); + else if (NOT == n.GetKind() && BVGETBIT == n[0].GetKind()) + index = GetUnsignedConst(n[0][1]); + else + index = 0; + double initial_activity = pow(base,(double)index); + newS.updateInitialActivity(it->second,initial_activity); + } + else { + double initial_activity = pow(base,pow(base,(double)index)); + newS.updateInitialActivity(it->second,initial_activity); + } + } + } + */ + +//This function prints the output of the STP solver +void BeevMgr::PrintOutput(bool true_iff_valid) +{ + //self-explanatory + if (print_output) + { + if (smtlib_parser_enable) + { + if (true_iff_valid && (BEEV::input_status == TO_BE_SATISFIABLE)) + { + cerr << "Warning. Expected satisfiable, FOUND unsatisfiable" << endl; + } + else if (!true_iff_valid && (BEEV::input_status == TO_BE_UNSATISFIABLE)) + { + cerr << "Warning. Expected unsatisfiable, FOUND satisfiable" << endl; + } + } + } + + if (true_iff_valid) + { + ValidFlag = true; + if (print_output) + { + if (smtlib_parser_enable) + cout << "unsat\n"; + else + cout << "Valid.\n"; + } + } else - cout << "Invalid.\n"; - } - } - } -}; //end of namespace BEEV + { + ValidFlag = false; + if (print_output) + { + if (smtlib_parser_enable) + cout << "sat\n"; + else + cout << "Invalid.\n"; + } + } +} +} +; //end of namespace BEEV diff --git a/AST/Transform.cpp b/AST/Transform.cpp index a9d8274..ecb5223 100644 --- a/AST/Transform.cpp +++ b/AST/Transform.cpp @@ -10,613 +10,630 @@ #include "AST.h" #include #include -namespace BEEV { - - //Translates signed BVDIV/BVMOD into unsigned variety - ASTNode BeevMgr::TranslateSignedDivMod(const ASTNode& in) { - if(!(SBVREM == in.GetKind() || SBVDIV == in.GetKind())) { - FatalError("TranslateSignedDivMod: input must be signed DIV/MOD\n",in); - } - - ASTNode dividend = in[0]; - ASTNode divisor = in[1]; - unsigned len = in.GetValueWidth(); - - ASTNode hi1 = CreateBVConst(32,len-1); - ASTNode one = CreateOneConst(1); - ASTNode zero = CreateZeroConst(1); - // create the condition for the dividend - ASTNode cond_dividend = CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,dividend,hi1,hi1)); - // create the condition for the divisor - ASTNode cond_divisor = CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,divisor,hi1,hi1)); - - if(SBVREM == in.GetKind()) { - //if(TopBit(dividend)==1) - // - //then -BVMOD(-dividend,abs(divisor)) - // - //else BVMOD(dividend,abs(divisor)) - - //create the condition and conditional for the divisor - ASTNode pos_divisor = CreateTerm(ITE,len,cond_divisor,CreateTerm(BVUMINUS,len,divisor),divisor); - - //create the modulus term for each case - ASTNode modnode = CreateTerm(BVMOD,len,dividend,pos_divisor); - ASTNode minus_modnode = CreateTerm(BVMOD,len,CreateTerm(BVUMINUS,len,dividend),pos_divisor); - minus_modnode = CreateTerm(BVUMINUS,len,minus_modnode); - - //put everything together, simplify, and return - ASTNode n = CreateTerm(ITE,len,cond_dividend,minus_modnode,modnode); - return SimplifyTerm_TopLevel(n); - } - - if(SBVMOD == in.GetKind()) { - // (let (?msb_s (extract[|m-1|:|m-1|] s)) - // (let (?msb_t (extract[|m-1|:|m-1|] t)) - // (ite (and (= ?msb_s bit0) (= ?msb_t bit0)) - // (bvurem s t) - // (ite (and (= ?msb_s bit1) (= ?msb_t bit0)) - // (bvadd (bvneg (bvurem (bvneg s) t)) t) - // (ite (and (= ?msb_s bit0) (= ?msb_t bit1)) - // (bvadd (bvurem s (bvneg t)) t) - // (bvneg (bvurem (bvneg s) (bvneg t))))))) - ASTNode & s = dividend; - ASTNode & t = divisor; - ASTNode & msb_s = cond_dividend; - ASTNode & msb_t = cond_divisor; - - ASTNode isSPos = CreateNode(EQ, msb_s, zero); // (= ?msb_s bit0) - ASTNode isSNeg = CreateNode(EQ, msb_s, one); // (= ?msb_s bit1) - ASTNode isTPos = CreateNode(EQ, msb_t, zero); // (= ?msb_t bit0) - ASTNode isTNeg = CreateNode(EQ, msb_t, one); // (= ?msb_t bit1) - - ASTNode negS = CreateTerm(BVUMINUS, len, s); // (bvneg s) - ASTNode negT = CreateTerm(BVUMINUS, len, t); // (bvneg s) - - // (bvneg (bvurem (bvneg s) (bvneg t))) - ASTNode branch4 = CreateTerm(BVUMINUS, len, CreateTerm(BVMOD, len, negS, negT)); - // (bvadd (bvurem s (bvneg t)) t) - ASTNode branch3 = CreateTerm(BVPLUS, len, CreateTerm(BVMOD, len, s, negT), t); - // (bvadd (bvneg (bvurem (bvneg s) t)) t) - ASTNode branch2 = CreateTerm(BVPLUS, len, CreateTerm(BVUMINUS, len, CreateTerm(BVMOD, len, negS, t)), t); - // (bvurem s t) - ASTNode branch1 = CreateTerm(BVMOD, len, s, t); - - ASTNode ite3 = CreateTerm(ITE, len, CreateNode(AND, isSPos, isTNeg), branch3, branch4); - ASTNode ite2 = CreateTerm(ITE, len, CreateNode(AND, isSNeg, isTPos), branch2, ite3); - ASTNode ite1 = CreateTerm(ITE, len, CreateNode(AND, isSPos, isTPos), branch1, ite2); - - return SimplifyTerm_TopLevel(ite1); - } - - //now handle the BVDIV case - //if topBit(dividend) is 1 and topBit(divisor) is 0 - // - //then output is -BVDIV(-dividend,divisor) - // - //elseif topBit(dividend) is 0 and topBit(divisor) is 1 - // - //then output is -BVDIV(dividend,-divisor) - // - //elseif topBit(dividend) is 1 and topBit(divisor) is 1 - // - // then output is BVDIV(-dividend,-divisor) - // - //else simply output BVDIV(dividend,divisor) - ASTNode divnode = CreateTerm(BVDIV, len, dividend, divisor); - - ASTNode cond1 = CreateNode(AND, - CreateNode(EQ,zero,CreateTerm(BVEXTRACT,1,dividend,hi1,hi1)), - CreateNode(EQ,one, CreateTerm(BVEXTRACT,1,divisor,hi1,hi1))); - ASTNode minus_divnode1 = CreateTerm(BVDIV,len, - dividend, - CreateTerm(BVUMINUS,len,divisor)); - minus_divnode1 = CreateTerm(BVUMINUS,len,minus_divnode1); - - ASTNode cond2 = CreateNode(AND, - CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,dividend,hi1,hi1)), - CreateNode(EQ,zero,CreateTerm(BVEXTRACT,1,divisor,hi1,hi1))); - ASTNode minus_divnode2 = CreateTerm(BVDIV,len, - CreateTerm(BVUMINUS,len,dividend), - divisor); - minus_divnode2 = CreateTerm(BVUMINUS,len,minus_divnode2); - - ASTNode cond3 = CreateNode(AND, - CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,dividend,hi1,hi1)), - CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,divisor,hi1,hi1))); - ASTNode minus_divnode3 = CreateTerm(BVDIV,len, - CreateTerm(BVUMINUS,len,dividend), - CreateTerm(BVUMINUS,len,divisor)); - ASTNode n = CreateTerm(ITE,len, - cond1, - minus_divnode1, - CreateTerm(ITE,len, - cond2, - minus_divnode2, - CreateTerm(ITE,len, - cond3, - minus_divnode3, - divnode))); - return SimplifyTerm_TopLevel(n); - }//end of TranslateSignedDivMod() - - /* - //Translates signed BVDIV/BVMOD into unsigned variety - ASTNode BeevMgr::TranslateSignedDivMod(const ASTNode& in) { - if(!(SBVREM == in.GetKind() || SBVDIV == in.GetKind())) { - FatalError("TranslateSignedDivMod: input must be signed DIV/MOD\n",in); - } - - ASTNode dividend = in[0]; - ASTNode divisor = in[1]; - unsigned len = in.GetValueWidth(); - if(SBVMOD == in.GetKind()) { - //if(TopBit(dividend)==1) - // - //then -BVMOD(-dividend,abs(divisor)) - // - //else BVMOD(dividend,abs(divisor)) - - //create the condition for the dividend - ASTNode hi1 = CreateBVConst(32,len-1); - ASTNode one = CreateOneConst(1); - ASTNode cond = CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,dividend,hi1,hi1)); - - //create the condition and conditional for the divisor - ASTNode cond_divisor = CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,divisor,hi1,hi1)); - ASTNode pos_divisor = CreateTerm(ITE,len,cond_divisor,CreateTerm(BVUMINUS,len,divisor),divisor); - - //create the modulus term for each case - ASTNode modnode = CreateTerm(BVMOD,len,dividend,pos_divisor); - ASTNode minus_modnode = CreateTerm(BVMOD,len,CreateTerm(BVUMINUS,len,dividend),pos_divisor); - minus_modnode = CreateTerm(BVUMINUS,len,minus_modnode); - - //put everything together, simplify, and return - ASTNode n = CreateTerm(ITE,len,cond,minus_modnode,modnode); - return SimplifyTerm_TopLevel(n); - } - - //now handle the BVDIV case - //if topBit(dividend) is 1 and topBit(divisor) is 0 - // - //then output is -BVDIV(-dividend,divisor) - // - //elseif topBit(dividend) is 0 and topBit(divisor) is 1 - // - //then output is -BVDIV(dividend,-divisor) - // - //elseif topBit(dividend) is 1 and topBit(divisor) is 1 - // - // then output is BVDIV(-dividend,-divisor) - // - //else simply output BVDIV(dividend,divisor) - ASTNode hi1 = CreateBVConst(32,len-1); - ASTNode zero = CreateZeroConst(1); - ASTNode one = CreateOneConst(1); - ASTNode divnode = CreateTerm(BVDIV, len, dividend, divisor); - - ASTNode cond1 = CreateNode(AND, - CreateNode(EQ,zero,CreateTerm(BVEXTRACT,1,dividend,hi1,hi1)), - CreateNode(EQ,one, CreateTerm(BVEXTRACT,1,divisor,hi1,hi1))); - ASTNode minus_divnode1 = CreateTerm(BVDIV,len, - dividend, - CreateTerm(BVUMINUS,len,divisor)); - minus_divnode1 = CreateTerm(BVUMINUS,len,minus_divnode1); - - ASTNode cond2 = CreateNode(AND, - CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,dividend,hi1,hi1)), - CreateNode(EQ,zero,CreateTerm(BVEXTRACT,1,divisor,hi1,hi1))); - ASTNode minus_divnode2 = CreateTerm(BVDIV,len, - CreateTerm(BVUMINUS,len,dividend), - divisor); - minus_divnode2 = CreateTerm(BVUMINUS,len,minus_divnode2); - - ASTNode cond3 = CreateNode(AND, - CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,dividend,hi1,hi1)), - CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,divisor,hi1,hi1))); - ASTNode minus_divnode3 = CreateTerm(BVDIV,len, - CreateTerm(BVUMINUS,len,dividend), - CreateTerm(BVUMINUS,len,divisor)); - ASTNode n = CreateTerm(ITE,len, - cond1, - minus_divnode1, - CreateTerm(ITE,len, - cond2, - minus_divnode2, - CreateTerm(ITE,len, - cond3, - minus_divnode3, - divnode))); - return SimplifyTerm_TopLevel(n); - }//end of TranslateSignedDivMod() - */ - - ASTNode BeevMgr::TransformFormula(const ASTNode& form) { - ASTNode result; - - ASTNode simpleForm = form; - Kind k = simpleForm.GetKind(); - if(!(is_Form_kind(k) && BOOLEAN_TYPE == simpleForm.GetType())) { - //FIXME: "You have inputted a NON-formula"? - FatalError("TransformFormula: You have input a NON-formula",simpleForm); - } - - ASTNodeMap::iterator iter; - if((iter = TransformMap.find(simpleForm)) != TransformMap.end()) - return iter->second; - - switch(k) { - case TRUE: - case FALSE: { - result = simpleForm; - break; - } - case NOT: { - ASTVec c; - c.push_back(TransformFormula(simpleForm[0])); - result = CreateNode(NOT,c); - break; - } - case BVLT: - case BVLE: - case BVGT: - case BVGE: - case BVSLT: - case BVSLE: - case BVSGT: - case BVSGE: - case NEQ: { - ASTVec c; - c.push_back(TransformTerm(simpleForm[0])); - c.push_back(TransformTerm(simpleForm[1])); - result = CreateNode(k,c); - break; - } - case EQ: { - ASTNode term1 = TransformTerm(simpleForm[0]); - ASTNode term2 = TransformTerm(simpleForm[1]); - result = CreateSimplifiedEQ(term1,term2); - break; - } - case AND: - case OR: - case NAND: - case NOR: - case IFF: - case XOR: - case ITE: - case IMPLIES: { - ASTVec vec; - ASTNode o; - for (ASTVec::const_iterator it = simpleForm.begin(),itend=simpleForm.end(); it != itend; it++){ - o = TransformFormula(*it); - vec.push_back(o); - } - - result = CreateNode(k, vec); - break; - } - default: - if(k == SYMBOL && BOOLEAN_TYPE == simpleForm.GetType()) - result = simpleForm; - else { - cerr << "The input is: " << simpleForm << endl; - cerr << "The valuewidth of input is : " << simpleForm.GetValueWidth() << endl; - FatalError("TransformFormula: Illegal kind: ",ASTUndefined, k); - } - break; - } - //BVTypeCheck(result); - TransformMap[simpleForm] = result; - return result; - } //End of TransformFormula - - ASTNode BeevMgr::TransformTerm(const ASTNode& inputterm) { - ASTNode result; - ASTNode term = inputterm; - - Kind k = term.GetKind(); - if(!is_Term_kind(k)) - FatalError("TransformTerm: Illegal kind: You have input a nonterm:", inputterm, k); - ASTNodeMap::iterator iter; - if((iter = TransformMap.find(term)) != TransformMap.end()) - return iter->second; - switch(k) { - case SYMBOL: { - // ASTNodeMap::iterator itsym; -// if((itsym = CounterExampleMap.find(term)) != CounterExampleMap.end()) -// result = itsym->second; -// else - result = term; - break; - } - case BVCONST: - result = term; - break; - case WRITE: - FatalError("TransformTerm: this kind is not supported",term); - break; - case READ: - result = TransformArray(term); - break; - case ITE: { - ASTNode cond = term[0]; - ASTNode thn = term[1]; - ASTNode els = term[2]; - cond = TransformFormula(cond); - thn = TransformTerm(thn); - els = TransformTerm(els); - //result = CreateTerm(ITE,term.GetValueWidth(),cond,thn,els); - result = CreateSimplifiedTermITE(cond,thn,els); - result.SetIndexWidth(term.GetIndexWidth()); - break; - } - default: { - ASTVec c = term.GetChildren(); - ASTVec::iterator it = c.begin(); - ASTVec::iterator itend = c.end(); - unsigned width = term.GetValueWidth(); - unsigned indexwidth = term.GetIndexWidth(); - ASTVec o; - for(;it!=itend;it++) { - o.push_back(TransformTerm(*it)); - } - - result = CreateTerm(k,width,o); - result.SetIndexWidth(indexwidth); - - if(SBVDIV == result.GetKind() || SBVREM == result.GetKind() || SBVMOD == result.GetKind()) { - result = TranslateSignedDivMod(result); - } - break; - } - } - - TransformMap[term] = result; - if(term.GetValueWidth() != result.GetValueWidth()) - FatalError("TransformTerm: result and input terms are of different length", result); - if(term.GetIndexWidth() != result.GetIndexWidth()) { - cerr << "TransformTerm: input term is : " << term << endl; - FatalError("TransformTerm: result and input terms have different index length", result); - } - return result; - } //End of TransformTerm - - /* This function transforms Array Reads, Read over Writes, Read over - * ITEs into flattened form. - * - * Transform1: Suppose there are two array reads in the input - * Read(A,i) and Read(A,j) over the same array. Then Read(A,i) is - * replaced with a symbolic constant, say v1, and Read(A,j) is - * replaced with the following ITE: - * - * ITE(i=j,v1,v2) - * - * Transform2: - * - * Transform3: - */ - ASTNode BeevMgr::TransformArray(const ASTNode& term) { - ASTNode result = term; - - unsigned int width = term.GetValueWidth(); - Kind k = term.GetKind(); - if (!is_Term_kind(k)) - FatalError("TransformArray: Illegal kind: You have input a nonterm:", ASTUndefined, k); - ASTNodeMap::iterator iter; - if((iter = TransformMap.find(term)) != TransformMap.end()) - return iter->second; - - switch(k) { - //'term' is of the form READ(arrName, readIndex) - case READ: { - ASTNode arrName = term[0]; - switch (arrName.GetKind()) { - case SYMBOL: { - /* input is of the form: READ(A, readIndex) - * - * output is of the from: A1, if this is the first READ over A - * - * ITE(previous_readIndex=readIndex,A1,A2) - * - * ..... - */ - - // Recursively transform read index, which may also contain reads. - ASTNode readIndex = TransformTerm(term[1]); - ASTNode processedTerm = CreateTerm(READ,width,arrName,readIndex); - - //check if the 'processedTerm' has a corresponding ITE construct - //already. if so, return it. else continue processing. - ASTNodeMap::iterator it; - if((it = _arrayread_ite.find(processedTerm)) != _arrayread_ite.end()) { - result = it->second; - break; +namespace BEEV +{ + +//Translates signed BVDIV/BVMOD into unsigned variety +ASTNode BeevMgr::TranslateSignedDivMod(const ASTNode& in) +{ + if (!(SBVREM == in.GetKind() || SBVDIV == in.GetKind())) + { + FatalError("TranslateSignedDivMod: input must be signed DIV/MOD\n", in); } - //Constructing Symbolic variable corresponding to 'processedTerm' - ASTNode CurrentSymbol; - ASTNodeMap::iterator it1; - // First, check if read index is constant and it has a constant value in the substitution map. - if(CheckSubstitutionMap(processedTerm,CurrentSymbol)) { - _arrayread_symbol[processedTerm] = CurrentSymbol; + + ASTNode dividend = in[0]; + ASTNode divisor = in[1]; + unsigned len = in.GetValueWidth(); + + ASTNode hi1 = CreateBVConst(32, len - 1); + ASTNode one = CreateOneConst(1); + ASTNode zero = CreateZeroConst(1); + // create the condition for the dividend + ASTNode cond_dividend = CreateNode(EQ, one, CreateTerm(BVEXTRACT, 1, dividend, hi1, hi1)); + // create the condition for the divisor + ASTNode cond_divisor = CreateNode(EQ, one, CreateTerm(BVEXTRACT, 1, divisor, hi1, hi1)); + + if (SBVREM == in.GetKind()) + { + //if(TopBit(dividend)==1) + // + //then -BVMOD(-dividend,abs(divisor)) + // + //else BVMOD(dividend,abs(divisor)) + + //create the condition and conditional for the divisor + ASTNode pos_divisor = CreateTerm(ITE, len, cond_divisor, CreateTerm(BVUMINUS, len, divisor), divisor); + + //create the modulus term for each case + ASTNode modnode = CreateTerm(BVMOD, len, dividend, pos_divisor); + ASTNode minus_modnode = CreateTerm(BVMOD, len, CreateTerm(BVUMINUS, len, dividend), pos_divisor); + minus_modnode = CreateTerm(BVUMINUS, len, minus_modnode); + + //put everything together, simplify, and return + ASTNode n = CreateTerm(ITE, len, cond_dividend, minus_modnode, modnode); + return SimplifyTerm_TopLevel(n); } - // Check if it already has an abstract variable. - else if((it1 = _arrayread_symbol.find(processedTerm)) != _arrayread_symbol.end()) { - CurrentSymbol = it1->second; + + if (SBVMOD == in.GetKind()) + { + // (let (?msb_s (extract[|m-1|:|m-1|] s)) + // (let (?msb_t (extract[|m-1|:|m-1|] t)) + // (ite (and (= ?msb_s bit0) (= ?msb_t bit0)) + // (bvurem s t) + // (ite (and (= ?msb_s bit1) (= ?msb_t bit0)) + // (bvadd (bvneg (bvurem (bvneg s) t)) t) + // (ite (and (= ?msb_s bit0) (= ?msb_t bit1)) + // (bvadd (bvurem s (bvneg t)) t) + // (bvneg (bvurem (bvneg s) (bvneg t))))))) + ASTNode & s = dividend; + ASTNode & t = divisor; + ASTNode & msb_s = cond_dividend; + ASTNode & msb_t = cond_divisor; + + ASTNode isSPos = CreateNode(EQ, msb_s, zero); // (= ?msb_s bit0) + ASTNode isSNeg = CreateNode(EQ, msb_s, one); // (= ?msb_s bit1) + ASTNode isTPos = CreateNode(EQ, msb_t, zero); // (= ?msb_t bit0) + ASTNode isTNeg = CreateNode(EQ, msb_t, one); // (= ?msb_t bit1) + + ASTNode negS = CreateTerm(BVUMINUS, len, s); // (bvneg s) + ASTNode negT = CreateTerm(BVUMINUS, len, t); // (bvneg s) + + // (bvneg (bvurem (bvneg s) (bvneg t))) + ASTNode branch4 = CreateTerm(BVUMINUS, len, CreateTerm(BVMOD, len, negS, negT)); + // (bvadd (bvurem s (bvneg t)) t) + ASTNode branch3 = CreateTerm(BVPLUS, len, CreateTerm(BVMOD, len, s, negT), t); + // (bvadd (bvneg (bvurem (bvneg s) t)) t) + ASTNode branch2 = CreateTerm(BVPLUS, len, CreateTerm(BVUMINUS, len, CreateTerm(BVMOD, len, negS, t)), t); + // (bvurem s t) + ASTNode branch1 = CreateTerm(BVMOD, len, s, t); + + ASTNode ite3 = CreateTerm(ITE, len, CreateNode(AND, isSPos, isTNeg), branch3, branch4); + ASTNode ite2 = CreateTerm(ITE, len, CreateNode(AND, isSNeg, isTPos), branch2, ite3); + ASTNode ite1 = CreateTerm(ITE, len, CreateNode(AND, isSPos, isTPos), branch1, ite2); + + return SimplifyTerm_TopLevel(ite1); } - else { - // Make up a new abstract variable. - // FIXME: Make this into a method (there already may BE a method) and - // get rid of the fixed-length buffer! - //build symbolic name corresponding to array read. The symbolic - //name has 2 components: stringname, and a count - const char * b = arrName.GetName(); - std::string c(b); - char d[32]; - sprintf(d,"%d",_symbol_count++); - std::string ccc(d); - c += "array_" + ccc; - - CurrentSymbol = CreateSymbol(c.c_str()); - CurrentSymbol.SetValueWidth(processedTerm.GetValueWidth()); - CurrentSymbol.SetIndexWidth(processedTerm.GetIndexWidth()); - _arrayread_symbol[processedTerm] = CurrentSymbol; + + //now handle the BVDIV case + //if topBit(dividend) is 1 and topBit(divisor) is 0 + // + //then output is -BVDIV(-dividend,divisor) + // + //elseif topBit(dividend) is 0 and topBit(divisor) is 1 + // + //then output is -BVDIV(dividend,-divisor) + // + //elseif topBit(dividend) is 1 and topBit(divisor) is 1 + // + // then output is BVDIV(-dividend,-divisor) + // + //else simply output BVDIV(dividend,divisor) + ASTNode divnode = CreateTerm(BVDIV, len, dividend, divisor); + + ASTNode cond1 = CreateNode(AND, CreateNode(EQ, zero, CreateTerm(BVEXTRACT, 1, dividend, hi1, hi1)), CreateNode(EQ, one, CreateTerm(BVEXTRACT, 1, + divisor, hi1, hi1))); + ASTNode minus_divnode1 = CreateTerm(BVDIV, len, dividend, CreateTerm(BVUMINUS, len, divisor)); + minus_divnode1 = CreateTerm(BVUMINUS, len, minus_divnode1); + + ASTNode cond2 = CreateNode(AND, CreateNode(EQ, one, CreateTerm(BVEXTRACT, 1, dividend, hi1, hi1)), CreateNode(EQ, zero, CreateTerm(BVEXTRACT, 1, + divisor, hi1, hi1))); + ASTNode minus_divnode2 = CreateTerm(BVDIV, len, CreateTerm(BVUMINUS, len, dividend), divisor); + minus_divnode2 = CreateTerm(BVUMINUS, len, minus_divnode2); + + ASTNode cond3 = CreateNode(AND, CreateNode(EQ, one, CreateTerm(BVEXTRACT, 1, dividend, hi1, hi1)), CreateNode(EQ, one, CreateTerm(BVEXTRACT, 1, + divisor, hi1, hi1))); + ASTNode minus_divnode3 = CreateTerm(BVDIV, len, CreateTerm(BVUMINUS, len, dividend), CreateTerm(BVUMINUS, len, divisor)); + ASTNode n = CreateTerm(ITE, len, cond1, minus_divnode1, CreateTerm(ITE, len, cond2, minus_divnode2, CreateTerm(ITE, len, cond3, minus_divnode3, + divnode))); + return SimplifyTerm_TopLevel(n); +}//end of TranslateSignedDivMod() + +/* + //Translates signed BVDIV/BVMOD into unsigned variety + ASTNode BeevMgr::TranslateSignedDivMod(const ASTNode& in) { + if(!(SBVREM == in.GetKind() || SBVDIV == in.GetKind())) { + FatalError("TranslateSignedDivMod: input must be signed DIV/MOD\n",in); + } + + ASTNode dividend = in[0]; + ASTNode divisor = in[1]; + unsigned len = in.GetValueWidth(); + if(SBVMOD == in.GetKind()) { + //if(TopBit(dividend)==1) + // + //then -BVMOD(-dividend,abs(divisor)) + // + //else BVMOD(dividend,abs(divisor)) + + //create the condition for the dividend + ASTNode hi1 = CreateBVConst(32,len-1); + ASTNode one = CreateOneConst(1); + ASTNode cond = CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,dividend,hi1,hi1)); + + //create the condition and conditional for the divisor + ASTNode cond_divisor = CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,divisor,hi1,hi1)); + ASTNode pos_divisor = CreateTerm(ITE,len,cond_divisor,CreateTerm(BVUMINUS,len,divisor),divisor); + + //create the modulus term for each case + ASTNode modnode = CreateTerm(BVMOD,len,dividend,pos_divisor); + ASTNode minus_modnode = CreateTerm(BVMOD,len,CreateTerm(BVUMINUS,len,dividend),pos_divisor); + minus_modnode = CreateTerm(BVUMINUS,len,minus_modnode); + + //put everything together, simplify, and return + ASTNode n = CreateTerm(ITE,len,cond,minus_modnode,modnode); + return SimplifyTerm_TopLevel(n); + } + + //now handle the BVDIV case + //if topBit(dividend) is 1 and topBit(divisor) is 0 + // + //then output is -BVDIV(-dividend,divisor) + // + //elseif topBit(dividend) is 0 and topBit(divisor) is 1 + // + //then output is -BVDIV(dividend,-divisor) + // + //elseif topBit(dividend) is 1 and topBit(divisor) is 1 + // + // then output is BVDIV(-dividend,-divisor) + // + //else simply output BVDIV(dividend,divisor) + ASTNode hi1 = CreateBVConst(32,len-1); + ASTNode zero = CreateZeroConst(1); + ASTNode one = CreateOneConst(1); + ASTNode divnode = CreateTerm(BVDIV, len, dividend, divisor); + + ASTNode cond1 = CreateNode(AND, + CreateNode(EQ,zero,CreateTerm(BVEXTRACT,1,dividend,hi1,hi1)), + CreateNode(EQ,one, CreateTerm(BVEXTRACT,1,divisor,hi1,hi1))); + ASTNode minus_divnode1 = CreateTerm(BVDIV,len, + dividend, + CreateTerm(BVUMINUS,len,divisor)); + minus_divnode1 = CreateTerm(BVUMINUS,len,minus_divnode1); + + ASTNode cond2 = CreateNode(AND, + CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,dividend,hi1,hi1)), + CreateNode(EQ,zero,CreateTerm(BVEXTRACT,1,divisor,hi1,hi1))); + ASTNode minus_divnode2 = CreateTerm(BVDIV,len, + CreateTerm(BVUMINUS,len,dividend), + divisor); + minus_divnode2 = CreateTerm(BVUMINUS,len,minus_divnode2); + + ASTNode cond3 = CreateNode(AND, + CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,dividend,hi1,hi1)), + CreateNode(EQ,one,CreateTerm(BVEXTRACT,1,divisor,hi1,hi1))); + ASTNode minus_divnode3 = CreateTerm(BVDIV,len, + CreateTerm(BVUMINUS,len,dividend), + CreateTerm(BVUMINUS,len,divisor)); + ASTNode n = CreateTerm(ITE,len, + cond1, + minus_divnode1, + CreateTerm(ITE,len, + cond2, + minus_divnode2, + CreateTerm(ITE,len, + cond3, + minus_divnode3, + divnode))); + return SimplifyTerm_TopLevel(n); + }//end of TranslateSignedDivMod() + */ + +ASTNode BeevMgr::TransformFormula(const ASTNode& form) +{ + ASTNode result; + + ASTNode simpleForm = form; + Kind k = simpleForm.GetKind(); + if (!(is_Form_kind(k) && BOOLEAN_TYPE == simpleForm.GetType())) + { + //FIXME: "You have inputted a NON-formula"? + FatalError("TransformFormula: You have input a NON-formula", simpleForm); } - - //list of array-read indices corresponding to arrName, seen while - //traversing the AST tree. we need this list to construct the ITEs - // Dill: we hope to make this irrelevant. Harmless for now. - ASTVec readIndices = _arrayname_readindices[arrName]; - - //construct the ITE structure for this array-read - ASTNode ite = CurrentSymbol; - _introduced_symbols.insert(CurrentSymbol); - BVTypeCheck(ite); - - if(arrayread_refinement) { - // ite is really a variable here; it is an ite in the - // else-branch - result = ite; + + ASTNodeMap::iterator iter; + if ((iter = TransformMap.find(simpleForm)) != TransformMap.end()) + return iter->second; + + switch (k) + { + case TRUE: + case FALSE: + { + result = simpleForm; + break; + } + case NOT: + { + ASTVec c; + c.push_back(TransformFormula(simpleForm[0])); + result = CreateNode(NOT, c); + break; + } + case BVLT: + case BVLE: + case BVGT: + case BVGE: + case BVSLT: + case BVSLE: + case BVSGT: + case BVSGE: + case NEQ: + { + ASTVec c; + c.push_back(TransformTerm(simpleForm[0])); + c.push_back(TransformTerm(simpleForm[1])); + result = CreateNode(k, c); + break; + } + case EQ: + { + ASTNode term1 = TransformTerm(simpleForm[0]); + ASTNode term2 = TransformTerm(simpleForm[1]); + result = CreateSimplifiedEQ(term1, term2); + break; + } + case AND: + case OR: + case NAND: + case NOR: + case IFF: + case XOR: + case ITE: + case IMPLIES: + { + ASTVec vec; + ASTNode o; + for (ASTVec::const_iterator it = simpleForm.begin(), itend = simpleForm.end(); it != itend; it++) + { + o = TransformFormula(*it); + vec.push_back(o); + } + + result = CreateNode(k, vec); + break; + } + default: + if (k == SYMBOL && BOOLEAN_TYPE == simpleForm.GetType()) + result = simpleForm; + else + { + cerr << "The input is: " << simpleForm << endl; + cerr << "The valuewidth of input is : " << simpleForm.GetValueWidth() << endl; + FatalError("TransformFormula: Illegal kind: ", ASTUndefined, k); + } + break; } - else { - // Full Seshia transform if we're not doing read refinement. - //do not loop if the current readIndex is a BVCONST - // if(BVCONST == term[1].GetKind() && !SeenNonConstReadIndex && optimize) { - // result = ite; - // } - // else { - //else part: SET the SeenNonConstReadIndex var, and do the hard work - //SeenNonConstReadIndex = true; - ASTVec::reverse_iterator it2=readIndices.rbegin(); - ASTVec::reverse_iterator it2end=readIndices.rend(); - for(;it2!=it2end;it2++) { - ASTNode cond = CreateSimplifiedEQ(readIndex,*it2); - if(ASTFalse == cond) - continue; - - ASTNode arrRead = CreateTerm(READ,width,arrName,*it2); - //Good idea to TypeCheck internally constructed nodes - BVTypeCheck(arrRead); - - ASTNode arrayreadSymbol = _arrayread_symbol[arrRead]; - if(arrayreadSymbol.IsNull()) - FatalError("TransformArray:symbolic variable for processedTerm, p," - "does not exist:p = ",arrRead); - ite = CreateSimplifiedTermITE(cond,arrayreadSymbol,ite); - } - result = ite; - //} + //BVTypeCheck(result); + TransformMap[simpleForm] = result; + return result; +} //End of TransformFormula + +ASTNode BeevMgr::TransformTerm(const ASTNode& inputterm) +{ + ASTNode result; + ASTNode term = inputterm; + + Kind k = term.GetKind(); + if (!is_Term_kind(k)) + FatalError("TransformTerm: Illegal kind: You have input a nonterm:", inputterm, k); + ASTNodeMap::iterator iter; + if ((iter = TransformMap.find(term)) != TransformMap.end()) + return iter->second; + switch (k) + { + case SYMBOL: + { + // ASTNodeMap::iterator itsym; + // if((itsym = CounterExampleMap.find(term)) != CounterExampleMap.end()) + // result = itsym->second; + // else + result = term; + break; + } + case BVCONST: + result = term; + break; + case WRITE: + FatalError("TransformTerm: this kind is not supported", term); + break; + case READ: + result = TransformArray(term); + break; + case ITE: + { + ASTNode cond = term[0]; + ASTNode thn = term[1]; + ASTNode els = term[2]; + cond = TransformFormula(cond); + thn = TransformTerm(thn); + els = TransformTerm(els); + //result = CreateTerm(ITE,term.GetValueWidth(),cond,thn,els); + result = CreateSimplifiedTermITE(cond, thn, els); + result.SetIndexWidth(term.GetIndexWidth()); + break; + } + default: + { + ASTVec c = term.GetChildren(); + ASTVec::iterator it = c.begin(); + ASTVec::iterator itend = c.end(); + unsigned width = term.GetValueWidth(); + unsigned indexwidth = term.GetIndexWidth(); + ASTVec o; + for (; it != itend; it++) + { + o.push_back(TransformTerm(*it)); + } + + result = CreateTerm(k, width, o); + result.SetIndexWidth(indexwidth); + + if (SBVDIV == result.GetKind() || SBVREM == result.GetKind() || SBVMOD == result.GetKind()) + { + result = TranslateSignedDivMod(result); + } + break; + } } - - _arrayname_readindices[arrName].push_back(readIndex); - //save the ite corresponding to 'processedTerm' - _arrayread_ite[processedTerm] = result; - break; - } //end of READ over a SYMBOL - case WRITE:{ - /* The input to this case is: READ((WRITE A i val) j) - * - * The output of this case is: ITE( (= i j) val (READ A i)) - */ - - /* 1. arrName or term[0] is infact a WRITE(A,i,val) expression - * - * 2. term[1] is the read-index j - * - * 3. arrName[0] is the new arrName i.e. A. A can be either a - SYMBOL or a nested WRITE. no other possibility - * - * 4. arrName[1] is the WRITE index i.e. i - * - * 5. arrName[2] is the WRITE value i.e. val (val can inturn - * be an array read) - */ - ASTNode readIndex = TransformTerm(term[1]); - ASTNode writeIndex = TransformTerm(arrName[1]); - ASTNode writeVal = TransformTerm(arrName[2]); - - if(!(SYMBOL == arrName[0].GetKind() || - WRITE == arrName[0].GetKind())) - FatalError("TransformArray: An array write is being attempted on a non-array:",term); - if(ARRAY_TYPE != arrName[0].GetType()) - FatalError("TransformArray: An array write is being attempted on a non-array:",term); - - ASTNode cond = CreateSimplifiedEQ(writeIndex,readIndex); - //TypeCheck internally created node - BVTypeCheck(cond); - ASTNode readTerm = CreateTerm(READ,width,arrName[0],readIndex); - //TypeCheck internally created node - BVTypeCheck(readTerm); - ASTNode readPushedIn = TransformArray(readTerm); - //TypeCheck internally created node - BVTypeCheck(readPushedIn); - //result = CreateTerm(ITE, arrName[0].GetValueWidth(),cond,writeVal,readPushedIn); - result = CreateSimplifiedTermITE(cond,writeVal,readPushedIn); - - //Good idea to typecheck terms created inside the system - BVTypeCheck(result); - break; - } //end of READ over a WRITE - case ITE: { - /* READ((ITE cond thn els) j) - * - * is transformed into - * - * (ITE cond (READ thn j) (READ els j)) - */ - - //(ITE cond thn els) - ASTNode term0 = term[0]; - //READINDEX j - ASTNode j = TransformTerm(term[1]); - - ASTNode cond = term0[0]; - //first array - ASTNode t01 = term0[1]; - //second array - ASTNode t02 = term0[2]; - - cond = TransformFormula(cond); - ASTNode thn = TransformTerm(t01); - ASTNode els = TransformTerm(t02); - - if(!(t01.GetValueWidth() == t02.GetValueWidth() && - t01.GetValueWidth() == thn.GetValueWidth() && - t01.GetValueWidth() == els.GetValueWidth())) - FatalError("TransformArray: length of THENbranch != length of ELSEbranch in the term t = \n",term); - - if(!(t01.GetIndexWidth() == t02.GetIndexWidth() && - t01.GetIndexWidth() == thn.GetIndexWidth() && - t01.GetIndexWidth() == els.GetIndexWidth())) - FatalError("TransformArray: length of THENbranch != length of ELSEbranch in the term t = \n",term); - - //(READ thn j) - ASTNode thnRead = CreateTerm(READ,width,thn,j); - BVTypeCheck(thnRead); - thnRead = TransformArray(thnRead); - - //(READ els j) - ASTNode elsRead = CreateTerm(READ,width,els,j); - BVTypeCheck(elsRead); - elsRead = TransformArray(elsRead); - - //(ITE cond (READ thn j) (READ els j)) - result = CreateSimplifiedTermITE(cond,thnRead,elsRead); - BVTypeCheck(result); - break; - } - default: - FatalError("TransformArray: The READ is NOT over SYMBOL/WRITE/ITE",term); - break; - } - break; - } //end of READ switch - default: - FatalError("TransformArray: input term is of wrong kind: ",ASTUndefined); - break; - } - - TransformMap[term] = result; - return result; - } //end of TransformArray() + + TransformMap[term] = result; + if (term.GetValueWidth() != result.GetValueWidth()) + FatalError("TransformTerm: result and input terms are of different length", result); + if (term.GetIndexWidth() != result.GetIndexWidth()) + { + cerr << "TransformTerm: input term is : " << term << endl; + FatalError("TransformTerm: result and input terms have different index length", result); + } + return result; +} //End of TransformTerm + +/* This function transforms Array Reads, Read over Writes, Read over + * ITEs into flattened form. + * + * Transform1: Suppose there are two array reads in the input + * Read(A,i) and Read(A,j) over the same array. Then Read(A,i) is + * replaced with a symbolic constant, say v1, and Read(A,j) is + * replaced with the following ITE: + * + * ITE(i=j,v1,v2) + * + * Transform2: + * + * Transform3: + */ +ASTNode BeevMgr::TransformArray(const ASTNode& term) +{ + ASTNode result = term; + + unsigned int width = term.GetValueWidth(); + Kind k = term.GetKind(); + if (!is_Term_kind(k)) + FatalError("TransformArray: Illegal kind: You have input a nonterm:", ASTUndefined, k); + ASTNodeMap::iterator iter; + if ((iter = TransformMap.find(term)) != TransformMap.end()) + return iter->second; + + switch (k) + { + //'term' is of the form READ(arrName, readIndex) + case READ: + { + ASTNode arrName = term[0]; + switch (arrName.GetKind()) + { + case SYMBOL: + { + /* input is of the form: READ(A, readIndex) + * + * output is of the from: A1, if this is the first READ over A + * + * ITE(previous_readIndex=readIndex,A1,A2) + * + * ..... + */ + + // Recursively transform read index, which may also contain reads. + ASTNode readIndex = TransformTerm(term[1]); + ASTNode processedTerm = CreateTerm(READ, width, arrName, readIndex); + + //check if the 'processedTerm' has a corresponding ITE construct + //already. if so, return it. else continue processing. + ASTNodeMap::iterator it; + if ((it = _arrayread_ite.find(processedTerm)) != _arrayread_ite.end()) + { + result = it->second; + break; + } + //Constructing Symbolic variable corresponding to 'processedTerm' + ASTNode CurrentSymbol; + ASTNodeMap::iterator it1; + // First, check if read index is constant and it has a constant value in the substitution map. + if (CheckSubstitutionMap(processedTerm, CurrentSymbol)) + { + _arrayread_symbol[processedTerm] = CurrentSymbol; + } + // Check if it already has an abstract variable. + else if ((it1 = _arrayread_symbol.find(processedTerm)) != _arrayread_symbol.end()) + { + CurrentSymbol = it1->second; + } + else + { + // Make up a new abstract variable. + // FIXME: Make this into a method (there already may BE a method) and + // get rid of the fixed-length buffer! + //build symbolic name corresponding to array read. The symbolic + //name has 2 components: stringname, and a count + const char * b = arrName.GetName(); + std::string c(b); + char d[32]; + sprintf(d, "%d", _symbol_count++); + std::string ccc(d); + c += "array_" + ccc; + + CurrentSymbol = CreateSymbol(c.c_str()); + CurrentSymbol.SetValueWidth(processedTerm.GetValueWidth()); + CurrentSymbol.SetIndexWidth(processedTerm.GetIndexWidth()); + _arrayread_symbol[processedTerm] = CurrentSymbol; + } + + //list of array-read indices corresponding to arrName, seen while + //traversing the AST tree. we need this list to construct the ITEs + // Dill: we hope to make this irrelevant. Harmless for now. + ASTVec readIndices = _arrayname_readindices[arrName]; + + //construct the ITE structure for this array-read + ASTNode ite = CurrentSymbol; + _introduced_symbols.insert(CurrentSymbol); + BVTypeCheck(ite); + + if (arrayread_refinement) + { + // ite is really a variable here; it is an ite in the + // else-branch + result = ite; + } + else + { + // Full Seshia transform if we're not doing read refinement. + //do not loop if the current readIndex is a BVCONST + // if(BVCONST == term[1].GetKind() && !SeenNonConstReadIndex && optimize) { + // result = ite; + // } + // else { + //else part: SET the SeenNonConstReadIndex var, and do the hard work + //SeenNonConstReadIndex = true; + ASTVec::reverse_iterator it2 = readIndices.rbegin(); + ASTVec::reverse_iterator it2end = readIndices.rend(); + for (; it2 != it2end; it2++) + { + ASTNode cond = CreateSimplifiedEQ(readIndex, *it2); + if (ASTFalse == cond) + continue; + + ASTNode arrRead = CreateTerm(READ, width, arrName, *it2); + //Good idea to TypeCheck internally constructed nodes + BVTypeCheck(arrRead); + + ASTNode arrayreadSymbol = _arrayread_symbol[arrRead]; + if (arrayreadSymbol.IsNull()) + FatalError("TransformArray:symbolic variable for processedTerm, p," + "does not exist:p = ", arrRead); + ite = CreateSimplifiedTermITE(cond, arrayreadSymbol, ite); + } + result = ite; + //} + } + + _arrayname_readindices[arrName].push_back(readIndex); + //save the ite corresponding to 'processedTerm' + _arrayread_ite[processedTerm] = result; + break; + } //end of READ over a SYMBOL + case WRITE: + { + /* The input to this case is: READ((WRITE A i val) j) + * + * The output of this case is: ITE( (= i j) val (READ A i)) + */ + + /* 1. arrName or term[0] is infact a WRITE(A,i,val) expression + * + * 2. term[1] is the read-index j + * + * 3. arrName[0] is the new arrName i.e. A. A can be either a + SYMBOL or a nested WRITE. no other possibility + * + * 4. arrName[1] is the WRITE index i.e. i + * + * 5. arrName[2] is the WRITE value i.e. val (val can inturn + * be an array read) + */ + ASTNode readIndex = TransformTerm(term[1]); + ASTNode writeIndex = TransformTerm(arrName[1]); + ASTNode writeVal = TransformTerm(arrName[2]); + + if (!(SYMBOL == arrName[0].GetKind() || WRITE == arrName[0].GetKind())) + FatalError("TransformArray: An array write is being attempted on a non-array:", term); + if (ARRAY_TYPE != arrName[0].GetType()) + FatalError("TransformArray: An array write is being attempted on a non-array:", term); + + ASTNode cond = CreateSimplifiedEQ(writeIndex, readIndex); + //TypeCheck internally created node + BVTypeCheck(cond); + ASTNode readTerm = CreateTerm(READ, width, arrName[0], readIndex); + //TypeCheck internally created node + BVTypeCheck(readTerm); + ASTNode readPushedIn = TransformArray(readTerm); + //TypeCheck internally created node + BVTypeCheck(readPushedIn); + //result = CreateTerm(ITE, arrName[0].GetValueWidth(),cond,writeVal,readPushedIn); + result = CreateSimplifiedTermITE(cond, writeVal, readPushedIn); + + //Good idea to typecheck terms created inside the system + BVTypeCheck(result); + break; + } //end of READ over a WRITE + case ITE: + { + /* READ((ITE cond thn els) j) + * + * is transformed into + * + * (ITE cond (READ thn j) (READ els j)) + */ + + //(ITE cond thn els) + ASTNode term0 = term[0]; + //READINDEX j + ASTNode j = TransformTerm(term[1]); + + ASTNode cond = term0[0]; + //first array + ASTNode t01 = term0[1]; + //second array + ASTNode t02 = term0[2]; + + cond = TransformFormula(cond); + ASTNode thn = TransformTerm(t01); + ASTNode els = TransformTerm(t02); + + if (!(t01.GetValueWidth() == t02.GetValueWidth() && t01.GetValueWidth() == thn.GetValueWidth() && t01.GetValueWidth() + == els.GetValueWidth())) + FatalError("TransformArray: length of THENbranch != length of ELSEbranch in the term t = \n", term); + + if (!(t01.GetIndexWidth() == t02.GetIndexWidth() && t01.GetIndexWidth() == thn.GetIndexWidth() && t01.GetIndexWidth() + == els.GetIndexWidth())) + FatalError("TransformArray: length of THENbranch != length of ELSEbranch in the term t = \n", term); + + //(READ thn j) + ASTNode thnRead = CreateTerm(READ, width, thn, j); + BVTypeCheck(thnRead); + thnRead = TransformArray(thnRead); + + //(READ els j) + ASTNode elsRead = CreateTerm(READ, width, els, j); + BVTypeCheck(elsRead); + elsRead = TransformArray(elsRead); + + //(ITE cond (READ thn j) (READ els j)) + result = CreateSimplifiedTermITE(cond, thnRead, elsRead); + BVTypeCheck(result); + break; + } + default: + FatalError("TransformArray: The READ is NOT over SYMBOL/WRITE/ITE", term); + break; + } + break; + } //end of READ switch + default: + FatalError("TransformArray: input term is of wrong kind: ", ASTUndefined); + break; + } + + TransformMap[term] = result; + return result; +} //end of TransformArray() } //end of namespace BEEV diff --git a/AST/asttest.cpp b/AST/asttest.cpp index 57f3d20..f2a8c60 100644 --- a/AST/asttest.cpp +++ b/AST/asttest.cpp @@ -5,25 +5,25 @@ using namespace BEEV; int main() { - BeevMgr * bm = new BeevMgr(); - ASTNode s1 = bm->CreateSymbol("foo"); - s1 = bm->CreateSymbol("foo1"); - s1 = bm->CreateSymbol("foo2"); - ASTNode s2 = bm->CreateSymbol("bar"); - cout << "s1" << s1 << endl; - cout << "s2" << s2 << endl; + BeevMgr * bm = new BeevMgr(); + ASTNode s1 = bm->CreateSymbol("foo"); + s1 = bm->CreateSymbol("foo1"); + s1 = bm->CreateSymbol("foo2"); + ASTNode s2 = bm->CreateSymbol("bar"); + cout << "s1" << s1 << endl; + cout << "s2" << s2 << endl; - ASTNode b1 = bm->CreateBVConst(5,12); - ASTNode b2 = bm->CreateBVConst(6,36); - cout << "b1: " << b1 << endl; - cout << "b2: " << b2 << endl; + ASTNode b1 = bm->CreateBVConst(5, 12); + ASTNode b2 = bm->CreateBVConst(6, 36); + cout << "b1: " << b1 << endl; + cout << "b2: " << b2 << endl; - ASTNode a1 = bm->CreateNode(EQ, s1, s2); - ASTNode a2 = bm->CreateNode(AND, s1, s2); - a1 = bm->CreateNode(OR, s1, s2); - ASTNode a3 = bm->CreateNode(IMPLIES, a1, a2); - ASTNode a4 = bm->CreateNode(IMPLIES, s1, a2); - cout << "a3" << a3 << endl; - cout << "a4" << a4 << endl; - return 0; + ASTNode a1 = bm->CreateNode(EQ, s1, s2); + ASTNode a2 = bm->CreateNode(AND, s1, s2); + a1 = bm->CreateNode(OR, s1, s2); + ASTNode a3 = bm->CreateNode(IMPLIES, a1, a2); + ASTNode a4 = bm->CreateNode(IMPLIES, s1, a2); + cout << "a3" << a3 << endl; + cout << "a4" << a4 << endl; + return 0; } diff --git a/AST/bbtest.cpp b/AST/bbtest.cpp index 83aa6a4..7fd5c95 100644 --- a/AST/bbtest.cpp +++ b/AST/bbtest.cpp @@ -4,93 +4,93 @@ using namespace BEEV; int main() { - const int size = 32; - - BeevMgr *bm = new BeevMgr(); - ASTNode s1 = bm->CreateSymbol("x"); - s1.SetValueWidth(size); - cout << "s1" << s1 << endl; - ASTNode s2 = bm->CreateSymbol("y"); - s2.SetValueWidth(size); - cout << "s2" << s2 << endl; - ASTNode s3 = bm->CreateSymbol("z"); - s3.SetValueWidth(size); - cout << "s3" << s3 << endl; - - ASTNode c1 = bm->CreateBVConst(size,0); - cout << "c1" << c1 << endl; - ASTVec bbc1 = bm->BBTerm(c1); - cout << "bitblasted c1 " << endl; - LispPrintVec(cout, bbc1, 0); - cout << endl; - bm->AlreadyPrintedSet.clear(); - - ASTNode c2 = bm->CreateBVConst(size,1); - c2.SetValueWidth(size); - cout << "c2" << c2 << endl; - ASTVec bbc2 = bm->BBTerm(c2); - cout << "bitblasted c2 " << endl; - LispPrintVec(cout, bbc2, 0); - cout << endl; - bm->AlreadyPrintedSet.clear(); - - ASTNode c3 = bm->CreateBVConst(size, 0xFFFFFFFF); - c3.SetValueWidth(size); - cout << "c3" << c3 << endl; - ASTVec bbc3 = bm->BBTerm(c3); - cout << "bitblasted c3 " << endl; - LispPrintVec(cout, bbc3, 0); - cout << endl; - bm->AlreadyPrintedSet.clear(); - - ASTNode c4 = bm->CreateBVConst(size, 0xAAAAAAAA); - c4.SetValueWidth(size); - cout << "c4" << c4 << endl; - ASTVec bbc4 = bm->BBTerm(c4); - cout << "bitblasted c4 " << endl; - LispPrintVec(cout, bbc4, 0); - cout << endl; - bm->AlreadyPrintedSet.clear(); - -// ASTNode b1 = bm->CreateBVConst(12); -// ASTNode b2 = bm->CreateBVConst(36); -// cout << "b1: " << b1 << endl; -// cout << "b2: " << b2 << endl; - - ASTNode a1 = bm->CreateNode(BVPLUS, s1, s2); - a1.SetValueWidth(size); - - ASTVec& bba1 = bm->BBTerm(a1); - cout << "bitblasted a1 " << endl; - LispPrintVec(cout, bba1, 0); - cout << endl; - bm->AlreadyPrintedSet.clear(); - - ASTNode a2 = bm->CreateNode(BVPLUS, s1, s2, s3); - a1.SetValueWidth(2); - - ASTVec& bba2 = bm->BBTerm(a2); - cout << "bitblasted a2 " << endl; - LispPrintVec(cout, bba2, 0); - cout << endl; - bm->AlreadyPrintedSet.clear(); - - ASTNode a3 = bm->CreateNode(BVXOR, s1, s2); - a3.SetValueWidth(2); - - ASTVec& bba3 = bm->BBTerm(a3); - cout << "bitblasted a3 " << endl; - LispPrintVec(cout, bba3, 0); - cout << endl; - bm->AlreadyPrintedSet.clear(); - - ASTNode a4 = bm->CreateNode(EQ, s1, s2); - ASTNode bba4 = bm->BBForm(a4); - cout << "bitblasted a4 " << endl << bba4 << endl; - - ASTNode a5 = bm->CreateNode(BVLE, s1, s2); - ASTNode bba5 = bm->BBForm(a5); - cout << "bitblasted a5 " << endl << bba5 << endl; - - return 0; + const int size = 32; + + BeevMgr *bm = new BeevMgr(); + ASTNode s1 = bm->CreateSymbol("x"); + s1.SetValueWidth(size); + cout << "s1" << s1 << endl; + ASTNode s2 = bm->CreateSymbol("y"); + s2.SetValueWidth(size); + cout << "s2" << s2 << endl; + ASTNode s3 = bm->CreateSymbol("z"); + s3.SetValueWidth(size); + cout << "s3" << s3 << endl; + + ASTNode c1 = bm->CreateBVConst(size, 0); + cout << "c1" << c1 << endl; + ASTVec bbc1 = bm->BBTerm(c1); + cout << "bitblasted c1 " << endl; + LispPrintVec(cout, bbc1, 0); + cout << endl; + bm->AlreadyPrintedSet.clear(); + + ASTNode c2 = bm->CreateBVConst(size, 1); + c2.SetValueWidth(size); + cout << "c2" << c2 << endl; + ASTVec bbc2 = bm->BBTerm(c2); + cout << "bitblasted c2 " << endl; + LispPrintVec(cout, bbc2, 0); + cout << endl; + bm->AlreadyPrintedSet.clear(); + + ASTNode c3 = bm->CreateBVConst(size, 0xFFFFFFFF); + c3.SetValueWidth(size); + cout << "c3" << c3 << endl; + ASTVec bbc3 = bm->BBTerm(c3); + cout << "bitblasted c3 " << endl; + LispPrintVec(cout, bbc3, 0); + cout << endl; + bm->AlreadyPrintedSet.clear(); + + ASTNode c4 = bm->CreateBVConst(size, 0xAAAAAAAA); + c4.SetValueWidth(size); + cout << "c4" << c4 << endl; + ASTVec bbc4 = bm->BBTerm(c4); + cout << "bitblasted c4 " << endl; + LispPrintVec(cout, bbc4, 0); + cout << endl; + bm->AlreadyPrintedSet.clear(); + + // ASTNode b1 = bm->CreateBVConst(12); + // ASTNode b2 = bm->CreateBVConst(36); + // cout << "b1: " << b1 << endl; + // cout << "b2: " << b2 << endl; + + ASTNode a1 = bm->CreateNode(BVPLUS, s1, s2); + a1.SetValueWidth(size); + + ASTVec& bba1 = bm->BBTerm(a1); + cout << "bitblasted a1 " << endl; + LispPrintVec(cout, bba1, 0); + cout << endl; + bm->AlreadyPrintedSet.clear(); + + ASTNode a2 = bm->CreateNode(BVPLUS, s1, s2, s3); + a1.SetValueWidth(2); + + ASTVec& bba2 = bm->BBTerm(a2); + cout << "bitblasted a2 " << endl; + LispPrintVec(cout, bba2, 0); + cout << endl; + bm->AlreadyPrintedSet.clear(); + + ASTNode a3 = bm->CreateNode(BVXOR, s1, s2); + a3.SetValueWidth(2); + + ASTVec& bba3 = bm->BBTerm(a3); + cout << "bitblasted a3 " << endl; + LispPrintVec(cout, bba3, 0); + cout << endl; + bm->AlreadyPrintedSet.clear(); + + ASTNode a4 = bm->CreateNode(EQ, s1, s2); + ASTNode bba4 = bm->BBForm(a4); + cout << "bitblasted a4 " << endl << bba4 << endl; + + ASTNode a5 = bm->CreateNode(BVLE, s1, s2); + ASTNode bba5 = bm->BBForm(a5); + cout << "bitblasted a5 " << endl << bba5 << endl; + + return 0; } diff --git a/AST/cnftest.cpp b/AST/cnftest.cpp index 7ce270c..2c337c4 100644 --- a/AST/cnftest.cpp +++ b/AST/cnftest.cpp @@ -8,40 +8,40 @@ using namespace BEEV; int main() { - const int size = 1; - - BeevMgr *bm = new BeevMgr(); - ASTNode s1 = bm->CreateSymbol("x"); - s1.SetValueWidth(size); - - cout << "s1" << s1 << endl; - ASTNode s2 = bm->CreateSymbol("y"); - s2.SetValueWidth(size); - - cout << "s2" << s2 << endl; - ASTNode s3 = bm->CreateSymbol("z"); - s3.SetValueWidth(size); - - cout << "s3" << s3 << endl; - - ASTNode bbs1 = bm->BBForm(s1); - cout << "bitblasted s1" << endl << bbs1 << endl; - bm->PrintClauseList(cout, bm->ToCNF(bbs1)); - - ASTNode a2 = bm->CreateNode(AND, s1, s2); - ASTNode bba2 = bm->BBForm(a2); - cout << "bitblasted a2" << endl << bba2 << endl; - bm->PrintClauseList(cout, bm->ToCNF(bba2)); - - ASTNode a3 = bm->CreateNode(OR, s1, s2); - ASTNode bba3 = bm->BBForm(a3); - cout << "bitblasted a3" << endl << bba3 << endl; - bm->PrintClauseList(cout, bm->ToCNF(bba3)); - - ASTNode a4 = bm->CreateNode(EQ, s1, s2); - ASTNode bba4 = bm->BBForm(a4); - cout << "bitblasted a4 " << endl << bba4 << endl; - - bm->PrintClauseList(cout, bm->ToCNF(bba4)); + const int size = 1; + + BeevMgr *bm = new BeevMgr(); + ASTNode s1 = bm->CreateSymbol("x"); + s1.SetValueWidth(size); + + cout << "s1" << s1 << endl; + ASTNode s2 = bm->CreateSymbol("y"); + s2.SetValueWidth(size); + + cout << "s2" << s2 << endl; + ASTNode s3 = bm->CreateSymbol("z"); + s3.SetValueWidth(size); + + cout << "s3" << s3 << endl; + + ASTNode bbs1 = bm->BBForm(s1); + cout << "bitblasted s1" << endl << bbs1 << endl; + bm->PrintClauseList(cout, bm->ToCNF(bbs1)); + + ASTNode a2 = bm->CreateNode(AND, s1, s2); + ASTNode bba2 = bm->BBForm(a2); + cout << "bitblasted a2" << endl << bba2 << endl; + bm->PrintClauseList(cout, bm->ToCNF(bba2)); + + ASTNode a3 = bm->CreateNode(OR, s1, s2); + ASTNode bba3 = bm->BBForm(a3); + cout << "bitblasted a3" << endl << bba3 << endl; + bm->PrintClauseList(cout, bm->ToCNF(bba3)); + + ASTNode a4 = bm->CreateNode(EQ, s1, s2); + ASTNode bba4 = bm->BBForm(a4); + cout << "bitblasted a4 " << endl << bba4 << endl; + + bm->PrintClauseList(cout, bm->ToCNF(bba4)); } diff --git a/AST/printer/CPrinter.cpp b/AST/printer/CPrinter.cpp index 482c72a..34358bb 100644 --- a/AST/printer/CPrinter.cpp +++ b/AST/printer/CPrinter.cpp @@ -1,11 +1,11 @@ #include "printers.h" -namespace printer { +namespace printer +{ using std::string; using namespace BEEV; - // printer for C code (copied from PL_Print()) // TODO: this does not fully implement printing of all of the STP // language - FatalError calls inserted for unimplemented @@ -13,14 +13,16 @@ using namespace BEEV; // FatalError("C_Print1: printing not implemented for this kind: ",*this); // helper function for printing C code (copied from PL_Print1()) -void C_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { +void C_Print1(ostream& os, const ASTNode n, int indentation, bool letize) +{ unsigned int upper, lower, num_bytes; Kind LHSkind, RHSkind; //os << spaces(indentation); //os << endl << spaces(indentation); - if (!n.IsDefined()) { + if (!n.IsDefined()) + { os << ""; return; } @@ -30,14 +32,16 @@ void C_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { //this is to print letvars for shared subterms inside the printing //of "(LET v0 = term1, v1=term1@term2,... - if ((bm.NodeLetVarMap1.find(n) != bm.NodeLetVarMap1.end()) && !letize) { + if ((bm.NodeLetVarMap1.find(n) != bm.NodeLetVarMap1.end()) && !letize) + { C_Print1(os, (bm.NodeLetVarMap1[n]), indentation, letize); return; } //this is to print letvars for shared subterms inside the actual //term to be printed - if ((bm.NodeLetVarMap.find(n) != bm.NodeLetVarMap.end()) && letize) { + if ((bm.NodeLetVarMap.find(n) != bm.NodeLetVarMap.end()) && letize) + { C_Print1(os, (bm.NodeLetVarMap[n]), indentation, letize); return; } @@ -45,7 +49,8 @@ void C_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { //otherwise print it normally Kind kind = n.GetKind(); const ASTVec &c = n.GetChildren(); - switch (kind) { + switch (kind) + { case BVGETBIT: FatalError("C_Print1: printing not implemented for this kind: ", n); C_Print1(os, c[0], indentation, letize); @@ -110,7 +115,7 @@ void C_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { case BVCONCAT: FatalError("C_Print1: printing not implemented for this kind: ", n); // stopgap for un-implemented features os << "("; - C_Print1(os,c[0], indentation, letize); + C_Print1(os, c[0], indentation, letize); os << " @ "; C_Print1(os, c[1], indentation, letize); os << ")" << endl; @@ -143,13 +148,15 @@ void C_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { assert (num_bytes > 0); // for multi-byte extraction, use the ADDRESS - if (num_bytes > 1) { + if (num_bytes > 1) + { os << "&"; C_Print1(os, c[0], indentation, letize); os << "[" << lower / 8 << "]"; } // for single-byte extraction, use the VALUE - else { + else + { C_Print1(os, c[0], indentation, letize); os << "[" << lower / 8 << "]"; } @@ -166,7 +173,7 @@ void C_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { case BVRIGHTSHIFT: FatalError("C_Print1: printing not implemented for this kind: ", n); // stopgap for un-implemented features os << "("; - C_Print1(os,c[0], indentation, letize); + C_Print1(os, c[0], indentation, letize); os << " >> "; os << GetUnsignedConst(c[1]); os << ")"; @@ -180,7 +187,8 @@ void C_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { case BVMOD: os << kind << "("; os << n.GetValueWidth(); - for (ASTVec::const_iterator it = c.begin(), itend = c.end(); it != itend; it++) { + for (ASTVec::const_iterator it = c.begin(), itend = c.end(); it != itend; it++) + { os << ", " << endl; C_Print1(os, *it, indentation, letize); } @@ -284,34 +292,39 @@ void C_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { // try to figure out whether it's a single-byte or multi-byte // comparison - if (LHSkind == BVEXTRACT) { + if (LHSkind == BVEXTRACT) + { upper = GetUnsignedConst(c[0].GetChildren()[1]); lower = GetUnsignedConst(c[0].GetChildren()[2]); num_bytes = (upper - lower + 1) / 8; } - else if (RHSkind == BVEXTRACT) { + else if (RHSkind == BVEXTRACT) + { upper = GetUnsignedConst(c[1].GetChildren()[1]); lower = GetUnsignedConst(c[1].GetChildren()[2]); num_bytes = (upper - lower + 1) / 8; } - if (num_bytes > 1) { + if (num_bytes > 1) + { os << "(memcmp("; - C_Print1(os,c[0], indentation, letize); + C_Print1(os, c[0], indentation, letize); os << ", "; C_Print1(os, c[1], indentation, letize); os << ", "; os << num_bytes; os << ") == 0)"; } - else if (num_bytes == 1) { + else if (num_bytes == 1) + { os << "("; C_Print1(os, c[0], indentation, letize); os << " == "; C_Print1(os, c[1], indentation, letize); os << ")"; } - else { + else + { FatalError("C_Print1: ugh problem in implementing =="); } @@ -326,15 +339,18 @@ void C_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { case OR: case NAND: case NOR: - case XOR: { + case XOR: + { os << "("; C_Print1(os, c[0], indentation, letize); ASTVec::const_iterator it = c.begin(); ASTVec::const_iterator itend = c.end(); it++; - for (; it != itend; it++) { - switch (kind) { + for (; it != itend; it++) + { + switch (kind) + { case AND: os << " && "; break; @@ -362,11 +378,11 @@ void C_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { FatalError("C_Print1: printing not implemented for this kind: ", n); // stopgap for un-implemented features os << "("; os << "("; - C_Print1(os,c[0], indentation, letize); + C_Print1(os, c[0], indentation, letize); os << ")"; os << " <=> "; os << "("; - C_Print1(os,c[1], indentation, letize); + C_Print1(os, c[1], indentation, letize); os << ")"; os << ")"; os << endl; @@ -375,7 +391,7 @@ void C_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { FatalError("C_Print1: printing not implemented for this kind: ", n); // stopgap for un-implemented features os << "("; os << "("; - C_Print1(os, c[0],indentation, letize); + C_Print1(os, c[0], indentation, letize); os << ")"; os << " => "; os << "("; @@ -388,7 +404,7 @@ void C_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { FatalError("C_Print1: printing not implemented for this kind: ", n); // stopgap for un-implemented features os << kind << "("; - C_Print1(os, c[0],indentation, letize); + C_Print1(os, c[0], indentation, letize); os << ","; os << n.GetValueWidth(); os << ")" << endl; @@ -411,7 +427,8 @@ void C_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { //2. In the second pass print a "global let" and then print N //2. as follows: Every occurence of a node occuring more than //2. once is replaced with the corresponding let variable. -ostream& C_Print(ostream &os, const ASTNode n, int indentation) { +ostream& C_Print(ostream &os, const ASTNode n, int indentation) +{ // Clear the PrintMap BeevMgr& bm = n.GetBeevMgr(); bm.PLPrintNodeSet.clear(); @@ -432,7 +449,8 @@ ostream& C_Print(ostream &os, const ASTNode n, int indentation) { //3. Then print the Node itself, replacing every occurence of //3. expr1 with var1, expr2 with var2, ... //os << "("; - if (0 < bm.NodeLetVarMap.size()) { + if (0 < bm.NodeLetVarMap.size()) + { //ASTNodeMap::iterator it=bm.NodeLetVarMap.begin(); //ASTNodeMap::iterator itend=bm.NodeLetVarMap.end(); std::vector >::iterator it = bm.NodeLetVarVec.begin(); @@ -441,10 +459,12 @@ ostream& C_Print(ostream &os, const ASTNode n, int indentation) { // start a new block to create new static scope os << "{" << endl; - for (; it != itend; it++) { + for (; it != itend; it++) + { // see if it's a BVEXTRACT, and if so, whether it's multi-byte - if (it->second.GetKind() == BVEXTRACT) { + if (it->second.GetKind() == BVEXTRACT) + { upper = GetUnsignedConst(it->second.GetChildren()[1]); lower = GetUnsignedConst(it->second.GetChildren()[2]); num_bytes = (upper - lower + 1) / 8; @@ -452,25 +472,27 @@ ostream& C_Print(ostream &os, const ASTNode n, int indentation) { } //print the let var first - if (num_bytes > 1) { + if (num_bytes > 1) + { // for multi-byte assignment, use 'memcpy' and array notation os << "unsigned char "; - C_Print1(os, it->first,indentation, false); + C_Print1(os, it->first, indentation, false); os << "[" << num_bytes << "]; "; os << "memcpy("; - C_Print1(os,it->first, indentation, false); + C_Print1(os, it->first, indentation, false); os << ", "; //print the expr - C_Print1(os,it->second, indentation, false); + C_Print1(os, it->second, indentation, false); os << ", " << num_bytes << ");"; } - else { + else + { // for single-byte assignment, use '=' os << "unsigned char "; - C_Print1(os, it->first,indentation, false); + C_Print1(os, it->first, indentation, false); os << " = "; //print the expr - C_Print1(os, it->second,indentation, false); + C_Print1(os, it->second, indentation, false); os << ";" << endl; } @@ -483,7 +505,8 @@ ostream& C_Print(ostream &os, const ASTNode n, int indentation) { os << ";" << endl << "}"; } - else { + else + { os << "stp_assert "; C_Print1(os, n, indentation, false); os << ";"; diff --git a/AST/printer/SMTLIBPrinter.cpp b/AST/printer/SMTLIBPrinter.cpp index c041677..d761fe6 100644 --- a/AST/printer/SMTLIBPrinter.cpp +++ b/AST/printer/SMTLIBPrinter.cpp @@ -1,6 +1,7 @@ #include "printers.h" -namespace printer { +namespace printer +{ using std::string; using namespace BEEV; @@ -8,15 +9,18 @@ using namespace BEEV; string functionToSMTLIBName(const BEEV::Kind k); void SMTLIB_Print1(ostream& os, const BEEV::ASTNode n, int indentation, bool letize); -void outputBitVec(const ASTNode n, ostream& os) { +void outputBitVec(const ASTNode n, ostream& os) +{ Kind k = n.GetKind(); const ASTVec &c = n.GetChildren(); ASTNode op; - if (BITVECTOR == k) { + if (BITVECTOR == k) + { op = c[0]; } - else if (BVCONST == k) { + else if (BVCONST == k) + { op = n; } else @@ -33,10 +37,12 @@ void outputBitVec(const ASTNode n, ostream& os) { CONSTANTBV::BitVector_Dispose(str); } -void SMTLIB_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { +void SMTLIB_Print1(ostream& os, const ASTNode n, int indentation, bool letize) +{ //os << spaces(indentation); //os << endl << spaces(indentation); - if (!n.IsDefined()) { + if (!n.IsDefined()) + { os << ""; return; } @@ -46,14 +52,16 @@ void SMTLIB_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { //this is to print letvars for shared subterms inside the printing //of "(LET v0 = term1, v1=term1@term2,... - if ((bm.NodeLetVarMap1.find(n) != bm.NodeLetVarMap1.end()) && !letize) { + if ((bm.NodeLetVarMap1.find(n) != bm.NodeLetVarMap1.end()) && !letize) + { SMTLIB_Print1(os, (bm.NodeLetVarMap1[n]), indentation, letize); return; } //this is to print letvars for shared subterms inside the actual //term to be printed - if ((bm.NodeLetVarMap.find(n) != bm.NodeLetVarMap.end()) && letize) { + if ((bm.NodeLetVarMap.find(n) != bm.NodeLetVarMap.end()) && letize) + { SMTLIB_Print1(os, (bm.NodeLetVarMap[n]), indentation, letize); return; } @@ -61,7 +69,8 @@ void SMTLIB_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { //otherwise print it normally Kind kind = n.GetKind(); const ASTVec &c = n.GetChildren(); - switch (kind) { + switch (kind) + { case BITVECTOR: case BVCONST: outputBitVec(n, os); @@ -78,7 +87,8 @@ void SMTLIB_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { break; case BVSX: - case BVZX: { + case BVZX: + { unsigned int amount = GetUnsignedConst(c[1]); if (BVZX == kind) os << "(zero_extend["; @@ -90,7 +100,8 @@ void SMTLIB_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { os << ")"; } break; - case BVEXTRACT: { + case BVEXTRACT: + { unsigned int upper = GetUnsignedConst(c[1]); unsigned int lower = GetUnsignedConst(c[2]); assert(upper >= lower); @@ -99,11 +110,13 @@ void SMTLIB_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { os << ")"; } break; - default: { + default: + { os << "(" << functionToSMTLIBName(kind); ASTVec::const_iterator iend = c.end(); - for (ASTVec::const_iterator i = c.begin(); i != iend; i++) { + for (ASTVec::const_iterator i = c.begin(); i != iend; i++) + { os << " "; SMTLIB_Print1(os, *i, 0, letize); } @@ -114,7 +127,8 @@ void SMTLIB_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { } // copied from Presentation Langauge printer. -ostream& SMTLIB_Print(ostream &os, const ASTNode n, const int indentation) { +ostream& SMTLIB_Print(ostream &os, const ASTNode n, const int indentation) +{ // Clear the PrintMap BeevMgr& bm = n.GetBeevMgr(); bm.PLPrintNodeSet.clear(); @@ -133,7 +147,8 @@ ostream& SMTLIB_Print(ostream &os, const ASTNode n, const int indentation) { //3. Then print the Node itself, replacing every occurence of //3. expr1 with var1, expr2 with var2, ... //os << "("; - if (0 < bm.NodeLetVarMap.size()) { + if (0 < bm.NodeLetVarMap.size()) + { //ASTNodeMap::iterator it=bm.NodeLetVarMap.begin(); //ASTNodeMap::iterator itend=bm.NodeLetVarMap.end(); std::vector >::iterator it = bm.NodeLetVarVec.begin(); @@ -149,7 +164,8 @@ ostream& SMTLIB_Print(ostream &os, const ASTNode n, const int indentation) { //update the second map for proper printing of LET bm.NodeLetVarMap1[it->second] = it->first; - for (it++; it != itend; it++) { + for (it++; it != itend; it++) + { os << "," << endl; //print the let var first SMTLIB_Print1(os, it->first, indentation, false); @@ -172,8 +188,10 @@ ostream& SMTLIB_Print(ostream &os, const ASTNode n, const int indentation) { return os; } -string functionToSMTLIBName(const Kind k) { - switch (k) { +string functionToSMTLIBName(const Kind k) +{ + switch (k) + { case AND: case BVAND: case BVNAND: @@ -233,7 +251,8 @@ string functionToSMTLIBName(const Kind k) { case SBVREM: return "bvsrem"; - default: { + default: + { cerr << "Unknown name when outputting:"; FatalError(_kind_names[k]); return ""; // to quieten compiler/ diff --git a/AST/printer/dotPrinter.cpp b/AST/printer/dotPrinter.cpp index 0ffd9f2..7038567 100644 --- a/AST/printer/dotPrinter.cpp +++ b/AST/printer/dotPrinter.cpp @@ -4,14 +4,16 @@ * Outputs in DOT graph format. Can be layed out by the dotty/neato tools. */ -namespace printer { +namespace printer +{ using std::string; using namespace BEEV; void outputBitVec(const ASTNode n, ostream& os); -void Dot_Print1(ostream &os, const ASTNode n, hash_set *alreadyOutput) { +void Dot_Print1(ostream &os, const ASTNode n, hash_set *alreadyOutput) +{ // check if this node has already been printed. If so return. if (alreadyOutput->find(n.GetNodeNum()) != alreadyOutput->end()) @@ -20,7 +22,7 @@ void Dot_Print1(ostream &os, const ASTNode n, hash_set *alreadyOutput) { alreadyOutput->insert(n.GetNodeNum()); os << "n" << n.GetNodeNum() << "[label =\""; - switch(n.GetKind()) + switch (n.GetKind()) { case SYMBOL: n.nodeprint(os); @@ -35,27 +37,26 @@ void Dot_Print1(ostream &os, const ASTNode n, hash_set *alreadyOutput) { os << _kind_names[n.GetKind()]; } - - os << "\"];" << endl; - + os << "\"];" << endl; // print the edges to each child. - ASTVec ch = n.GetChildren(); - ASTVec::iterator itend = ch.end(); - int i =0; - for(ASTVec::iterator it = ch.begin(); it < itend; it++) - { - os << "n" << n.GetNodeNum() << " -> " << "n" << it->GetNodeNum() << "[label=" << i++ << "];" << endl; - } - - // print each of the children. - for(ASTVec::iterator it = ch.begin(); it < itend; it++) - { - Dot_Print1(os, *it, alreadyOutput); - } + ASTVec ch = n.GetChildren(); + ASTVec::iterator itend = ch.end(); + int i = 0; + for (ASTVec::iterator it = ch.begin(); it < itend; it++) + { + os << "n" << n.GetNodeNum() << " -> " << "n" << it->GetNodeNum() << "[label=" << i++ << "];" << endl; + } + + // print each of the children. + for (ASTVec::iterator it = ch.begin(); it < itend; it++) + { + Dot_Print1(os, *it, alreadyOutput); + } } -ostream& Dot_Print(ostream &os, const ASTNode n) { +ostream& Dot_Print(ostream &os, const ASTNode n) +{ os << "digraph G{" << endl; diff --git a/AST/printer/printers.h b/AST/printer/printers.h index fb99658..ae38669 100644 --- a/AST/printer/printers.h +++ b/AST/printer/printers.h @@ -5,13 +5,12 @@ #include "../ASTUtil.h" #include "../ASTKind.h" - namespace printer { - ostream& Dot_Print(ostream &os, const BEEV::ASTNode n); - ostream& SMTLIB_Print(ostream &os, const BEEV::ASTNode n, const int indentation=0); - ostream& C_Print(ostream &os, const BEEV::ASTNode n, const int indentation=0); +ostream& Dot_Print(ostream &os, const BEEV::ASTNode n); +ostream& SMTLIB_Print(ostream &os, const BEEV::ASTNode n, const int indentation = 0); +ostream& C_Print(ostream &os, const BEEV::ASTNode n, const int indentation = 0); } #endif /* PRINTERS_H_ */ diff --git a/bitvec/consteval.cpp b/bitvec/consteval.cpp index 8683763..e6ca42a 100644 --- a/bitvec/consteval.cpp +++ b/bitvec/consteval.cpp @@ -9,1082 +9,1141 @@ #include "../AST/AST.h" #include "../AST/ASTUtil.h" -namespace BEEV { +namespace BEEV +{ - //error printing - static void BVConstEvaluatorError(CONSTANTBV::ErrCode e, const ASTNode& t){ - std::string ss("BVConstEvaluator:"); - ss += (const char*)BitVector_Error(e); - FatalError(ss.c_str(), t); - } +//error printing +static void BVConstEvaluatorError(CONSTANTBV::ErrCode e, const ASTNode& t) +{ + std::string ss("BVConstEvaluator:"); + ss += (const char*) BitVector_Error(e); + FatalError(ss.c_str(), t); +} #ifndef NATIVE_C_ARITH - ASTNode BeevMgr::BVConstEvaluator(const ASTNode& t) { - ASTNode OutputNode; - Kind k = t.GetKind(); - - if(CheckSolverMap(t,OutputNode)) - return OutputNode; - OutputNode = t; - - unsigned int inputwidth = t.GetValueWidth(); - unsigned int outputwidth = inputwidth; - CBV output = NULL; - - CBV tmp0 = NULL; - CBV tmp1 = NULL; - - //saving some typing. BVPLUS does not use these variables. if the - //input BVPLUS has two nodes, then we want to avoid setting these - //variables. - if(1 == t.Degree() ){ - tmp0 = BVConstEvaluator(t[0]).GetBVConst(); - }else if(2 == t.Degree() && k != BVPLUS ) { - tmp0 = BVConstEvaluator(t[0]).GetBVConst(); - tmp1 = BVConstEvaluator(t[1]).GetBVConst(); - } - - switch(k) { - case UNDEFINED: - case READ: - case WRITE: - case SYMBOL: - FatalError("BVConstEvaluator: term is not a constant-term",t); - break; - case BVCONST: - //FIXME Handle this special case better - OutputNode = t; - break; - case BVNEG:{ - output = CONSTANTBV::BitVector_Create(inputwidth,true); - CONSTANTBV::Set_Complement(output,tmp0); - OutputNode = CreateBVConst(output,outputwidth); - break; - } - case BVSX: { - output = CONSTANTBV::BitVector_Create(inputwidth,true); - //unsigned * out0 = BVConstEvaluator(t[0]).GetBVConst(); - unsigned t0_width = t[0].GetValueWidth(); - if(inputwidth == t0_width) { - CONSTANTBV::BitVector_Copy(output, tmp0); - OutputNode = CreateBVConst(output, outputwidth); - } - else { - bool topbit_sign = (CONSTANTBV::BitVector_Sign(tmp0) < 0 ); - - if(topbit_sign){ - CONSTANTBV::BitVector_Fill(output); - } - CONSTANTBV::BitVector_Interval_Copy(output, tmp0, 0, 0, t0_width); - OutputNode = CreateBVConst(output, outputwidth); - } - break; - } - - case BVZX: { - output = CONSTANTBV::BitVector_Create(inputwidth,true); - unsigned t0_width = t[0].GetValueWidth(); - if(inputwidth == t0_width) { - CONSTANTBV::BitVector_Copy(output, tmp0); - OutputNode = CreateBVConst(output, outputwidth); - } - else { - CONSTANTBV::BitVector_Interval_Copy(output, tmp0, 0, 0, t0_width); - OutputNode = CreateBVConst(output, outputwidth); - } - break; - } - - - case BVLEFTSHIFT: - { - output = CONSTANTBV::BitVector_Create(inputwidth,true); - - // the shift is destructive, get a copy. - CONSTANTBV::BitVector_Interval_Copy(output, tmp0, 0, 0, inputwidth); - - // get the number of bits to shift it. - unsigned int shift = GetUnsignedConst(BVConstEvaluator(t[1])); - - CONSTANTBV::BitVector_Move_Left(output,shift); - OutputNode = CreateBVConst(output,outputwidth); - break; - } - case BVRIGHTSHIFT: - { - output = CONSTANTBV::BitVector_Create(inputwidth,true); - - // the shift is destructive, get a copy. - CONSTANTBV::BitVector_Interval_Copy(output, tmp0, 0, 0, inputwidth); - - // get the number of bits to shift it. - unsigned int shift = GetUnsignedConst(BVConstEvaluator(t[1])); - - CONSTANTBV::BitVector_Move_Right(output,shift); - OutputNode = CreateBVConst(output,outputwidth); - break; - } - - - case BVAND: { - output = CONSTANTBV::BitVector_Create(inputwidth,true); - CONSTANTBV::Set_Intersection(output,tmp0,tmp1); - OutputNode = CreateBVConst(output, outputwidth); - break; - } - case BVOR: { - output = CONSTANTBV::BitVector_Create(inputwidth,true); - CONSTANTBV::Set_Union(output,tmp0,tmp1); - OutputNode = CreateBVConst(output, outputwidth); - break; - } - case BVXOR: { - output = CONSTANTBV::BitVector_Create(inputwidth,true); - CONSTANTBV::Set_ExclusiveOr(output,tmp0,tmp1); - OutputNode = CreateBVConst(output, outputwidth); - break; - } - case BVSUB: { - output = CONSTANTBV::BitVector_Create(inputwidth,true); - bool carry = false; - CONSTANTBV::BitVector_sub(output,tmp0,tmp1,&carry); - OutputNode = CreateBVConst(output, outputwidth); - break; - } - case BVUMINUS: { - output = CONSTANTBV::BitVector_Create(inputwidth,true); - CONSTANTBV::BitVector_Negate(output, tmp0); - OutputNode = CreateBVConst(output, outputwidth); - break; - } - case BVEXTRACT: { - output = CONSTANTBV::BitVector_Create(inputwidth,true); - tmp0 = BVConstEvaluator(t[0]).GetBVConst(); - unsigned int hi = GetUnsignedConst(BVConstEvaluator(t[1])); - unsigned int low = GetUnsignedConst(BVConstEvaluator(t[2])); - unsigned int len = hi-low+1; - - CONSTANTBV::BitVector_Destroy(output); - output = CONSTANTBV::BitVector_Create(len, false); - CONSTANTBV::BitVector_Interval_Copy(output, tmp0, 0, low, len); - outputwidth = len; - OutputNode = CreateBVConst(output, outputwidth); - break; - } - //FIXME Only 2 inputs? - case BVCONCAT: { - output = CONSTANTBV::BitVector_Create(inputwidth,true); - unsigned t0_width = t[0].GetValueWidth(); - unsigned t1_width = t[1].GetValueWidth(); - CONSTANTBV::BitVector_Destroy(output); - - output = CONSTANTBV::BitVector_Concat(tmp0, tmp1); - outputwidth = t0_width + t1_width; - OutputNode = CreateBVConst(output, outputwidth); - - break; - } - case BVMULT: { - output = CONSTANTBV::BitVector_Create(inputwidth,true); - CBV tmp = CONSTANTBV::BitVector_Create(2*inputwidth,true); - CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Multiply(tmp,tmp0,tmp1); - - if(0 != e) { - BVConstEvaluatorError(e,t); - } - //FIXME WHAT IS MY OUTPUT???? THE SECOND HALF of tmp? - //CONSTANTBV::BitVector_Interval_Copy(output, tmp, 0, inputwidth, inputwidth); - CONSTANTBV::BitVector_Interval_Copy(output, tmp, 0, 0, inputwidth); - OutputNode = CreateBVConst(output, outputwidth); - CONSTANTBV::BitVector_Destroy(tmp); - break; - } - case BVPLUS: { - output = CONSTANTBV::BitVector_Create(inputwidth,true); - bool carry = false; - ASTVec c = t.GetChildren(); - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - CBV kk = BVConstEvaluator(*it).GetBVConst(); - CONSTANTBV::BitVector_add(output,output,kk,&carry); - carry = false; - //CONSTANTBV::BitVector_Destroy(kk); - } - OutputNode = CreateBVConst(output, outputwidth); - break; - } - //FIXME ANOTHER SPECIAL CASE - case SBVDIV: - case SBVREM:{ - OutputNode = BVConstEvaluator(TranslateSignedDivMod(t)); - break; - } - case BVDIV: - case BVMOD: { - CBV quotient = CONSTANTBV::BitVector_Create(inputwidth,true); - CBV remainder = CONSTANTBV::BitVector_Create(inputwidth,true); - - // tmp0 is dividend, tmp1 is the divisor - //All parameters to BitVector_Div_Pos must be distinct unlike BitVector_Divide - //FIXME the contents of the second parameter to Div_Pos is destroyed - //As tmp0 is currently the same as the copy belonging to an ASTNode t[0] - //this must be copied. - tmp0 = CONSTANTBV::BitVector_Clone(tmp0); - CONSTANTBV::ErrCode e= CONSTANTBV::BitVector_Div_Pos(quotient,tmp0,tmp1,remainder); - CONSTANTBV::BitVector_Destroy(tmp0); - - if(0 != e) { - //error printing - if(counterexample_checking_during_refinement) { - output = CONSTANTBV::BitVector_Create(inputwidth,true); - OutputNode = CreateBVConst(output, outputwidth); - bvdiv_exception_occured = true; - - // CONSTANTBV::BitVector_Destroy(output); - break; +ASTNode BeevMgr::BVConstEvaluator(const ASTNode& t) +{ + ASTNode OutputNode; + Kind k = t.GetKind(); + + if (CheckSolverMap(t, OutputNode)) + return OutputNode; + OutputNode = t; + + unsigned int inputwidth = t.GetValueWidth(); + unsigned int outputwidth = inputwidth; + CBV output = NULL; + + CBV tmp0 = NULL; + CBV tmp1 = NULL; + + //saving some typing. BVPLUS does not use these variables. if the + //input BVPLUS has two nodes, then we want to avoid setting these + //variables. + if (1 == t.Degree()) + { + tmp0 = BVConstEvaluator(t[0]).GetBVConst(); } - else { - BVConstEvaluatorError(e,t); + else if (2 == t.Degree() && k != BVPLUS) + { + tmp0 = BVConstEvaluator(t[0]).GetBVConst(); + tmp1 = BVConstEvaluator(t[1]).GetBVConst(); } - } //end of error printing - - //FIXME Not very standard in the current scheme - if(BVDIV == k){ - OutputNode = CreateBVConst(quotient, outputwidth); - CONSTANTBV::BitVector_Destroy(remainder); - }else{ - OutputNode = CreateBVConst(remainder, outputwidth); - CONSTANTBV::BitVector_Destroy(quotient); - } - - break; - } - case ITE: - if(ASTTrue == t[0]) - OutputNode = BVConstEvaluator(t[1]); - else if(ASTFalse == t[0]) - OutputNode = BVConstEvaluator(t[2]); - else - FatalError("BVConstEvaluator: ITE condiional must be either TRUE or FALSE:",t); - break; - case EQ: - if(CONSTANTBV::BitVector_equal(tmp0,tmp1)) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - case NEQ: - if(!CONSTANTBV::BitVector_equal(tmp0,tmp1)) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - case BVLT: - if(-1 == CONSTANTBV::BitVector_Lexicompare(tmp0,tmp1)) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - case BVLE: { - int comp = CONSTANTBV::BitVector_Lexicompare(tmp0,tmp1); - if(comp <= 0) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - } - case BVGT: - if(1 == CONSTANTBV::BitVector_Lexicompare(tmp0,tmp1)) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - case BVGE: { - int comp = CONSTANTBV::BitVector_Lexicompare(tmp0,tmp1); - if(comp >= 0) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - } - case BVSLT: - if(-1 == CONSTANTBV::BitVector_Compare(tmp0,tmp1)) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - case BVSLE: { - signed int comp = CONSTANTBV::BitVector_Compare(tmp0,tmp1); - if(comp <= 0) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - } - case BVSGT: - if(1 == CONSTANTBV::BitVector_Compare(tmp0,tmp1)) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - case BVSGE: { - int comp = CONSTANTBV::BitVector_Compare(tmp0,tmp1); - if(comp >= 0) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - } - default: - FatalError("BVConstEvaluator: The input kind is not supported yet:",t); - break; - } -/* - if(BVCONST != k){ - cerr< 32bits",t); - if(!(0 <= low <= hi <= 64)) - FatalError("ConstantEvaluator: low bit in BVEXTRACT is > 32bits or hi",t); - - //64 bit mask. - unsigned long long int mask1 = 0xffffffffffffffffLL; - mask1 >>= 64-(hi+1); - - //extract val[hi:0] - val &= mask1; - //extract val[hi:low] - val >>= low; - output = val; - break; - } - case BVCONCAT: { - unsigned long long int q = BVConstEvaluator(t0).GetBVConst(); - unsigned long long int r = BVConstEvaluator(t1).GetBVConst(); - - unsigned int qlen = t[0].GetValueWidth(); - unsigned int rlen = t[1].GetValueWidth(); - unsigned int slen = t.GetValueWidth(); - if(!(0 < qlen + rlen <= 64)) - FatalError("BVConstEvaluator:" - "lengths of childnodes of BVCONCAT are > 64:",t); - - //64 bit mask for q - unsigned long long int qmask = 0xffffffffffffffffLL; - qmask >>= 64-qlen; - //zero the useless bits of q - q &= qmask; - - //64 bit mask for r - unsigned long long int rmask = 0xffffffffffffffffLL; - rmask >>= 64-rlen; - //zero the useless bits of r - r &= rmask; - - //concatenate - q <<= rlen; - q |= r; - - //64 bit mask for output s - unsigned long long int smask = 0xffffffffffffffffLL; - smask >>= 64-slen; - - //currently q has the output - output = q; - output &= smask; - break; - } - case BVMULT: { - output = t0.GetBVConst() * t1.GetBVConst(); - - //64 bit mask - unsigned long long int mask = 0xffffffffffffffffLL; - mask = mask >> (64 - inputwidth); - output &= mask; - break; - } - case BVPLUS: { - ASTVec c = t.GetChildren(); - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) - output += BVConstEvaluator(*it).GetBVConst(); - - //64 bit mask - unsigned long long int mask = 0xffffffffffffffffLL; - mask = mask >> (64 -inputwidth); - output &= mask; - break; - } - case SBVDIV: - case SBVREM: { - output = BVConstEvaluator(TranslateSignedDivMod(t)).GetBVConst(); - break; - } - case BVDIV: { - if(0 == t1.GetBVConst()) { - //if denominator is 0 then - // (if refinement is ON then output is set to 0) - // (else produce a fatal error) - if(counterexample_checking_during_refinement) { - output = 0; - bvdiv_exception_occured = true; - break; - } - else { - FatalError("BVConstEvaluator: divide by zero not allowed:",t); + + switch (k) + { + case UNDEFINED: + case READ: + case WRITE: + case SYMBOL: + FatalError("BVConstEvaluator: term is not a constant-term", t); + break; + case BVCONST: + //FIXME Handle this special case better + OutputNode = t; + break; + case BVNEG: + { + output = CONSTANTBV::BitVector_Create(inputwidth, true); + CONSTANTBV::Set_Complement(output, tmp0); + OutputNode = CreateBVConst(output, outputwidth); + break; + } + case BVSX: + { + output = CONSTANTBV::BitVector_Create(inputwidth, true); + //unsigned * out0 = BVConstEvaluator(t[0]).GetBVConst(); + unsigned t0_width = t[0].GetValueWidth(); + if (inputwidth == t0_width) + { + CONSTANTBV::BitVector_Copy(output, tmp0); + OutputNode = CreateBVConst(output, outputwidth); + } + else + { + bool topbit_sign = (CONSTANTBV::BitVector_Sign(tmp0) < 0); + + if (topbit_sign) + { + CONSTANTBV::BitVector_Fill(output); + } + CONSTANTBV::BitVector_Interval_Copy(output, tmp0, 0, 0, t0_width); + OutputNode = CreateBVConst(output, outputwidth); + } + break; + } + + case BVZX: + { + output = CONSTANTBV::BitVector_Create(inputwidth, true); + unsigned t0_width = t[0].GetValueWidth(); + if (inputwidth == t0_width) + { + CONSTANTBV::BitVector_Copy(output, tmp0); + OutputNode = CreateBVConst(output, outputwidth); + } + else + { + CONSTANTBV::BitVector_Interval_Copy(output, tmp0, 0, 0, t0_width); + OutputNode = CreateBVConst(output, outputwidth); + } + break; + } + + case BVLEFTSHIFT: + { + output = CONSTANTBV::BitVector_Create(inputwidth, true); + + // the shift is destructive, get a copy. + CONSTANTBV::BitVector_Interval_Copy(output, tmp0, 0, 0, inputwidth); + + // get the number of bits to shift it. + unsigned int shift = GetUnsignedConst(BVConstEvaluator(t[1])); + + CONSTANTBV::BitVector_Move_Left(output, shift); + OutputNode = CreateBVConst(output, outputwidth); + break; + } + case BVRIGHTSHIFT: + { + output = CONSTANTBV::BitVector_Create(inputwidth, true); + + // the shift is destructive, get a copy. + CONSTANTBV::BitVector_Interval_Copy(output, tmp0, 0, 0, inputwidth); + + // get the number of bits to shift it. + unsigned int shift = GetUnsignedConst(BVConstEvaluator(t[1])); + + CONSTANTBV::BitVector_Move_Right(output, shift); + OutputNode = CreateBVConst(output, outputwidth); + break; + } + + case BVAND: + { + output = CONSTANTBV::BitVector_Create(inputwidth, true); + CONSTANTBV::Set_Intersection(output, tmp0, tmp1); + OutputNode = CreateBVConst(output, outputwidth); + break; + } + case BVOR: + { + output = CONSTANTBV::BitVector_Create(inputwidth, true); + CONSTANTBV::Set_Union(output, tmp0, tmp1); + OutputNode = CreateBVConst(output, outputwidth); + break; + } + case BVXOR: + { + output = CONSTANTBV::BitVector_Create(inputwidth, true); + CONSTANTBV::Set_ExclusiveOr(output, tmp0, tmp1); + OutputNode = CreateBVConst(output, outputwidth); + break; + } + case BVSUB: + { + output = CONSTANTBV::BitVector_Create(inputwidth, true); + bool carry = false; + CONSTANTBV::BitVector_sub(output, tmp0, tmp1, &carry); + OutputNode = CreateBVConst(output, outputwidth); + break; + } + case BVUMINUS: + { + output = CONSTANTBV::BitVector_Create(inputwidth, true); + CONSTANTBV::BitVector_Negate(output, tmp0); + OutputNode = CreateBVConst(output, outputwidth); + break; + } + case BVEXTRACT: + { + output = CONSTANTBV::BitVector_Create(inputwidth, true); + tmp0 = BVConstEvaluator(t[0]).GetBVConst(); + unsigned int hi = GetUnsignedConst(BVConstEvaluator(t[1])); + unsigned int low = GetUnsignedConst(BVConstEvaluator(t[2])); + unsigned int len = hi - low + 1; + + CONSTANTBV::BitVector_Destroy(output); + output = CONSTANTBV::BitVector_Create(len, false); + CONSTANTBV::BitVector_Interval_Copy(output, tmp0, 0, low, len); + outputwidth = len; + OutputNode = CreateBVConst(output, outputwidth); + break; + } + //FIXME Only 2 inputs? + case BVCONCAT: + { + output = CONSTANTBV::BitVector_Create(inputwidth, true); + unsigned t0_width = t[0].GetValueWidth(); + unsigned t1_width = t[1].GetValueWidth(); + CONSTANTBV::BitVector_Destroy(output); + + output = CONSTANTBV::BitVector_Concat(tmp0, tmp1); + outputwidth = t0_width + t1_width; + OutputNode = CreateBVConst(output, outputwidth); + + break; + } + case BVMULT: + { + output = CONSTANTBV::BitVector_Create(inputwidth, true); + CBV tmp = CONSTANTBV::BitVector_Create(2* inputwidth , true); + CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Multiply(tmp, tmp0, tmp1); + + if (0 != e) + { + BVConstEvaluatorError(e, t); + } + //FIXME WHAT IS MY OUTPUT???? THE SECOND HALF of tmp? + //CONSTANTBV::BitVector_Interval_Copy(output, tmp, 0, inputwidth, inputwidth); + CONSTANTBV::BitVector_Interval_Copy(output, tmp, 0, 0, inputwidth); + OutputNode = CreateBVConst(output, outputwidth); + CONSTANTBV::BitVector_Destroy(tmp); + break; + } + case BVPLUS: + { + output = CONSTANTBV::BitVector_Create(inputwidth, true); + bool carry = false; + ASTVec c = t.GetChildren(); + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + CBV kk = BVConstEvaluator(*it).GetBVConst(); + CONSTANTBV::BitVector_add(output, output, kk, &carry); + carry = false; + //CONSTANTBV::BitVector_Destroy(kk); + } + OutputNode = CreateBVConst(output, outputwidth); + break; + } + //FIXME ANOTHER SPECIAL CASE + case SBVDIV: + case SBVREM: + { + OutputNode = BVConstEvaluator(TranslateSignedDivMod(t)); + break; + } + case BVDIV: + case BVMOD: + { + CBV quotient = CONSTANTBV::BitVector_Create(inputwidth, true); + CBV remainder = CONSTANTBV::BitVector_Create(inputwidth, true); + + // tmp0 is dividend, tmp1 is the divisor + //All parameters to BitVector_Div_Pos must be distinct unlike BitVector_Divide + //FIXME the contents of the second parameter to Div_Pos is destroyed + //As tmp0 is currently the same as the copy belonging to an ASTNode t[0] + //this must be copied. + tmp0 = CONSTANTBV::BitVector_Clone(tmp0); + CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Div_Pos(quotient, tmp0, tmp1, remainder); + CONSTANTBV::BitVector_Destroy(tmp0); + + if (0 != e) + { + //error printing + if (counterexample_checking_during_refinement) + { + output = CONSTANTBV::BitVector_Create(inputwidth, true); + OutputNode = CreateBVConst(output, outputwidth); + bvdiv_exception_occured = true; + + // CONSTANTBV::BitVector_Destroy(output); + break; + } + else + { + BVConstEvaluatorError(e, t); + } + } //end of error printing + + //FIXME Not very standard in the current scheme + if (BVDIV == k) + { + OutputNode = CreateBVConst(quotient, outputwidth); + CONSTANTBV::BitVector_Destroy(remainder); + } + else + { + OutputNode = CreateBVConst(remainder, outputwidth); + CONSTANTBV::BitVector_Destroy(quotient); + } + + break; + } + case ITE: + if (ASTTrue == t[0]) + OutputNode = BVConstEvaluator(t[1]); + else if (ASTFalse == t[0]) + OutputNode = BVConstEvaluator(t[2]); + else + FatalError("BVConstEvaluator: ITE condiional must be either TRUE or FALSE:", t); + break; + case EQ: + if (CONSTANTBV::BitVector_equal(tmp0, tmp1)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case NEQ: + if (!CONSTANTBV::BitVector_equal(tmp0, tmp1)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVLT: + if (-1 == CONSTANTBV::BitVector_Lexicompare(tmp0, tmp1)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVLE: + { + int comp = CONSTANTBV::BitVector_Lexicompare(tmp0, tmp1); + if (comp <= 0) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + case BVGT: + if (1 == CONSTANTBV::BitVector_Lexicompare(tmp0, tmp1)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVGE: + { + int comp = CONSTANTBV::BitVector_Lexicompare(tmp0, tmp1); + if (comp >= 0) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + case BVSLT: + if (-1 == CONSTANTBV::BitVector_Compare(tmp0, tmp1)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVSLE: + { + signed int comp = CONSTANTBV::BitVector_Compare(tmp0, tmp1); + if (comp <= 0) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + case BVSGT: + if (1 == CONSTANTBV::BitVector_Compare(tmp0, tmp1)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVSGE: + { + int comp = CONSTANTBV::BitVector_Compare(tmp0, tmp1); + if (comp >= 0) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + default: + FatalError("BVConstEvaluator: The input kind is not supported yet:", t); + break; } - } - - output = t0.GetBVConst() / t1.GetBVConst(); - //64 bit mask - unsigned long long int mask = 0xffffffffffffffffLL; - mask = mask >> (64 - inputwidth); - output &= mask; - break; - } - case BVMOD: { - if(0 == t1.GetBVConst()) { - //if denominator is 0 then - // (if refinement is ON then output is set to 0) - // (else produce a fatal error) - if(counterexample_checking_during_refinement) { - output = 0; - bvdiv_exception_occured = true; - break; + /* + if(BVCONST != k){ + cerr< 32bits",t); + if(!(0 <= low <= hi <= 64)) + FatalError("ConstantEvaluator: low bit in BVEXTRACT is > 32bits or hi",t); + + //64 bit mask. + unsigned long long int mask1 = 0xffffffffffffffffLL; + mask1 >>= 64-(hi+1); + + //extract val[hi:0] + val &= mask1; + //extract val[hi:low] + val >>= low; + output = val; + break; + } + case BVCONCAT: + { + unsigned long long int q = BVConstEvaluator(t0).GetBVConst(); + unsigned long long int r = BVConstEvaluator(t1).GetBVConst(); + + unsigned int qlen = t[0].GetValueWidth(); + unsigned int rlen = t[1].GetValueWidth(); + unsigned int slen = t.GetValueWidth(); + if(!(0 < qlen + rlen <= 64)) + FatalError("BVConstEvaluator:" + "lengths of childnodes of BVCONCAT are > 64:",t); + + //64 bit mask for q + unsigned long long int qmask = 0xffffffffffffffffLL; + qmask >>= 64-qlen; + //zero the useless bits of q + q &= qmask; + + //64 bit mask for r + unsigned long long int rmask = 0xffffffffffffffffLL; + rmask >>= 64-rlen; + //zero the useless bits of r + r &= rmask; + + //concatenate + q <<= rlen; + q |= r; + + //64 bit mask for output s + unsigned long long int smask = 0xffffffffffffffffLL; + smask >>= 64-slen; + + //currently q has the output + output = q; + output &= smask; + break; + } + case BVMULT: + { + output = t0.GetBVConst() * t1.GetBVConst(); + + //64 bit mask + unsigned long long int mask = 0xffffffffffffffffLL; + mask = mask >> (64 - inputwidth); + output &= mask; + break; + } + case BVPLUS: + { + ASTVec c = t.GetChildren(); + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) + output += BVConstEvaluator(*it).GetBVConst(); + + //64 bit mask + unsigned long long int mask = 0xffffffffffffffffLL; + mask = mask >> (64 -inputwidth); + output &= mask; + break; + } + case SBVDIV: + case SBVREM: + { + output = BVConstEvaluator(TranslateSignedDivMod(t)).GetBVConst(); + break; + } + case BVDIV: + { + if(0 == t1.GetBVConst()) + { + //if denominator is 0 then + // (if refinement is ON then output is set to 0) + // (else produce a fatal error) + if(counterexample_checking_during_refinement) + { + output = 0; + bvdiv_exception_occured = true; + break; + } + else + { + FatalError("BVConstEvaluator: divide by zero not allowed:",t); + } + } + + output = t0.GetBVConst() / t1.GetBVConst(); + //64 bit mask + unsigned long long int mask = 0xffffffffffffffffLL; + mask = mask >> (64 - inputwidth); + output &= mask; + break; + } + case BVMOD: + { + if(0 == t1.GetBVConst()) + { + //if denominator is 0 then + // (if refinement is ON then output is set to 0) + // (else produce a fatal error) + if(counterexample_checking_during_refinement) + { + output = 0; + bvdiv_exception_occured = true; + break; + } + else + { + FatalError("BVConstEvaluator: divide by zero not allowed:",t); + } + } + + output = t0.GetBVConst() % t1.GetBVConst(); + //64 bit mask + unsigned long long int mask = 0xffffffffffffffffLL; + mask = mask >> (64 - inputwidth); + output &= mask; + break; + } + case ITE: + if(ASTTrue == t[0]) + OutputNode = BVConstEvaluator(t[1]); + else if(ASTFalse == t[0]) + OutputNode = BVConstEvaluator(t[2]); + else + FatalError("BVConstEvaluator:" + "ITE condiional must be either TRUE or FALSE:",t); + break; + case EQ: + if(t0.GetBVConst() == t1.GetBVConst()) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case NEQ: + if(t0.GetBVConst() != t1.GetBVConst()) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + break; + case BVLT: + { + unsigned long long n0 = t0.GetBVConst(); + unsigned long long n1 = t1.GetBVConst(); + if(n0 < n1) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + case BVLE: + if(t0.GetBVConst() <= t1.GetBVConst()) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVGT: + if(t0.GetBVConst() > t1.GetBVConst()) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVGE: + if(t0.GetBVConst() >= t1.GetBVConst()) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVSLT: + { + signed long long int n0 = SXBVConst64(t0); + signed long long int n1 = SXBVConst64(t1); + if(n0 < n1) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + case BVSLE: + { + signed long long int n0 = SXBVConst64(t0); + signed long long int n1 = SXBVConst64(t1); + if(n0 <= n1) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + case BVSGT: + { + signed long long int n0 = SXBVConst64(t0); + signed long long int n1 = SXBVConst64(t1); + if(n0 > n1) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + case BVSGE: + { + signed long long int n0 = SXBVConst64(t0); + signed long long int n1 = SXBVConst64(t1); + if(n0 >= n1) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + default: + FatalError("BVConstEvaluator: The input kind is not supported yet:",t); + break; } - } - - output = t0.GetBVConst() % t1.GetBVConst(); - //64 bit mask - unsigned long long int mask = 0xffffffffffffffffLL; - mask = mask >> (64 - inputwidth); - output &= mask; - break; - } - case ITE: - if(ASTTrue == t[0]) - OutputNode = BVConstEvaluator(t[1]); - else if(ASTFalse == t[0]) - OutputNode = BVConstEvaluator(t[2]); - else - FatalError("BVConstEvaluator:" - "ITE condiional must be either TRUE or FALSE:",t); - break; - case EQ: - if(t0.GetBVConst() == t1.GetBVConst()) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - case NEQ: - if(t0.GetBVConst() != t1.GetBVConst()) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - break; - case BVLT: { - unsigned long long n0 = t0.GetBVConst(); - unsigned long long n1 = t1.GetBVConst(); - if(n0 < n1) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - } - case BVLE: - if(t0.GetBVConst() <= t1.GetBVConst()) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - case BVGT: - if(t0.GetBVConst() > t1.GetBVConst()) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - case BVGE: - if(t0.GetBVConst() >= t1.GetBVConst()) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - case BVSLT: { - signed long long int n0 = SXBVConst64(t0); - signed long long int n1 = SXBVConst64(t1); - if(n0 < n1) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - } - case BVSLE: { - signed long long int n0 = SXBVConst64(t0); - signed long long int n1 = SXBVConst64(t1); - if(n0 <= n1) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - } - case BVSGT: { - signed long long int n0 = SXBVConst64(t0); - signed long long int n1 = SXBVConst64(t1); - if(n0 > n1) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - } - case BVSGE: { - signed long long int n0 = SXBVConst64(t0); - signed long long int n1 = SXBVConst64(t1); - if(n0 >= n1) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - } - default: - FatalError("BVConstEvaluator: The input kind is not supported yet:",t); - break; - } - - if(ASTTrue != OutputNode && ASTFalse != OutputNode) - OutputNode = CreateBVConst(inputwidth, output); - UpdateSolverMap(t,OutputNode); - //UpdateSimplifyMap(t,OutputNode,false); - return OutputNode; - } //End of BVConstEvaluator + + if(ASTTrue != OutputNode && ASTFalse != OutputNode) + OutputNode = CreateBVConst(inputwidth, output); + UpdateSolverMap(t,OutputNode); + //UpdateSimplifyMap(t,OutputNode,false); + return OutputNode; +} //End of BVConstEvaluator #endif //In the block below is the old string based version //It is included here as an easy reference while the current code is being worked on. /* - ASTNode BeevMgr::BVConstEvaluator(const ASTNode& t) { - ASTNode OutputNode; - Kind k = t.GetKind(); - - if(CheckSolverMap(t,OutputNode)) - return OutputNode; - OutputNode = t; - - unsigned int inputwidth = t.GetValueWidth(); - unsigned * output = CONSTANTBV::BitVector_Create(inputwidth,true); - unsigned * One = CONSTANTBV::BitVector_Create(inputwidth,true); - CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_from_Bin(One, (unsigned char*)"1"); - //error printing - if(0 != e) { - std::string ss("BVConstEvaluator:"); - ss += (const char*)BitVector_Error(e); - FatalError(ss.c_str(), t); - } - - unsigned * Zero = CONSTANTBV::BitVector_Create(inputwidth,true); - unsigned int * iii = One; - unsigned int * jjj = Zero; - - //saving some typing. BVPLUS does not use these variables. if the - //input BVPLUS has two nodes, then we want to avoid setting these - //variables. - if(2 == t.Degree() && k != BVPLUS && k != BVCONCAT) { - iii = ConvertToCONSTANTBV(BVConstEvaluator(t[0]).GetBVConst()); - jjj = ConvertToCONSTANTBV(BVConstEvaluator(t[1]).GetBVConst()); - } - - char * cccc; - switch(k) { - case UNDEFINED: - case READ: - case WRITE: - case SYMBOL: - FatalError("BVConstEvaluator: term is not a constant-term",t); - break; - case BVCONST: - OutputNode = t; - break; - case BVNEG:{ - //AARON - if (iii != One) free(iii); - //AARON - - iii = ConvertToCONSTANTBV(BVConstEvaluator(t[0]).GetBVConst()); - CONSTANTBV::Set_Complement(output,iii); - cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); - OutputNode = CreateBVConst(cccc,2); - break; - } - case BVSX: { - unsigned * out0 = ConvertToCONSTANTBV(BVConstEvaluator(t[0]).GetBVConst()); - unsigned t0_width = t[0].GetValueWidth(); - if(inputwidth == t0_width) { - cccc = (char *)CONSTANTBV::BitVector_to_Bin(out0); - OutputNode = CreateBVConst(cccc,2); - - //AARON - free(cccc); - //AARON - - CONSTANTBV::BitVector_Destroy(out0); - } - else { - // FIXME: (Dill) I'm guessing that BitVector sign returns 1 if the - // number is positive, 0 if 0, and -1 if negative. But I'm only - // guessing. - signed int topbit_sign = (CONSTANTBV::BitVector_Sign(out0) < 0); - //out1 is the sign-extension bits - unsigned * out1 = CONSTANTBV::BitVector_Create(inputwidth-t0_width,true); - if(topbit_sign) - CONSTANTBV::BitVector_Fill(out1); - - //AARON - CONSTANTBV::BitVector_Destroy(output); - //AARON - - output = CONSTANTBV::BitVector_Concat(out1,out0); - cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); - OutputNode = CreateBVConst(cccc,2); - - //AARON - free(cccc); - //AARON - - CONSTANTBV::BitVector_Destroy(out0); - CONSTANTBV::BitVector_Destroy(out1); - } - break; - } - case BVAND: { - CONSTANTBV::Set_Intersection(output,iii,jjj); - cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); - OutputNode = CreateBVConst(cccc,2); - - //AARON - free(cccc); - //AARON - - break; - } - case BVOR: { - CONSTANTBV::Set_Union(output,iii,jjj); - cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); - OutputNode = CreateBVConst(cccc,2); - - //AARON - free(cccc); - //AARON - - break; - } - case BVXOR: { - CONSTANTBV::Set_ExclusiveOr(output,iii,jjj); - cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); - OutputNode = CreateBVConst(cccc,2); - - //AARON - free(cccc); - //AARON - - break; - } - case BVSUB: { - bool carry = false; - CONSTANTBV::BitVector_sub(output,iii,jjj,&carry); - cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); - OutputNode = CreateBVConst(cccc,2); - - //AARON - free(cccc); - //AARON - - break; - } - case BVUMINUS: { - bool carry = false; - - //AARON - if (iii != One) free(iii); - //AARON - - iii = ConvertToCONSTANTBV(BVConstEvaluator(t[0]).GetBVConst()); - CONSTANTBV::Set_Complement(output,iii); - CONSTANTBV::BitVector_add(output,output,One,&carry); - cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); - OutputNode = CreateBVConst(cccc,2); - - //AARON - free(cccc); - //AARON - - break; - } - case BVEXTRACT: { - string s(BVConstEvaluator(t[0]).GetBVConst()); - unsigned int hi = GetUnsignedConst(BVConstEvaluator(t[1])); - unsigned int low = GetUnsignedConst(BVConstEvaluator(t[2])); - - //length of substr to chop - unsigned int len = hi-low+1; - //distance from MSB - hi = s.size()-1 - hi; - string ss = s.substr(hi,len); - OutputNode = CreateBVConst(ss.c_str(),2); - break; - } - case BVCONCAT: { - string s(BVConstEvaluator(t[0]).GetBVConst()); - string r(BVConstEvaluator(t[1]).GetBVConst()); - - string q(s+r); - OutputNode = CreateBVConst(q.c_str(),2); - break; - } - case BVMULT: { - unsigned * output1 = CONSTANTBV::BitVector_Create(2*inputwidth,true); - CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Multiply(output1,iii,jjj); - //error printing - if(0 != e) { - std::string ss("BVConstEvaluator:"); - ss += (const char*)BitVector_Error(e); - //destroy all the CONSTANTBV bitvectors - CONSTANTBV::BitVector_Destroy(iii); - CONSTANTBV::BitVector_Destroy(jjj); - CONSTANTBV::BitVector_Destroy(One); - CONSTANTBV::BitVector_Destroy(Zero); - FatalError(ss.c_str(), t); - } - - cccc = (char *)CONSTANTBV::BitVector_to_Bin(output1); - std::string s(cccc); - - //AARON - free(cccc); - //AARON - - s = s.substr(inputwidth,inputwidth); - OutputNode = CreateBVConst(s.c_str(),2); - CONSTANTBV::BitVector_Destroy(output1); - break; - } - case BVPLUS: { - bool carry = false; - ASTVec c = t.GetChildren(); - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - unsigned int * kk = ConvertToCONSTANTBV(BVConstEvaluator(*it).GetBVConst()); - CONSTANTBV::BitVector_add(output,output,kk,&carry); - carry = false; - CONSTANTBV::BitVector_Destroy(kk); - } - cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); - OutputNode = CreateBVConst(cccc,2); - - //AARON - free(cccc); - //AARON - - break; - } - case SBVDIV: - case SBVREM: { - OutputNode = BVConstEvaluator(TranslateSignedDivMod(t)); - break; - } - case BVDIV: { - unsigned * quotient = CONSTANTBV::BitVector_Create(inputwidth,true); - unsigned * remainder = CONSTANTBV::BitVector_Create(inputwidth,true); - // iii is dividend, jjj is the divisor - CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Div_Pos(quotient,iii,jjj,remainder); - - if(0 != e) { - //error printing - if(counterexample_checking_during_refinement) { - OutputNode = CreateZeroConst(inputwidth); - bvdiv_exception_occured = true; - break; - } - else { - std::string ss("BVConstEvaluator:"); - ss += (const char*)BitVector_Error(e); - //destroy all the CONSTANTBV bitvectors - CONSTANTBV::BitVector_Destroy(iii); - CONSTANTBV::BitVector_Destroy(jjj); - CONSTANTBV::BitVector_Destroy(One); - CONSTANTBV::BitVector_Destroy(Zero); - - //AARON - iii = jjj = One = Zero = NULL; - //AARON - - FatalError(ss.c_str(), t); - } - } //end of error printing - - cccc = (char *)CONSTANTBV::BitVector_to_Bin(quotient); - OutputNode = CreateBVConst(cccc,2); - - //AARON - free(cccc); - CONSTANTBV::BitVector_Destroy(quotient); - CONSTANTBV::BitVector_Destroy(remainder); - //AARON - - break; - } - case BVMOD: { - unsigned * quotient = CONSTANTBV::BitVector_Create(inputwidth,true); - unsigned * remainder = CONSTANTBV::BitVector_Create(inputwidth,true); - // iii is dividend, jjj is the divisor - CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Div_Pos(quotient,iii,jjj,remainder); - - if(0 != e) { - //error printing - if(counterexample_checking_during_refinement) { - OutputNode = CreateZeroConst(inputwidth); - bvdiv_exception_occured = true; - break; - } - else { - std::string ss("BVConstEvaluator:"); - ss += (const char*)BitVector_Error(e); - //destroy all the CONSTANTBV bitvectors - CONSTANTBV::BitVector_Destroy(iii); - CONSTANTBV::BitVector_Destroy(jjj); - CONSTANTBV::BitVector_Destroy(One); - CONSTANTBV::BitVector_Destroy(Zero); - - //AARON - iii = jjj = One = Zero = NULL; - //AARON - - FatalError(ss.c_str(), t); - } - } //end of errory printing - - cccc = (char *)CONSTANTBV::BitVector_to_Bin(remainder); - OutputNode = CreateBVConst(cccc,2); - - //AARON - free(cccc); - CONSTANTBV::BitVector_Destroy(quotient); - CONSTANTBV::BitVector_Destroy(remainder); - //AARON - - break; - } - case ITE: - if(ASTTrue == t[0]) - OutputNode = BVConstEvaluator(t[1]); - else if(ASTFalse == t[0]) - OutputNode = BVConstEvaluator(t[2]); - else - FatalError("BVConstEvaluator: ITE condiional must be either TRUE or FALSE:",t); - break; - case EQ: - if(CONSTANTBV::BitVector_equal(iii,jjj)) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - case NEQ: - if(!CONSTANTBV::BitVector_equal(iii,jjj)) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - case BVLT: - if(-1 == CONSTANTBV::BitVector_Lexicompare(iii,jjj)) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - case BVLE: { - int comp = CONSTANTBV::BitVector_Lexicompare(iii,jjj); - if(comp <= 0) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - } - case BVGT: - if(1 == CONSTANTBV::BitVector_Lexicompare(iii,jjj)) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - case BVGE: { - int comp = CONSTANTBV::BitVector_Lexicompare(iii,jjj); - if(comp >= 0) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - } - case BVSLT: - if(-1 == CONSTANTBV::BitVector_Compare(iii,jjj)) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - case BVSLE: { - signed int comp = CONSTANTBV::BitVector_Compare(iii,jjj); - if(comp <= 0) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - } - case BVSGT: - if(1 == CONSTANTBV::BitVector_Compare(iii,jjj)) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - case BVSGE: { - int comp = CONSTANTBV::BitVector_Compare(iii,jjj); - if(comp >= 0) - OutputNode = ASTTrue; - else - OutputNode = ASTFalse; - break; - } - default: - FatalError("BVConstEvaluator: The input kind is not supported yet:",t); - break; - } - - - - // //destroy all the CONSTANTBV bitvectors -// CONSTANTBV::BitVector_Destroy(iii); -// CONSTANTBV::BitVector_Destroy(jjj); -// CONSTANTBV::BitVector_Destroy(output); - -// if(k == BVNEG || k == BVUMINUS) -// CONSTANTBV::BitVector_Destroy(One); -// else if(k == BVAND || k == BVOR || k == BVXOR || k == BVSUB || -// k == BVMULT || k == EQ || k == NEQ || k == BVLT || -// k == BVLE || k == BVGT || k == BVGE || k == BVSLT || -// k == BVSLE || k == BVSGT || k == BVSGE) { -// CONSTANTBV::BitVector_Destroy(One); -// CONSTANTBV::BitVector_Destroy(Zero); -// } - - //AARON - if (output != NULL) CONSTANTBV::BitVector_Destroy(output); - if (One != NULL) CONSTANTBV::BitVector_Destroy(One); - if (Zero != NULL) CONSTANTBV::BitVector_Destroy(Zero); - if (iii != NULL && iii != One) CONSTANTBV::BitVector_Destroy(iii); - if (jjj != NULL && jjj != Zero) CONSTANTBV::BitVector_Destroy(jjj); - //AARON - - UpdateSolverMap(t,OutputNode); - //UpdateSimplifyMap(t,OutputNode,false); - return OutputNode; - } - - - unsigned int * ConvertToCONSTANTBV(const char * s) { - unsigned int length = strlen(s); - unsigned char * ccc = (unsigned char *)s; - unsigned * iii = CONSTANTBV::BitVector_Create(length,true); - CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_from_Bin(iii,ccc); - //error printing - if(0 != e) { - cerr << "ConverToCONSTANTBV: wrong bin value: " << BitVector_Error(e); - FatalError(""); - } - - return iii; - } -*/ -}; //end of namespace BEEV + ASTNode BeevMgr::BVConstEvaluator(const ASTNode& t) { + ASTNode OutputNode; + Kind k = t.GetKind(); + + if(CheckSolverMap(t,OutputNode)) + return OutputNode; + OutputNode = t; + + unsigned int inputwidth = t.GetValueWidth(); + unsigned * output = CONSTANTBV::BitVector_Create(inputwidth,true); + unsigned * One = CONSTANTBV::BitVector_Create(inputwidth,true); + CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_from_Bin(One, (unsigned char*)"1"); + //error printing + if(0 != e) { + std::string ss("BVConstEvaluator:"); + ss += (const char*)BitVector_Error(e); + FatalError(ss.c_str(), t); + } + + unsigned * Zero = CONSTANTBV::BitVector_Create(inputwidth,true); + unsigned int * iii = One; + unsigned int * jjj = Zero; + + //saving some typing. BVPLUS does not use these variables. if the + //input BVPLUS has two nodes, then we want to avoid setting these + //variables. + if(2 == t.Degree() && k != BVPLUS && k != BVCONCAT) { + iii = ConvertToCONSTANTBV(BVConstEvaluator(t[0]).GetBVConst()); + jjj = ConvertToCONSTANTBV(BVConstEvaluator(t[1]).GetBVConst()); + } + + char * cccc; + switch(k) { + case UNDEFINED: + case READ: + case WRITE: + case SYMBOL: + FatalError("BVConstEvaluator: term is not a constant-term",t); + break; + case BVCONST: + OutputNode = t; + break; + case BVNEG:{ + //AARON + if (iii != One) free(iii); + //AARON + + iii = ConvertToCONSTANTBV(BVConstEvaluator(t[0]).GetBVConst()); + CONSTANTBV::Set_Complement(output,iii); + cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); + OutputNode = CreateBVConst(cccc,2); + break; + } + case BVSX: { + unsigned * out0 = ConvertToCONSTANTBV(BVConstEvaluator(t[0]).GetBVConst()); + unsigned t0_width = t[0].GetValueWidth(); + if(inputwidth == t0_width) { + cccc = (char *)CONSTANTBV::BitVector_to_Bin(out0); + OutputNode = CreateBVConst(cccc,2); + + //AARON + free(cccc); + //AARON + + CONSTANTBV::BitVector_Destroy(out0); + } + else { + // FIXME: (Dill) I'm guessing that BitVector sign returns 1 if the + // number is positive, 0 if 0, and -1 if negative. But I'm only + // guessing. + signed int topbit_sign = (CONSTANTBV::BitVector_Sign(out0) < 0); + //out1 is the sign-extension bits + unsigned * out1 = CONSTANTBV::BitVector_Create(inputwidth-t0_width,true); + if(topbit_sign) + CONSTANTBV::BitVector_Fill(out1); + + //AARON + CONSTANTBV::BitVector_Destroy(output); + //AARON + + output = CONSTANTBV::BitVector_Concat(out1,out0); + cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); + OutputNode = CreateBVConst(cccc,2); + + //AARON + free(cccc); + //AARON + + CONSTANTBV::BitVector_Destroy(out0); + CONSTANTBV::BitVector_Destroy(out1); + } + break; + } + case BVAND: { + CONSTANTBV::Set_Intersection(output,iii,jjj); + cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); + OutputNode = CreateBVConst(cccc,2); + + //AARON + free(cccc); + //AARON + + break; + } + case BVOR: { + CONSTANTBV::Set_Union(output,iii,jjj); + cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); + OutputNode = CreateBVConst(cccc,2); + + //AARON + free(cccc); + //AARON + + break; + } + case BVXOR: { + CONSTANTBV::Set_ExclusiveOr(output,iii,jjj); + cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); + OutputNode = CreateBVConst(cccc,2); + + //AARON + free(cccc); + //AARON + + break; + } + case BVSUB: { + bool carry = false; + CONSTANTBV::BitVector_sub(output,iii,jjj,&carry); + cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); + OutputNode = CreateBVConst(cccc,2); + + //AARON + free(cccc); + //AARON + + break; + } + case BVUMINUS: { + bool carry = false; + + //AARON + if (iii != One) free(iii); + //AARON + + iii = ConvertToCONSTANTBV(BVConstEvaluator(t[0]).GetBVConst()); + CONSTANTBV::Set_Complement(output,iii); + CONSTANTBV::BitVector_add(output,output,One,&carry); + cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); + OutputNode = CreateBVConst(cccc,2); + + //AARON + free(cccc); + //AARON + + break; + } + case BVEXTRACT: { + string s(BVConstEvaluator(t[0]).GetBVConst()); + unsigned int hi = GetUnsignedConst(BVConstEvaluator(t[1])); + unsigned int low = GetUnsignedConst(BVConstEvaluator(t[2])); + + //length of substr to chop + unsigned int len = hi-low+1; + //distance from MSB + hi = s.size()-1 - hi; + string ss = s.substr(hi,len); + OutputNode = CreateBVConst(ss.c_str(),2); + break; + } + case BVCONCAT: { + string s(BVConstEvaluator(t[0]).GetBVConst()); + string r(BVConstEvaluator(t[1]).GetBVConst()); + + string q(s+r); + OutputNode = CreateBVConst(q.c_str(),2); + break; + } + case BVMULT: { + unsigned * output1 = CONSTANTBV::BitVector_Create(2*inputwidth,true); + CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Multiply(output1,iii,jjj); + //error printing + if(0 != e) { + std::string ss("BVConstEvaluator:"); + ss += (const char*)BitVector_Error(e); + //destroy all the CONSTANTBV bitvectors + CONSTANTBV::BitVector_Destroy(iii); + CONSTANTBV::BitVector_Destroy(jjj); + CONSTANTBV::BitVector_Destroy(One); + CONSTANTBV::BitVector_Destroy(Zero); + FatalError(ss.c_str(), t); + } + + cccc = (char *)CONSTANTBV::BitVector_to_Bin(output1); + std::string s(cccc); + + //AARON + free(cccc); + //AARON + + s = s.substr(inputwidth,inputwidth); + OutputNode = CreateBVConst(s.c_str(),2); + CONSTANTBV::BitVector_Destroy(output1); + break; + } + case BVPLUS: { + bool carry = false; + ASTVec c = t.GetChildren(); + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { + unsigned int * kk = ConvertToCONSTANTBV(BVConstEvaluator(*it).GetBVConst()); + CONSTANTBV::BitVector_add(output,output,kk,&carry); + carry = false; + CONSTANTBV::BitVector_Destroy(kk); + } + cccc = (char *)CONSTANTBV::BitVector_to_Bin(output); + OutputNode = CreateBVConst(cccc,2); + + //AARON + free(cccc); + //AARON + + break; + } + case SBVDIV: + case SBVREM: { + OutputNode = BVConstEvaluator(TranslateSignedDivMod(t)); + break; + } + case BVDIV: { + unsigned * quotient = CONSTANTBV::BitVector_Create(inputwidth,true); + unsigned * remainder = CONSTANTBV::BitVector_Create(inputwidth,true); + // iii is dividend, jjj is the divisor + CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Div_Pos(quotient,iii,jjj,remainder); + + if(0 != e) { + //error printing + if(counterexample_checking_during_refinement) { + OutputNode = CreateZeroConst(inputwidth); + bvdiv_exception_occured = true; + break; + } + else { + std::string ss("BVConstEvaluator:"); + ss += (const char*)BitVector_Error(e); + //destroy all the CONSTANTBV bitvectors + CONSTANTBV::BitVector_Destroy(iii); + CONSTANTBV::BitVector_Destroy(jjj); + CONSTANTBV::BitVector_Destroy(One); + CONSTANTBV::BitVector_Destroy(Zero); + + //AARON + iii = jjj = One = Zero = NULL; + //AARON + + FatalError(ss.c_str(), t); + } + } //end of error printing + + cccc = (char *)CONSTANTBV::BitVector_to_Bin(quotient); + OutputNode = CreateBVConst(cccc,2); + + //AARON + free(cccc); + CONSTANTBV::BitVector_Destroy(quotient); + CONSTANTBV::BitVector_Destroy(remainder); + //AARON + + break; + } + case BVMOD: { + unsigned * quotient = CONSTANTBV::BitVector_Create(inputwidth,true); + unsigned * remainder = CONSTANTBV::BitVector_Create(inputwidth,true); + // iii is dividend, jjj is the divisor + CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Div_Pos(quotient,iii,jjj,remainder); + + if(0 != e) { + //error printing + if(counterexample_checking_during_refinement) { + OutputNode = CreateZeroConst(inputwidth); + bvdiv_exception_occured = true; + break; + } + else { + std::string ss("BVConstEvaluator:"); + ss += (const char*)BitVector_Error(e); + //destroy all the CONSTANTBV bitvectors + CONSTANTBV::BitVector_Destroy(iii); + CONSTANTBV::BitVector_Destroy(jjj); + CONSTANTBV::BitVector_Destroy(One); + CONSTANTBV::BitVector_Destroy(Zero); + + //AARON + iii = jjj = One = Zero = NULL; + //AARON + + FatalError(ss.c_str(), t); + } + } //end of errory printing + + cccc = (char *)CONSTANTBV::BitVector_to_Bin(remainder); + OutputNode = CreateBVConst(cccc,2); + + //AARON + free(cccc); + CONSTANTBV::BitVector_Destroy(quotient); + CONSTANTBV::BitVector_Destroy(remainder); + //AARON + + break; + } + case ITE: + if(ASTTrue == t[0]) + OutputNode = BVConstEvaluator(t[1]); + else if(ASTFalse == t[0]) + OutputNode = BVConstEvaluator(t[2]); + else + FatalError("BVConstEvaluator: ITE condiional must be either TRUE or FALSE:",t); + break; + case EQ: + if(CONSTANTBV::BitVector_equal(iii,jjj)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case NEQ: + if(!CONSTANTBV::BitVector_equal(iii,jjj)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVLT: + if(-1 == CONSTANTBV::BitVector_Lexicompare(iii,jjj)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVLE: { + int comp = CONSTANTBV::BitVector_Lexicompare(iii,jjj); + if(comp <= 0) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + case BVGT: + if(1 == CONSTANTBV::BitVector_Lexicompare(iii,jjj)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVGE: { + int comp = CONSTANTBV::BitVector_Lexicompare(iii,jjj); + if(comp >= 0) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + case BVSLT: + if(-1 == CONSTANTBV::BitVector_Compare(iii,jjj)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVSLE: { + signed int comp = CONSTANTBV::BitVector_Compare(iii,jjj); + if(comp <= 0) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + case BVSGT: + if(1 == CONSTANTBV::BitVector_Compare(iii,jjj)) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + case BVSGE: { + int comp = CONSTANTBV::BitVector_Compare(iii,jjj); + if(comp >= 0) + OutputNode = ASTTrue; + else + OutputNode = ASTFalse; + break; + } + default: + FatalError("BVConstEvaluator: The input kind is not supported yet:",t); + break; + } + + + + // //destroy all the CONSTANTBV bitvectors + // CONSTANTBV::BitVector_Destroy(iii); + // CONSTANTBV::BitVector_Destroy(jjj); + // CONSTANTBV::BitVector_Destroy(output); + + // if(k == BVNEG || k == BVUMINUS) + // CONSTANTBV::BitVector_Destroy(One); + // else if(k == BVAND || k == BVOR || k == BVXOR || k == BVSUB || + // k == BVMULT || k == EQ || k == NEQ || k == BVLT || + // k == BVLE || k == BVGT || k == BVGE || k == BVSLT || + // k == BVSLE || k == BVSGT || k == BVSGE) { + // CONSTANTBV::BitVector_Destroy(One); + // CONSTANTBV::BitVector_Destroy(Zero); + // } + + //AARON + if (output != NULL) CONSTANTBV::BitVector_Destroy(output); + if (One != NULL) CONSTANTBV::BitVector_Destroy(One); + if (Zero != NULL) CONSTANTBV::BitVector_Destroy(Zero); + if (iii != NULL && iii != One) CONSTANTBV::BitVector_Destroy(iii); + if (jjj != NULL && jjj != Zero) CONSTANTBV::BitVector_Destroy(jjj); + //AARON + + UpdateSolverMap(t,OutputNode); + //UpdateSimplifyMap(t,OutputNode,false); + return OutputNode; + } + + + unsigned int * ConvertToCONSTANTBV(const char * s) { + unsigned int length = strlen(s); + unsigned char * ccc = (unsigned char *)s; + unsigned * iii = CONSTANTBV::BitVector_Create(length,true); + CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_from_Bin(iii,ccc); + //error printing + if(0 != e) { + cerr << "ConverToCONSTANTBV: wrong bin value: " << BitVector_Error(e); + FatalError(""); + } + + return iii; + } + */ +} +; //end of namespace BEEV diff --git a/format_config.xml b/format_config.xml new file mode 100644 index 0000000..d2f242f --- /dev/null +++ b/format_config.xml @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/simplifier/bvsolver.cpp b/simplifier/bvsolver.cpp index 1c08f30..f873d4e 100644 --- a/simplifier/bvsolver.cpp +++ b/simplifier/bvsolver.cpp @@ -11,704 +11,764 @@ #include "../AST/ASTUtil.h" #include "bvsolver.h" - //This file contains the implementation of member functions of - //bvsolver class, which represents the bitvector arithmetic linear - //solver. Please also refer the STP's CAV 2007 paper for the - //complete description of the linear solver algorithm - // - //The bitvector solver is a partial solver, i.e. it does not solve - //for all variables in the system of equations. it is - //best-effort. it relies on the SAT solver to be complete. - // - //The BVSolver assumes that the input equations are normalized, and - //have liketerms combined etc. - // - //0. Traverse top-down over the input DAG, looking for a conjunction - //0. of equations. if you find one, then for each equation in the - //0. conjunction, do the following steps. - // - //1. check for Linearity of the input equation - // - //2. Solve for a "chosen" variable. The variable should occur - //2. exactly once and must have an odd coeff. Refer STP's CAV 2007 - //2. paper for actual solving procedure - // - //4. Outside the solver, Substitute and Re-normalize the input DAG -namespace BEEV { - //check the solver map for 'key'. If key is present, then return the - //value by reference in the argument 'output' - bool BVSolver::CheckAlreadySolvedMap(const ASTNode& key, ASTNode& output) { - ASTNodeMap::iterator it; - if((it = FormulasAlreadySolvedMap.find(key)) != FormulasAlreadySolvedMap.end()) { - output = it->second; - return true; - } - return false; - } //CheckAlreadySolvedMap() - - void BVSolver::UpdateAlreadySolvedMap(const ASTNode& key, const ASTNode& value) { - FormulasAlreadySolvedMap[key] = value; - } //end of UpdateAlreadySolvedMap() - - //FIXME This is doing way more arithmetic than it needs to. - //accepts an even number "in", and splits it into an odd number and - //a power of 2. i.e " in = b.(2^k) ". returns the odd number, and - //the power of two by reference - ASTNode BVSolver::SplitEven_into_Oddnum_PowerOf2(const ASTNode& in, - unsigned int& number_shifts) { - if(BVCONST != in.GetKind() || _bm->BVConstIsOdd(in)) { - FatalError("BVSolver:SplitNum_Odd_PowerOf2: input must be a BVCONST and even\n",in); - } - - unsigned int len = in.GetValueWidth(); - ASTNode zero = _bm->CreateZeroConst(len); - ASTNode two = _bm->CreateTwoConst(len); - ASTNode div_by_2 = in; - ASTNode mod_by_2 = - _bm->BVConstEvaluator(_bm->CreateTerm(BVMOD,len,div_by_2,two)); - while(mod_by_2 == zero) { - div_by_2 = - _bm->BVConstEvaluator(_bm->CreateTerm(BVDIV,len,div_by_2,two)); - number_shifts++; - mod_by_2 = - _bm->BVConstEvaluator(_bm->CreateTerm(BVMOD,len,div_by_2,two)); - } - return div_by_2; - } //end of SplitEven_into_Oddnum_PowerOf2() - - //Checks if there are any ARRAYREADS in the term, after the - //alreadyseenmap is cleared, i.e. traversing a new term altogether - bool BVSolver::CheckForArrayReads_TopLevel(const ASTNode& term) { - TermsAlreadySeenMap.clear(); - return CheckForArrayReads(term); - } - - //Checks if there are any ARRAYREADS in the term - bool BVSolver::CheckForArrayReads(const ASTNode& term) { - ASTNode a = term; - ASTNodeMap::iterator it; - if((it = TermsAlreadySeenMap.find(term)) != TermsAlreadySeenMap.end()) { - //if the term has been seen, then simply return true, else - //return false - if(ASTTrue == (it->second)) { - return true; - } - else { +//This file contains the implementation of member functions of +//bvsolver class, which represents the bitvector arithmetic linear +//solver. Please also refer the STP's CAV 2007 paper for the +//complete description of the linear solver algorithm +// +//The bitvector solver is a partial solver, i.e. it does not solve +//for all variables in the system of equations. it is +//best-effort. it relies on the SAT solver to be complete. +// +//The BVSolver assumes that the input equations are normalized, and +//have liketerms combined etc. +// +//0. Traverse top-down over the input DAG, looking for a conjunction +//0. of equations. if you find one, then for each equation in the +//0. conjunction, do the following steps. +// +//1. check for Linearity of the input equation +// +//2. Solve for a "chosen" variable. The variable should occur +//2. exactly once and must have an odd coeff. Refer STP's CAV 2007 +//2. paper for actual solving procedure +// +//4. Outside the solver, Substitute and Re-normalize the input DAG +namespace BEEV +{ +//check the solver map for 'key'. If key is present, then return the +//value by reference in the argument 'output' +bool BVSolver::CheckAlreadySolvedMap(const ASTNode& key, ASTNode& output) +{ + ASTNodeMap::iterator it; + if ((it = FormulasAlreadySolvedMap.find(key)) != FormulasAlreadySolvedMap.end()) + { + output = it->second; + return true; + } return false; - } - } - - switch(term.GetKind()) { - case READ: - //an array read has been seen. Make an entry in the map and - //return true - TermsAlreadySeenMap[term] = ASTTrue; - return true; - default: { - ASTVec c = term.GetChildren(); - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - if(CheckForArrayReads(*it)) { - return true; +} //CheckAlreadySolvedMap() + +void BVSolver::UpdateAlreadySolvedMap(const ASTNode& key, const ASTNode& value) +{ + FormulasAlreadySolvedMap[key] = value; +} //end of UpdateAlreadySolvedMap() + +//FIXME This is doing way more arithmetic than it needs to. +//accepts an even number "in", and splits it into an odd number and +//a power of 2. i.e " in = b.(2^k) ". returns the odd number, and +//the power of two by reference +ASTNode BVSolver::SplitEven_into_Oddnum_PowerOf2(const ASTNode& in, unsigned int& number_shifts) +{ + if (BVCONST != in.GetKind() || _bm->BVConstIsOdd(in)) + { + FatalError("BVSolver:SplitNum_Odd_PowerOf2: input must be a BVCONST and even\n", in); } - } - break; - } - } - - //If control is here, then it means that no arrayread was seen for - //the input 'term'. Make an entry in the map with the term as key - //and FALSE as value. - TermsAlreadySeenMap[term] = ASTFalse; - return false; - } //end of CheckForArrayReads() - - //check the solver map for 'key'. If key is present, then return the - //value by reference in the argument 'output' - bool BeevMgr::CheckSolverMap(const ASTNode& key, ASTNode& output) { - ASTNodeMap::iterator it; - if((it = SolverMap.find(key)) != SolverMap.end()) { - output = it->second; - return true; - } - return false; - } //end of CheckSolverMap() - - bool BeevMgr::CheckSolverMap(const ASTNode& key) { - if(SolverMap.find(key) != SolverMap.end()) - return true; - else - return false; - } //end of CheckSolverMap() - - //update solvermap with (key,value) pair - bool BeevMgr::UpdateSolverMap(const ASTNode& key, const ASTNode& value) { - ASTNode var = (BVEXTRACT == key.GetKind()) ? key[0] : key; - if(!CheckSolverMap(var) && key != value) { - SolverMap[key] = value; - return true; - } - return false; - } //end of UpdateSolverMap() - - //collects the vars in the term 'lhs' into the multiset Vars - void BVSolver::VarsInTheTerm_TopLevel(const ASTNode& lhs, ASTNodeMultiSet& Vars) { - TermsAlreadySeenMap.clear(); - VarsInTheTerm(lhs,Vars); - } - - //collects the vars in the term 'lhs' into the multiset Vars - void BVSolver::VarsInTheTerm(const ASTNode& term, ASTNodeMultiSet& Vars) { - ASTNode a = term; - ASTNodeMap::iterator it; - if((it = TermsAlreadySeenMap.find(term)) != TermsAlreadySeenMap.end()) { - //if the term has been seen, then simply return - return; - } - - switch(term.GetKind()) { - case BVCONST: - return; - case SYMBOL: - //cerr << "debugging: symbol added: " << term << endl; - Vars.insert(term); - break; - case READ: - //skip the arrayname, provided the arrayname is a SYMBOL - if(SYMBOL == term[0].GetKind()) { - VarsInTheTerm(term[1],Vars); - } - else { - VarsInTheTerm(term[0],Vars); - VarsInTheTerm(term[1],Vars); - } - break; - default: { - ASTVec c = term.GetChildren(); - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - VarsInTheTerm(*it,Vars); - } - break; - } - } - - //ensures that you don't double count. if you have seen the term - //once, then memoize - TermsAlreadySeenMap[term] = ASTTrue; - return; - } //end of VarsInTheTerm() - - bool BVSolver::DoNotSolveThis(const ASTNode& var) { - if(DoNotSolve_TheseVars.find(var) != DoNotSolve_TheseVars.end()) { - return true; - } - return false; - } - - //chooses a variable in the lhs and returns the chosen variable - ASTNode BVSolver::ChooseMonom(const ASTNode& eq, ASTNode& modifiedlhs) { - if(!(EQ == eq.GetKind() && BVPLUS == eq[0].GetKind())) { - FatalError("ChooseMonom: input must be a EQ",eq); - } - - ASTNode lhs = eq[0]; - ASTNode rhs = eq[1]; - ASTNode zero = _bm->CreateZeroConst(32); - - //collect all the vars in the lhs and rhs - ASTNodeMultiSet Vars; - VarsInTheTerm_TopLevel(lhs,Vars); - - //handle BVPLUS case - ASTVec c = lhs.GetChildren(); - ASTVec o; - ASTNode outmonom = _bm->CreateNode(UNDEFINED); - bool chosen_symbol = false; - bool chosen_odd = false; - - //choose variables with no coeffs - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - ASTNode monom = *it; - if(SYMBOL == monom.GetKind() && - Vars.count(monom) == 1 && - !_bm->VarSeenInTerm(monom,rhs) && - !DoNotSolveThis(monom) && - !chosen_symbol) { - outmonom = monom; - chosen_symbol = true; - } - else if(BVUMINUS == monom.GetKind() && - SYMBOL == monom[0].GetKind() && - Vars.count(monom[0]) == 1 && - !DoNotSolveThis(monom[0]) && - !_bm->VarSeenInTerm(monom[0],rhs) && - !chosen_symbol) { - //cerr << "Chosen Monom: " << monom << endl; - outmonom = monom; - chosen_symbol = true; - } - else { - o.push_back(monom); - } - } - - //try to choose only odd coeffed variables first - if(!chosen_symbol) { - o.clear(); - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - ASTNode monom = *it; - ASTNode var = (BVMULT == monom.GetKind()) ? monom[1] : _bm->CreateNode(UNDEFINED); - - if(BVMULT == monom.GetKind() && - BVCONST == monom[0].GetKind() && - _bm->BVConstIsOdd(monom[0]) && - ((SYMBOL == var.GetKind() && - Vars.count(var) == 1) - || - (BVEXTRACT == var.GetKind() && - SYMBOL == var[0].GetKind() && - BVCONST == var[1].GetKind() && - zero == var[2] && - !_bm->VarSeenInTerm(var[0],rhs) && - !DoNotSolveThis(var[0])) - ) && - !DoNotSolveThis(var) && - !_bm->VarSeenInTerm(var,rhs) && - !chosen_odd) { - //monom[0] is odd. - outmonom = monom; - chosen_odd = true; + + unsigned int len = in.GetValueWidth(); + ASTNode zero = _bm->CreateZeroConst(len); + ASTNode two = _bm->CreateTwoConst(len); + ASTNode div_by_2 = in; + ASTNode mod_by_2 = _bm->BVConstEvaluator(_bm->CreateTerm(BVMOD, len, div_by_2, two)); + while (mod_by_2 == zero) + { + div_by_2 = _bm->BVConstEvaluator(_bm->CreateTerm(BVDIV, len, div_by_2, two)); + number_shifts++; + mod_by_2 = _bm->BVConstEvaluator(_bm->CreateTerm(BVMOD, len, div_by_2, two)); } - else { - o.push_back(monom); + return div_by_2; +} //end of SplitEven_into_Oddnum_PowerOf2() + +//Checks if there are any ARRAYREADS in the term, after the +//alreadyseenmap is cleared, i.e. traversing a new term altogether +bool BVSolver::CheckForArrayReads_TopLevel(const ASTNode& term) +{ + TermsAlreadySeenMap.clear(); + return CheckForArrayReads(term); +} + +//Checks if there are any ARRAYREADS in the term +bool BVSolver::CheckForArrayReads(const ASTNode& term) +{ + ASTNode a = term; + ASTNodeMap::iterator it; + if ((it = TermsAlreadySeenMap.find(term)) != TermsAlreadySeenMap.end()) + { + //if the term has been seen, then simply return true, else + //return false + if (ASTTrue == (it->second)) + { + return true; + } + else + { + return false; + } } - } - } - - modifiedlhs = (o.size() > 1) ? _bm->CreateTerm(BVPLUS,lhs.GetValueWidth(),o) : o[0]; - return outmonom; - } //end of choosemonom() - - //solver function which solves for variables with odd coefficient - ASTNode BVSolver::BVSolve_Odd(const ASTNode& input) { - ASTNode eq = input; - //cerr << "Input to BVSolve_Odd()" << eq << endl; - if(!(wordlevel_solve && EQ == eq.GetKind())) { - return input; - } - - ASTNode output = input; - if(CheckAlreadySolvedMap(input,output)) { - return output; - } - - //get the lhs and the rhs, and case-split on the lhs kind - ASTNode lhs = eq[0]; - ASTNode rhs = eq[1]; - if(BVPLUS == lhs.GetKind()) { - ASTNode chosen_monom = _bm->CreateNode(UNDEFINED); - ASTNode leftover_lhs; - - //choose monom makes sure that it gets only those vars that - //occur exactly once in lhs and rhs put together - chosen_monom = ChooseMonom(eq, leftover_lhs); - if(chosen_monom == _bm->CreateNode(UNDEFINED)) { - //no monomial was chosen - return eq; - } - - //if control is here then it means that a monom was chosen - // - //construct: rhs - (lhs without the chosen monom) - unsigned int len = lhs.GetValueWidth(); - leftover_lhs = _bm->SimplifyTerm_TopLevel(_bm->CreateTerm(BVUMINUS,len,leftover_lhs)); - ASTNode newrhs = _bm->SimplifyTerm(_bm->CreateTerm(BVPLUS,len,rhs,leftover_lhs)); - lhs = chosen_monom; - rhs = newrhs; - } //end of if(BVPLUS ...) - - if(BVUMINUS == lhs.GetKind()) { - //equation is of the form (-lhs0) = rhs - ASTNode lhs0 = lhs[0]; - rhs = _bm->SimplifyTerm(_bm->CreateTerm(BVUMINUS,rhs.GetValueWidth(),rhs)); - lhs = lhs0; - } - - switch(lhs.GetKind()) { - case SYMBOL: { - //input is of the form x = rhs first make sure that the lhs - //symbol does not occur on the rhs or that it has not been - //solved for - if(_bm->VarSeenInTerm(lhs,rhs)) { - //found the lhs in the rhs. Abort! - DoNotSolve_TheseVars.insert(lhs); - return eq; - } - - //rhs should not have arrayreads in it. it complicates matters - //during transformation - // if(CheckForArrayReads_TopLevel(rhs)) { - // return eq; - // } - - DoNotSolve_TheseVars.insert(lhs); - if(!_bm->UpdateSolverMap(lhs,rhs)) { - return eq; - } - - output = ASTTrue; - break; - } - case BVEXTRACT: { - ASTNode zero = _bm->CreateZeroConst(32); - - if(!(SYMBOL == lhs[0].GetKind() && - BVCONST == lhs[1].GetKind() && - zero == lhs[2] && - !_bm->VarSeenInTerm(lhs[0],rhs) && - !DoNotSolveThis(lhs[0]))) { - return eq; - } - - if(_bm->VarSeenInTerm(lhs[0],rhs)) { - DoNotSolve_TheseVars.insert(lhs[0]); - return eq; - } - - DoNotSolve_TheseVars.insert(lhs[0]); - if(!_bm->UpdateSolverMap(lhs,rhs)) { - return eq; - } - - //if the extract of x[i:0] = t is entered into the solvermap, - //then also add another entry for x = x1@t - ASTNode var = lhs[0]; - ASTNode newvar = NewVar(var.GetValueWidth() - lhs.GetValueWidth()); - newvar = _bm->CreateTerm(BVCONCAT,var.GetValueWidth(),newvar,rhs); - _bm->UpdateSolverMap(var,newvar); - output = ASTTrue; - break; - } - case BVMULT: { - //the input is of the form a*x = t. If 'a' is odd, then compute - //its multiplicative inverse a^-1, multiply 't' with it, and - //update the solver map - if(BVCONST != lhs[0].GetKind()) { - return eq; - } - - if(!(SYMBOL == lhs[1].GetKind() || - (BVEXTRACT == lhs[1].GetKind() && - SYMBOL == lhs[1][0].GetKind()))) { - return eq; - } - bool ChosenVar_Is_Extract = (BVEXTRACT == lhs[1].GetKind()) ? true : false; + switch (term.GetKind()) + { + case READ: + //an array read has been seen. Make an entry in the map and + //return true + TermsAlreadySeenMap[term] = ASTTrue; + return true; + default: + { + ASTVec c = term.GetChildren(); + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + if (CheckForArrayReads(*it)) + { + return true; + } + } + break; + } + } - //if coeff is even, then we know that all the coeffs in the eqn - //are even. Simply return the eqn - if(!_bm->BVConstIsOdd(lhs[0])) { - return eq; - } - - ASTNode a = _bm->MultiplicativeInverse(lhs[0]); - ASTNode chosenvar = (BVEXTRACT == lhs[1].GetKind()) ? lhs[1][0] : lhs[1]; - ASTNode chosenvar_value = - _bm->SimplifyTerm(_bm->CreateTerm(BVMULT,rhs.GetValueWidth(),a,rhs)); - - //if chosenvar is seen in chosenvar_value then abort - if(_bm->VarSeenInTerm(chosenvar,chosenvar_value)) { - //abort solving - DoNotSolve_TheseVars.insert(lhs); - return eq; - } - - //rhs should not have arrayreads in it. it complicates matters - //during transformation - // if(CheckForArrayReads_TopLevel(chosenvar_value)) { - // return eq; - // } - - //found a variable to solve - DoNotSolve_TheseVars.insert(chosenvar); - chosenvar = lhs[1]; - if(!_bm->UpdateSolverMap(chosenvar,chosenvar_value)) { - return eq; - } - - if(ChosenVar_Is_Extract) { - ASTNode var = lhs[1][0]; - ASTNode newvar = NewVar(var.GetValueWidth() - lhs[1].GetValueWidth()); - newvar = _bm->CreateTerm(BVCONCAT,var.GetValueWidth(),newvar,chosenvar_value); - _bm->UpdateSolverMap(var,newvar); - } - output = ASTTrue; - break; - } - default: - output = eq; - break; - } - - UpdateAlreadySolvedMap(input,output); - return output; - } //end of BVSolve_Odd() - - //Create a new variable of ValueWidth 'n' - ASTNode BVSolver::NewVar(unsigned int n) { - std:: string c("v"); - char d[32]; - sprintf(d,"%d",_symbol_count++); - std::string ccc(d); - c += "_solver_" + ccc; - - ASTNode CurrentSymbol = _bm->CreateSymbol(c.c_str()); - CurrentSymbol.SetValueWidth(n); - CurrentSymbol.SetIndexWidth(0); - return CurrentSymbol; - } //end of NewVar() - - //The toplevel bvsolver(). Checks if the formula has already been - //solved. If not, the solver() is invoked. If yes, then simply drop - //the formula - ASTNode BVSolver::TopLevelBVSolve(const ASTNode& input) { - if(!wordlevel_solve) { - return input; - } - - Kind k = input.GetKind(); - if(!(EQ == k || AND == k)) { - return input; - } - - ASTNode output = input; - if(CheckAlreadySolvedMap(input,output)) { - //output is TRUE. The formula is thus dropped - return output; - } - ASTVec o; - ASTVec c; - if(EQ == k) - c.push_back(input); - else - c = input.GetChildren(); - ASTVec eveneqns; - ASTNode solved = ASTFalse; - for(ASTVec::iterator it = c.begin(), itend = c.end();it != itend;it++) { - //_bm->ASTNodeStats("Printing before calling simplifyformula inside the solver:", *it); - ASTNode aaa = (ASTTrue == solved && EQ == it->GetKind()) ? _bm->SimplifyFormula(*it,false) : *it; - //ASTNode aaa = *it; - //_bm->ASTNodeStats("Printing after calling simplifyformula inside the solver:", aaa); - aaa = BVSolve_Odd(aaa); - //_bm->ASTNodeStats("Printing after oddsolver:", aaa); - bool even = false; - aaa = CheckEvenEqn(aaa, even); - if(even) { - eveneqns.push_back(aaa); - } - else { - if(ASTTrue != aaa) { - o.push_back(aaa); + //If control is here, then it means that no arrayread was seen for + //the input 'term'. Make an entry in the map with the term as key + //and FALSE as value. + TermsAlreadySeenMap[term] = ASTFalse; + return false; +} //end of CheckForArrayReads() + +//check the solver map for 'key'. If key is present, then return the +//value by reference in the argument 'output' +bool BeevMgr::CheckSolverMap(const ASTNode& key, ASTNode& output) +{ + ASTNodeMap::iterator it; + if ((it = SolverMap.find(key)) != SolverMap.end()) + { + output = it->second; + return true; + } + return false; +} //end of CheckSolverMap() + +bool BeevMgr::CheckSolverMap(const ASTNode& key) +{ + if (SolverMap.find(key) != SolverMap.end()) + return true; + else + return false; +} //end of CheckSolverMap() + +//update solvermap with (key,value) pair +bool BeevMgr::UpdateSolverMap(const ASTNode& key, const ASTNode& value) +{ + ASTNode var = (BVEXTRACT == key.GetKind()) ? key[0] : key; + if (!CheckSolverMap(var) && key != value) + { + SolverMap[key] = value; + return true; + } + return false; +} //end of UpdateSolverMap() + +//collects the vars in the term 'lhs' into the multiset Vars +void BVSolver::VarsInTheTerm_TopLevel(const ASTNode& lhs, ASTNodeMultiSet& Vars) +{ + TermsAlreadySeenMap.clear(); + VarsInTheTerm(lhs, Vars); +} + +//collects the vars in the term 'lhs' into the multiset Vars +void BVSolver::VarsInTheTerm(const ASTNode& term, ASTNodeMultiSet& Vars) +{ + ASTNode a = term; + ASTNodeMap::iterator it; + if ((it = TermsAlreadySeenMap.find(term)) != TermsAlreadySeenMap.end()) + { + //if the term has been seen, then simply return + return; + } + + switch (term.GetKind()) + { + case BVCONST: + return; + case SYMBOL: + //cerr << "debugging: symbol added: " << term << endl; + Vars.insert(term); + break; + case READ: + //skip the arrayname, provided the arrayname is a SYMBOL + if (SYMBOL == term[0].GetKind()) + { + VarsInTheTerm(term[1], Vars); + } + else + { + VarsInTheTerm(term[0], Vars); + VarsInTheTerm(term[1], Vars); + } + break; + default: + { + ASTVec c = term.GetChildren(); + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + VarsInTheTerm(*it, Vars); + } + break; + } + } + + //ensures that you don't double count. if you have seen the term + //once, then memoize + TermsAlreadySeenMap[term] = ASTTrue; + return; +} //end of VarsInTheTerm() + +bool BVSolver::DoNotSolveThis(const ASTNode& var) +{ + if (DoNotSolve_TheseVars.find(var) != DoNotSolve_TheseVars.end()) + { + return true; + } + return false; +} + +//chooses a variable in the lhs and returns the chosen variable +ASTNode BVSolver::ChooseMonom(const ASTNode& eq, ASTNode& modifiedlhs) +{ + if (!(EQ == eq.GetKind() && BVPLUS == eq[0].GetKind())) + { + FatalError("ChooseMonom: input must be a EQ", eq); + } + + ASTNode lhs = eq[0]; + ASTNode rhs = eq[1]; + ASTNode zero = _bm->CreateZeroConst(32); + + //collect all the vars in the lhs and rhs + ASTNodeMultiSet Vars; + VarsInTheTerm_TopLevel(lhs, Vars); + + //handle BVPLUS case + ASTVec c = lhs.GetChildren(); + ASTVec o; + ASTNode outmonom = _bm->CreateNode(UNDEFINED); + bool chosen_symbol = false; + bool chosen_odd = false; + + //choose variables with no coeffs + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + ASTNode monom = *it; + if (SYMBOL == monom.GetKind() && Vars.count(monom) == 1 && !_bm->VarSeenInTerm(monom, rhs) && !DoNotSolveThis(monom) && !chosen_symbol) + { + outmonom = monom; + chosen_symbol = true; + } + else if (BVUMINUS == monom.GetKind() && SYMBOL == monom[0].GetKind() && Vars.count(monom[0]) == 1 && !DoNotSolveThis(monom[0]) + && !_bm->VarSeenInTerm(monom[0], rhs) && !chosen_symbol) + { + //cerr << "Chosen Monom: " << monom << endl; + outmonom = monom; + chosen_symbol = true; + } + else + { + o.push_back(monom); + } + } + + //try to choose only odd coeffed variables first + if (!chosen_symbol) + { + o.clear(); + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + ASTNode monom = *it; + ASTNode var = (BVMULT == monom.GetKind()) ? monom[1] : _bm->CreateNode(UNDEFINED); + + if (BVMULT == monom.GetKind() && BVCONST == monom[0].GetKind() && _bm->BVConstIsOdd(monom[0]) && ((SYMBOL == var.GetKind() && Vars.count( + var) == 1) || (BVEXTRACT == var.GetKind() && SYMBOL == var[0].GetKind() && BVCONST == var[1].GetKind() && zero == var[2] + && !_bm->VarSeenInTerm(var[0], rhs) && !DoNotSolveThis(var[0]))) && !DoNotSolveThis(var) && !_bm->VarSeenInTerm(var, rhs) + && !chosen_odd) + { + //monom[0] is odd. + outmonom = monom; + chosen_odd = true; + } + else + { + o.push_back(monom); + } + } + } + + modifiedlhs = (o.size() > 1) ? _bm->CreateTerm(BVPLUS, lhs.GetValueWidth(), o) : o[0]; + return outmonom; +} //end of choosemonom() + +//solver function which solves for variables with odd coefficient +ASTNode BVSolver::BVSolve_Odd(const ASTNode& input) +{ + ASTNode eq = input; + //cerr << "Input to BVSolve_Odd()" << eq << endl; + if (!(wordlevel_solve && EQ == eq.GetKind())) + { + return input; } - } - solved = aaa; - } - - ASTNode evens; - if(eveneqns.size() > 0) { - //if there is a system of even equations then solve them - evens = (eveneqns.size() > 1) ? _bm->CreateNode(AND,eveneqns) : eveneqns[0]; - //evens = _bm->SimplifyFormula(evens,false); - evens = BVSolve_Even(evens); - _bm->ASTNodeStats("Printing after evensolver:", evens); - } - else { - evens = ASTTrue; - } - output = (o.size() > 0) ? ((o.size() > 1) ? _bm->CreateNode(AND,o) : o[0]) : ASTTrue; - output = _bm->CreateNode(AND,output,evens); - - UpdateAlreadySolvedMap(input,output); - return output; - } //end of TopLevelBVSolve() - - ASTNode BVSolver::CheckEvenEqn(const ASTNode& input, bool& evenflag) { - ASTNode eq = input; - //cerr << "Input to BVSolve_Odd()" << eq << endl; - if(!(wordlevel_solve && EQ == eq.GetKind())) { - evenflag = false; - return eq; - } - - ASTNode lhs = eq[0]; - ASTNode rhs = eq[1]; - ASTNode zero = _bm->CreateZeroConst(rhs.GetValueWidth()); - //lhs must be a BVPLUS, and rhs must be a BVCONST - if(!(BVPLUS == lhs.GetKind() && zero == rhs)) { - evenflag = false; - return eq; - } - - ASTVec lhs_c = lhs.GetChildren(); - ASTNode savetheconst = rhs; - for(ASTVec::iterator it=lhs_c.begin(),itend=lhs_c.end();it!=itend;it++) { - ASTNode aaa = *it; - Kind itk = aaa.GetKind(); - - if(BVCONST == itk){ - //check later if the constant is even or not - savetheconst = aaa; - continue; - } - - if(!(BVMULT == itk && - BVCONST == aaa[0].GetKind() && - SYMBOL == aaa[1].GetKind() && - !_bm->BVConstIsOdd(aaa[0]))) { - //If the monomials of the lhs are NOT of the form 'a*x' where - //'a' is even, then return the false - evenflag = false; + + ASTNode output = input; + if (CheckAlreadySolvedMap(input, output)) + { + return output; + } + + //get the lhs and the rhs, and case-split on the lhs kind + ASTNode lhs = eq[0]; + ASTNode rhs = eq[1]; + if (BVPLUS == lhs.GetKind()) + { + ASTNode chosen_monom = _bm->CreateNode(UNDEFINED); + ASTNode leftover_lhs; + + //choose monom makes sure that it gets only those vars that + //occur exactly once in lhs and rhs put together + chosen_monom = ChooseMonom(eq, leftover_lhs); + if (chosen_monom == _bm->CreateNode(UNDEFINED)) + { + //no monomial was chosen + return eq; + } + + //if control is here then it means that a monom was chosen + // + //construct: rhs - (lhs without the chosen monom) + unsigned int len = lhs.GetValueWidth(); + leftover_lhs = _bm->SimplifyTerm_TopLevel(_bm->CreateTerm(BVUMINUS, len, leftover_lhs)); + ASTNode newrhs = _bm->SimplifyTerm(_bm->CreateTerm(BVPLUS, len, rhs, leftover_lhs)); + lhs = chosen_monom; + rhs = newrhs; + } //end of if(BVPLUS ...) + + if (BVUMINUS == lhs.GetKind()) + { + //equation is of the form (-lhs0) = rhs + ASTNode lhs0 = lhs[0]; + rhs = _bm->SimplifyTerm(_bm->CreateTerm(BVUMINUS, rhs.GetValueWidth(), rhs)); + lhs = lhs0; + } + + switch (lhs.GetKind()) + { + case SYMBOL: + { + //input is of the form x = rhs first make sure that the lhs + //symbol does not occur on the rhs or that it has not been + //solved for + if (_bm->VarSeenInTerm(lhs, rhs)) + { + //found the lhs in the rhs. Abort! + DoNotSolve_TheseVars.insert(lhs); + return eq; + } + + //rhs should not have arrayreads in it. it complicates matters + //during transformation + // if(CheckForArrayReads_TopLevel(rhs)) { + // return eq; + // } + + DoNotSolve_TheseVars.insert(lhs); + if (!_bm->UpdateSolverMap(lhs, rhs)) + { + return eq; + } + + output = ASTTrue; + break; + } + case BVEXTRACT: + { + ASTNode zero = _bm->CreateZeroConst(32); + + if (!(SYMBOL == lhs[0].GetKind() && BVCONST == lhs[1].GetKind() && zero == lhs[2] && !_bm->VarSeenInTerm(lhs[0], rhs) && !DoNotSolveThis( + lhs[0]))) + { + return eq; + } + + if (_bm->VarSeenInTerm(lhs[0], rhs)) + { + DoNotSolve_TheseVars.insert(lhs[0]); + return eq; + } + + DoNotSolve_TheseVars.insert(lhs[0]); + if (!_bm->UpdateSolverMap(lhs, rhs)) + { + return eq; + } + + //if the extract of x[i:0] = t is entered into the solvermap, + //then also add another entry for x = x1@t + ASTNode var = lhs[0]; + ASTNode newvar = NewVar(var.GetValueWidth() - lhs.GetValueWidth()); + newvar = _bm->CreateTerm(BVCONCAT, var.GetValueWidth(), newvar, rhs); + _bm->UpdateSolverMap(var, newvar); + output = ASTTrue; + break; + } + case BVMULT: + { + //the input is of the form a*x = t. If 'a' is odd, then compute + //its multiplicative inverse a^-1, multiply 't' with it, and + //update the solver map + if (BVCONST != lhs[0].GetKind()) + { + return eq; + } + + if (!(SYMBOL == lhs[1].GetKind() || (BVEXTRACT == lhs[1].GetKind() && SYMBOL == lhs[1][0].GetKind()))) + { + return eq; + } + + bool ChosenVar_Is_Extract = (BVEXTRACT == lhs[1].GetKind()) ? true : false; + + //if coeff is even, then we know that all the coeffs in the eqn + //are even. Simply return the eqn + if (!_bm->BVConstIsOdd(lhs[0])) + { + return eq; + } + + ASTNode a = _bm->MultiplicativeInverse(lhs[0]); + ASTNode chosenvar = (BVEXTRACT == lhs[1].GetKind()) ? lhs[1][0] : lhs[1]; + ASTNode chosenvar_value = _bm->SimplifyTerm(_bm->CreateTerm(BVMULT, rhs.GetValueWidth(), a, rhs)); + + //if chosenvar is seen in chosenvar_value then abort + if (_bm->VarSeenInTerm(chosenvar, chosenvar_value)) + { + //abort solving + DoNotSolve_TheseVars.insert(lhs); + return eq; + } + + //rhs should not have arrayreads in it. it complicates matters + //during transformation + // if(CheckForArrayReads_TopLevel(chosenvar_value)) { + // return eq; + // } + + //found a variable to solve + DoNotSolve_TheseVars.insert(chosenvar); + chosenvar = lhs[1]; + if (!_bm->UpdateSolverMap(chosenvar, chosenvar_value)) + { + return eq; + } + + if (ChosenVar_Is_Extract) + { + ASTNode var = lhs[1][0]; + ASTNode newvar = NewVar(var.GetValueWidth() - lhs[1].GetValueWidth()); + newvar = _bm->CreateTerm(BVCONCAT, var.GetValueWidth(), newvar, chosenvar_value); + _bm->UpdateSolverMap(var, newvar); + } + output = ASTTrue; + break; + } + default: + output = eq; + break; + } + + UpdateAlreadySolvedMap(input, output); + return output; +} //end of BVSolve_Odd() + +//Create a new variable of ValueWidth 'n' +ASTNode BVSolver::NewVar(unsigned int n) +{ + std::string c("v"); + char d[32]; + sprintf(d, "%d", _symbol_count++); + std::string ccc(d); + c += "_solver_" + ccc; + + ASTNode CurrentSymbol = _bm->CreateSymbol(c.c_str()); + CurrentSymbol.SetValueWidth(n); + CurrentSymbol.SetIndexWidth(0); + return CurrentSymbol; +} //end of NewVar() + +//The toplevel bvsolver(). Checks if the formula has already been +//solved. If not, the solver() is invoked. If yes, then simply drop +//the formula +ASTNode BVSolver::TopLevelBVSolve(const ASTNode& input) +{ + if (!wordlevel_solve) + { + return input; + } + + Kind k = input.GetKind(); + if (!(EQ == k || AND == k)) + { + return input; + } + + ASTNode output = input; + if (CheckAlreadySolvedMap(input, output)) + { + //output is TRUE. The formula is thus dropped + return output; + } + ASTVec o; + ASTVec c; + if (EQ == k) + c.push_back(input); + else + c = input.GetChildren(); + ASTVec eveneqns; + ASTNode solved = ASTFalse; + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + //_bm->ASTNodeStats("Printing before calling simplifyformula inside the solver:", *it); + ASTNode aaa = (ASTTrue == solved && EQ == it->GetKind()) ? _bm->SimplifyFormula(*it, false) : *it; + //ASTNode aaa = *it; + //_bm->ASTNodeStats("Printing after calling simplifyformula inside the solver:", aaa); + aaa = BVSolve_Odd(aaa); + //_bm->ASTNodeStats("Printing after oddsolver:", aaa); + bool even = false; + aaa = CheckEvenEqn(aaa, even); + if (even) + { + eveneqns.push_back(aaa); + } + else + { + if (ASTTrue != aaa) + { + o.push_back(aaa); + } + } + solved = aaa; + } + + ASTNode evens; + if (eveneqns.size() > 0) + { + //if there is a system of even equations then solve them + evens = (eveneqns.size() > 1) ? _bm->CreateNode(AND, eveneqns) : eveneqns[0]; + //evens = _bm->SimplifyFormula(evens,false); + evens = BVSolve_Even(evens); + _bm->ASTNodeStats("Printing after evensolver:", evens); + } + else + { + evens = ASTTrue; + } + output = (o.size() > 0) ? ((o.size() > 1) ? _bm->CreateNode(AND, o) : o[0]) : ASTTrue; + output = _bm->CreateNode(AND, output, evens); + + UpdateAlreadySolvedMap(input, output); + return output; +} //end of TopLevelBVSolve() + +ASTNode BVSolver::CheckEvenEqn(const ASTNode& input, bool& evenflag) +{ + ASTNode eq = input; + //cerr << "Input to BVSolve_Odd()" << eq << endl; + if (!(wordlevel_solve && EQ == eq.GetKind())) + { + evenflag = false; + return eq; + } + + ASTNode lhs = eq[0]; + ASTNode rhs = eq[1]; + ASTNode zero = _bm->CreateZeroConst(rhs.GetValueWidth()); + //lhs must be a BVPLUS, and rhs must be a BVCONST + if (!(BVPLUS == lhs.GetKind() && zero == rhs)) + { + evenflag = false; + return eq; + } + + ASTVec lhs_c = lhs.GetChildren(); + ASTNode savetheconst = rhs; + for (ASTVec::iterator it = lhs_c.begin(), itend = lhs_c.end(); it != itend; it++) + { + ASTNode aaa = *it; + Kind itk = aaa.GetKind(); + + if (BVCONST == itk) + { + //check later if the constant is even or not + savetheconst = aaa; + continue; + } + + if (!(BVMULT == itk && BVCONST == aaa[0].GetKind() && SYMBOL == aaa[1].GetKind() && !_bm->BVConstIsOdd(aaa[0]))) + { + //If the monomials of the lhs are NOT of the form 'a*x' where + //'a' is even, then return the false + evenflag = false; + return eq; + } + }//end of for loop + + //if control is here then it means that all coeffs are even. the + //only remaining thing is to check if the constant is even or not + if (_bm->BVConstIsOdd(savetheconst)) + { + //the constant turned out to be odd. we have UNSAT eqn + evenflag = false; + return ASTFalse; + } + + //all is clear. the eqn in even, through and through + evenflag = true; return eq; - } - }//end of for loop - - //if control is here then it means that all coeffs are even. the - //only remaining thing is to check if the constant is even or not - if(_bm->BVConstIsOdd(savetheconst)) { - //the constant turned out to be odd. we have UNSAT eqn - evenflag = false; - return ASTFalse; - } - - //all is clear. the eqn in even, through and through - evenflag = true; - return eq; - } //end of CheckEvenEqn - - //solve an eqn whose monomials have only even coefficients - ASTNode BVSolver::BVSolve_Even(const ASTNode& input) { - if(!wordlevel_solve) { - return input; - } - - if(!(EQ == input.GetKind() || AND == input.GetKind())) { - return input; - } - - ASTNode output; - if(CheckAlreadySolvedMap(input,output)) { - return output; - } - - ASTVec input_c; - if(EQ == input.GetKind()) { - input_c.push_back(input); - } - else { - input_c = input.GetChildren(); - } - - //power_of_2 holds the exponent of 2 in the coeff - unsigned int power_of_2 = 0; - //we need this additional variable to find the lowest power of 2 - unsigned int power_of_2_lowest = 0xffffffff; - //the monom which has the least power of 2 in the coeff - ASTNode monom_with_best_coeff; - for(ASTVec::iterator jt=input_c.begin(),jtend=input_c.end();jt!=jtend;jt++) { - ASTNode eq = *jt; - ASTNode lhs = eq[0]; - ASTNode rhs = eq[1]; - ASTNode zero = _bm->CreateZeroConst(rhs.GetValueWidth()); - //lhs must be a BVPLUS, and rhs must be a BVCONST - if(!(BVPLUS == lhs.GetKind() && zero == rhs)) { - return input; - } - - ASTVec lhs_c = lhs.GetChildren(); - ASTNode odd; - for(ASTVec::iterator it=lhs_c.begin(),itend=lhs_c.end();it!=itend;it++) { - ASTNode aaa = *it; - Kind itk = aaa.GetKind(); - if(!(BVCONST == itk && - !_bm->BVConstIsOdd(aaa)) && - !(BVMULT == itk && - BVCONST == aaa[0].GetKind() && - SYMBOL == aaa[1].GetKind() && - !_bm->BVConstIsOdd(aaa[0]))) { - //If the monomials of the lhs are NOT of the form 'a*x' or 'a' - //where 'a' is even, then return the eqn - return input; +} //end of CheckEvenEqn + +//solve an eqn whose monomials have only even coefficients +ASTNode BVSolver::BVSolve_Even(const ASTNode& input) +{ + if (!wordlevel_solve) + { + return input; + } + + if (!(EQ == input.GetKind() || AND == input.GetKind())) + { + return input; } - - //we are gauranteed that if control is here then the monomial is - //of the form 'a*x' or 'a', where 'a' is even - ASTNode coeff = (BVCONST == itk) ? aaa : aaa[0]; - odd = SplitEven_into_Oddnum_PowerOf2(coeff,power_of_2); - if(power_of_2 < power_of_2_lowest) { - power_of_2_lowest = power_of_2; - monom_with_best_coeff = aaa; + + ASTNode output; + if (CheckAlreadySolvedMap(input, output)) + { + return output; } - power_of_2 = 0; - }//end of inner for loop - } //end of outer for loop - - //get the exponent - power_of_2 = power_of_2_lowest; - - //if control is here, we are gauranteed that we have chosen a - //monomial with fewest powers of 2 - ASTVec formula_out; - for(ASTVec::iterator jt=input_c.begin(),jtend=input_c.end();jt!=jtend;jt++) { - ASTNode eq = *jt; - ASTNode lhs = eq[0]; - ASTNode rhs = eq[1]; - ASTNode zero = _bm->CreateZeroConst(rhs.GetValueWidth()); - //lhs must be a BVPLUS, and rhs must be a BVCONST - if(!(BVPLUS == lhs.GetKind() && zero == rhs)) { - return input; - } - - unsigned len = lhs.GetValueWidth(); - ASTNode hi = _bm->CreateBVConst(32,len-1); - ASTNode low = _bm->CreateBVConst(32,len - power_of_2); - ASTNode low_minus_one = _bm->CreateBVConst(32,len - power_of_2 - 1); - ASTNode low_zero = _bm->CreateZeroConst(32); - unsigned newlen = len - power_of_2; - ASTNode two_const = _bm->CreateTwoConst(len); - - unsigned count = power_of_2; - ASTNode two = two_const; - while(--count) { - two = _bm->BVConstEvaluator(_bm->CreateTerm(BVMULT,len,two_const,two)); - } - ASTVec lhs_c = lhs.GetChildren(); - ASTVec lhs_out; - for(ASTVec::iterator it=lhs_c.begin(),itend=lhs_c.end();it!=itend;it++) { - ASTNode aaa = *it; - Kind itk = aaa.GetKind(); - if(BVCONST == itk) { - aaa = _bm->BVConstEvaluator(_bm->CreateTerm(BVDIV,len,aaa,two)); - aaa = _bm->BVConstEvaluator(_bm->CreateTerm(BVEXTRACT,newlen,aaa,low_minus_one,low_zero)); + + ASTVec input_c; + if (EQ == input.GetKind()) + { + input_c.push_back(input); } - else { - //it must be of the form a*x - ASTNode coeff = _bm->BVConstEvaluator(_bm->CreateTerm(BVDIV,len,aaa[0],two)); - coeff = _bm->BVConstEvaluator(_bm->CreateTerm(BVEXTRACT,newlen,coeff,low_minus_one,low_zero)); - ASTNode upper_x, lower_x; - //upper_x = _bm->SimplifyTerm(_bm->CreateTerm(BVEXTRACT, power_of_2, aaa[1], hi, low)); - lower_x = _bm->SimplifyTerm(_bm->CreateTerm(BVEXTRACT, newlen,aaa[1],low_minus_one,low_zero)); - aaa = _bm->CreateTerm(BVMULT,newlen,coeff,lower_x); + else + { + input_c = input.GetChildren(); } - lhs_out.push_back(aaa); - }//end of inner forloop() - rhs = _bm->CreateZeroConst(newlen); - lhs = _bm->CreateTerm(BVPLUS,newlen,lhs_out); - formula_out.push_back(_bm->CreateSimplifiedEQ(lhs,rhs)); - } //end of outer forloop() - - output = - (formula_out.size() > 0) ? (formula_out.size() > 1) ? _bm->CreateNode(AND,formula_out) : formula_out[0] : ASTTrue; - - UpdateAlreadySolvedMap(input,output); - return output; - } //end of BVSolve_Even() -};//end of namespace BEEV + + //power_of_2 holds the exponent of 2 in the coeff + unsigned int power_of_2 = 0; + //we need this additional variable to find the lowest power of 2 + unsigned int power_of_2_lowest = 0xffffffff; + //the monom which has the least power of 2 in the coeff + ASTNode monom_with_best_coeff; + for (ASTVec::iterator jt = input_c.begin(), jtend = input_c.end(); jt != jtend; jt++) + { + ASTNode eq = *jt; + ASTNode lhs = eq[0]; + ASTNode rhs = eq[1]; + ASTNode zero = _bm->CreateZeroConst(rhs.GetValueWidth()); + //lhs must be a BVPLUS, and rhs must be a BVCONST + if (!(BVPLUS == lhs.GetKind() && zero == rhs)) + { + return input; + } + + ASTVec lhs_c = lhs.GetChildren(); + ASTNode odd; + for (ASTVec::iterator it = lhs_c.begin(), itend = lhs_c.end(); it != itend; it++) + { + ASTNode aaa = *it; + Kind itk = aaa.GetKind(); + if (!(BVCONST == itk && !_bm->BVConstIsOdd(aaa)) && !(BVMULT == itk && BVCONST == aaa[0].GetKind() && SYMBOL == aaa[1].GetKind() + && !_bm->BVConstIsOdd(aaa[0]))) + { + //If the monomials of the lhs are NOT of the form 'a*x' or 'a' + //where 'a' is even, then return the eqn + return input; + } + + //we are gauranteed that if control is here then the monomial is + //of the form 'a*x' or 'a', where 'a' is even + ASTNode coeff = (BVCONST == itk) ? aaa : aaa[0]; + odd = SplitEven_into_Oddnum_PowerOf2(coeff, power_of_2); + if (power_of_2 < power_of_2_lowest) + { + power_of_2_lowest = power_of_2; + monom_with_best_coeff = aaa; + } + power_of_2 = 0; + }//end of inner for loop + } //end of outer for loop + + //get the exponent + power_of_2 = power_of_2_lowest; + + //if control is here, we are gauranteed that we have chosen a + //monomial with fewest powers of 2 + ASTVec formula_out; + for (ASTVec::iterator jt = input_c.begin(), jtend = input_c.end(); jt != jtend; jt++) + { + ASTNode eq = *jt; + ASTNode lhs = eq[0]; + ASTNode rhs = eq[1]; + ASTNode zero = _bm->CreateZeroConst(rhs.GetValueWidth()); + //lhs must be a BVPLUS, and rhs must be a BVCONST + if (!(BVPLUS == lhs.GetKind() && zero == rhs)) + { + return input; + } + + unsigned len = lhs.GetValueWidth(); + ASTNode hi = _bm->CreateBVConst(32, len - 1); + ASTNode low = _bm->CreateBVConst(32, len - power_of_2); + ASTNode low_minus_one = _bm->CreateBVConst(32, len - power_of_2 - 1); + ASTNode low_zero = _bm->CreateZeroConst(32); + unsigned newlen = len - power_of_2; + ASTNode two_const = _bm->CreateTwoConst(len); + + unsigned count = power_of_2; + ASTNode two = two_const; + while (--count) + { + two = _bm->BVConstEvaluator(_bm->CreateTerm(BVMULT, len, two_const, two)); + } + ASTVec lhs_c = lhs.GetChildren(); + ASTVec lhs_out; + for (ASTVec::iterator it = lhs_c.begin(), itend = lhs_c.end(); it != itend; it++) + { + ASTNode aaa = *it; + Kind itk = aaa.GetKind(); + if (BVCONST == itk) + { + aaa = _bm->BVConstEvaluator(_bm->CreateTerm(BVDIV, len, aaa, two)); + aaa = _bm->BVConstEvaluator(_bm->CreateTerm(BVEXTRACT, newlen, aaa, low_minus_one, low_zero)); + } + else + { + //it must be of the form a*x + ASTNode coeff = _bm->BVConstEvaluator(_bm->CreateTerm(BVDIV, len, aaa[0], two)); + coeff = _bm->BVConstEvaluator(_bm->CreateTerm(BVEXTRACT, newlen, coeff, low_minus_one, low_zero)); + ASTNode upper_x, lower_x; + //upper_x = _bm->SimplifyTerm(_bm->CreateTerm(BVEXTRACT, power_of_2, aaa[1], hi, low)); + lower_x = _bm->SimplifyTerm(_bm->CreateTerm(BVEXTRACT, newlen, aaa[1], low_minus_one, low_zero)); + aaa = _bm->CreateTerm(BVMULT, newlen, coeff, lower_x); + } + lhs_out.push_back(aaa); + }//end of inner forloop() + rhs = _bm->CreateZeroConst(newlen); + lhs = _bm->CreateTerm(BVPLUS, newlen, lhs_out); + formula_out.push_back(_bm->CreateSimplifiedEQ(lhs, rhs)); + } //end of outer forloop() + + output = (formula_out.size() > 0) ? (formula_out.size() > 1) ? _bm->CreateNode(AND, formula_out) : formula_out[0] : ASTTrue; + + UpdateAlreadySolvedMap(input, output); + return output; +} //end of BVSolve_Even() +} +;//end of namespace BEEV diff --git a/simplifier/bvsolver.h b/simplifier/bvsolver.h index bb76718..c19b529 100644 --- a/simplifier/bvsolver.h +++ b/simplifier/bvsolver.h @@ -9,128 +9,135 @@ #include "../AST/AST.h" #include "../AST/ASTUtil.h" -namespace BEEV { - - //This class represents the bitvector arithmetic linear solver. - // - //The bitvector solver is a partial solver, i.e. it does not solve - //for all variables in the system of equations. it is - //best-effort. it relies on the SAT solver to be complete. - // - //The BVSolver assumes that the input equations are normalized, and - //have liketerms combined etc. - // - //0. Traverse top-down over the input DAG, looking for a conjunction - //0. of equations. if you find one, then for each equation in the - //0. conjunction, do the following steps. - // - //1. check for Linearity of the input equation - // - //2. Solve for a "chosen" variable. The variable should occur - //2. exactly once and must have an odd coeff. Refer STP's CAV 2007 - //2. paper for actual solving procedure - // - //4. Outside the solver, Substitute and Re-normalize the input DAG - class BVSolver { - //Ptr to toplevel manager that manages bit-vector expressions - //(i.e. construct various kinds of expressions), and also has - //member functions that simplify bit-vector expressions - BeevMgr * _bm; - ASTNode ASTTrue, ASTFalse; - - //Those formulas which have already been solved. If the same - //formula occurs twice then do not solve the second occurence, and - //instead drop it - ASTNodeMap FormulasAlreadySolvedMap; - - //this map is useful while traversing terms and uniquely - //identifying variables in the those terms. Prevents double - //counting. - ASTNodeMap TermsAlreadySeenMap; - ASTNodeMap TermsAlreadySeenMap_ForArrays; - - //count is used in the creation of new variables - unsigned int _symbol_count; - - //solved variables list: If a variable has been solved for then do - //not solve for it again - ASTNodeSet DoNotSolve_TheseVars; - - //checks if var has been solved for or not. if yes, then return - //true else return false - bool DoNotSolveThis(const ASTNode& var); - - //traverses a term, and creates a multiset of all variables in the - //term. Does memoization to avoid double counting. - void VarsInTheTerm(const ASTNode& lhs, ASTNodeMultiSet& v); - void VarsInTheTerm_TopLevel(const ASTNode& lhs, ASTNodeMultiSet& v); - - //choose a suitable var from the term - ASTNode ChooseMonom(const ASTNode& eq, ASTNode& modifiedterm); - //accepts an equation and solves for a variable or a monom in it - ASTNode BVSolve_Odd(const ASTNode& eq); - - //solves equations of the form a*x=t where 'a' is even. Has a - //return value, unlike the normal BVSolve() - ASTNode BVSolve_Even(const ASTNode& eq); - ASTNode CheckEvenEqn(const ASTNode& input, bool& evenflag); - - //Checks for arrayreads in a term. if yes then returns true, else - //return false - bool CheckForArrayReads(const ASTNode& term); - bool CheckForArrayReads_TopLevel(const ASTNode& term); - - //Creates new variables used in solving - ASTNode NewVar(unsigned int n); - - //this function return true if the var occurs in term, else the - //function returns false - bool VarSeenInTerm(const ASTNode& var, const ASTNode& term); - - //takes an even number "in" as input, and returns an odd number - //(return value) and a power of 2 (as number_shifts by reference), - //such that in = (odd_number * power_of_2). - // - //Refer STP's CAV 2007 (or Clark Barrett's 1998 paper on - //bit-vector arithmetic published in DAC 1998) paper for precise - //understanding of the algorithm - ASTNode SplitEven_into_Oddnum_PowerOf2(const ASTNode& in, unsigned int& number_shifts); - - //Once a formula has been solved, then update the alreadysolvedmap - //with the formula, and the solved value. The solved value can be - //described using the following example: Suppose input to the - //solver is - // - // input key: x = 2 AND y = x + t - // - // output value: y = 2 + t - void UpdateAlreadySolvedMap(const ASTNode& key, const ASTNode& value); - - //This function checks if the key (formula) has already been - //solved for. - // - //If yes it returns TRUE and fills the "output" with the - //solved-value (call by reference argument), - // - //else returns FALSE - bool CheckAlreadySolvedMap(const ASTNode& key, ASTNode& output); - public: - //constructor - BVSolver(BeevMgr * bm) : _bm(bm), _symbol_count(0) { - ASTTrue = _bm->CreateNode(TRUE); - ASTFalse = _bm->CreateNode(FALSE); - }; - - //Destructor - ~BVSolver() { - TermsAlreadySeenMap.clear(); - DoNotSolve_TheseVars.clear(); - FormulasAlreadySolvedMap.clear(); - TermsAlreadySeenMap_ForArrays.clear(); - } - - //Top Level Solver: Goes over the input DAG, identifies the - //equation to be solved, solves them, - ASTNode TopLevelBVSolve(const ASTNode& a); - }; //end of class bvsolver -};//end of namespace BEEV +namespace BEEV +{ + +//This class represents the bitvector arithmetic linear solver. +// +//The bitvector solver is a partial solver, i.e. it does not solve +//for all variables in the system of equations. it is +//best-effort. it relies on the SAT solver to be complete. +// +//The BVSolver assumes that the input equations are normalized, and +//have liketerms combined etc. +// +//0. Traverse top-down over the input DAG, looking for a conjunction +//0. of equations. if you find one, then for each equation in the +//0. conjunction, do the following steps. +// +//1. check for Linearity of the input equation +// +//2. Solve for a "chosen" variable. The variable should occur +//2. exactly once and must have an odd coeff. Refer STP's CAV 2007 +//2. paper for actual solving procedure +// +//4. Outside the solver, Substitute and Re-normalize the input DAG +class BVSolver +{ + //Ptr to toplevel manager that manages bit-vector expressions + //(i.e. construct various kinds of expressions), and also has + //member functions that simplify bit-vector expressions + BeevMgr * _bm; + ASTNode ASTTrue, ASTFalse; + + //Those formulas which have already been solved. If the same + //formula occurs twice then do not solve the second occurence, and + //instead drop it + ASTNodeMap FormulasAlreadySolvedMap; + + //this map is useful while traversing terms and uniquely + //identifying variables in the those terms. Prevents double + //counting. + ASTNodeMap TermsAlreadySeenMap; + ASTNodeMap TermsAlreadySeenMap_ForArrays; + + //count is used in the creation of new variables + unsigned int _symbol_count; + + //solved variables list: If a variable has been solved for then do + //not solve for it again + ASTNodeSet DoNotSolve_TheseVars; + + //checks if var has been solved for or not. if yes, then return + //true else return false + bool DoNotSolveThis(const ASTNode& var); + + //traverses a term, and creates a multiset of all variables in the + //term. Does memoization to avoid double counting. + void VarsInTheTerm(const ASTNode& lhs, ASTNodeMultiSet& v); + void VarsInTheTerm_TopLevel(const ASTNode& lhs, ASTNodeMultiSet& v); + + //choose a suitable var from the term + ASTNode ChooseMonom(const ASTNode& eq, ASTNode& modifiedterm); + //accepts an equation and solves for a variable or a monom in it + ASTNode BVSolve_Odd(const ASTNode& eq); + + //solves equations of the form a*x=t where 'a' is even. Has a + //return value, unlike the normal BVSolve() + ASTNode BVSolve_Even(const ASTNode& eq); + ASTNode CheckEvenEqn(const ASTNode& input, bool& evenflag); + + //Checks for arrayreads in a term. if yes then returns true, else + //return false + bool CheckForArrayReads(const ASTNode& term); + bool CheckForArrayReads_TopLevel(const ASTNode& term); + + //Creates new variables used in solving + ASTNode NewVar(unsigned int n); + + //this function return true if the var occurs in term, else the + //function returns false + bool VarSeenInTerm(const ASTNode& var, const ASTNode& term); + + //takes an even number "in" as input, and returns an odd number + //(return value) and a power of 2 (as number_shifts by reference), + //such that in = (odd_number * power_of_2). + // + //Refer STP's CAV 2007 (or Clark Barrett's 1998 paper on + //bit-vector arithmetic published in DAC 1998) paper for precise + //understanding of the algorithm + ASTNode SplitEven_into_Oddnum_PowerOf2(const ASTNode& in, unsigned int& number_shifts); + + //Once a formula has been solved, then update the alreadysolvedmap + //with the formula, and the solved value. The solved value can be + //described using the following example: Suppose input to the + //solver is + // + // input key: x = 2 AND y = x + t + // + // output value: y = 2 + t + void UpdateAlreadySolvedMap(const ASTNode& key, const ASTNode& value); + + //This function checks if the key (formula) has already been + //solved for. + // + //If yes it returns TRUE and fills the "output" with the + //solved-value (call by reference argument), + // + //else returns FALSE + bool CheckAlreadySolvedMap(const ASTNode& key, ASTNode& output); +public: + //constructor + BVSolver(BeevMgr * bm) : + _bm(bm), _symbol_count(0) + { + ASTTrue = _bm->CreateNode(TRUE); + ASTFalse = _bm->CreateNode(FALSE); + } + ; + + //Destructor + ~BVSolver() + { + TermsAlreadySeenMap.clear(); + DoNotSolve_TheseVars.clear(); + FormulasAlreadySolvedMap.clear(); + TermsAlreadySeenMap_ForArrays.clear(); + } + + //Top Level Solver: Goes over the input DAG, identifies the + //equation to be solved, solves them, + ASTNode TopLevelBVSolve(const ASTNode& a); +}; //end of class bvsolver +} +;//end of namespace BEEV diff --git a/simplifier/simplifier.cpp b/simplifier/simplifier.cpp index d1406a5..77c374f 100644 --- a/simplifier/simplifier.cpp +++ b/simplifier/simplifier.cpp @@ -9,592 +9,645 @@ #include "../AST/AST.h" #include "../AST/ASTUtil.h" -namespace BEEV { - - bool BeevMgr::CheckSimplifyMap(const ASTNode& key, - ASTNode& output, bool pushNeg) { - ASTNodeMap::iterator it, itend; - it = pushNeg ? SimplifyNegMap->find(key) : SimplifyMap->find(key); - itend = pushNeg ? SimplifyNegMap->end() : SimplifyMap->end(); - - if(it != itend) { - output = it->second; - CountersAndStats("Successful_CheckSimplifyMap"); - return true; - } - - if(pushNeg && (it = SimplifyMap->find(key)) != SimplifyMap->end()) { - output = - (ASTFalse == it->second) ? - ASTTrue : - (ASTTrue == it->second) ? ASTFalse : CreateNode(NOT, it->second); - CountersAndStats("2nd_Successful_CheckSimplifyMap"); - return true; - } - - return false; - } - - void BeevMgr::UpdateSimplifyMap(const ASTNode& key, const ASTNode& value, bool pushNeg) { - if(pushNeg) - (*SimplifyNegMap)[key] = value; - else - (*SimplifyMap)[key] = value; - } - - bool BeevMgr::CheckSubstitutionMap(const ASTNode& key, ASTNode& output) { - ASTNodeMap::iterator it; - if((it = SolverMap.find(key)) != SolverMap.end()) { - output = it->second; - return true; - } - return false; - } - - bool BeevMgr::CheckSubstitutionMap(const ASTNode& key) { - if(SolverMap.find(key) != SolverMap.end()) - return true; - else - return false; - } - - bool BeevMgr::UpdateSubstitutionMap(const ASTNode& e0, const ASTNode& e1) { - int i = TermOrder(e0,e1); - if(0 == i) - return false; - - //e0 is of the form READ(Arr,const), and e1 is const, or - //e0 is of the form var, and e1 is const - if(1 == i && !CheckSubstitutionMap(e0)) { - SolverMap[e0] = e1; - return true; - } - - //e1 is of the form READ(Arr,const), and e0 is const, or - //e1 is of the form var, and e0 is const - if (-1 == i && !CheckSubstitutionMap(e1)) { - SolverMap[e1] = e0; - return true; - } - - return false; - } - - bool BeevMgr::CheckMultInverseMap(const ASTNode& key, ASTNode& output) { - ASTNodeMap::iterator it; - if((it = MultInverseMap.find(key)) != MultInverseMap.end()) { - output = it->second; - return true; - } - return false; - } - - void BeevMgr::UpdateMultInverseMap(const ASTNode& key, const ASTNode& value) { - MultInverseMap[key] = value; - } - - - bool BeevMgr::CheckAlwaysTrueFormMap(const ASTNode& key) { - ASTNodeSet::iterator it = AlwaysTrueFormMap.find(key); - ASTNodeSet::iterator itend = AlwaysTrueFormMap.end(); - - if(it != itend) { - //cerr << "found:" << *it << endl; - CountersAndStats("Successful_CheckAlwaysTrueFormMap"); - return true; - } - - return false; - } - - void BeevMgr::UpdateAlwaysTrueFormMap(const ASTNode& key) { - AlwaysTrueFormMap.insert(key); - } - - //if a is READ(Arr,const) or SYMBOL, and b is BVCONST then return 1 - //if b is READ(Arr,const) or SYMBOL, and a is BVCONST then return -1 - // - //else return 0 by default - int BeevMgr::TermOrder(const ASTNode& a, const ASTNode& b) { - Kind k1 = a.GetKind(); - Kind k2 = b.GetKind(); - - //a is of the form READ(Arr,const), and b is const, or - //a is of the form var, and b is const - if((k1 == READ - && - a[0].GetKind() == SYMBOL && - a[1].GetKind() == BVCONST - ) - && - (k2 == BVCONST) - ) - return 1; - - if(SYMBOL == k1 && (BVCONST == k2 || TRUE == k2 || FALSE == k2)) - return 1; - - //b is of the form READ(Arr,const), and a is const, or - //b is of the form var, and a is const - if((k1 == BVCONST) - && - ((k2 == READ - && - b[0].GetKind() == SYMBOL && - b[1].GetKind() == BVCONST - ) - )) - return -1; - - if(SYMBOL == k2 && (BVCONST == k1 || TRUE == k1 || FALSE == k1)) - return -1; - - return 0; - } - - //This function records all the const-indices seen so far for each - //array. It populates the map '_arrayname_readindices' whose key is - //the arrayname, and vlaue is a vector of read-indices. - // - //fill the arrayname_readindices vector if e0 is a READ(Arr,index) - //and index is a BVCONST. - // - //Since these arrayreads are being nuked and recorded in the - //substitutionmap, we have to also record the fact that each - //arrayread (e0 is of the form READ(Arr,const) here is represented - //by a BVCONST (e1). This is necessary for later Leibnitz Axiom - //generation - void BeevMgr::FillUp_ArrReadIndex_Vec(const ASTNode& e0, const ASTNode& e1) { - int i = TermOrder(e0,e1); - if(0 == i) return; - - if(1 == i && e0.GetKind() != SYMBOL && !CheckSubstitutionMap(e0)) { - _arrayname_readindices[e0[0]].push_back(e0[1]); - //e0 is the array read : READ(A,i) and e1 is a bvconst - _arrayread_symbol[e0] = e1; - return; - } - if(-1 == i && e1.GetKind() != SYMBOL && !CheckSubstitutionMap(e1)) { - _arrayname_readindices[e1[0]].push_back(e1[1]); - //e0 is the array read : READ(A,i) and e1 is a bvconst - _arrayread_symbol[e1] = e0; - return; - } - } - - ASTNode BeevMgr::SimplifyFormula_NoRemoveWrites(const ASTNode& b, bool pushNeg) { - Begin_RemoveWrites = false; - ASTNode out = SimplifyFormula(b,pushNeg); - return out; - } - - ASTNode BeevMgr::SimplifyFormula_TopLevel(const ASTNode& b, bool pushNeg) { - ResetSimplifyMaps(); - ASTNode out = SimplifyFormula(b,pushNeg); - ResetSimplifyMaps(); - return out; - } - - ASTNode BeevMgr::SimplifyFormula(const ASTNode& b, bool pushNeg){ - if(!optimize) - return b; - - Kind kind = b.GetKind(); - if(BOOLEAN_TYPE != b.GetType()) { - FatalError(" SimplifyFormula: You have input a nonformula kind: ",ASTUndefined,kind); - } - - ASTNode a = b; - ASTVec ca = a.GetChildren(); - if(!(IMPLIES == kind || - ITE == kind || - isAtomic(kind))) { - SortByArith(ca); - a = CreateNode(kind,ca); - } - - ASTNode output; - if(CheckSimplifyMap(a,output,pushNeg)) - return output; - - switch(kind){ - case AND: - case OR: - output = SimplifyAndOrFormula(a,pushNeg); - break; - case NOT: - output = SimplifyNotFormula(a,pushNeg); - break; - case XOR: - output = SimplifyXorFormula(a,pushNeg); - break; - case NAND: - output = SimplifyNandFormula(a,pushNeg); - break; - case NOR: - output = SimplifyNorFormula(a,pushNeg); - break; - case IFF: - output = SimplifyIffFormula(a,pushNeg); - break; - case IMPLIES: - output = SimplifyImpliesFormula(a,pushNeg); - break; - case ITE: - output = SimplifyIteFormula(a,pushNeg); - break; - default: - //kind can be EQ,NEQ,BVLT,BVLE,... or a propositional variable - output = SimplifyAtomicFormula(a,pushNeg); - //output = pushNeg ? CreateNode(NOT,a) : a; - break; - } - - //memoize - UpdateSimplifyMap(a,output, pushNeg); - return output; - } - - ASTNode BeevMgr::SimplifyAtomicFormula(const ASTNode& a, bool pushNeg) { - if(!optimize) { - return a; - } - - ASTNode output; - if(CheckSimplifyMap(a,output,pushNeg)) { - return output; - } - - ASTNode left,right; - if(a.Degree() == 2) { - //cerr << "Input to simplifyterm: left: " << a[0] << endl; - left = SimplifyTerm(a[0]); - //cerr << "Output of simplifyterm:left: " << left << endl; - //cerr << "Input to simplifyterm: right: " << a[1] << endl; - right = SimplifyTerm(a[1]); - //cerr << "Output of simplifyterm:left: " << right << endl; - } - - Kind kind = a.GetKind(); - switch(kind) { - case TRUE: - output = pushNeg ? ASTFalse : ASTTrue; - break; - case FALSE: - output = pushNeg ? ASTTrue : ASTFalse; - break; - case SYMBOL: - if(!CheckSolverMap(a,output)) { - output = a; - } - output = pushNeg ? CreateNode(NOT,output) : output; - break; - case BVGETBIT: { - ASTNode term = SimplifyTerm(a[0]); - ASTNode thebit = a[1]; - ASTNode zero = CreateZeroConst(1); - ASTNode one = CreateOneConst(1); - ASTNode getthebit = SimplifyTerm(CreateTerm(BVEXTRACT,1,term,thebit,thebit)); - if(getthebit == zero) - output = pushNeg ? ASTTrue : ASTFalse; - else if(getthebit == one) - output = pushNeg ? ASTFalse : ASTTrue; - else { - output = CreateNode(BVGETBIT,term,thebit); - output = pushNeg ? CreateNode(NOT,output) : output; - } - break; - } - case EQ:{ - output = CreateSimplifiedEQ(left,right); - output = LhsMinusRhs(output); - output = ITEOpt_InEqs(output); - if(output == ASTTrue) - output = pushNeg ? ASTFalse : ASTTrue; - else if (output == ASTFalse) - output = pushNeg ? ASTTrue : ASTFalse; - else - output = pushNeg ? CreateNode(NOT,output) : output; - break; - } - case NEQ: { - output = CreateSimplifiedEQ(left,right); - output = LhsMinusRhs(output); - if(output == ASTTrue) - output = pushNeg ? ASTTrue : ASTFalse; - else if (output == ASTFalse) - output = pushNeg ? ASTFalse : ASTTrue; - else - output = pushNeg ? output : CreateNode(NOT,output); - break; - } - case BVLT: - case BVLE: - case BVGT: - case BVGE: - case BVSLT: - case BVSLE: - case BVSGT: - case BVSGE: { - //output = CreateNode(kind,left,right); - //output = pushNeg ? CreateNode(NOT,output) : output; - output = CreateSimplifiedINEQ(kind,left,right,pushNeg); - break; - } - default: - FatalError("SimplifyAtomicFormula: NO atomic formula of the kind: ",ASTUndefined,kind); - break; - } - - //memoize - UpdateSimplifyMap(a,output,pushNeg); - return output; - } //end of SimplifyAtomicFormula() - - ASTNode BeevMgr::CreateSimplifiedINEQ(Kind k, - const ASTNode& left, - const ASTNode& right, - bool pushNeg) { - ASTNode output; - if(BVCONST == left.GetKind() && BVCONST == right.GetKind()) { - output = BVConstEvaluator(CreateNode(k,left,right)); - output = pushNeg ? (ASTFalse == output) ? ASTTrue : ASTFalse : output; - return output; - } - - unsigned len = left.GetValueWidth(); - ASTNode zero = CreateZeroConst(len); - ASTNode one = CreateOneConst(len); - ASTNode max = CreateMaxConst(len); - switch(k){ - case BVLT: - if(right == zero) { - output = pushNeg ? ASTTrue : ASTFalse; - } - else if(left == right) { - output = pushNeg ? ASTTrue : ASTFalse; - } - else if(one == right) { - output = CreateSimplifiedEQ(left,zero); - output = pushNeg ? CreateNode(NOT,output) : output; - } - else { - output = pushNeg ? CreateNode(BVLE,right,left) : CreateNode(BVLT,left,right); - } - break; - case BVLE: - if(left == zero) { - output = pushNeg ? ASTFalse : ASTTrue; - } - else if(left == right) { - output = pushNeg ? ASTFalse : ASTTrue; - } - else if(max == right) { - output = pushNeg ? ASTFalse : ASTTrue; - } - else if(zero == right) { - output = CreateSimplifiedEQ(left,zero); - output = pushNeg ? CreateNode(NOT,output) : output; - } - else { - output = pushNeg ? CreateNode(BVLT,right,left) : CreateNode(BVLE,left,right); - } - break; - case BVGT: - if(left == zero) { - output = pushNeg ? ASTTrue : ASTFalse; - } - else if(left == right) { - output = pushNeg ? ASTTrue : ASTFalse; - } - else { - output = pushNeg ? CreateNode(BVLE,left,right) : CreateNode(BVLT,right,left); - } - break; - case BVGE: - if(right == zero) { - output = pushNeg ? ASTFalse : ASTTrue; - } - else if(left == right) { - output = pushNeg ? ASTFalse : ASTTrue; - } - else { - output = pushNeg ? CreateNode(BVLT,left,right) : CreateNode(BVLE,right,left); - } - break; - case BVSLT: - case BVSLE: - case BVSGE: - case BVSGT: { - output = CreateNode(k,left,right); - output = pushNeg ? CreateNode(NOT,output) : output; - } - break; - default: - FatalError("Wrong Kind"); - break; - } - - return output; - } - - //takes care of some simple ITE Optimizations in the context of equations - ASTNode BeevMgr::ITEOpt_InEqs(const ASTNode& in) { - CountersAndStats("ITEOpts_InEqs"); - - if(!(EQ == in.GetKind() && optimize)) { - return in; - } - - ASTNode output; - if(CheckSimplifyMap(in,output,false)) { - return output; - } - - ASTNode in1 = in[0]; - ASTNode in2 = in[1]; - Kind k1 = in1.GetKind(); - Kind k2 = in2.GetKind(); - if(in1 == in2) { - //terms are syntactically the same - output = ASTTrue; - } - else if(BVCONST == k1 && BVCONST == k2) { - //here the terms are definitely not syntactically equal but may - //be semantically equal. - output = ASTFalse; - } - else if(ITE == k1 && - BVCONST == in1[1].GetKind() && - BVCONST == in1[2].GetKind() && BVCONST == k2) { - //if one side is a BVCONST and the other side is an ITE over - //BVCONST then we can do the following optimization: - // - // c = ITE(cond,c,d) <=> cond - // - // similarly ITE(cond,c,d) = c <=> cond - // - // c = ITE(cond,d,c) <=> NOT(cond) - // - //similarly ITE(cond,d,c) = d <=> NOT(cond) - ASTNode cond = in1[0]; - if(in1[1] == in2) { - //ITE(cond, c, d) = c <=> cond - output = cond; - } - else if(in1[2] == in2) { - cond = SimplifyFormula(cond,true); - output = cond; - } - else { - //last resort is to CreateNode - output = CreateNode(EQ,in1,in2); - } - } - else if(ITE == k2 && - BVCONST == in2[1].GetKind() && - BVCONST == in2[2].GetKind() && BVCONST == k1) { - ASTNode cond = in2[0]; - if(in2[1] == in1) { - //ITE(cond, c, d) = c <=> cond - output = cond; - } - else if(in2[2] == in1) { - cond = SimplifyFormula(cond,true); - output = cond; - } - else { +namespace BEEV +{ + +bool BeevMgr::CheckSimplifyMap(const ASTNode& key, ASTNode& output, bool pushNeg) +{ + ASTNodeMap::iterator it, itend; + it = pushNeg ? SimplifyNegMap->find(key) : SimplifyMap->find(key); + itend = pushNeg ? SimplifyNegMap->end() : SimplifyMap->end(); + + if (it != itend) + { + output = it->second; + CountersAndStats("Successful_CheckSimplifyMap"); + return true; + } + + if (pushNeg && (it = SimplifyMap->find(key)) != SimplifyMap->end()) + { + output = (ASTFalse == it->second) ? ASTTrue : (ASTTrue == it->second) ? ASTFalse : CreateNode(NOT, it->second); + CountersAndStats("2nd_Successful_CheckSimplifyMap"); + return true; + } + + return false; +} + +void BeevMgr::UpdateSimplifyMap(const ASTNode& key, const ASTNode& value, bool pushNeg) +{ + if (pushNeg) + (*SimplifyNegMap)[key] = value; + else + (*SimplifyMap)[key] = value; +} + +bool BeevMgr::CheckSubstitutionMap(const ASTNode& key, ASTNode& output) +{ + ASTNodeMap::iterator it; + if ((it = SolverMap.find(key)) != SolverMap.end()) + { + output = it->second; + return true; + } + return false; +} + +bool BeevMgr::CheckSubstitutionMap(const ASTNode& key) +{ + if (SolverMap.find(key) != SolverMap.end()) + return true; + else + return false; +} + +bool BeevMgr::UpdateSubstitutionMap(const ASTNode& e0, const ASTNode& e1) +{ + int i = TermOrder(e0, e1); + if (0 == i) + return false; + + //e0 is of the form READ(Arr,const), and e1 is const, or + //e0 is of the form var, and e1 is const + if (1 == i && !CheckSubstitutionMap(e0)) + { + SolverMap[e0] = e1; + return true; + } + + //e1 is of the form READ(Arr,const), and e0 is const, or + //e1 is of the form var, and e0 is const + if (-1 == i && !CheckSubstitutionMap(e1)) + { + SolverMap[e1] = e0; + return true; + } + + return false; +} + +bool BeevMgr::CheckMultInverseMap(const ASTNode& key, ASTNode& output) +{ + ASTNodeMap::iterator it; + if ((it = MultInverseMap.find(key)) != MultInverseMap.end()) + { + output = it->second; + return true; + } + return false; +} + +void BeevMgr::UpdateMultInverseMap(const ASTNode& key, const ASTNode& value) +{ + MultInverseMap[key] = value; +} + +bool BeevMgr::CheckAlwaysTrueFormMap(const ASTNode& key) +{ + ASTNodeSet::iterator it = AlwaysTrueFormMap.find(key); + ASTNodeSet::iterator itend = AlwaysTrueFormMap.end(); + + if (it != itend) + { + //cerr << "found:" << *it << endl; + CountersAndStats("Successful_CheckAlwaysTrueFormMap"); + return true; + } + + return false; +} + +void BeevMgr::UpdateAlwaysTrueFormMap(const ASTNode& key) +{ + AlwaysTrueFormMap.insert(key); +} + +//if a is READ(Arr,const) or SYMBOL, and b is BVCONST then return 1 +//if b is READ(Arr,const) or SYMBOL, and a is BVCONST then return -1 +// +//else return 0 by default +int BeevMgr::TermOrder(const ASTNode& a, const ASTNode& b) +{ + Kind k1 = a.GetKind(); + Kind k2 = b.GetKind(); + + //a is of the form READ(Arr,const), and b is const, or + //a is of the form var, and b is const + if ((k1 == READ && a[0].GetKind() == SYMBOL && a[1].GetKind() == BVCONST) && (k2 == BVCONST)) + return 1; + + if (SYMBOL == k1 && (BVCONST == k2 || TRUE == k2 || FALSE == k2)) + return 1; + + //b is of the form READ(Arr,const), and a is const, or + //b is of the form var, and a is const + if ((k1 == BVCONST) && ((k2 == READ && b[0].GetKind() == SYMBOL && b[1].GetKind() == BVCONST))) + return -1; + + if (SYMBOL == k2 && (BVCONST == k1 || TRUE == k1 || FALSE == k1)) + return -1; + + return 0; +} + +//This function records all the const-indices seen so far for each +//array. It populates the map '_arrayname_readindices' whose key is +//the arrayname, and vlaue is a vector of read-indices. +// +//fill the arrayname_readindices vector if e0 is a READ(Arr,index) +//and index is a BVCONST. +// +//Since these arrayreads are being nuked and recorded in the +//substitutionmap, we have to also record the fact that each +//arrayread (e0 is of the form READ(Arr,const) here is represented +//by a BVCONST (e1). This is necessary for later Leibnitz Axiom +//generation +void BeevMgr::FillUp_ArrReadIndex_Vec(const ASTNode& e0, const ASTNode& e1) +{ + int i = TermOrder(e0, e1); + if (0 == i) + return; + + if (1 == i && e0.GetKind() != SYMBOL && !CheckSubstitutionMap(e0)) + { + _arrayname_readindices[e0[0]].push_back(e0[1]); + //e0 is the array read : READ(A,i) and e1 is a bvconst + _arrayread_symbol[e0] = e1; + return; + } + if (-1 == i && e1.GetKind() != SYMBOL && !CheckSubstitutionMap(e1)) + { + _arrayname_readindices[e1[0]].push_back(e1[1]); + //e0 is the array read : READ(A,i) and e1 is a bvconst + _arrayread_symbol[e1] = e0; + return; + } +} + +ASTNode BeevMgr::SimplifyFormula_NoRemoveWrites(const ASTNode& b, bool pushNeg) +{ + Begin_RemoveWrites = false; + ASTNode out = SimplifyFormula(b, pushNeg); + return out; +} + +ASTNode BeevMgr::SimplifyFormula_TopLevel(const ASTNode& b, bool pushNeg) +{ + ResetSimplifyMaps(); + ASTNode out = SimplifyFormula(b, pushNeg); + ResetSimplifyMaps(); + return out; +} + +ASTNode BeevMgr::SimplifyFormula(const ASTNode& b, bool pushNeg) +{ + if (!optimize) + return b; + + Kind kind = b.GetKind(); + if (BOOLEAN_TYPE != b.GetType()) + { + FatalError(" SimplifyFormula: You have input a nonformula kind: ", ASTUndefined, kind); + } + + ASTNode a = b; + ASTVec ca = a.GetChildren(); + if (!(IMPLIES == kind || ITE == kind || isAtomic(kind))) + { + SortByArith(ca); + a = CreateNode(kind, ca); + } + + ASTNode output; + if (CheckSimplifyMap(a, output, pushNeg)) + return output; + + switch (kind) + { + case AND: + case OR: + output = SimplifyAndOrFormula(a, pushNeg); + break; + case NOT: + output = SimplifyNotFormula(a, pushNeg); + break; + case XOR: + output = SimplifyXorFormula(a, pushNeg); + break; + case NAND: + output = SimplifyNandFormula(a, pushNeg); + break; + case NOR: + output = SimplifyNorFormula(a, pushNeg); + break; + case IFF: + output = SimplifyIffFormula(a, pushNeg); + break; + case IMPLIES: + output = SimplifyImpliesFormula(a, pushNeg); + break; + case ITE: + output = SimplifyIteFormula(a, pushNeg); + break; + default: + //kind can be EQ,NEQ,BVLT,BVLE,... or a propositional variable + output = SimplifyAtomicFormula(a, pushNeg); + //output = pushNeg ? CreateNode(NOT,a) : a; + break; + } + + //memoize + UpdateSimplifyMap(a, output, pushNeg); + return output; +} + +ASTNode BeevMgr::SimplifyAtomicFormula(const ASTNode& a, bool pushNeg) +{ + if (!optimize) + { + return a; + } + + ASTNode output; + if (CheckSimplifyMap(a, output, pushNeg)) + { + return output; + } + + ASTNode left, right; + if (a.Degree() == 2) + { + //cerr << "Input to simplifyterm: left: " << a[0] << endl; + left = SimplifyTerm(a[0]); + //cerr << "Output of simplifyterm:left: " << left << endl; + //cerr << "Input to simplifyterm: right: " << a[1] << endl; + right = SimplifyTerm(a[1]); + //cerr << "Output of simplifyterm:left: " << right << endl; + } + + Kind kind = a.GetKind(); + switch (kind) + { + case TRUE: + output = pushNeg ? ASTFalse : ASTTrue; + break; + case FALSE: + output = pushNeg ? ASTTrue : ASTFalse; + break; + case SYMBOL: + if (!CheckSolverMap(a, output)) + { + output = a; + } + output = pushNeg ? CreateNode(NOT, output) : output; + break; + case BVGETBIT: + { + ASTNode term = SimplifyTerm(a[0]); + ASTNode thebit = a[1]; + ASTNode zero = CreateZeroConst(1); + ASTNode one = CreateOneConst(1); + ASTNode getthebit = SimplifyTerm(CreateTerm(BVEXTRACT, 1, term, thebit, thebit)); + if (getthebit == zero) + output = pushNeg ? ASTTrue : ASTFalse; + else if (getthebit == one) + output = pushNeg ? ASTFalse : ASTTrue; + else + { + output = CreateNode(BVGETBIT, term, thebit); + output = pushNeg ? CreateNode(NOT, output) : output; + } + break; + } + case EQ: + { + output = CreateSimplifiedEQ(left, right); + output = LhsMinusRhs(output); + output = ITEOpt_InEqs(output); + if (output == ASTTrue) + output = pushNeg ? ASTFalse : ASTTrue; + else if (output == ASTFalse) + output = pushNeg ? ASTTrue : ASTFalse; + else + output = pushNeg ? CreateNode(NOT, output) : output; + break; + } + case NEQ: + { + output = CreateSimplifiedEQ(left, right); + output = LhsMinusRhs(output); + if (output == ASTTrue) + output = pushNeg ? ASTTrue : ASTFalse; + else if (output == ASTFalse) + output = pushNeg ? ASTFalse : ASTTrue; + else + output = pushNeg ? output : CreateNode(NOT, output); + break; + } + case BVLT: + case BVLE: + case BVGT: + case BVGE: + case BVSLT: + case BVSLE: + case BVSGT: + case BVSGE: + { + //output = CreateNode(kind,left,right); + //output = pushNeg ? CreateNode(NOT,output) : output; + output = CreateSimplifiedINEQ(kind, left, right, pushNeg); + break; + } + default: + FatalError("SimplifyAtomicFormula: NO atomic formula of the kind: ", ASTUndefined, kind); + break; + } + + //memoize + UpdateSimplifyMap(a, output, pushNeg); + return output; +} //end of SimplifyAtomicFormula() + +ASTNode BeevMgr::CreateSimplifiedINEQ(Kind k, const ASTNode& left, const ASTNode& right, bool pushNeg) +{ + ASTNode output; + if (BVCONST == left.GetKind() && BVCONST == right.GetKind()) + { + output = BVConstEvaluator(CreateNode(k, left, right)); + output = pushNeg ? (ASTFalse == output) ? ASTTrue : ASTFalse : output; + return output; + } + + unsigned len = left.GetValueWidth(); + ASTNode zero = CreateZeroConst(len); + ASTNode one = CreateOneConst(len); + ASTNode max = CreateMaxConst(len); + switch (k) + { + case BVLT: + if (right == zero) + { + output = pushNeg ? ASTTrue : ASTFalse; + } + else if (left == right) + { + output = pushNeg ? ASTTrue : ASTFalse; + } + else if (one == right) + { + output = CreateSimplifiedEQ(left, zero); + output = pushNeg ? CreateNode(NOT, output) : output; + } + else + { + output = pushNeg ? CreateNode(BVLE, right, left) : CreateNode(BVLT, left, right); + } + break; + case BVLE: + if (left == zero) + { + output = pushNeg ? ASTFalse : ASTTrue; + } + else if (left == right) + { + output = pushNeg ? ASTFalse : ASTTrue; + } + else if (max == right) + { + output = pushNeg ? ASTFalse : ASTTrue; + } + else if (zero == right) + { + output = CreateSimplifiedEQ(left, zero); + output = pushNeg ? CreateNode(NOT, output) : output; + } + else + { + output = pushNeg ? CreateNode(BVLT, right, left) : CreateNode(BVLE, left, right); + } + break; + case BVGT: + if (left == zero) + { + output = pushNeg ? ASTTrue : ASTFalse; + } + else if (left == right) + { + output = pushNeg ? ASTTrue : ASTFalse; + } + else + { + output = pushNeg ? CreateNode(BVLE, left, right) : CreateNode(BVLT, right, left); + } + break; + case BVGE: + if (right == zero) + { + output = pushNeg ? ASTFalse : ASTTrue; + } + else if (left == right) + { + output = pushNeg ? ASTFalse : ASTTrue; + } + else + { + output = pushNeg ? CreateNode(BVLT, left, right) : CreateNode(BVLE, right, left); + } + break; + case BVSLT: + case BVSLE: + case BVSGE: + case BVSGT: + { + output = CreateNode(k, left, right); + output = pushNeg ? CreateNode(NOT, output) : output; + } + break; + default: + FatalError("Wrong Kind"); + break; + } + + return output; +} + +//takes care of some simple ITE Optimizations in the context of equations +ASTNode BeevMgr::ITEOpt_InEqs(const ASTNode& in) +{ + CountersAndStats("ITEOpts_InEqs"); + + if (!(EQ == in.GetKind() && optimize)) + { + return in; + } + + ASTNode output; + if (CheckSimplifyMap(in, output, false)) + { + return output; + } + + ASTNode in1 = in[0]; + ASTNode in2 = in[1]; + Kind k1 = in1.GetKind(); + Kind k2 = in2.GetKind(); + if (in1 == in2) + { + //terms are syntactically the same + output = ASTTrue; + } + else if (BVCONST == k1 && BVCONST == k2) + { + //here the terms are definitely not syntactically equal but may + //be semantically equal. + output = ASTFalse; + } + else if (ITE == k1 && BVCONST == in1[1].GetKind() && BVCONST == in1[2].GetKind() && BVCONST == k2) + { + //if one side is a BVCONST and the other side is an ITE over + //BVCONST then we can do the following optimization: + // + // c = ITE(cond,c,d) <=> cond + // + // similarly ITE(cond,c,d) = c <=> cond + // + // c = ITE(cond,d,c) <=> NOT(cond) + // + //similarly ITE(cond,d,c) = d <=> NOT(cond) + ASTNode cond = in1[0]; + if (in1[1] == in2) + { + //ITE(cond, c, d) = c <=> cond + output = cond; + } + else if (in1[2] == in2) + { + cond = SimplifyFormula(cond, true); + output = cond; + } + else + { + //last resort is to CreateNode + output = CreateNode(EQ, in1, in2); + } + } + else if (ITE == k2 && BVCONST == in2[1].GetKind() && BVCONST == in2[2].GetKind() && BVCONST == k1) + { + ASTNode cond = in2[0]; + if (in2[1] == in1) + { + //ITE(cond, c, d) = c <=> cond + output = cond; + } + else if (in2[2] == in1) + { + cond = SimplifyFormula(cond, true); + output = cond; + } + else + { + //last resort is to CreateNode + output = CreateNode(EQ, in1, in2); + } + } + else + { + //last resort is to CreateNode + output = CreateNode(EQ, in1, in2); + } + + UpdateSimplifyMap(in, output, false); + return output; +} //End of ITEOpts_InEqs() + +//Tries to simplify the input to TRUE/FALSE. if it fails, then +//return the constructed equality +ASTNode BeevMgr::CreateSimplifiedEQ(const ASTNode& in1, const ASTNode& in2) +{ + CountersAndStats("CreateSimplifiedEQ"); + Kind k1 = in1.GetKind(); + Kind k2 = in2.GetKind(); + + if (!optimize) + { + return CreateNode(EQ, in1, in2); + } + + if (in1 == in2) + //terms are syntactically the same + return ASTTrue; + + //here the terms are definitely not syntactically equal but may be + //semantically equal. + if (BVCONST == k1 && BVCONST == k2) + return ASTFalse; + //last resort is to CreateNode - output = CreateNode(EQ,in1,in2); - } - } - else { - //last resort is to CreateNode - output = CreateNode(EQ,in1,in2); - } - - UpdateSimplifyMap(in,output,false); - return output; - } //End of ITEOpts_InEqs() - - //Tries to simplify the input to TRUE/FALSE. if it fails, then - //return the constructed equality - ASTNode BeevMgr::CreateSimplifiedEQ(const ASTNode& in1, const ASTNode& in2) { - CountersAndStats("CreateSimplifiedEQ"); - Kind k1 = in1.GetKind(); - Kind k2 = in2.GetKind(); - - if(!optimize) { - return CreateNode(EQ,in1,in2); - } - - if(in1 == in2) - //terms are syntactically the same - return ASTTrue; - - //here the terms are definitely not syntactically equal but may be - //semantically equal. - if(BVCONST == k1 && BVCONST == k2) - return ASTFalse; - - - //last resort is to CreateNode - return CreateNode(EQ,in1,in2); - } - - //accepts cond == t1, then part is t2, and else part is t3 - ASTNode BeevMgr::CreateSimplifiedTermITE(const ASTNode& in0, - const ASTNode& in1, const ASTNode& in2) { - ASTNode t0 = in0; - ASTNode t1 = in1; - ASTNode t2 = in2; - CountersAndStats("CreateSimplifiedITE"); - if(!optimize) { - if(t1.GetValueWidth() != t2.GetValueWidth()) { - cerr << "t2 is : = " << t2; - FatalError("CreateSimplifiedTermITE: the lengths of then and else branches don't match",t1); - } - if(t1.GetIndexWidth() != t2.GetIndexWidth()) { - cerr << "t2 is : = " << t2; - FatalError("CreateSimplifiedTermITE: the lengths of then and else branches don't match",t1); - } - return CreateTerm(ITE,t1.GetValueWidth(),t0,t1,t2); - } - - if(t0 == ASTTrue) - return t1; - if (t0 == ASTFalse) - return t2; - if(t1 == t2) - return t1; - if(CheckAlwaysTrueFormMap(t0)) { - return t1; - } - if(CheckAlwaysTrueFormMap(CreateNode(NOT,t0)) || - (NOT == t0.GetKind() && CheckAlwaysTrueFormMap(t0[0]))) { - return t2; - } - - return CreateTerm(ITE,t1.GetValueWidth(),t0,t1,t2); - } - -ASTNode BeevMgr::CreateSimplifiedFormulaITE(const ASTNode& in0, const ASTNode& in1, const ASTNode& in2) { + return CreateNode(EQ, in1, in2); +} + +//accepts cond == t1, then part is t2, and else part is t3 +ASTNode BeevMgr::CreateSimplifiedTermITE(const ASTNode& in0, const ASTNode& in1, const ASTNode& in2) +{ + ASTNode t0 = in0; + ASTNode t1 = in1; + ASTNode t2 = in2; + CountersAndStats("CreateSimplifiedITE"); + if (!optimize) + { + if (t1.GetValueWidth() != t2.GetValueWidth()) + { + cerr << "t2 is : = " << t2; + FatalError("CreateSimplifiedTermITE: the lengths of then and else branches don't match", t1); + } + if (t1.GetIndexWidth() != t2.GetIndexWidth()) + { + cerr << "t2 is : = " << t2; + FatalError("CreateSimplifiedTermITE: the lengths of then and else branches don't match", t1); + } + return CreateTerm(ITE, t1.GetValueWidth(), t0, t1, t2); + } + + if (t0 == ASTTrue) + return t1; + if (t0 == ASTFalse) + return t2; + if (t1 == t2) + return t1; + if (CheckAlwaysTrueFormMap(t0)) + { + return t1; + } + if (CheckAlwaysTrueFormMap(CreateNode(NOT, t0)) || (NOT == t0.GetKind() && CheckAlwaysTrueFormMap(t0[0]))) + { + return t2; + } + + return CreateTerm(ITE, t1.GetValueWidth(), t0, t1, t2); +} + +ASTNode BeevMgr::CreateSimplifiedFormulaITE(const ASTNode& in0, const ASTNode& in1, const ASTNode& in2) +{ ASTNode t0 = in0; ASTNode t1 = in1; ASTNode t2 = in2; CountersAndStats("CreateSimplifiedFormulaITE"); - if (optimize) { + if (optimize) + { if (t0 == ASTTrue) return t1; if (t0 == ASTFalse) return t2; if (t1 == t2) return t1; - if (CheckAlwaysTrueFormMap(t0)) { + if (CheckAlwaysTrueFormMap(t0)) + { return t1; } - if (CheckAlwaysTrueFormMap(CreateNode(NOT, t0)) || (NOT == t0.GetKind() && CheckAlwaysTrueFormMap(t0[0]))) { + if (CheckAlwaysTrueFormMap(CreateNode(NOT, t0)) || (NOT == t0.GetKind() && CheckAlwaysTrueFormMap(t0[0]))) + { return t2; } } @@ -603,2629 +656,2918 @@ ASTNode BeevMgr::CreateSimplifiedFormulaITE(const ASTNode& in0, const ASTNode& i return result; } +ASTNode BeevMgr::SimplifyAndOrFormula(const ASTNode& a, bool pushNeg) +{ + ASTNode output; + //cerr << "input:\n" << a << endl; + + if (CheckSimplifyMap(a, output, pushNeg)) + return output; + + ASTVec c, outvec; + c = a.GetChildren(); + ASTNode flat = FlattenOneLevel(a); + c = flat.GetChildren(); + SortByArith(c); + + Kind k = a.GetKind(); + bool isAnd = (k == AND) ? true : false; + + ASTNode annihilator = isAnd ? (pushNeg ? ASTTrue : ASTFalse) : (pushNeg ? ASTFalse : ASTTrue); + + ASTNode identity = isAnd ? (pushNeg ? ASTFalse : ASTTrue) : (pushNeg ? ASTTrue : ASTFalse); + + //do the work + ASTVec::const_iterator next_it; + for (ASTVec::const_iterator i = c.begin(), iend = c.end(); i != iend; i++) + { + ASTNode aaa = *i; + next_it = i + 1; + bool nextexists = (next_it < iend); + + aaa = SimplifyFormula(aaa, pushNeg); + if (annihilator == aaa) + { + //memoize + UpdateSimplifyMap(*i, annihilator, pushNeg); + UpdateSimplifyMap(a, annihilator, pushNeg); + //cerr << "annihilator1: output:\n" << annihilator << endl; + return annihilator; + } + ASTNode bbb = ASTFalse; + if (nextexists) + { + bbb = SimplifyFormula(*next_it, pushNeg); + } + if (nextexists && bbb == aaa) + { + //skip the duplicate aaa. *next_it will be included + } + else if (nextexists && ((bbb.GetKind() == NOT && bbb[0] == aaa))) + { + //memoize + UpdateSimplifyMap(a, annihilator, pushNeg); + //cerr << "annihilator2: output:\n" << annihilator << endl; + return annihilator; + } + else if (identity == aaa) + { + // //drop identites + } + else if ((!isAnd && !pushNeg) || (isAnd && pushNeg)) + { + outvec.push_back(aaa); + } + else if ((isAnd && !pushNeg) || (!isAnd && pushNeg)) + { + outvec.push_back(aaa); + } + else + { + outvec.push_back(aaa); + } + } - ASTNode BeevMgr::SimplifyAndOrFormula(const ASTNode& a, bool pushNeg) { - ASTNode output; - //cerr << "input:\n" << a << endl; - - if(CheckSimplifyMap(a,output,pushNeg)) - return output; + switch (outvec.size()) + { + case 0: + { + //only identities were dropped + output = identity; + break; + } + case 1: + { + output = SimplifyFormula(outvec[0], false); + break; + } + default: + { + output = (isAnd) ? (pushNeg ? CreateNode(OR, outvec) : CreateNode(AND, outvec)) : (pushNeg ? CreateNode(AND, outvec) : CreateNode(OR, + outvec)); + //output = FlattenOneLevel(output); + break; + } + } + //memoize + UpdateSimplifyMap(a, output, pushNeg); + //cerr << "output:\n" << output << endl; + return output; +} //end of SimplifyAndOrFormula - ASTVec c, outvec; - c = a.GetChildren(); - ASTNode flat = FlattenOneLevel(a); - c = flat.GetChildren(); - SortByArith(c); - Kind k = a.GetKind(); - bool isAnd = (k == AND) ? true : false; +ASTNode BeevMgr::SimplifyNotFormula(const ASTNode& a, bool pushNeg) +{ + ASTNode output; + if (CheckSimplifyMap(a, output, pushNeg)) + return output; + + if (!(a.Degree() == 1 && NOT == a.GetKind())) + FatalError("SimplifyNotFormula: input vector with more than 1 node", ASTUndefined); + + //if pushNeg is set then there is NOT on top + unsigned int NotCount = pushNeg ? 1 : 0; + ASTNode o = a; + //count the number of NOTs in 'a' + while (NOT == o.GetKind()) + { + o = o[0]; + NotCount++; + } - ASTNode annihilator = isAnd ? - (pushNeg ? ASTTrue : ASTFalse): - (pushNeg ? ASTFalse : ASTTrue); + //pushnegation if there are odd number of NOTs + bool pn = (NotCount % 2 == 0) ? false : true; - ASTNode identity = isAnd ? - (pushNeg ? ASTFalse : ASTTrue): - (pushNeg ? ASTTrue : ASTFalse); + if (CheckAlwaysTrueFormMap(o)) + { + output = pn ? ASTFalse : ASTTrue; + return output; + } - //do the work - ASTVec::const_iterator next_it; - for(ASTVec::const_iterator i=c.begin(),iend=c.end();i!=iend;i++) { - ASTNode aaa = *i; - next_it = i+1; - bool nextexists = (next_it < iend); + if (CheckSimplifyMap(o, output, pn)) + { + return output; + } - aaa = SimplifyFormula(aaa,pushNeg); - if(annihilator == aaa) { - //memoize - UpdateSimplifyMap(*i,annihilator,pushNeg); - UpdateSimplifyMap(a, annihilator,pushNeg); - //cerr << "annihilator1: output:\n" << annihilator << endl; - return annihilator; - } - ASTNode bbb = ASTFalse; - if(nextexists) { - bbb = SimplifyFormula(*next_it,pushNeg); - } - if(nextexists && bbb == aaa) { - //skip the duplicate aaa. *next_it will be included - } - else if(nextexists && - ((bbb.GetKind() == NOT && bbb[0] == aaa))) { - //memoize - UpdateSimplifyMap(a, annihilator,pushNeg); - //cerr << "annihilator2: output:\n" << annihilator << endl; - return annihilator; - } - else if(identity == aaa) { - // //drop identites - } - else if((!isAnd && !pushNeg) || - (isAnd && pushNeg)) { - outvec.push_back(aaa); - } - else if((isAnd && !pushNeg) || - (!isAnd && pushNeg)) { - outvec.push_back(aaa); - } - else { - outvec.push_back(aaa); - } - } - - switch(outvec.size()) { - case 0: { - //only identities were dropped - output = identity; - break; - } - case 1: { - output = SimplifyFormula(outvec[0],false); - break; - } - default: { - output = (isAnd) ? - (pushNeg ? CreateNode(OR,outvec) : CreateNode(AND,outvec)): - (pushNeg ? CreateNode(AND,outvec) : CreateNode(OR,outvec)); - //output = FlattenOneLevel(output); - break; - } - } - //memoize - UpdateSimplifyMap(a,output,pushNeg); - //cerr << "output:\n" << output << endl; - return output; - } //end of SimplifyAndOrFormula - - - ASTNode BeevMgr::SimplifyNotFormula(const ASTNode& a, bool pushNeg) { - ASTNode output; - if(CheckSimplifyMap(a,output,pushNeg)) - return output; - - if(!(a.Degree() == 1 && NOT == a.GetKind())) - FatalError("SimplifyNotFormula: input vector with more than 1 node",ASTUndefined); - - //if pushNeg is set then there is NOT on top - unsigned int NotCount = pushNeg ? 1 : 0; - ASTNode o = a; - //count the number of NOTs in 'a' - while(NOT == o.GetKind()) { - o = o[0]; - NotCount++; - } - - //pushnegation if there are odd number of NOTs - bool pn = (NotCount % 2 == 0) ? false : true; - - if(CheckAlwaysTrueFormMap(o)) { - output = pn ? ASTFalse : ASTTrue; - return output; - } - - if(CheckSimplifyMap(o,output,pn)) { - return output; - } - - if (ASTTrue == o) { - output = pn ? ASTFalse : ASTTrue; - } - else if (ASTFalse == o) { - output = pn ? ASTTrue : ASTFalse; - } - else { - output = SimplifyFormula(o,pn); - } - //memoize - UpdateSimplifyMap(o,output,pn); - UpdateSimplifyMap(a,output,pushNeg); - return output; - } - - ASTNode BeevMgr::SimplifyXorFormula(const ASTNode& a, bool pushNeg) { - ASTNode output; - if(CheckSimplifyMap(a,output,pushNeg)) - return output; - - if (a.GetChildren().size() > 2) { - FatalError("Simplify got an XOR with more than two children."); - } - - ASTNode a0 = SimplifyFormula(a[0],false); - ASTNode a1 = SimplifyFormula(a[1],false); - output = pushNeg ? CreateNode(IFF,a0,a1) : CreateNode(XOR,a0,a1); - - if(XOR == output.GetKind()) { - a0 = output[0]; - a1 = output[1]; - if(a0 == a1) - output = ASTFalse; - else if(a0 == ASTTrue && a1 == ASTFalse || - a0 == ASTFalse && a1 == ASTTrue) - output = ASTTrue; - } - - //memoize - UpdateSimplifyMap(a,output,pushNeg); - return output; - } - - ASTNode BeevMgr::SimplifyNandFormula(const ASTNode& a, bool pushNeg) { - ASTNode output,a0,a1; - if(CheckSimplifyMap(a,output,pushNeg)) - return output; - - //the two NOTs cancel out - if(pushNeg) { - a0 = SimplifyFormula(a[0],false); - a1 = SimplifyFormula(a[1],false); - output = CreateNode(AND,a0,a1); - } - else { - //push the NOT implicit in the NAND - a0 = SimplifyFormula(a[0],true); - a1 = SimplifyFormula(a[1],true); - output = CreateNode(OR,a0,a1); - } - - //memoize - UpdateSimplifyMap(a,output,pushNeg); - return output; - } - - ASTNode BeevMgr::SimplifyNorFormula(const ASTNode& a, bool pushNeg) { - ASTNode output,a0,a1; - if(CheckSimplifyMap(a,output,pushNeg)) - return output; - - //the two NOTs cancel out - if(pushNeg) { - a0 = SimplifyFormula(a[0],false); - a1 = SimplifyFormula(a[1],false); - output = CreateNode(OR,a0,a1); - } - else { - //push the NOT implicit in the NAND - a0 = SimplifyFormula(a[0],true); - a1 = SimplifyFormula(a[1],true); - output = CreateNode(AND,a0,a1); - } - - //memoize - UpdateSimplifyMap(a,output,pushNeg); - return output; - } - - ASTNode BeevMgr::SimplifyImpliesFormula(const ASTNode& a, bool pushNeg) { - ASTNode output; - if(CheckSimplifyMap(a,output,pushNeg)) - return output; - - if(!(a.Degree()==2 && IMPLIES==a.GetKind())) - FatalError("SimplifyImpliesFormula: vector with wrong num of nodes",ASTUndefined); - - ASTNode c0,c1; - if(pushNeg) { - c0 = SimplifyFormula(a[0],false); - c1 = SimplifyFormula(a[1],true); - output = CreateNode(AND,c0,c1); - } - else { - c0 = SimplifyFormula(a[0],false); - c1 = SimplifyFormula(a[1],false); - if(ASTFalse == c0) { - output = ASTTrue; - } - else if (ASTTrue == c0) { - output = c1; - } - else if (c0 == c1) { - output = ASTTrue; - } - else if(CheckAlwaysTrueFormMap(c0)) { - // c0 AND (~c0 OR c1) <==> c1 - // - //applying modus ponens - output = c1; - } - else if(CheckAlwaysTrueFormMap(c1) || - CheckAlwaysTrueFormMap(CreateNode(NOT,c0)) || - (NOT == c0.GetKind() && CheckAlwaysTrueFormMap(c0[0]))) { - //(~c0 AND (~c0 OR c1)) <==> TRUE - // - //(c0 AND ~c0->c1) <==> TRUE - output = ASTTrue; - } - else if (CheckAlwaysTrueFormMap(CreateNode(NOT,c1)) || - (NOT == c1.GetKind() && CheckAlwaysTrueFormMap(c1[0]))) { - //(~c1 AND c0->c1) <==> (~c1 AND ~c1->~c0) <==> ~c0 - //(c1 AND c0->~c1) <==> (c1 AND c1->~c0) <==> ~c0 - output = CreateNode(NOT,c0); - } - else { - if(NOT == c0.GetKind()) { - output = CreateNode(OR,c0[0],c1); - } - else { - output = CreateNode(OR,CreateNode(NOT,c0),c1); - } - } - } - - //memoize - UpdateSimplifyMap(a,output,pushNeg); - return output; - } - - ASTNode BeevMgr::SimplifyIffFormula(const ASTNode& a, bool pushNeg) { - ASTNode output; - if(CheckSimplifyMap(a,output,pushNeg)) - return output; - - if(!(a.Degree()==2 && IFF==a.GetKind())) - FatalError("SimplifyIffFormula: vector with wrong num of nodes",ASTUndefined); - - ASTNode c0 = a[0]; - ASTNode c1 = SimplifyFormula(a[1],false); - - if(pushNeg) - c0 = SimplifyFormula(c0,true); - else - c0 = SimplifyFormula(c0,false); - - if(ASTTrue == c0) { - output = c1; - } - else if (ASTFalse == c0) { - output = SimplifyFormula(c1,true); - } - else if (ASTTrue == c1) { - output = c0; - } - else if (ASTFalse == c1) { - output = SimplifyFormula(c0,true); - } - else if (c0 == c1) { - output = ASTTrue; - } - else if((NOT == c0.GetKind() && c0[0] == c1) || - (NOT == c1.GetKind() && c0 == c1[0])) { - output = ASTFalse; - } - else if(CheckAlwaysTrueFormMap(c0)) { - output = c1; - } - else if(CheckAlwaysTrueFormMap(c1)) { - output = c0; - } - else if(CheckAlwaysTrueFormMap(CreateNode(NOT,c0))) { - output = CreateNode(NOT,c1); - } - else if(CheckAlwaysTrueFormMap(CreateNode(NOT,c1))) { - output = CreateNode(NOT,c0); - } - else { - output = CreateNode(IFF,c0,c1); - } - - //memoize - UpdateSimplifyMap(a,output,pushNeg); - return output; - } - - ASTNode BeevMgr::SimplifyIteFormula(const ASTNode& b, bool pushNeg) { - if(!optimize) - return b; - - ASTNode output; - if(CheckSimplifyMap(b,output,pushNeg)) - return output; - - if(!(b.Degree() == 3 && ITE == b.GetKind())) - FatalError("SimplifyIteFormula: vector with wrong num of nodes",ASTUndefined); - - ASTNode a = b; - ASTNode t0 = SimplifyFormula(a[0],false); - ASTNode t1,t2; - if(pushNeg) { - t1 = SimplifyFormula(a[1],true); - t2 = SimplifyFormula(a[2],true); - } - else { - t1 = SimplifyFormula(a[1],false); - t2 = SimplifyFormula(a[2],false); - } - - if(ASTTrue == t0) { - output = t1; - } - else if (ASTFalse == t0) { - output = t2; - } - else if (t1 == t2) { - output = t1; - } - else if(ASTTrue == t1 && ASTFalse == t2) { - output = t0; - } - else if(ASTFalse == t1 && ASTTrue == t2) { - output = SimplifyFormula(t0,true); - } - else if(ASTTrue == t1) { - output = CreateNode(OR,t0,t2); - } - else if(ASTFalse == t1) { - output = CreateNode(AND,CreateNode(NOT,t0),t2); - } - else if(ASTTrue == t2) { - output = CreateNode(OR,CreateNode(NOT,t0),t1); - } - else if(ASTFalse == t2) { - output = CreateNode(AND,t0,t1); - } - else if(CheckAlwaysTrueFormMap(t0)) { - output = t1; - } - else if(CheckAlwaysTrueFormMap(CreateNode(NOT,t0)) || - (NOT == t0.GetKind() && CheckAlwaysTrueFormMap(t0[0]))) { - output = t2; - } - else { - output = CreateNode(ITE,t0,t1,t2); - } - - //memoize - UpdateSimplifyMap(a,output,pushNeg); - return output; - } - - //one level deep flattening - ASTNode BeevMgr::FlattenOneLevel(const ASTNode& a) { - Kind k = a.GetKind(); - if(!(BVPLUS == k || - AND == k || OR == k - //|| BVAND == k - //|| BVOR == k - ) - ) { - return a; - } - - ASTNode output; - // if(CheckSimplifyMap(a,output,false)) { - // //check memo table - // //cerr << "output of SimplifyTerm Cache: " << output << endl; - // return output; - // } - - ASTVec c = a.GetChildren(); - ASTVec o; - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - ASTNode aaa = *it; - if(k == aaa.GetKind()) { - ASTVec ac = aaa.GetChildren(); - o.insert(o.end(),ac.begin(),ac.end()); - } - else - o.push_back(aaa); - } - - if(is_Form_kind(k)) - output = CreateNode(k,o); - else - output = CreateTerm(k,a.GetValueWidth(),o); - - //UpdateSimplifyMap(a,output,false); - return output; - //memoize - } //end of flattenonelevel() - - ASTNode BeevMgr::SimplifyTerm_TopLevel(const ASTNode& b) { - ResetSimplifyMaps(); - ASTNode out = SimplifyTerm(b); - ResetSimplifyMaps(); - return out; - } - - //This function simplifies terms based on their kind - ASTNode BeevMgr::SimplifyTerm(const ASTNode& inputterm) { - //cout << "SimplifyTerm: input: " << a << endl; - if(!optimize) { - return inputterm; - } - - ASTNode output; - BVTypeCheck(inputterm); - - //######################################## - //######################################## - - if(wordlevel_solve && CheckSolverMap(inputterm,output)) { - //cout << "SimplifyTerm: output: " << output << endl; - return SimplifyTerm(output); - } - - - if(CheckSimplifyMap(inputterm,output,false)) { - //cerr << "output of SimplifyTerm Cache: " << output << endl; - return output; - } - //######################################## - //######################################## - - Kind k = inputterm.GetKind(); - if(!is_Term_kind(k)) { - FatalError("SimplifyTerm: You have input a Non-term",ASTUndefined); - } - - unsigned int inputValueWidth = inputterm.GetValueWidth(); - switch(k) { - case BVCONST: - output = inputterm; - break; - case SYMBOL: - if(CheckSolverMap(inputterm,output)) { - return SimplifyTerm(output); - } - output = inputterm; - break; - case BVMULT: - { - if(2 != inputterm.Degree()) - { - FatalError("SimplifyTerm: We assume that BVMULT is binary",inputterm); - } - - // Described nicely by Warren, Hacker's Delight pg 135. - // Turn sequences of one bits into subtractions. - // 28*x == 32x - 4x (two instructions), rather than 16x+ 8x+ 4x. - // When fully implemented. I.e. supporting sequences of 1 anywhere. - // Other simplifications will try to fold these back in. So need to be careful - // about when the simplifications are applied. But in this version it won't - // be simplified down by anything else. - - - // This (temporary) version only simplifies if all the left most bits are set. - // All the leftmost bits being set simplifies very nicely down. - const ASTNode& n0 = inputterm.GetChildren()[0]; - const ASTNode& n1 = inputterm.GetChildren()[1]; - - // This implementation has two problems. - // 1) It causes a segfault for cmu-model15,16,17 - // 2) It doesn't count the number of bits saved, so if there is a single - // leading bit it will invert it. Even though that will take more shifts - // and adds when it's finally done. - - // disabled. - if (false && (BVCONST == n0.GetKind()) ^ (BVCONST == n1.GetKind())) - { - CBV constant = (BVCONST == n0.GetKind())? n0.GetBVConst(): n1.GetBVConst(); - ASTNode other = (BVCONST == n0.GetKind())? n1: n0; - - int startSequence = 0; - for (unsigned int i = 0; i < inputValueWidth; i++) - { - if (!CONSTANTBV::BitVector_bit_test(constant,i)) - startSequence = i; - } - - if((inputValueWidth - startSequence) > 3) - { - // turn off all bits from "startSequence to the end", then add one. - CBV maskedPlusOne = CONSTANTBV::BitVector_Create(inputValueWidth,true); - for (int i=0; i < startSequence;i++) - { - if (!CONSTANTBV::BitVector_bit_test(constant,i)) // swap - CONSTANTBV::BitVector_Bit_On(maskedPlusOne, i); - } - CONSTANTBV::BitVector_increment(maskedPlusOne); - ASTNode temp = CreateTerm(BVMULT,inputValueWidth, CreateBVConst(maskedPlusOne,inputValueWidth),other); - output = CreateTerm(BVNEG, inputValueWidth, temp); - } - } - - } - if(NULL != output) - break; - - case BVPLUS:{ - - ASTVec c = FlattenOneLevel(inputterm).GetChildren(); - SortByArith(c); - ASTVec constkids, nonconstkids; - - //go through the childnodes, and separate constant and - //nonconstant nodes. combine the constant nodes using the - //constevaluator. if the resultant constant is zero and k == - //BVPLUS, then ignore it (similarily for 1 and BVMULT). else, - //add the computed constant to the nonconst vector, flatten, - //sort, and create BVPLUS/BVMULT and return - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - ASTNode aaa = SimplifyTerm(*it); - if(BVCONST == aaa.GetKind()) { - constkids.push_back(aaa); - } - else { - nonconstkids.push_back(aaa); - } - } - - ASTNode one = CreateOneConst(inputValueWidth); - ASTNode max = CreateMaxConst(inputValueWidth); - ASTNode zero = CreateZeroConst(inputValueWidth); - - //initialize constoutput to zero, in case there are no elements - //in constkids - ASTNode constoutput = (k == BVPLUS) ? zero : one; - - if(1 == constkids.size()) { - //only one element in constkids - constoutput = constkids[0]; - } - else if (1 < constkids.size()) { - //many elements in constkids. simplify it - constoutput = CreateTerm(k,inputterm.GetValueWidth(),constkids); - constoutput = BVConstEvaluator(constoutput); - } - - if(BVMULT == k && zero == constoutput) { - output = zero; - } - else if(BVMULT == k && - 1 == nonconstkids.size() && - constoutput == max) { - //useful special case opt: when input is BVMULT(max_const,t), - //then output = BVUMINUS(t). this is easier on the bitblaster - output = CreateTerm(BVUMINUS,inputValueWidth,nonconstkids); - } - else { - if(0 < nonconstkids.size()) { - //nonconstkids is not empty. First, combine const and - //nonconstkids - if(BVPLUS == k && constoutput != zero) { - nonconstkids.push_back(constoutput); - } - else if(BVMULT == k && constoutput != one) { - nonconstkids.push_back(constoutput); - } - - if(1 == nonconstkids.size()) { - //exactly one element in nonconstkids. output is exactly - //nonconstkids[0] - output = nonconstkids[0]; - } - else { - //more than 1 element in nonconstkids. create BVPLUS term - SortByArith(nonconstkids); - output = CreateTerm(k,inputValueWidth,nonconstkids); - output = FlattenOneLevel(output); - output = DistributeMultOverPlus(output,true); - output = CombineLikeTerms(output); - } - } - else { - //nonconstkids was empty, all childnodes were constant, hence - //constoutput is the output. - output = constoutput; - } - } - if(BVMULT == output.GetKind() - || BVPLUS == output.GetKind() - ) { - ASTVec d = output.GetChildren(); - SortByArith(d); - output = CreateTerm(output.GetKind(),output.GetValueWidth(),d); - } - break; - } - case BVSUB: { - ASTVec c = inputterm.GetChildren(); - ASTNode a0 = SimplifyTerm(inputterm[0]); - ASTNode a1 = SimplifyTerm(inputterm[1]); - unsigned int l = inputValueWidth; - if(a0 == a1) - output = CreateZeroConst(l); - else { - //covert x-y into x+(-y) and simplify. this transformation - //triggers more simplifications - // - a1 = SimplifyTerm(CreateTerm(BVUMINUS,l,a1)); - output = SimplifyTerm(CreateTerm(BVPLUS,l,a0,a1)); - } - break; - } - case BVUMINUS: { - //important to treat BVUMINUS as a special case, because it - //helps in arithmetic transformations. e.g. x + BVUMINUS(x) is - //actually 0. One way to reveal this fact is to strip bvuminus - //out, and replace with something else so that combineliketerms - //can catch this fact. - ASTNode a0 = SimplifyTerm(inputterm[0]); - Kind k1 = a0.GetKind(); - unsigned int l = a0.GetValueWidth(); - ASTNode one = CreateOneConst(l); - switch(k1) { - case BVUMINUS: - output = a0[0]; - break; - case BVCONST: { - output = BVConstEvaluator(CreateTerm(BVUMINUS,l,a0)); - break; - } - case BVNEG: { - output = SimplifyTerm(CreateTerm(BVPLUS,l,a0[0],one)); - break; - } - case BVMULT: { - if(BVUMINUS == a0[0].GetKind()) { - output = CreateTerm(BVMULT,l,a0[0][0],a0[1]); - } - else if(BVUMINUS == a0[1].GetKind()) { - output = CreateTerm(BVMULT,l,a0[0],a0[1][0]); - } - else { - ASTNode a00 = SimplifyTerm(CreateTerm(BVUMINUS,l,a0[0])); - output = CreateTerm(BVMULT,l,a00,a0[1]); - } - break; - } - case BVPLUS: { - //push BVUMINUS over all the monomials of BVPLUS. Simplify - //along the way - // - //BVUMINUS(a1x1 + a2x2 + ...) <=> BVPLUS(BVUMINUS(a1x1) + - //BVUMINUS(a2x2) + ... - ASTVec c = a0.GetChildren(); - ASTVec o; - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - //Simplify(BVUMINUS(a1x1)) - ASTNode aaa = SimplifyTerm(CreateTerm(BVUMINUS,l,*it)); - o.push_back(aaa); - } - //simplify the bvplus - output = SimplifyTerm(CreateTerm(BVPLUS,l,o)); - break; - } - case BVSUB: { - //BVUMINUS(BVSUB(x,y)) <=> BVSUB(y,x) - output = SimplifyTerm(CreateTerm(BVSUB,l,a0[1],a0[0])); - break; - } - case ITE: { - //BVUMINUS(ITE(c,t1,t2)) <==> ITE(c,BVUMINUS(t1),BVUMINUS(t2)) - ASTNode c = a0[0]; - ASTNode t1 = SimplifyTerm(CreateTerm(BVUMINUS,l,a0[1])); - ASTNode t2 = SimplifyTerm(CreateTerm(BVUMINUS,l,a0[2])); - output = CreateSimplifiedTermITE(c,t1,t2); - break; - } - default: { - output = CreateTerm(BVUMINUS,l,a0); - break; - } - } - break; - } - case BVEXTRACT:{ - //it is important to take care of wordlevel transformation in - //BVEXTRACT. it exposes oppurtunities for later simplification - //and solving (variable elimination) - ASTNode a0 = SimplifyTerm(inputterm[0]); - Kind k1 = a0.GetKind(); - unsigned int a_len = inputValueWidth; - - //indices for BVEXTRACT - ASTNode i = inputterm[1]; - ASTNode j = inputterm[2]; - ASTNode zero = CreateBVConst(32,0); - //recall that the indices of BVEXTRACT are always 32 bits - //long. therefore doing a GetBVUnsigned is ok. - unsigned int i_val = GetUnsignedConst(i); - unsigned int j_val = GetUnsignedConst(j); - - // a0[i:0] and len(a0)=i+1, then return a0 - if(0 == j_val && a_len == a0.GetValueWidth()) - return a0; - - switch(k1) { - case BVCONST: { - //extract the constant - output = BVConstEvaluator(CreateTerm(BVEXTRACT,a_len,a0,i,j)); - break; - } - case BVCONCAT:{ - //assumes concatenation is binary - // - //input is of the form a0[i:j] - // - //a0 is the conatentation t@u, and a0[0] is t, and a0[1] is u - ASTNode t = a0[0]; - ASTNode u = a0[1]; - unsigned int len_a0 = a0.GetValueWidth(); - unsigned int len_u = u.GetValueWidth(); - - if(len_u > i_val) { - //Apply the following rule: - // (t@u)[i:j] <==> u[i:j], if len(u) > i - // - output = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,u,i,j)); - } - else if(len_a0 > i_val && j_val >= len_u) { - //Apply the rule: - // (t@u)[i:j] <==> t[i-len_u:j-len_u], if len(t@u) > i >= j >= len(u) - i = CreateBVConst(32, i_val - len_u); - j = CreateBVConst(32, j_val - len_u); - output = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,t,i,j)); - } - else { - //Apply the rule: - // (t@u)[i:j] <==> t[i-len_u:0] @ u[len_u-1:j] - i = CreateBVConst(32,i_val-len_u); - ASTNode m = CreateBVConst(32, len_u-1); - t = SimplifyTerm(CreateTerm(BVEXTRACT,i_val-len_u+1,t,i,zero)); - u = SimplifyTerm(CreateTerm(BVEXTRACT,len_u-j_val,u,m,j)); - output = CreateTerm(BVCONCAT,a_len,t,u); - } - break; - } - case BVPLUS: - case BVMULT: { - // (BVMULT(n,t,u))[i:j] <==> BVMULT(i+1,t[i:0],u[i:0])[i:j] - //similar rule for BVPLUS - ASTVec c = a0.GetChildren(); - ASTVec o; - for(ASTVec::iterator jt=c.begin(),jtend=c.end();jt!=jtend;jt++) { - ASTNode aaa = *jt; - aaa = SimplifyTerm(CreateTerm(BVEXTRACT,i_val+1,aaa,i,zero)); - o.push_back(aaa); - } - output = CreateTerm(a0.GetKind(),i_val+1,o); - if(j_val != 0) { - //add extraction only if j is not zero - output = CreateTerm(BVEXTRACT,a_len,output,i,j); - } - break; - } - case BVAND: - case BVOR: - case BVXOR: { - //assumes these operators are binary - // - // (t op u)[i:j] <==> t[i:j] op u[i:j] - ASTNode t = a0[0]; - ASTNode u = a0[1]; - t = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,t,i,j)); - u = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,u,i,j)); - BVTypeCheck(t); - BVTypeCheck(u); - output = CreateTerm(k1,a_len,t,u); - break; - } - case BVNEG:{ - // (~t)[i:j] <==> ~(t[i:j]) - ASTNode t = a0[0]; - t = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,t,i,j)); - output = CreateTerm(BVNEG,a_len,t); - break; - } - // case BVSX:{ -// //(BVSX(t,n)[i:j] <==> BVSX(t,i+1), if n >= i+1 and j=0 -// ASTNode t = a0[0]; -// unsigned int bvsx_len = a0.GetValueWidth(); -// if(bvsx_len < a_len) { -// FatalError("SimplifyTerm: BVEXTRACT over BVSX:" -// "the length of BVSX term must be greater than extract-len",inputterm); -// } -// if(j != zero) { -// output = CreateTerm(BVEXTRACT,a_len,a0,i,j); -// } -// else { -// output = CreateTerm(BVSX,a_len,t,CreateBVConst(32,a_len)); -// } -// break; -// } - case ITE: { - ASTNode t0 = a0[0]; - ASTNode t1 = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,a0[1],i,j)); - ASTNode t2 = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,a0[2],i,j)); - output = CreateSimplifiedTermITE(t0,t1,t2); - break; - } - default: { - output = CreateTerm(BVEXTRACT,a_len,a0,i,j); - break; - } - } - break; - } - case BVNEG: { - ASTNode a0 = SimplifyTerm(inputterm[0]); - unsigned len = inputValueWidth; - switch(a0.GetKind()) { - case BVCONST: - output = BVConstEvaluator(CreateTerm(BVNEG,len,a0)); - break; - case BVNEG: - output = a0[0]; - break; - // case ITE: { -// ASTNode cond = a0[0]; -// ASTNode thenpart = SimplifyTerm(CreateTerm(BVNEG,len,a0[1])); -// ASTNode elsepart = SimplifyTerm(CreateTerm(BVNEG,len,a0[2])); -// output = CreateSimplifiedTermITE(cond,thenpart,elsepart); -// break; -// } - default: - output = CreateTerm(BVNEG,len,a0); - break; - } - break; - } - - case BVZX: - { - ASTNode a0 = SimplifyTerm(inputterm[0]); - if (a0.GetKind() == BVCONST) - output = BVConstEvaluator(CreateTerm(BVZX,inputValueWidth,a0,inputterm[1])); + if (ASTTrue == o) + { + output = pn ? ASTFalse : ASTTrue; + } + else if (ASTFalse == o) + { + output = pn ? ASTTrue : ASTFalse; + } else - output = CreateTerm(BVZX,inputValueWidth,a0,inputterm[1]); - } - break; - - - case BVSX:{ - //a0 is the expr which is being sign extended - ASTNode a0 = SimplifyTerm(inputterm[0]); - //a1 represents the length of the term BVSX(a0) - ASTNode a1 = inputterm[1]; - //output length of the BVSX term - unsigned len = inputValueWidth; - - if(a0.GetValueWidth() == len) { - //nothing to signextend - return a0; - } - - switch(a0.GetKind()) { - case BVCONST: - output = BVConstEvaluator(CreateTerm(BVSX,len,a0,a1)); - break; - case BVNEG: - output = CreateTerm(a0.GetKind(),len,CreateTerm(BVSX,len,a0[0],a1)); - break; - case BVAND: - case BVOR: - //assuming BVAND and BVOR are binary - output = CreateTerm(a0.GetKind(),len, - CreateTerm(BVSX,len,a0[0],a1), - CreateTerm(BVSX,len,a0[1],a1)); - break; - case BVPLUS: { - //BVSX(m,BVPLUS(n,BVSX(t1),BVSX(t2))) <==> BVPLUS(m,BVSX(m,t1),BVSX(m,t2)) - ASTVec c = a0.GetChildren(); - bool returnflag = false; - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - if(BVSX != it->GetKind()) { - returnflag = true; - break; - } - } - if(returnflag) { - output = CreateTerm(BVSX,len,a0,a1); - } - else { - ASTVec o; - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - ASTNode aaa = SimplifyTerm(CreateTerm(BVSX,len,*it,a1)); - o.push_back(aaa); - } - output = CreateTerm(a0.GetKind(),len,o); - } - break; - } - case BVSX: { - //if you have BVSX(m,BVSX(n,a)) then you can drop the inner - //BVSX provided m is greater than n. - a0 = SimplifyTerm(a0[0]); - output = CreateTerm(BVSX,len,a0,a1); - break; - } - case ITE: { - ASTNode cond = a0[0]; - ASTNode thenpart = SimplifyTerm(CreateTerm(BVSX,len,a0[1],a1)); - ASTNode elsepart = SimplifyTerm(CreateTerm(BVSX,len,a0[2],a1)); - output = CreateSimplifiedTermITE(cond,thenpart,elsepart); - break; - } - default: - output = CreateTerm(BVSX,len,a0,a1); - break; - } - break; - } - case BVAND: - case BVOR:{ - ASTNode max = CreateMaxConst(inputValueWidth); - ASTNode zero = CreateZeroConst(inputValueWidth); - - ASTNode identity = (BVAND == k) ? max : zero; - ASTNode annihilator = (BVAND == k) ? zero : max; - ASTVec c = FlattenOneLevel(inputterm).GetChildren(); - SortByArith(c); - ASTVec o; - bool constant = true; - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - ASTNode aaa = SimplifyTerm(*it); - if(BVCONST != aaa.GetKind()) { - constant = false; - } - - if(aaa == annihilator) { - output = annihilator; - //memoize - UpdateSimplifyMap(inputterm,output,false); - //cerr << "output of SimplifyTerm: " << output << endl; - return output; - } - - if(aaa != identity) { - o.push_back(aaa); - } - } - - switch(o.size()) { - case 0: - output = identity; - break; - case 1: - output = o[0]; - break; - default: - SortByArith(o); - output = CreateTerm(k,inputValueWidth,o); - if(constant) { - output = BVConstEvaluator(output); - } - break; - } - break; - } - case BVCONCAT:{ - ASTNode t = SimplifyTerm(inputterm[0]); - ASTNode u = SimplifyTerm(inputterm[1]); - Kind tkind = t.GetKind(); - Kind ukind = u.GetKind(); - - - if(BVCONST == tkind && BVCONST == ukind) { - output = BVConstEvaluator(CreateTerm(BVCONCAT,inputValueWidth,t,u)); - } - else if(BVEXTRACT == tkind && - BVEXTRACT == ukind && - t[0] == u[0]) { - //to handle the case x[m:n]@x[n-1:k] <==> x[m:k] - ASTNode t_hi = t[1]; - ASTNode t_low = t[2]; - ASTNode u_hi = u[1]; - ASTNode u_low = u[2]; - ASTNode c = BVConstEvaluator(CreateTerm(BVPLUS,32,u_hi,CreateOneConst(32))); - if(t_low == c) { - output = CreateTerm(BVEXTRACT,inputValueWidth,t[0],t_hi,u_low); - } - else { - output = CreateTerm(BVCONCAT,inputValueWidth,t,u); - } - } - else { - output = CreateTerm(BVCONCAT,inputValueWidth,t,u); - } - break; - } - case BVXOR: - case BVXNOR: - case BVNAND: - case BVNOR: - case BVLEFTSHIFT: - case BVRIGHTSHIFT: - case BVVARSHIFT: - case BVSRSHIFT: - case BVDIV: - case BVMOD: { - ASTVec c = inputterm.GetChildren(); - ASTVec o; - bool constant = true; - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - ASTNode aaa = SimplifyTerm(*it); - if(BVCONST != aaa.GetKind()) { - constant = false; - } - o.push_back(aaa); - } - output = CreateTerm(k,inputValueWidth,o); - if(constant) - output = BVConstEvaluator(output); - break; - } - case READ: { - ASTNode out1; - //process only if not in the substitution map. simplifymap - //has been checked already - if(!CheckSubstitutionMap(inputterm,out1)) { - if(WRITE == inputterm[0].GetKind()) { - //get rid of all writes - ASTNode nowrites = RemoveWrites_TopLevel(inputterm); - out1 = nowrites; - } - else if (ITE == inputterm[0].GetKind()){ - ASTNode cond = SimplifyFormula(inputterm[0][0],false); - ASTNode index = SimplifyTerm(inputterm[1]); - - ASTNode read1 = CreateTerm(READ,inputValueWidth,inputterm[0][1],index); - ASTNode read2 = CreateTerm(READ,inputValueWidth,inputterm[0][2],index); - - read1 = SimplifyTerm(read1); - read2 = SimplifyTerm(read2); - out1 = CreateSimplifiedTermITE(cond,read1,read2); - } - else { - //arr is a SYMBOL for sure - ASTNode arr = inputterm[0]; - ASTNode index = SimplifyTerm(inputterm[1]); - out1 = CreateTerm(READ,inputValueWidth,arr,index); - } - } - //it is possible that after all the procesing the READ term - //reduces to READ(Symbol,const) and hence we should check the - //substitutionmap once again. - if(!CheckSubstitutionMap(out1,output)) - output = out1; - break; - } - case ITE: { - ASTNode t0 = SimplifyFormula(inputterm[0],false); - ASTNode t1 = SimplifyTerm(inputterm[1]); - ASTNode t2 = SimplifyTerm(inputterm[2]); - output = CreateSimplifiedTermITE(t0,t1,t2); - break; - } - case SBVREM: - case SBVDIV: { - ASTVec c = inputterm.GetChildren(); - ASTVec o; - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - ASTNode aaa = SimplifyTerm(*it); - o.push_back(aaa); - } - output = CreateTerm(k,inputValueWidth,o); - break; - } - case WRITE: - default: - FatalError("SimplifyTerm: Control should never reach here:", inputterm, k); - return inputterm; - break; - } - assert(NULL != output); + { + output = SimplifyFormula(o, pn); + } + //memoize + UpdateSimplifyMap(o, output, pn); + UpdateSimplifyMap(a, output, pushNeg); + return output; +} +ASTNode BeevMgr::SimplifyXorFormula(const ASTNode& a, bool pushNeg) +{ + ASTNode output; + if (CheckSimplifyMap(a, output, pushNeg)) + return output; - //memoize - UpdateSimplifyMap(inputterm,output,false); - //cerr << "SimplifyTerm: output" << output << endl; - // CheckSimplifyInvariant(inputterm,output); - - return output; - } //end of SimplifyTerm() - - ASTNode BeevMgr::SimplifyTermAux(const ASTNode& inputterm) { - //cout << "SimplifyTerm: input: " << a << endl; - if(!optimize) { - return inputterm; - } - - ASTNode output; - BVTypeCheck(inputterm); - - //######################################## - //######################################## - - if(wordlevel_solve && CheckSolverMap(inputterm,output)) { - //cout << "SimplifyTerm: output: " << output << endl; - return SimplifyTermAux(output); - } - - Kind k = inputterm.GetKind(); - if(!is_Term_kind(k)) { - FatalError("SimplifyTerm: You have input a Non-term",ASTUndefined); - } - - unsigned int inputValueWidth = inputterm.GetValueWidth(); - switch(k) { - case BVCONST: - output = inputterm; - break; - case SYMBOL: - if(CheckSolverMap(inputterm,output)) { - return SimplifyTerm(output); - } - output = inputterm; - break; - case BVMULT: - case BVPLUS:{ - if(BVMULT == k && 2 != inputterm.Degree()) { - FatalError("SimplifyTerm: We assume that BVMULT is binary",inputterm); - } - - ASTVec c = FlattenOneLevel(inputterm).GetChildren(); - SortByArith(c); - ASTVec constkids, nonconstkids; - - //go through the childnodes, and separate constant and - //nonconstant nodes. combine the constant nodes using the - //constevaluator. if the resultant constant is zero and k == - //BVPLUS, then ignore it (similarily for 1 and BVMULT). else, - //add the computed constant to the nonconst vector, flatten, - //sort, and create BVPLUS/BVMULT and return - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - ASTNode aaa = SimplifyTerm(*it); - if(BVCONST == aaa.GetKind()) { - constkids.push_back(aaa); - } - else { - nonconstkids.push_back(aaa); - } - } - - ASTNode one = CreateOneConst(inputValueWidth); - ASTNode max = CreateMaxConst(inputValueWidth); - ASTNode zero = CreateZeroConst(inputValueWidth); - - //initialize constoutput to zero, in case there are no elements - //in constkids - ASTNode constoutput = (k == BVPLUS) ? zero : one; - - if(1 == constkids.size()) { - //only one element in constkids - constoutput = constkids[0]; - } - else if (1 < constkids.size()) { - //many elements in constkids. simplify it - constoutput = CreateTerm(k,inputterm.GetValueWidth(),constkids); - constoutput = BVConstEvaluator(constoutput); - } - - if(BVMULT == k && zero == constoutput) { - output = zero; - } - else if(BVMULT == k && - 1 == nonconstkids.size() && - constoutput == max) { - //useful special case opt: when input is BVMULT(max_const,t), - //then output = BVUMINUS(t). this is easier on the bitblaster - output = CreateTerm(BVUMINUS,inputValueWidth,nonconstkids); - } - else { - if(0 < nonconstkids.size()) { - //nonconstkids is not empty. First, combine const and - //nonconstkids - if(BVPLUS == k && constoutput != zero) { - nonconstkids.push_back(constoutput); - } - else if(BVMULT == k && constoutput != one) { - nonconstkids.push_back(constoutput); - } - - if(1 == nonconstkids.size()) { - //exactly one element in nonconstkids. output is exactly - //nonconstkids[0] - output = nonconstkids[0]; - } - else { - //more than 1 element in nonconstkids. create BVPLUS term - SortByArith(nonconstkids); - output = CreateTerm(k,inputValueWidth,nonconstkids); - output = FlattenOneLevel(output); - output = DistributeMultOverPlus(output,true); - output = CombineLikeTerms(output); - } - } - else { - //nonconstkids was empty, all childnodes were constant, hence - //constoutput is the output. - output = constoutput; - } - } - if(BVMULT == output.GetKind() - || BVPLUS == output.GetKind() - ) { - ASTVec d = output.GetChildren(); - SortByArith(d); - output = CreateTerm(output.GetKind(),output.GetValueWidth(),d); - } - break; - } - case BVSUB: { - ASTVec c = inputterm.GetChildren(); - ASTNode a0 = SimplifyTerm(inputterm[0]); - ASTNode a1 = SimplifyTerm(inputterm[1]); - unsigned int l = inputValueWidth; - if(a0 == a1) - output = CreateZeroConst(l); - else { - //covert x-y into x+(-y) and simplify. this transformation - //triggers more simplifications - // - a1 = SimplifyTerm(CreateTerm(BVUMINUS,l,a1)); - output = SimplifyTerm(CreateTerm(BVPLUS,l,a0,a1)); - } - break; - } - case BVUMINUS: { - //important to treat BVUMINUS as a special case, because it - //helps in arithmetic transformations. e.g. x + BVUMINUS(x) is - //actually 0. One way to reveal this fact is to strip bvuminus - //out, and replace with something else so that combineliketerms - //can catch this fact. - ASTNode a0 = SimplifyTerm(inputterm[0]); - Kind k1 = a0.GetKind(); - unsigned int l = a0.GetValueWidth(); - ASTNode one = CreateOneConst(l); - switch(k1) { - case BVUMINUS: - output = a0[0]; - break; - case BVCONST: { - output = BVConstEvaluator(CreateTerm(BVUMINUS,l,a0)); - break; - } - case BVNEG: { - output = SimplifyTerm(CreateTerm(BVPLUS,l,a0[0],one)); - break; - } - case BVMULT: { - if(BVUMINUS == a0[0].GetKind()) { - output = CreateTerm(BVMULT,l,a0[0][0],a0[1]); - } - else if(BVUMINUS == a0[1].GetKind()) { - output = CreateTerm(BVMULT,l,a0[0],a0[1][0]); - } - else { - ASTNode a00 = SimplifyTerm(CreateTerm(BVUMINUS,l,a0[0])); - output = CreateTerm(BVMULT,l,a00,a0[1]); - } - break; - } - case BVPLUS: { - //push BVUMINUS over all the monomials of BVPLUS. Simplify - //along the way - // - //BVUMINUS(a1x1 + a2x2 + ...) <=> BVPLUS(BVUMINUS(a1x1) + - //BVUMINUS(a2x2) + ... - ASTVec c = a0.GetChildren(); - ASTVec o; - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - //Simplify(BVUMINUS(a1x1)) - ASTNode aaa = SimplifyTerm(CreateTerm(BVUMINUS,l,*it)); - o.push_back(aaa); - } - //simplify the bvplus - output = SimplifyTerm(CreateTerm(BVPLUS,l,o)); - break; - } - case BVSUB: { - //BVUMINUS(BVSUB(x,y)) <=> BVSUB(y,x) - output = SimplifyTerm(CreateTerm(BVSUB,l,a0[1],a0[0])); - break; - } - case ITE: { - //BVUMINUS(ITE(c,t1,t2)) <==> ITE(c,BVUMINUS(t1),BVUMINUS(t2)) - ASTNode c = a0[0]; - ASTNode t1 = SimplifyTerm(CreateTerm(BVUMINUS,l,a0[1])); - ASTNode t2 = SimplifyTerm(CreateTerm(BVUMINUS,l,a0[2])); - output = CreateSimplifiedTermITE(c,t1,t2); - break; - } - default: { - output = CreateTerm(BVUMINUS,l,a0); - break; - } - } - break; - } - case BVEXTRACT:{ - //it is important to take care of wordlevel transformation in - //BVEXTRACT. it exposes oppurtunities for later simplification - //and solving (variable elimination) - ASTNode a0 = SimplifyTerm(inputterm[0]); - Kind k1 = a0.GetKind(); - unsigned int a_len = inputValueWidth; - - //indices for BVEXTRACT - ASTNode i = inputterm[1]; - ASTNode j = inputterm[2]; - ASTNode zero = CreateBVConst(32,0); - //recall that the indices of BVEXTRACT are always 32 bits - //long. therefore doing a GetBVUnsigned is ok. - unsigned int i_val = GetUnsignedConst(i); - unsigned int j_val = GetUnsignedConst(j); - - // a0[i:0] and len(a0)=i+1, then return a0 - if(0 == j_val && a_len == a0.GetValueWidth()) - return a0; - - switch(k1) { - case BVCONST: { - //extract the constant - output = BVConstEvaluator(CreateTerm(BVEXTRACT,a_len,a0,i,j)); - break; - } - case BVCONCAT:{ - //assumes concatenation is binary - // - //input is of the form a0[i:j] - // - //a0 is the conatentation t@u, and a0[0] is t, and a0[1] is u - ASTNode t = a0[0]; - ASTNode u = a0[1]; - unsigned int len_a0 = a0.GetValueWidth(); - unsigned int len_u = u.GetValueWidth(); - - if(len_u > i_val) { - //Apply the following rule: - // (t@u)[i:j] <==> u[i:j], if len(u) > i - // - output = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,u,i,j)); - } - else if(len_a0 > i_val && j_val >= len_u) { - //Apply the rule: - // (t@u)[i:j] <==> t[i-len_u:j-len_u], if len(t@u) > i >= j >= len(u) - i = CreateBVConst(32, i_val - len_u); - j = CreateBVConst(32, j_val - len_u); - output = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,t,i,j)); - } - else { - //Apply the rule: - // (t@u)[i:j] <==> t[i-len_u:0] @ u[len_u-1:j] - i = CreateBVConst(32,i_val-len_u); - ASTNode m = CreateBVConst(32, len_u-1); - t = SimplifyTerm(CreateTerm(BVEXTRACT,i_val-len_u+1,t,i,zero)); - u = SimplifyTerm(CreateTerm(BVEXTRACT,len_u-j_val,u,m,j)); - output = CreateTerm(BVCONCAT,a_len,t,u); - } - break; - } - case BVPLUS: - case BVMULT: { - // (BVMULT(n,t,u))[i:j] <==> BVMULT(i+1,t[i:0],u[i:0])[i:j] - //similar rule for BVPLUS - ASTVec c = a0.GetChildren(); - ASTVec o; - for(ASTVec::iterator jt=c.begin(),jtend=c.end();jt!=jtend;jt++) { - ASTNode aaa = *jt; - aaa = SimplifyTerm(CreateTerm(BVEXTRACT,i_val+1,aaa,i,zero)); - o.push_back(aaa); - } - output = CreateTerm(a0.GetKind(),i_val+1,o); - if(j_val != 0) { - //add extraction only if j is not zero - output = CreateTerm(BVEXTRACT,a_len,output,i,j); - } - break; - } - case BVAND: - case BVOR: - case BVXOR: { - //assumes these operators are binary - // - // (t op u)[i:j] <==> t[i:j] op u[i:j] - ASTNode t = a0[0]; - ASTNode u = a0[1]; - t = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,t,i,j)); - u = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,u,i,j)); - BVTypeCheck(t); - BVTypeCheck(u); - output = CreateTerm(k1,a_len,t,u); - break; - } - case BVNEG:{ - // (~t)[i:j] <==> ~(t[i:j]) - ASTNode t = a0[0]; - t = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,t,i,j)); - output = CreateTerm(BVNEG,a_len,t); - break; - } - // case BVSX:{ -// //(BVSX(t,n)[i:j] <==> BVSX(t,i+1), if n >= i+1 and j=0 -// ASTNode t = a0[0]; -// unsigned int bvsx_len = a0.GetValueWidth(); -// if(bvsx_len < a_len) { -// FatalError("SimplifyTerm: BVEXTRACT over BVSX:" -// "the length of BVSX term must be greater than extract-len",inputterm); -// } -// if(j != zero) { -// output = CreateTerm(BVEXTRACT,a_len,a0,i,j); -// } -// else { -// output = CreateTerm(BVSX,a_len,t,CreateBVConst(32,a_len)); -// } -// break; -// } - case ITE: { - ASTNode t0 = a0[0]; - ASTNode t1 = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,a0[1],i,j)); - ASTNode t2 = SimplifyTerm(CreateTerm(BVEXTRACT,a_len,a0[2],i,j)); - output = CreateSimplifiedTermITE(t0,t1,t2); - break; - } - default: { - output = CreateTerm(BVEXTRACT,a_len,a0,i,j); - break; - } - } - break; - } - case BVNEG: { - ASTNode a0 = SimplifyTerm(inputterm[0]); - unsigned len = inputValueWidth; - switch(a0.GetKind()) { - case BVCONST: - output = BVConstEvaluator(CreateTerm(BVNEG,len,a0)); - break; - case BVNEG: - output = a0[0]; - break; - // case ITE: { -// ASTNode cond = a0[0]; -// ASTNode thenpart = SimplifyTerm(CreateTerm(BVNEG,len,a0[1])); -// ASTNode elsepart = SimplifyTerm(CreateTerm(BVNEG,len,a0[2])); -// output = CreateSimplifiedTermITE(cond,thenpart,elsepart); -// break; -// } - default: - output = CreateTerm(BVNEG,len,a0); - break; - } - break; - } - case BVZX: - { - //a0 is the expr which is being zero extended - ASTNode a0 = SimplifyTerm(inputterm[0]); - //a1 represents the length of the term BVZX(a0) - ASTNode a1 = inputterm[1]; - //output length of the BVSX term - unsigned len = inputValueWidth; - - output = CreateTerm(BVZX,len,a0,a1); - break; - } - break; - - case BVSX:{ - //a0 is the expr which is being sign extended - ASTNode a0 = SimplifyTerm(inputterm[0]); - //a1 represents the length of the term BVSX(a0) - ASTNode a1 = inputterm[1]; - //output length of the BVSX term - unsigned len = inputValueWidth; - - if(a0.GetValueWidth() == len) { - //nothing to signextend - return a0; - } - - switch(a0.GetKind()) { - case BVCONST: - output = BVConstEvaluator(CreateTerm(BVSX,len,a0,a1)); - break; - case BVNEG: - output = CreateTerm(a0.GetKind(),len,CreateTerm(BVSX,len,a0[0],a1)); - break; - case BVAND: - case BVOR: - //assuming BVAND and BVOR are binary - output = CreateTerm(a0.GetKind(),len, - CreateTerm(BVSX,len,a0[0],a1), - CreateTerm(BVSX,len,a0[1],a1)); - break; - case BVPLUS: { - //BVSX(m,BVPLUS(n,BVSX(t1),BVSX(t2))) <==> BVPLUS(m,BVSX(m,t1),BVSX(m,t2)) - ASTVec c = a0.GetChildren(); - bool returnflag = false; - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - if(BVSX != it->GetKind()) { - returnflag = true; - break; - } - } - if(returnflag) { - output = CreateTerm(BVSX,len,a0,a1); - } - else { - ASTVec o; - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - ASTNode aaa = SimplifyTerm(CreateTerm(BVSX,len,*it,a1)); - o.push_back(aaa); - } - output = CreateTerm(a0.GetKind(),len,o); - } - break; - } - case BVSX: { - //if you have BVSX(m,BVSX(n,a)) then you can drop the inner - //BVSX provided m is greater than n. - a0 = SimplifyTerm(a0[0]); - output = CreateTerm(BVSX,len,a0,a1); - break; - } - case ITE: { - ASTNode cond = a0[0]; - ASTNode thenpart = SimplifyTerm(CreateTerm(BVSX,len,a0[1],a1)); - ASTNode elsepart = SimplifyTerm(CreateTerm(BVSX,len,a0[2],a1)); - output = CreateSimplifiedTermITE(cond,thenpart,elsepart); - break; - } - default: - output = CreateTerm(BVSX,len,a0,a1); - break; - } - break; - } - case BVAND: - case BVOR:{ - ASTNode max = CreateMaxConst(inputValueWidth); - ASTNode zero = CreateZeroConst(inputValueWidth); - - ASTNode identity = (BVAND == k) ? max : zero; - ASTNode annihilator = (BVAND == k) ? zero : max; - ASTVec c = FlattenOneLevel(inputterm).GetChildren(); - SortByArith(c); - ASTVec o; - bool constant = true; - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - ASTNode aaa = SimplifyTerm(*it); - if(BVCONST != aaa.GetKind()) { - constant = false; - } - - if(aaa == annihilator) { - output = annihilator; - return output; - } - - if(aaa != identity) { - o.push_back(aaa); - } - } - - switch(o.size()) { - case 0: - output = identity; - break; - case 1: - output = o[0]; - break; - default: - SortByArith(o); - output = CreateTerm(k,inputValueWidth,o); - if(constant) { - output = BVConstEvaluator(output); - } - break; - } - break; - } - case BVCONCAT:{ - ASTNode t = SimplifyTerm(inputterm[0]); - ASTNode u = SimplifyTerm(inputterm[1]); - Kind tkind = t.GetKind(); - Kind ukind = u.GetKind(); - - - if(BVCONST == tkind && BVCONST == ukind) { - output = BVConstEvaluator(CreateTerm(BVCONCAT,inputValueWidth,t,u)); - } - else if(BVEXTRACT == tkind && - BVEXTRACT == ukind && - t[0] == u[0]) { - //to handle the case x[m:n]@x[n-1:k] <==> x[m:k] - ASTNode t_hi = t[1]; - ASTNode t_low = t[2]; - ASTNode u_hi = u[1]; - ASTNode u_low = u[2]; - ASTNode c = BVConstEvaluator(CreateTerm(BVPLUS,32,u_hi,CreateOneConst(32))); - if(t_low == c) { - output = CreateTerm(BVEXTRACT,inputValueWidth,t[0],t_hi,u_low); - } - else { - output = CreateTerm(BVCONCAT,inputValueWidth,t,u); - } - } - else { - output = CreateTerm(BVCONCAT,inputValueWidth,t,u); - } - break; - } - case BVXOR: - case BVXNOR: - case BVNAND: - case BVNOR: - case BVLEFTSHIFT: - case BVRIGHTSHIFT: - case BVVARSHIFT: - case BVSRSHIFT: - case BVDIV: - case BVMOD: { - ASTVec c = inputterm.GetChildren(); - ASTVec o; - bool constant = true; - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - ASTNode aaa = SimplifyTerm(*it); - if(BVCONST != aaa.GetKind()) { - constant = false; - } - o.push_back(aaa); - } - output = CreateTerm(k,inputValueWidth,o); - if(constant) - output = BVConstEvaluator(output); - break; - } - case READ: { - ASTNode out1; - //process only if not in the substitution map. simplifymap - //has been checked already - if(!CheckSubstitutionMap(inputterm,out1)) { - if(WRITE == inputterm[0].GetKind()) { - //get rid of all writes - ASTNode nowrites = RemoveWrites_TopLevel(inputterm); - out1 = nowrites; - } - else if (ITE == inputterm[0].GetKind()){ - ASTNode cond = SimplifyFormula(inputterm[0][0],false); - ASTNode index = SimplifyTerm(inputterm[1]); - - ASTNode read1 = CreateTerm(READ,inputValueWidth,inputterm[0][1],index); - ASTNode read2 = CreateTerm(READ,inputValueWidth,inputterm[0][2],index); - - read1 = SimplifyTerm(read1); - read2 = SimplifyTerm(read2); - out1 = CreateSimplifiedTermITE(cond,read1,read2); - } - else { - //arr is a SYMBOL for sure - ASTNode arr = inputterm[0]; - ASTNode index = SimplifyTerm(inputterm[1]); - out1 = CreateTerm(READ,inputValueWidth,arr,index); - } - } - //it is possible that after all the procesing the READ term - //reduces to READ(Symbol,const) and hence we should check the - //substitutionmap once again. - if(!CheckSubstitutionMap(out1,output)) - output = out1; - break; - } - case ITE: { - ASTNode t0 = SimplifyFormula(inputterm[0],false); - ASTNode t1 = SimplifyTerm(inputterm[1]); - ASTNode t2 = SimplifyTerm(inputterm[2]); - output = CreateSimplifiedTermITE(t0,t1,t2); - break; - } - case SBVREM: - case SBVMOD: - case SBVDIV: { - ASTVec c = inputterm.GetChildren(); - ASTVec o; - for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { - ASTNode aaa = SimplifyTerm(*it); - o.push_back(aaa); - } - output = CreateTerm(k,inputValueWidth,o); - break; - } - case WRITE: - default: - FatalError("SimplifyTermAux: Control should never reach here:", inputterm, k); - return inputterm; - break; - } - - return output; - } - - //At the end of each simplification call, we want the output to be - //always smaller or equal to the input in size. - void BeevMgr::CheckSimplifyInvariant(const ASTNode& a, const ASTNode& output) { - - if(NodeSize(a,true) + 1 < NodeSize(output,true)) { - cerr << "lhs := " << a << endl; - cerr << "NodeSize of lhs is: " << NodeSize(a, true) << endl; - cerr << endl; - cerr << "rhs := " << output << endl; - cerr << "NodeSize of rhs is: " << NodeSize(output, true) << endl; - // FatalError("SimplifyFormula: The nodesize shoudl decrease from lhs to rhs: ",ASTUndefined); - } - } - - //this function assumes that the input is a vector of childnodes of - //a BVPLUS term. it combines like terms and returns a bvplus - //term. e.g. 1.x + 2.x is converted to 3.x - ASTNode BeevMgr::CombineLikeTerms(const ASTNode& a) { - if(BVPLUS != a.GetKind()) - return a; - - ASTNode output; - if(CheckSimplifyMap(a,output,false)) { - //check memo table - //cerr << "output of SimplifyTerm Cache: " << output << endl; - return output; - } - - const ASTVec& c = a.GetChildren(); - //map from variables to vector of constants - ASTNodeToVecMap vars_to_consts; - //vector to hold constants - ASTVec constkids; - ASTVec outputvec; - - //useful constants - unsigned int len = c[0].GetValueWidth(); - ASTNode one = CreateOneConst(len); - ASTNode zero = CreateZeroConst(len); - ASTNode max = CreateMaxConst(len); - - //go over the childnodes of the input bvplus, and collect like - //terms in a map. the key of the map are the variables, and the - //values are stored in a ASTVec - for(ASTVec::const_iterator it=c.begin(),itend=c.end();it!=itend;it++){ - ASTNode aaa = *it; - if(SYMBOL == aaa.GetKind()) { - vars_to_consts[aaa].push_back(one); - } - else if(BVMULT == aaa.GetKind() && - BVUMINUS == aaa[0].GetKind() && - BVCONST == aaa[0][0].GetKind()) { - //(BVUMINUS(c))*(y) <==> compute(BVUMINUS(c))*y - ASTNode compute_const = BVConstEvaluator(aaa[0]); - vars_to_consts[aaa[1]].push_back(compute_const); - } - else if(BVMULT == aaa.GetKind() && - BVUMINUS == aaa[1].GetKind() && - BVCONST == aaa[0].GetKind()) { - //c*(BVUMINUS(y)) <==> compute(BVUMINUS(c))*y - ASTNode cccc = BVConstEvaluator(CreateTerm(BVUMINUS,len,aaa[0])); - vars_to_consts[aaa[1][0]].push_back(cccc); - } - else if(BVMULT == aaa.GetKind() && BVCONST == aaa[0].GetKind()) { - //assumes that BVMULT is binary - vars_to_consts[aaa[1]].push_back(aaa[0]); - } - else if(BVMULT == aaa.GetKind() && BVUMINUS == aaa[0].GetKind()) { - //(-1*x)*(y) <==> -1*(xy) - ASTNode cccc = CreateTerm(BVMULT,len,aaa[0][0],aaa[1]); - ASTVec cNodes = cccc.GetChildren(); - SortByArith(cNodes); - vars_to_consts[cccc].push_back(max); - } - else if(BVMULT == aaa.GetKind() && BVUMINUS == aaa[1].GetKind()) { - //x*(-1*y) <==> -1*(xy) - ASTNode cccc = CreateTerm(BVMULT,len,aaa[0],aaa[1][0]); - ASTVec cNodes = cccc.GetChildren(); - SortByArith(cNodes); - vars_to_consts[cccc].push_back(max); - } - else if(BVCONST == aaa.GetKind()) { - constkids.push_back(aaa); - } - else if(BVUMINUS == aaa.GetKind()) { - //helps to convert BVUMINUS into a BVMULT. here the max - //constant represents -1. this transformation allows us to - //conclude that x + BVUMINUS(x) is 0. - vars_to_consts[aaa[0]].push_back(max); - } - else - vars_to_consts[aaa].push_back(one); - } //end of for loop - - //go over the map from variables to vector of values. combine the - //vector of values, multiply to the variable, and put the - //resultant monomial in the output BVPLUS. - for(ASTNodeToVecMap::iterator it=vars_to_consts.begin(),itend=vars_to_consts.end(); - it!=itend;it++){ - ASTVec ccc = it->second; - - ASTNode constant; - if(1 < ccc.size()) { - constant = CreateTerm(BVPLUS,ccc[0].GetValueWidth(),ccc); - constant = BVConstEvaluator(constant); - } - else - constant = ccc[0]; - - //constant * var - ASTNode monom; - if(zero == constant) - monom = zero; - else if (one == constant) - monom = it->first; - else{ - monom = - SimplifyTerm(CreateTerm(BVMULT,constant.GetValueWidth(),constant,it->first)); - } - if(zero != monom) { - outputvec.push_back(monom); - } - } //end of for loop - - if(constkids.size() > 1) { - ASTNode output = CreateTerm(BVPLUS,constkids[0].GetValueWidth(),constkids); - output = BVConstEvaluator(output); - if(output != zero) - outputvec.push_back(output); - } - else if (constkids.size() == 1) { - if(constkids[0] != zero) - outputvec.push_back(constkids[0]); - } - - if (outputvec.size() > 1) { - output = CreateTerm(BVPLUS,len,outputvec); - } - else if(outputvec.size() == 1) { - output = outputvec[0]; - } - else { - output = zero; - } - - //memoize - //UpdateSimplifyMap(a,output,false); - return output; - } //end of CombineLikeTerms() - - //accepts lhs and rhs, and returns lhs - rhs = 0. The function - //assumes that lhs and rhs have already been simplified. although - //this assumption is not needed for correctness, it is essential for - //performance. The function also assumes that lhs is a BVPLUS - ASTNode BeevMgr::LhsMinusRhs(const ASTNode& eq) { - //if input is not an equality, simply return it - if(EQ != eq.GetKind()) - return eq; - - ASTNode lhs = eq[0]; - ASTNode rhs = eq[1]; - Kind k_lhs = lhs.GetKind(); - Kind k_rhs = rhs.GetKind(); - //either the lhs has to be a BVPLUS or the rhs has to be a - //BVPLUS - if(!(BVPLUS == k_lhs || - BVPLUS == k_rhs || - (BVMULT == k_lhs && - BVMULT == k_rhs) - )) { - return eq; - } - - ASTNode output; - if(CheckSimplifyMap(eq,output,false)) { - //check memo table - //cerr << "output of SimplifyTerm Cache: " << output << endl; - return output; - } - - //if the lhs is not a BVPLUS, but the rhs is a BVPLUS, then swap - //the lhs and rhs - bool swap_flag = false; - if(BVPLUS != k_lhs && BVPLUS == k_rhs) { - ASTNode swap = lhs; - lhs = rhs; - rhs = swap; - swap_flag = true; - } - - unsigned int len = lhs.GetValueWidth(); - ASTNode zero = CreateZeroConst(len); - //right is -1*(rhs): Simplify(-1*rhs) - rhs = SimplifyTerm(CreateTerm(BVUMINUS,len,rhs)); - - ASTVec lvec = lhs.GetChildren(); - ASTVec rvec = rhs.GetChildren(); - ASTNode lhsplusrhs; - if(BVPLUS != lhs.GetKind() && BVPLUS != rhs.GetKind()) { - lhsplusrhs = CreateTerm(BVPLUS,len,lhs,rhs); - } - else if(BVPLUS == lhs.GetKind() && BVPLUS == rhs.GetKind()) { - //combine the childnodes of the left and the right - lvec.insert(lvec.end(),rvec.begin(),rvec.end()); - lhsplusrhs = CreateTerm(BVPLUS,len,lvec); - } - else if(BVPLUS == lhs.GetKind() && BVPLUS != rhs.GetKind()){ - lvec.push_back(rhs); - lhsplusrhs = CreateTerm(BVPLUS,len,lvec); - } - else { - //Control should never reach here - FatalError("LhsMinusRhs: Control should never reach here\n"); - } - - //combine like terms - output = CombineLikeTerms(lhsplusrhs); - output = SimplifyTerm(output); - // - //Now make output into: lhs-rhs = 0 - output = CreateSimplifiedEQ(output,zero); - //sort if BVPLUS - if(BVPLUS == output.GetKind()) { - ASTVec outv = output.GetChildren(); - SortByArith(outv); - output = CreateTerm(BVPLUS,len,outv); - } - - //memoize - //UpdateSimplifyMap(eq,output,false); - return output; - } //end of LhsMinusRHS() - - //THis function accepts a BVMULT(t1,t2) and distributes the mult - //over plus if either or both t1 and t2 are BVPLUSes. - // - // x*(y1 + y2 + ...+ yn) <==> x*y1 + x*y2 + ... + x*yn - // - // (y1 + y2 + ...+ yn)*x <==> x*y1 + x*y2 + ... + x*yn - // - // The function assumes that the BVPLUSes have been flattened - ASTNode BeevMgr::DistributeMultOverPlus(const ASTNode& a, bool startdistribution) { - if(!startdistribution) - return a; - Kind k = a.GetKind(); - if(BVMULT != k) - return a; - - ASTNode left = a[0]; - ASTNode right = a[1]; - Kind left_kind = left.GetKind(); - Kind right_kind = right.GetKind(); - - ASTNode output; - if(CheckSimplifyMap(a,output,false)) { - //check memo table - //cerr << "output of SimplifyTerm Cache: " << output << endl; - return output; - } - - //special case optimization: c1*(c2*t1) <==> (c1*c2)*t1 - if(BVCONST == left_kind && - BVMULT == right_kind && - BVCONST == right[0].GetKind()) { - ASTNode c = BVConstEvaluator(CreateTerm(BVMULT,a.GetValueWidth(),left,right[0])); - c = CreateTerm(BVMULT,a.GetValueWidth(),c,right[1]); - return c; - left = c[0]; - right = c[1]; - left_kind = left.GetKind(); - right_kind = right.GetKind(); - } - - //special case optimization: c1*(t1*c2) <==> (c1*c2)*t1 - if(BVCONST == left_kind && - BVMULT == right_kind && - BVCONST == right[1].GetKind()) { - ASTNode c = BVConstEvaluator(CreateTerm(BVMULT,a.GetValueWidth(),left,right[1])); - c = CreateTerm(BVMULT,a.GetValueWidth(),c,right[0]); - return c; - left = c[0]; - right = c[1]; - left_kind = left.GetKind(); - right_kind = right.GetKind(); - } - - //atleast one of left or right have to be BVPLUS - if(!(BVPLUS == left_kind || BVPLUS == right_kind)) { - return a; - } - - //if left is BVPLUS and right is not, then swap left and right. we - //can do this since BVMULT is communtative - ASTNode swap; - if(BVPLUS == left_kind && BVPLUS != right_kind) { - swap = left; - left = right; - right = swap; - } - left_kind = left.GetKind(); - right_kind = right.GetKind(); - - //by this point we are gauranteed that right is a BVPLUS, but left - //may not be - ASTVec rightnodes = right.GetChildren(); - ASTVec outputvec; - unsigned len = a.GetValueWidth(); - ASTNode zero = CreateZeroConst(len); - ASTNode one = CreateOneConst(len); - if(BVPLUS != left_kind) { - //if the multiplier is not a BVPLUS then we have a special case - // x*(y1 + y2 + ...+ yn) <==> x*y1 + x*y2 + ... + x*yn - if(zero == left) { - outputvec.push_back(zero); - } - else if(one == left) { - outputvec.push_back(left); - } - else { - for(ASTVec::iterator j=rightnodes.begin(),jend=rightnodes.end(); - j!=jend;j++) { - ASTNode out = SimplifyTerm(CreateTerm(BVMULT,len,left,*j)); - outputvec.push_back(out); - } - } - } - else { - ASTVec leftnodes = left.GetChildren(); - // (x1 + x2 + ... + xm)*(y1 + y2 + ...+ yn) <==> x1*y1 + x1*y2 + - // ... + x2*y1 + ... + xm*yn - for(ASTVec::iterator i=leftnodes.begin(),iend=leftnodes.end(); - i!=iend;i++) { - ASTNode multiplier = *i; - for(ASTVec::iterator j=rightnodes.begin(),jend=rightnodes.end(); - j!=jend;j++) { - ASTNode out = SimplifyTerm(CreateTerm(BVMULT,len,multiplier,*j)); - outputvec.push_back(out); - } - } - } - - //compute output here - if(outputvec.size() > 1) { - output = CombineLikeTerms(CreateTerm(BVPLUS,len,outputvec)); - output = SimplifyTerm(output); - } - else - output = SimplifyTerm(outputvec[0]); - - //memoize - //UpdateSimplifyMap(a,output,false); - return output; - } //end of distributemultoverplus() - - //converts the BVSX(len, a0) operator into ITE( check top bit, - //extend a0 by 1, extend a0 by 0) - ASTNode BeevMgr::ConvertBVSXToITE(const ASTNode& a) { - if(BVSX != a.GetKind()) - return a; - - ASTNode output; - if(CheckSimplifyMap(a,output,false)) { - //check memo table - //cerr << "output of ConvertBVSXToITE Cache: " << output << endl; - return output; - } - - ASTNode a0 = a[0]; - unsigned a_len = a.GetValueWidth(); - unsigned a0_len = a0.GetValueWidth(); - - if(a0_len > a_len){ - FatalError("Trying to sign_extend a larger BV into a smaller BV"); - return ASTUndefined; //to stop the compiler from producing bogus warnings - } - - //sign extend - unsigned extensionlen = a_len-a0_len; - if(0 == extensionlen) { - UpdateSimplifyMap(a,output,false); - return a; - } - - std::string ones; - for(unsigned c=0; c < extensionlen;c++) - ones += '1'; - std::string zeros; - for(unsigned c=0; c < extensionlen;c++) - zeros += '0'; - - //string of oness of length extensionlen - BEEV::ASTNode BVOnes = CreateBVConst(ones.c_str(),2); - //string of zeros of length extensionlen - BEEV::ASTNode BVZeros = CreateBVConst(zeros.c_str(),2); - - //string of ones BVCONCAT a0 - BEEV::ASTNode concatOnes = CreateTerm(BEEV::BVCONCAT,a_len,BVOnes,a0); - //string of zeros BVCONCAT a0 - BEEV::ASTNode concatZeros = CreateTerm(BEEV::BVCONCAT,a_len,BVZeros,a0); - - //extract top bit of a0 - BEEV::ASTNode hi = CreateBVConst(32,a0_len-1); - BEEV::ASTNode low = CreateBVConst(32,a0_len-1); - BEEV::ASTNode topBit = CreateTerm(BEEV::BVEXTRACT,1,a0,hi,low); - - //compare topBit of a0 with 0bin1 - BEEV::ASTNode condition = CreateSimplifiedEQ(CreateBVConst(1,1),topBit); - - //ITE(topbit = 0bin1, 0bin1111...a0, 0bin000...a0) - output = CreateSimplifiedTermITE(condition,concatOnes,concatZeros); - UpdateSimplifyMap(a,output,false); - return output; - } //end of ConvertBVSXToITE() - - - ASTNode BeevMgr::RemoveWrites_TopLevel(const ASTNode& term) { - if(READ != term.GetKind() && WRITE != term[0].GetKind()) { - FatalError("RemovesWrites: Input must be a READ over a WRITE",term); - } - - if(!Begin_RemoveWrites && - !SimplifyWrites_InPlace_Flag && - !start_abstracting) { - return term; - } - else if(!Begin_RemoveWrites && - SimplifyWrites_InPlace_Flag && - !start_abstracting) { - //return term; - return SimplifyWrites_InPlace(term); - } - else { - return RemoveWrites(term); - } - } //end of RemoveWrites_TopLevel() - - ASTNode BeevMgr::SimplifyWrites_InPlace(const ASTNode& term) { - ASTNodeMultiSet WriteIndicesSeenSoFar; - bool SeenNonConstWriteIndex = false; - - if(READ != term.GetKind() && - WRITE != term[0].GetKind()) { - FatalError("RemovesWrites: Input must be a READ over a WRITE",term); - } - - ASTNode output; - if(CheckSimplifyMap(term,output,false)) { - return output; - } - - ASTVec writeIndices, writeValues; - unsigned int width = term.GetValueWidth(); - ASTNode write = term[0]; - unsigned indexwidth = write.GetIndexWidth(); - ASTNode readIndex = SimplifyTerm(term[1]); - - do { - ASTNode writeIndex = SimplifyTerm(write[1]); - ASTNode writeVal = SimplifyTerm(write[2]); - - //compare the readIndex and the current writeIndex and see if they - //simplify to TRUE or FALSE or UNDETERMINABLE at this stage - ASTNode compare_readwrite_indices = - SimplifyFormula(CreateSimplifiedEQ(writeIndex,readIndex),false); - - //if readIndex and writeIndex are equal - if(ASTTrue == compare_readwrite_indices && !SeenNonConstWriteIndex) { - UpdateSimplifyMap(term,writeVal,false); - return writeVal; - } - - if(!(ASTTrue == compare_readwrite_indices || - ASTFalse == compare_readwrite_indices)) { - SeenNonConstWriteIndex = true; - } - - //if (readIndex=writeIndex <=> FALSE) - if(ASTFalse == compare_readwrite_indices - || - (WriteIndicesSeenSoFar.find(writeIndex) != WriteIndicesSeenSoFar.end()) - ) { - //drop the current level write - //do nothing - } - else { - writeIndices.push_back(writeIndex); - writeValues.push_back(writeVal); - } - - //record the write indices seen so far - //if(BVCONST == writeIndex.GetKind()) { - WriteIndicesSeenSoFar.insert(writeIndex); - //} - - //Setup the write for the new iteration, one level inner write - write = write[0]; - }while (SYMBOL != write.GetKind()); - - ASTVec::reverse_iterator it_index = writeIndices.rbegin(); - ASTVec::reverse_iterator itend_index = writeIndices.rend(); - ASTVec::reverse_iterator it_values = writeValues.rbegin(); - ASTVec::reverse_iterator itend_values = writeValues.rend(); - - //"write" must be a symbol at the control point before the - //begining of the "for loop" - - for(;it_index!=itend_index;it_index++,it_values++) { - write = CreateTerm(WRITE,width,write,*it_index,*it_values); - write.SetIndexWidth(indexwidth); - } - - output = CreateTerm(READ,width,write,readIndex); - UpdateSimplifyMap(term,output,false); - return output; - } //end of SimplifyWrites_In_Place() - - //accepts a read over a write and returns a term without the write - //READ(WRITE(A i val) j) <==> ITE(i=j,val,READ(A,j)). We use a memo - //table for this function called RemoveWritesMemoMap - ASTNode BeevMgr::RemoveWrites(const ASTNode& input) { - //unsigned int width = input.GetValueWidth(); - if(READ != input.GetKind() || WRITE != input[0].GetKind()) { - FatalError("RemovesWrites: Input must be a READ over a WRITE",input); - } - - ASTNodeMap::iterator it; - ASTNode output = input; - if(CheckSimplifyMap(input,output,false)) { - return output; - } - - if(!start_abstracting && Begin_RemoveWrites) { - output= ReadOverWrite_To_ITE(input); - } - - if(start_abstracting) { - ASTNode newVar; - if(!CheckSimplifyMap(input,newVar,false)) { - newVar = NewVar(input.GetValueWidth()); - ReadOverWrite_NewName_Map[input] = newVar; - NewName_ReadOverWrite_Map[newVar] = input; - - UpdateSimplifyMap(input,newVar,false); - ASTNodeStats("New Var Name which replace Read_Over_Write: ", newVar); - } - output = newVar; - } //end of start_abstracting if condition - - //memoize - UpdateSimplifyMap(input,output,false); - return output; - } //end of RemoveWrites() - - ASTNode BeevMgr::ReadOverWrite_To_ITE(const ASTNode& term) { - unsigned int width = term.GetValueWidth(); - ASTNode input = term; - if(READ != term.GetKind() || WRITE != term[0].GetKind()) { - FatalError("RemovesWrites: Input must be a READ over a WRITE",term); - } - - ASTNodeMap::iterator it; - ASTNode output; - // if(CheckSimplifyMap(term,output,false)) { - // return output; - // } - - ASTNode partialITE = term; - ASTNode writeA = ASTTrue; - ASTNode oldRead = term; - //iteratively expand read-over-write - do { - ASTNode write = input[0]; - ASTNode readIndex = SimplifyTerm(input[1]); - //DO NOT CALL SimplifyTerm() on write[0]. You will go into an - //infinite loop - writeA = write[0]; - ASTNode writeIndex = SimplifyTerm(write[1]); - ASTNode writeVal = SimplifyTerm(write[2]); - - ASTNode cond = SimplifyFormula(CreateSimplifiedEQ(writeIndex,readIndex),false); - ASTNode newRead = CreateTerm(READ,width,writeA,readIndex); - ASTNode newRead_memoized = newRead; - if(CheckSimplifyMap(newRead, newRead_memoized,false)) { - newRead = newRead_memoized; - } - - if(ASTTrue == cond && (term == partialITE)) { - //found the write-value in the first iteration itself. return - //it - output = writeVal; - UpdateSimplifyMap(term,output,false); - return output; - } - - if(READ == partialITE.GetKind() && WRITE == partialITE[0].GetKind()) { - //first iteration or (previous cond==ASTFALSE and partialITE is a "READ over WRITE") - partialITE = CreateSimplifiedTermITE(cond, writeVal, newRead); - } - else if (ITE == partialITE.GetKind()){ - //ITE(i1 = j, v1, R(A,j)) - ASTNode ElseITE = CreateSimplifiedTermITE(cond, writeVal, newRead); - //R(W(A,i1,v1),j) <==> ITE(i1 = j, v1, R(A,j)) - UpdateSimplifyMap(oldRead,ElseITE,false); - //ITE(i2 = j, v2, R(W(A,i1,v1),j)) <==> ITE(i2 = j, v2, ITE(i1 = j, v1, R(A,j))) - partialITE = SimplifyTerm(partialITE); - } - else { - FatalError("RemoveWrites: Control should not reach here\n"); - } - - if(ASTTrue == cond) { - //no more iterations required - output = partialITE; - UpdateSimplifyMap(term,output,false); + if (a.GetChildren().size() > 2) + { + FatalError("Simplify got an XOR with more than two children."); + } + + ASTNode a0 = SimplifyFormula(a[0], false); + ASTNode a1 = SimplifyFormula(a[1], false); + output = pushNeg ? CreateNode(IFF, a0, a1) : CreateNode(XOR, a0, a1); + + if (XOR == output.GetKind()) + { + a0 = output[0]; + a1 = output[1]; + if (a0 == a1) + output = ASTFalse; + else if (a0 == ASTTrue && a1 == ASTFalse || a0 == ASTFalse && a1 == ASTTrue) + output = ASTTrue; + } + + //memoize + UpdateSimplifyMap(a, output, pushNeg); return output; - } +} + +ASTNode BeevMgr::SimplifyNandFormula(const ASTNode& a, bool pushNeg) +{ + ASTNode output, a0, a1; + if (CheckSimplifyMap(a, output, pushNeg)) + return output; + + //the two NOTs cancel out + if (pushNeg) + { + a0 = SimplifyFormula(a[0], false); + a1 = SimplifyFormula(a[1], false); + output = CreateNode(AND, a0, a1); + } + else + { + //push the NOT implicit in the NAND + a0 = SimplifyFormula(a[0], true); + a1 = SimplifyFormula(a[1], true); + output = CreateNode(OR, a0, a1); + } - input = newRead; - oldRead = newRead; - } while(READ == input.GetKind() && WRITE == input[0].GetKind()); + //memoize + UpdateSimplifyMap(a, output, pushNeg); + return output; +} - output = partialITE; +ASTNode BeevMgr::SimplifyNorFormula(const ASTNode& a, bool pushNeg) +{ + ASTNode output, a0, a1; + if (CheckSimplifyMap(a, output, pushNeg)) + return output; + + //the two NOTs cancel out + if (pushNeg) + { + a0 = SimplifyFormula(a[0], false); + a1 = SimplifyFormula(a[1], false); + output = CreateNode(OR, a0, a1); + } + else + { + //push the NOT implicit in the NAND + a0 = SimplifyFormula(a[0], true); + a1 = SimplifyFormula(a[1], true); + output = CreateNode(AND, a0, a1); + } - //memoize - //UpdateSimplifyMap(term,output,false); - return output; - } //ReadOverWrite_To_ITE() + //memoize + UpdateSimplifyMap(a, output, pushNeg); + return output; +} - //compute the multiplicative inverse of the input - ASTNode BeevMgr::MultiplicativeInverse(const ASTNode& d) { - ASTNode c = d; - if(BVCONST != c.GetKind()) { - FatalError("Input must be a constant", c); - } +ASTNode BeevMgr::SimplifyImpliesFormula(const ASTNode& a, bool pushNeg) +{ + ASTNode output; + if (CheckSimplifyMap(a, output, pushNeg)) + return output; + + if (!(a.Degree() == 2 && IMPLIES == a.GetKind())) + FatalError("SimplifyImpliesFormula: vector with wrong num of nodes", ASTUndefined); + + ASTNode c0, c1; + if (pushNeg) + { + c0 = SimplifyFormula(a[0], false); + c1 = SimplifyFormula(a[1], true); + output = CreateNode(AND, c0, c1); + } + else + { + c0 = SimplifyFormula(a[0], false); + c1 = SimplifyFormula(a[1], false); + if (ASTFalse == c0) + { + output = ASTTrue; + } + else if (ASTTrue == c0) + { + output = c1; + } + else if (c0 == c1) + { + output = ASTTrue; + } + else if (CheckAlwaysTrueFormMap(c0)) + { + // c0 AND (~c0 OR c1) <==> c1 + // + //applying modus ponens + output = c1; + } + else if (CheckAlwaysTrueFormMap(c1) || CheckAlwaysTrueFormMap(CreateNode(NOT, c0)) || (NOT == c0.GetKind() && CheckAlwaysTrueFormMap(c0[0]))) + { + //(~c0 AND (~c0 OR c1)) <==> TRUE + // + //(c0 AND ~c0->c1) <==> TRUE + output = ASTTrue; + } + else if (CheckAlwaysTrueFormMap(CreateNode(NOT, c1)) || (NOT == c1.GetKind() && CheckAlwaysTrueFormMap(c1[0]))) + { + //(~c1 AND c0->c1) <==> (~c1 AND ~c1->~c0) <==> ~c0 + //(c1 AND c0->~c1) <==> (c1 AND c1->~c0) <==> ~c0 + output = CreateNode(NOT, c0); + } + else + { + if (NOT == c0.GetKind()) + { + output = CreateNode(OR, c0[0], c1); + } + else + { + output = CreateNode(OR, CreateNode(NOT, c0), c1); + } + } + } - if(!BVConstIsOdd(c)) { - FatalError("MultiplicativeInverse: Input must be odd: ",c); - } + //memoize + UpdateSimplifyMap(a, output, pushNeg); + return output; +} - //cerr << "input to multinverse function is: " << d << endl; - ASTNode inverse; - if(CheckMultInverseMap(d,inverse)) { - //cerr << "found the inverse of: " << d << "and it is: " << inverse << endl; - return inverse; - } +ASTNode BeevMgr::SimplifyIffFormula(const ASTNode& a, bool pushNeg) +{ + ASTNode output; + if (CheckSimplifyMap(a, output, pushNeg)) + return output; - inverse = c; - unsigned inputwidth = c.GetValueWidth(); + if (!(a.Degree() == 2 && IFF == a.GetKind())) + FatalError("SimplifyIffFormula: vector with wrong num of nodes", ASTUndefined); -#ifdef NATIVE_C_ARITH - ASTNode one = CreateOneConst(inputwidth); - while(c != one) { - //c = c*c - c = BVConstEvaluator(CreateTerm(BVMULT,inputwidth,c,c)); - //inverse = invsere*c - inverse = BVConstEvaluator(CreateTerm(BVMULT,inputwidth,inverse,c)); - } -#else - //Compute the multiplicative inverse of c using the extended - //euclidian algorithm - // - //create a '0' which is 1 bit long - ASTNode onebit_zero = CreateZeroConst(1); - //zero pad t0, i.e. 0 @ t0 - c = BVConstEvaluator(CreateTerm(BVCONCAT,inputwidth+1,onebit_zero,c)); - - //construct 2^(inputwidth), i.e. a bitvector of length - //'inputwidth+1', which is max(inputwidth)+1 - // - //all 1's - ASTNode max = CreateMaxConst(inputwidth); - //zero pad max - max = BVConstEvaluator(CreateTerm(BVCONCAT,inputwidth+1,onebit_zero,max)); - //Create a '1' which has leading zeros of length 'inputwidth' - ASTNode inputwidthplusone_one = CreateOneConst(inputwidth+1); - //add 1 to max - max = CreateTerm(BVPLUS,inputwidth+1,max,inputwidthplusone_one); - max = BVConstEvaluator(max); - - ASTNode zero = CreateZeroConst(inputwidth+1); - ASTNode max_bvgt_0 = CreateNode(BVGT,max,zero); - ASTNode quotient, remainder; - ASTNode x, x1, x2; - - //x1 initialized to zero - x1 = zero; - //x2 initialized to one - x2 = CreateOneConst(inputwidth+1); - while (ASTTrue == BVConstEvaluator(max_bvgt_0)) { - //quotient = (c divided by max) - quotient = BVConstEvaluator(CreateTerm(BVDIV,inputwidth+1, c, max)); - - //remainder of (c divided by max) - remainder = BVConstEvaluator(CreateTerm(BVMOD,inputwidth+1, c, max)); - - //x = x2 - q*x1 - x = CreateTerm(BVSUB,inputwidth+1,x2,CreateTerm(BVMULT,inputwidth+1,quotient,x1)); - x = BVConstEvaluator(x); - - //fix the inputs to the extended euclidian algo - c = max; - max = remainder; - max_bvgt_0 = CreateNode(BVGT,max,zero); - - x2 = x1; - x1 = x; - } - - ASTNode hi = CreateBVConst(32,inputwidth-1); - ASTNode low = CreateZeroConst(32); - inverse = CreateTerm(BVEXTRACT,inputwidth,x2,hi,low); - inverse = BVConstEvaluator(inverse); -#endif + ASTNode c0 = a[0]; + ASTNode c1 = SimplifyFormula(a[1], false); - UpdateMultInverseMap(d,inverse); - //cerr << "output of multinverse function is: " << inverse << endl; - return inverse; - } //end of MultiplicativeInverse() - - //returns true if the input is odd - bool BeevMgr::BVConstIsOdd(const ASTNode& c) { - if(BVCONST != c.GetKind()) { - FatalError("Input must be a constant", c); - } - - ASTNode zero = CreateZeroConst(1); - ASTNode hi = CreateZeroConst(32); - ASTNode low = hi; - ASTNode lowestbit = CreateTerm(BVEXTRACT,1,c,hi,low); - lowestbit = BVConstEvaluator(lowestbit); - - if(lowestbit == zero) { - return false; - } - else { - return true; - } - } //end of BVConstIsOdd() - - //The big substitution function - ASTNode BeevMgr::CreateSubstitutionMap(const ASTNode& a){ - if(!optimize) - return a; - - ASTNode output = a; - //if the variable has been solved for, then simply return it - if(CheckSolverMap(a,output)) - return output; - - //traverse a and populate the SubstitutionMap - Kind k = a.GetKind(); - if(SYMBOL == k && BOOLEAN_TYPE == a.GetType()) { - bool updated = UpdateSubstitutionMap(a,ASTTrue); - output = updated ? ASTTrue : a; - return output; - } - if(NOT == k - && SYMBOL == a[0].GetKind()) { - bool updated = UpdateSubstitutionMap(a[0],ASTFalse); - output = updated ? ASTTrue : a; - return output; - } - - if(IFF == k) { - ASTVec c = a.GetChildren(); - SortByArith(c); - if(SYMBOL != c[0].GetKind() || - VarSeenInTerm(c[0],SimplifyFormula_NoRemoveWrites(c[1],false))) { - return a; - } - bool updated = UpdateSubstitutionMap(c[0], SimplifyFormula(c[1],false)); - output = updated ? ASTTrue : a; - return output; - } - - if(EQ == k) { - //fill the arrayname readindices vector if e0 is a - //READ(Arr,index) and index is a BVCONST - ASTVec c = a.GetChildren(); - SortByArith(c); - FillUp_ArrReadIndex_Vec(c[0],c[1]); - - if(SYMBOL == c[0].GetKind() && - VarSeenInTerm(c[0],SimplifyTermAux(c[1]))) { - return a; - } - - if(1 == TermOrder(c[0],c[1]) && - READ == c[0].GetKind() && - VarSeenInTerm(c[0][0],SimplifyTermAux(c[1]))) { - return a; - } - bool updated = UpdateSubstitutionMap(c[0], SimplifyTermAux(c[1])); - output = updated ? ASTTrue : a; - return output; - } - - if(AND == k){ - ASTVec o; - ASTVec c = a.GetChildren(); - for(ASTVec::iterator it = c.begin(),itend=c.end();it!=itend;it++) { - UpdateAlwaysTrueFormMap(*it); - ASTNode aaa = CreateSubstitutionMap(*it); - - if(ASTTrue != aaa) { - if(ASTFalse == aaa) - return ASTFalse; - else - o.push_back(aaa); - } - } - if(o.size() == 0) - return ASTTrue; - - if(o.size() == 1) - return o[0]; - - return CreateNode(AND,o); - } - - //printf("I gave up on kind: %d node: %d\n", k, a.GetNodeNum()); - return output; - } //end of CreateSubstitutionMap() - - - bool BeevMgr::VarSeenInTerm(const ASTNode& var, const ASTNode& term) { - if(READ == term.GetKind() && - WRITE == term[0].GetKind() && !Begin_RemoveWrites) { - return false; - } - - if(READ == term.GetKind() && - WRITE == term[0].GetKind() && Begin_RemoveWrites) { - return true; - } - - ASTNodeMap::iterator it; - if((it = TermsAlreadySeenMap.find(term)) != TermsAlreadySeenMap.end()) { - if(it->second == var) { - return false; - } - } - - if(var == term) { - return true; - } - - for(ASTVec::const_iterator it=term.begin(),itend=term.end();it!=itend;it++){ - if(VarSeenInTerm(var,*it)) { - return true; - } - else { - TermsAlreadySeenMap[*it] = var; - } - } - - TermsAlreadySeenMap[term] = var; - return false; - } + if (pushNeg) + c0 = SimplifyFormula(c0, true); + else + c0 = SimplifyFormula(c0, false); -// in ext/hash_map, and tr/unordered_map, there is no provision to shrink down -// the number of buckets in a hash map. If the hash_map has previously held a -// lot of data, then it will have a lot of buckets. Slowing down iterators and -// clears() in particular. -void BeevMgr::ResetSimplifyMaps() -{ - delete SimplifyMap; - SimplifyMap = new ASTNodeMap(INITIAL_SIMPLIFY_MAP_SIZE); + if (ASTTrue == c0) + { + output = c1; + } + else if (ASTFalse == c0) + { + output = SimplifyFormula(c1, true); + } + else if (ASTTrue == c1) + { + output = c0; + } + else if (ASTFalse == c1) + { + output = SimplifyFormula(c0, true); + } + else if (c0 == c1) + { + output = ASTTrue; + } + else if ((NOT == c0.GetKind() && c0[0] == c1) || (NOT == c1.GetKind() && c0 == c1[0])) + { + output = ASTFalse; + } + else if (CheckAlwaysTrueFormMap(c0)) + { + output = c1; + } + else if (CheckAlwaysTrueFormMap(c1)) + { + output = c0; + } + else if (CheckAlwaysTrueFormMap(CreateNode(NOT, c0))) + { + output = CreateNode(NOT, c1); + } + else if (CheckAlwaysTrueFormMap(CreateNode(NOT, c1))) + { + output = CreateNode(NOT, c0); + } + else + { + output = CreateNode(IFF, c0, c1); + } - delete SimplifyNegMap; - SimplifyNegMap = new ASTNodeMap(INITIAL_SIMPLIFY_MAP_SIZE); + //memoize + UpdateSimplifyMap(a, output, pushNeg); + return output; } +ASTNode BeevMgr::SimplifyIteFormula(const ASTNode& b, bool pushNeg) +{ + if (!optimize) + return b; + + ASTNode output; + if (CheckSimplifyMap(b, output, pushNeg)) + return output; + + if (!(b.Degree() == 3 && ITE == b.GetKind())) + FatalError("SimplifyIteFormula: vector with wrong num of nodes", ASTUndefined); + + ASTNode a = b; + ASTNode t0 = SimplifyFormula(a[0], false); + ASTNode t1, t2; + if (pushNeg) + { + t1 = SimplifyFormula(a[1], true); + t2 = SimplifyFormula(a[2], true); + } + else + { + t1 = SimplifyFormula(a[1], false); + t2 = SimplifyFormula(a[2], false); + } + + if (ASTTrue == t0) + { + output = t1; + } + else if (ASTFalse == t0) + { + output = t2; + } + else if (t1 == t2) + { + output = t1; + } + else if (ASTTrue == t1 && ASTFalse == t2) + { + output = t0; + } + else if (ASTFalse == t1 && ASTTrue == t2) + { + output = SimplifyFormula(t0, true); + } + else if (ASTTrue == t1) + { + output = CreateNode(OR, t0, t2); + } + else if (ASTFalse == t1) + { + output = CreateNode(AND, CreateNode(NOT, t0), t2); + } + else if (ASTTrue == t2) + { + output = CreateNode(OR, CreateNode(NOT, t0), t1); + } + else if (ASTFalse == t2) + { + output = CreateNode(AND, t0, t1); + } + else if (CheckAlwaysTrueFormMap(t0)) + { + output = t1; + } + else if (CheckAlwaysTrueFormMap(CreateNode(NOT, t0)) || (NOT == t0.GetKind() && CheckAlwaysTrueFormMap(t0[0]))) + { + output = t2; + } + else + { + output = CreateNode(ITE, t0, t1, t2); + } + + //memoize + UpdateSimplifyMap(a, output, pushNeg); + return output; +} + +//one level deep flattening +ASTNode BeevMgr::FlattenOneLevel(const ASTNode& a) +{ + Kind k = a.GetKind(); + if (!(BVPLUS == k || AND == k || OR == k + //|| BVAND == k + //|| BVOR == k + )) + { + return a; + } + + ASTNode output; + // if(CheckSimplifyMap(a,output,false)) { + // //check memo table + // //cerr << "output of SimplifyTerm Cache: " << output << endl; + // return output; + // } + + ASTVec c = a.GetChildren(); + ASTVec o; + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + ASTNode aaa = *it; + if (k == aaa.GetKind()) + { + ASTVec ac = aaa.GetChildren(); + o.insert(o.end(), ac.begin(), ac.end()); + } + else + o.push_back(aaa); + } + + if (is_Form_kind(k)) + output = CreateNode(k, o); + else + output = CreateTerm(k, a.GetValueWidth(), o); + + //UpdateSimplifyMap(a,output,false); + return output; + //memoize +} //end of flattenonelevel() + +ASTNode BeevMgr::SimplifyTerm_TopLevel(const ASTNode& b) +{ + ResetSimplifyMaps(); + ASTNode out = SimplifyTerm(b); + ResetSimplifyMaps(); + return out; +} + +//This function simplifies terms based on their kind +ASTNode BeevMgr::SimplifyTerm(const ASTNode& inputterm) +{ + //cout << "SimplifyTerm: input: " << a << endl; + if (!optimize) + { + return inputterm; + } + + ASTNode output; + BVTypeCheck(inputterm); + + //######################################## + //######################################## + + if (wordlevel_solve && CheckSolverMap(inputterm, output)) + { + //cout << "SimplifyTerm: output: " << output << endl; + return SimplifyTerm(output); + } + + if (CheckSimplifyMap(inputterm, output, false)) + { + //cerr << "output of SimplifyTerm Cache: " << output << endl; + return output; + } + //######################################## + //######################################## + + Kind k = inputterm.GetKind(); + if (!is_Term_kind(k)) + { + FatalError("SimplifyTerm: You have input a Non-term", ASTUndefined); + } + + unsigned int inputValueWidth = inputterm.GetValueWidth(); + switch (k) + { + case BVCONST: + output = inputterm; + break; + case SYMBOL: + if (CheckSolverMap(inputterm, output)) + { + return SimplifyTerm(output); + } + output = inputterm; + break; + case BVMULT: + { + if (2 != inputterm.Degree()) + { + FatalError("SimplifyTerm: We assume that BVMULT is binary", inputterm); + } + + // Described nicely by Warren, Hacker's Delight pg 135. + // Turn sequences of one bits into subtractions. + // 28*x == 32x - 4x (two instructions), rather than 16x+ 8x+ 4x. + // When fully implemented. I.e. supporting sequences of 1 anywhere. + // Other simplifications will try to fold these back in. So need to be careful + // about when the simplifications are applied. But in this version it won't + // be simplified down by anything else. + + + // This (temporary) version only simplifies if all the left most bits are set. + // All the leftmost bits being set simplifies very nicely down. + const ASTNode& n0 = inputterm.GetChildren()[0]; + const ASTNode& n1 = inputterm.GetChildren()[1]; + + // This implementation has two problems. + // 1) It causes a segfault for cmu-model15,16,17 + // 2) It doesn't count the number of bits saved, so if there is a single + // leading bit it will invert it. Even though that will take more shifts + // and adds when it's finally done. + + // disabled. + if (false && (BVCONST == n0.GetKind()) ^ (BVCONST == n1.GetKind())) + { + CBV constant = (BVCONST == n0.GetKind()) ? n0.GetBVConst() : n1.GetBVConst(); + ASTNode other = (BVCONST == n0.GetKind()) ? n1 : n0; + + int startSequence = 0; + for (unsigned int i = 0; i < inputValueWidth; i++) + { + if (!CONSTANTBV::BitVector_bit_test(constant, i)) + startSequence = i; + } + + if ((inputValueWidth - startSequence) > 3) + { + // turn off all bits from "startSequence to the end", then add one. + CBV maskedPlusOne = CONSTANTBV::BitVector_Create(inputValueWidth, true); + for (int i = 0; i < startSequence; i++) + { + if (!CONSTANTBV::BitVector_bit_test(constant, i)) // swap + CONSTANTBV::BitVector_Bit_On(maskedPlusOne, i); + } + CONSTANTBV::BitVector_increment(maskedPlusOne); + ASTNode temp = CreateTerm(BVMULT, inputValueWidth, CreateBVConst(maskedPlusOne, inputValueWidth), other); + output = CreateTerm(BVNEG, inputValueWidth, temp); + } + } + + } + if (NULL != output) + break; + + case BVPLUS: + { + + ASTVec c = FlattenOneLevel(inputterm).GetChildren(); + SortByArith(c); + ASTVec constkids, nonconstkids; + + //go through the childnodes, and separate constant and + //nonconstant nodes. combine the constant nodes using the + //constevaluator. if the resultant constant is zero and k == + //BVPLUS, then ignore it (similarily for 1 and BVMULT). else, + //add the computed constant to the nonconst vector, flatten, + //sort, and create BVPLUS/BVMULT and return + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + ASTNode aaa = SimplifyTerm(*it); + if (BVCONST == aaa.GetKind()) + { + constkids.push_back(aaa); + } + else + { + nonconstkids.push_back(aaa); + } + } + + ASTNode one = CreateOneConst(inputValueWidth); + ASTNode max = CreateMaxConst(inputValueWidth); + ASTNode zero = CreateZeroConst(inputValueWidth); + + //initialize constoutput to zero, in case there are no elements + //in constkids + ASTNode constoutput = (k == BVPLUS) ? zero : one; + + if (1 == constkids.size()) + { + //only one element in constkids + constoutput = constkids[0]; + } + else if (1 < constkids.size()) + { + //many elements in constkids. simplify it + constoutput = CreateTerm(k, inputterm.GetValueWidth(), constkids); + constoutput = BVConstEvaluator(constoutput); + } + + if (BVMULT == k && zero == constoutput) + { + output = zero; + } + else if (BVMULT == k && 1 == nonconstkids.size() && constoutput == max) + { + //useful special case opt: when input is BVMULT(max_const,t), + //then output = BVUMINUS(t). this is easier on the bitblaster + output = CreateTerm(BVUMINUS, inputValueWidth, nonconstkids); + } + else + { + if (0 < nonconstkids.size()) + { + //nonconstkids is not empty. First, combine const and + //nonconstkids + if (BVPLUS == k && constoutput != zero) + { + nonconstkids.push_back(constoutput); + } + else if (BVMULT == k && constoutput != one) + { + nonconstkids.push_back(constoutput); + } + + if (1 == nonconstkids.size()) + { + //exactly one element in nonconstkids. output is exactly + //nonconstkids[0] + output = nonconstkids[0]; + } + else + { + //more than 1 element in nonconstkids. create BVPLUS term + SortByArith(nonconstkids); + output = CreateTerm(k, inputValueWidth, nonconstkids); + output = FlattenOneLevel(output); + output = DistributeMultOverPlus(output, true); + output = CombineLikeTerms(output); + } + } + else + { + //nonconstkids was empty, all childnodes were constant, hence + //constoutput is the output. + output = constoutput; + } + } + if (BVMULT == output.GetKind() || BVPLUS == output.GetKind()) + { + ASTVec d = output.GetChildren(); + SortByArith(d); + output = CreateTerm(output.GetKind(), output.GetValueWidth(), d); + } + break; + } + case BVSUB: + { + ASTVec c = inputterm.GetChildren(); + ASTNode a0 = SimplifyTerm(inputterm[0]); + ASTNode a1 = SimplifyTerm(inputterm[1]); + unsigned int l = inputValueWidth; + if (a0 == a1) + output = CreateZeroConst(l); + else + { + //covert x-y into x+(-y) and simplify. this transformation + //triggers more simplifications + // + a1 = SimplifyTerm(CreateTerm(BVUMINUS, l, a1)); + output = SimplifyTerm(CreateTerm(BVPLUS, l, a0, a1)); + } + break; + } + case BVUMINUS: + { + //important to treat BVUMINUS as a special case, because it + //helps in arithmetic transformations. e.g. x + BVUMINUS(x) is + //actually 0. One way to reveal this fact is to strip bvuminus + //out, and replace with something else so that combineliketerms + //can catch this fact. + ASTNode a0 = SimplifyTerm(inputterm[0]); + Kind k1 = a0.GetKind(); + unsigned int l = a0.GetValueWidth(); + ASTNode one = CreateOneConst(l); + switch (k1) + { + case BVUMINUS: + output = a0[0]; + break; + case BVCONST: + { + output = BVConstEvaluator(CreateTerm(BVUMINUS, l, a0)); + break; + } + case BVNEG: + { + output = SimplifyTerm(CreateTerm(BVPLUS, l, a0[0], one)); + break; + } + case BVMULT: + { + if (BVUMINUS == a0[0].GetKind()) + { + output = CreateTerm(BVMULT, l, a0[0][0], a0[1]); + } + else if (BVUMINUS == a0[1].GetKind()) + { + output = CreateTerm(BVMULT, l, a0[0], a0[1][0]); + } + else + { + ASTNode a00 = SimplifyTerm(CreateTerm(BVUMINUS, l, a0[0])); + output = CreateTerm(BVMULT, l, a00, a0[1]); + } + break; + } + case BVPLUS: + { + //push BVUMINUS over all the monomials of BVPLUS. Simplify + //along the way + // + //BVUMINUS(a1x1 + a2x2 + ...) <=> BVPLUS(BVUMINUS(a1x1) + + //BVUMINUS(a2x2) + ... + ASTVec c = a0.GetChildren(); + ASTVec o; + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + //Simplify(BVUMINUS(a1x1)) + ASTNode aaa = SimplifyTerm(CreateTerm(BVUMINUS, l, *it)); + o.push_back(aaa); + } + //simplify the bvplus + output = SimplifyTerm(CreateTerm(BVPLUS, l, o)); + break; + } + case BVSUB: + { + //BVUMINUS(BVSUB(x,y)) <=> BVSUB(y,x) + output = SimplifyTerm(CreateTerm(BVSUB, l, a0[1], a0[0])); + break; + } + case ITE: + { + //BVUMINUS(ITE(c,t1,t2)) <==> ITE(c,BVUMINUS(t1),BVUMINUS(t2)) + ASTNode c = a0[0]; + ASTNode t1 = SimplifyTerm(CreateTerm(BVUMINUS, l, a0[1])); + ASTNode t2 = SimplifyTerm(CreateTerm(BVUMINUS, l, a0[2])); + output = CreateSimplifiedTermITE(c, t1, t2); + break; + } + default: + { + output = CreateTerm(BVUMINUS, l, a0); + break; + } + } + break; + } + case BVEXTRACT: + { + //it is important to take care of wordlevel transformation in + //BVEXTRACT. it exposes oppurtunities for later simplification + //and solving (variable elimination) + ASTNode a0 = SimplifyTerm(inputterm[0]); + Kind k1 = a0.GetKind(); + unsigned int a_len = inputValueWidth; + + //indices for BVEXTRACT + ASTNode i = inputterm[1]; + ASTNode j = inputterm[2]; + ASTNode zero = CreateBVConst(32, 0); + //recall that the indices of BVEXTRACT are always 32 bits + //long. therefore doing a GetBVUnsigned is ok. + unsigned int i_val = GetUnsignedConst(i); + unsigned int j_val = GetUnsignedConst(j); + + // a0[i:0] and len(a0)=i+1, then return a0 + if (0 == j_val && a_len == a0.GetValueWidth()) + return a0; + + switch (k1) + { + case BVCONST: + { + //extract the constant + output = BVConstEvaluator(CreateTerm(BVEXTRACT, a_len, a0, i, j)); + break; + } + case BVCONCAT: + { + //assumes concatenation is binary + // + //input is of the form a0[i:j] + // + //a0 is the conatentation t@u, and a0[0] is t, and a0[1] is u + ASTNode t = a0[0]; + ASTNode u = a0[1]; + unsigned int len_a0 = a0.GetValueWidth(); + unsigned int len_u = u.GetValueWidth(); + + if (len_u > i_val) + { + //Apply the following rule: + // (t@u)[i:j] <==> u[i:j], if len(u) > i + // + output = SimplifyTerm(CreateTerm(BVEXTRACT, a_len, u, i, j)); + } + else if (len_a0 > i_val && j_val >= len_u) + { + //Apply the rule: + // (t@u)[i:j] <==> t[i-len_u:j-len_u], if len(t@u) > i >= j >= len(u) + i = CreateBVConst(32, i_val - len_u); + j = CreateBVConst(32, j_val - len_u); + output = SimplifyTerm(CreateTerm(BVEXTRACT, a_len, t, i, j)); + } + else + { + //Apply the rule: + // (t@u)[i:j] <==> t[i-len_u:0] @ u[len_u-1:j] + i = CreateBVConst(32, i_val - len_u); + ASTNode m = CreateBVConst(32, len_u - 1); + t = SimplifyTerm(CreateTerm(BVEXTRACT, i_val - len_u + 1, t, i, zero)); + u = SimplifyTerm(CreateTerm(BVEXTRACT, len_u - j_val, u, m, j)); + output = CreateTerm(BVCONCAT, a_len, t, u); + } + break; + } + case BVPLUS: + case BVMULT: + { + // (BVMULT(n,t,u))[i:j] <==> BVMULT(i+1,t[i:0],u[i:0])[i:j] + //similar rule for BVPLUS + ASTVec c = a0.GetChildren(); + ASTVec o; + for (ASTVec::iterator jt = c.begin(), jtend = c.end(); jt != jtend; jt++) + { + ASTNode aaa = *jt; + aaa = SimplifyTerm(CreateTerm(BVEXTRACT, i_val + 1, aaa, i, zero)); + o.push_back(aaa); + } + output = CreateTerm(a0.GetKind(), i_val + 1, o); + if (j_val != 0) + { + //add extraction only if j is not zero + output = CreateTerm(BVEXTRACT, a_len, output, i, j); + } + break; + } + case BVAND: + case BVOR: + case BVXOR: + { + //assumes these operators are binary + // + // (t op u)[i:j] <==> t[i:j] op u[i:j] + ASTNode t = a0[0]; + ASTNode u = a0[1]; + t = SimplifyTerm(CreateTerm(BVEXTRACT, a_len, t, i, j)); + u = SimplifyTerm(CreateTerm(BVEXTRACT, a_len, u, i, j)); + BVTypeCheck(t); + BVTypeCheck(u); + output = CreateTerm(k1, a_len, t, u); + break; + } + case BVNEG: + { + // (~t)[i:j] <==> ~(t[i:j]) + ASTNode t = a0[0]; + t = SimplifyTerm(CreateTerm(BVEXTRACT, a_len, t, i, j)); + output = CreateTerm(BVNEG, a_len, t); + break; + } + // case BVSX:{ + // //(BVSX(t,n)[i:j] <==> BVSX(t,i+1), if n >= i+1 and j=0 + // ASTNode t = a0[0]; + // unsigned int bvsx_len = a0.GetValueWidth(); + // if(bvsx_len < a_len) { + // FatalError("SimplifyTerm: BVEXTRACT over BVSX:" + // "the length of BVSX term must be greater than extract-len",inputterm); + // } + // if(j != zero) { + // output = CreateTerm(BVEXTRACT,a_len,a0,i,j); + // } + // else { + // output = CreateTerm(BVSX,a_len,t,CreateBVConst(32,a_len)); + // } + // break; + // } + case ITE: + { + ASTNode t0 = a0[0]; + ASTNode t1 = SimplifyTerm(CreateTerm(BVEXTRACT, a_len, a0[1], i, j)); + ASTNode t2 = SimplifyTerm(CreateTerm(BVEXTRACT, a_len, a0[2], i, j)); + output = CreateSimplifiedTermITE(t0, t1, t2); + break; + } + default: + { + output = CreateTerm(BVEXTRACT, a_len, a0, i, j); + break; + } + } + break; + } + case BVNEG: + { + ASTNode a0 = SimplifyTerm(inputterm[0]); + unsigned len = inputValueWidth; + switch (a0.GetKind()) + { + case BVCONST: + output = BVConstEvaluator(CreateTerm(BVNEG, len, a0)); + break; + case BVNEG: + output = a0[0]; + break; + // case ITE: { + // ASTNode cond = a0[0]; + // ASTNode thenpart = SimplifyTerm(CreateTerm(BVNEG,len,a0[1])); + // ASTNode elsepart = SimplifyTerm(CreateTerm(BVNEG,len,a0[2])); + // output = CreateSimplifiedTermITE(cond,thenpart,elsepart); + // break; + // } + default: + output = CreateTerm(BVNEG, len, a0); + break; + } + break; + } + + case BVZX: + { + ASTNode a0 = SimplifyTerm(inputterm[0]); + if (a0.GetKind() == BVCONST) + output = BVConstEvaluator(CreateTerm(BVZX, inputValueWidth, a0, inputterm[1])); + else + output = CreateTerm(BVZX, inputValueWidth, a0, inputterm[1]); + } + break; + + case BVSX: + { + //a0 is the expr which is being sign extended + ASTNode a0 = SimplifyTerm(inputterm[0]); + //a1 represents the length of the term BVSX(a0) + ASTNode a1 = inputterm[1]; + //output length of the BVSX term + unsigned len = inputValueWidth; + + if (a0.GetValueWidth() == len) + { + //nothing to signextend + return a0; + } + + switch (a0.GetKind()) + { + case BVCONST: + output = BVConstEvaluator(CreateTerm(BVSX, len, a0, a1)); + break; + case BVNEG: + output = CreateTerm(a0.GetKind(), len, CreateTerm(BVSX, len, a0[0], a1)); + break; + case BVAND: + case BVOR: + //assuming BVAND and BVOR are binary + output = CreateTerm(a0.GetKind(), len, CreateTerm(BVSX, len, a0[0], a1), CreateTerm(BVSX, len, a0[1], a1)); + break; + case BVPLUS: + { + //BVSX(m,BVPLUS(n,BVSX(t1),BVSX(t2))) <==> BVPLUS(m,BVSX(m,t1),BVSX(m,t2)) + ASTVec c = a0.GetChildren(); + bool returnflag = false; + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + if (BVSX != it->GetKind()) + { + returnflag = true; + break; + } + } + if (returnflag) + { + output = CreateTerm(BVSX, len, a0, a1); + } + else + { + ASTVec o; + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + ASTNode aaa = SimplifyTerm(CreateTerm(BVSX, len, *it, a1)); + o.push_back(aaa); + } + output = CreateTerm(a0.GetKind(), len, o); + } + break; + } + case BVSX: + { + //if you have BVSX(m,BVSX(n,a)) then you can drop the inner + //BVSX provided m is greater than n. + a0 = SimplifyTerm(a0[0]); + output = CreateTerm(BVSX, len, a0, a1); + break; + } + case ITE: + { + ASTNode cond = a0[0]; + ASTNode thenpart = SimplifyTerm(CreateTerm(BVSX, len, a0[1], a1)); + ASTNode elsepart = SimplifyTerm(CreateTerm(BVSX, len, a0[2], a1)); + output = CreateSimplifiedTermITE(cond, thenpart, elsepart); + break; + } + default: + output = CreateTerm(BVSX, len, a0, a1); + break; + } + break; + } + case BVAND: + case BVOR: + { + ASTNode max = CreateMaxConst(inputValueWidth); + ASTNode zero = CreateZeroConst(inputValueWidth); + + ASTNode identity = (BVAND == k) ? max : zero; + ASTNode annihilator = (BVAND == k) ? zero : max; + ASTVec c = FlattenOneLevel(inputterm).GetChildren(); + SortByArith(c); + ASTVec o; + bool constant = true; + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + ASTNode aaa = SimplifyTerm(*it); + if (BVCONST != aaa.GetKind()) + { + constant = false; + } + + if (aaa == annihilator) + { + output = annihilator; + //memoize + UpdateSimplifyMap(inputterm, output, false); + //cerr << "output of SimplifyTerm: " << output << endl; + return output; + } + + if (aaa != identity) + { + o.push_back(aaa); + } + } + + switch (o.size()) + { + case 0: + output = identity; + break; + case 1: + output = o[0]; + break; + default: + SortByArith(o); + output = CreateTerm(k, inputValueWidth, o); + if (constant) + { + output = BVConstEvaluator(output); + } + break; + } + break; + } + case BVCONCAT: + { + ASTNode t = SimplifyTerm(inputterm[0]); + ASTNode u = SimplifyTerm(inputterm[1]); + Kind tkind = t.GetKind(); + Kind ukind = u.GetKind(); + + if (BVCONST == tkind && BVCONST == ukind) + { + output = BVConstEvaluator(CreateTerm(BVCONCAT, inputValueWidth, t, u)); + } + else if (BVEXTRACT == tkind && BVEXTRACT == ukind && t[0] == u[0]) + { + //to handle the case x[m:n]@x[n-1:k] <==> x[m:k] + ASTNode t_hi = t[1]; + ASTNode t_low = t[2]; + ASTNode u_hi = u[1]; + ASTNode u_low = u[2]; + ASTNode c = BVConstEvaluator(CreateTerm(BVPLUS, 32, u_hi, CreateOneConst(32))); + if (t_low == c) + { + output = CreateTerm(BVEXTRACT, inputValueWidth, t[0], t_hi, u_low); + } + else + { + output = CreateTerm(BVCONCAT, inputValueWidth, t, u); + } + } + else + { + output = CreateTerm(BVCONCAT, inputValueWidth, t, u); + } + break; + } + case BVXOR: + case BVXNOR: + case BVNAND: + case BVNOR: + case BVLEFTSHIFT: + case BVRIGHTSHIFT: + case BVVARSHIFT: + case BVSRSHIFT: + case BVDIV: + case BVMOD: + { + ASTVec c = inputterm.GetChildren(); + ASTVec o; + bool constant = true; + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + ASTNode aaa = SimplifyTerm(*it); + if (BVCONST != aaa.GetKind()) + { + constant = false; + } + o.push_back(aaa); + } + output = CreateTerm(k, inputValueWidth, o); + if (constant) + output = BVConstEvaluator(output); + break; + } + case READ: + { + ASTNode out1; + //process only if not in the substitution map. simplifymap + //has been checked already + if (!CheckSubstitutionMap(inputterm, out1)) + { + if (WRITE == inputterm[0].GetKind()) + { + //get rid of all writes + ASTNode nowrites = RemoveWrites_TopLevel(inputterm); + out1 = nowrites; + } + else if (ITE == inputterm[0].GetKind()) + { + ASTNode cond = SimplifyFormula(inputterm[0][0], false); + ASTNode index = SimplifyTerm(inputterm[1]); + + ASTNode read1 = CreateTerm(READ, inputValueWidth, inputterm[0][1], index); + ASTNode read2 = CreateTerm(READ, inputValueWidth, inputterm[0][2], index); + + read1 = SimplifyTerm(read1); + read2 = SimplifyTerm(read2); + out1 = CreateSimplifiedTermITE(cond, read1, read2); + } + else + { + //arr is a SYMBOL for sure + ASTNode arr = inputterm[0]; + ASTNode index = SimplifyTerm(inputterm[1]); + out1 = CreateTerm(READ, inputValueWidth, arr, index); + } + } + //it is possible that after all the procesing the READ term + //reduces to READ(Symbol,const) and hence we should check the + //substitutionmap once again. + if (!CheckSubstitutionMap(out1, output)) + output = out1; + break; + } + case ITE: + { + ASTNode t0 = SimplifyFormula(inputterm[0], false); + ASTNode t1 = SimplifyTerm(inputterm[1]); + ASTNode t2 = SimplifyTerm(inputterm[2]); + output = CreateSimplifiedTermITE(t0, t1, t2); + break; + } + case SBVREM: + case SBVDIV: + { + ASTVec c = inputterm.GetChildren(); + ASTVec o; + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + ASTNode aaa = SimplifyTerm(*it); + o.push_back(aaa); + } + output = CreateTerm(k, inputValueWidth, o); + break; + } + case WRITE: + default: + FatalError("SimplifyTerm: Control should never reach here:", inputterm, k); + return inputterm; + break; + } + assert(NULL != output); + + //memoize + UpdateSimplifyMap(inputterm, output, false); + //cerr << "SimplifyTerm: output" << output << endl; + // CheckSimplifyInvariant(inputterm,output); + + return output; +} //end of SimplifyTerm() + +ASTNode BeevMgr::SimplifyTermAux(const ASTNode& inputterm) +{ + //cout << "SimplifyTerm: input: " << a << endl; + if (!optimize) + { + return inputterm; + } + + ASTNode output; + BVTypeCheck(inputterm); + + //######################################## + //######################################## + + if (wordlevel_solve && CheckSolverMap(inputterm, output)) + { + //cout << "SimplifyTerm: output: " << output << endl; + return SimplifyTermAux(output); + } -};//end of namespace + Kind k = inputterm.GetKind(); + if (!is_Term_kind(k)) + { + FatalError("SimplifyTerm: You have input a Non-term", ASTUndefined); + } + + unsigned int inputValueWidth = inputterm.GetValueWidth(); + switch (k) + { + case BVCONST: + output = inputterm; + break; + case SYMBOL: + if (CheckSolverMap(inputterm, output)) + { + return SimplifyTerm(output); + } + output = inputterm; + break; + case BVMULT: + case BVPLUS: + { + if (BVMULT == k && 2 != inputterm.Degree()) + { + FatalError("SimplifyTerm: We assume that BVMULT is binary", inputterm); + } + + ASTVec c = FlattenOneLevel(inputterm).GetChildren(); + SortByArith(c); + ASTVec constkids, nonconstkids; + + //go through the childnodes, and separate constant and + //nonconstant nodes. combine the constant nodes using the + //constevaluator. if the resultant constant is zero and k == + //BVPLUS, then ignore it (similarily for 1 and BVMULT). else, + //add the computed constant to the nonconst vector, flatten, + //sort, and create BVPLUS/BVMULT and return + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + ASTNode aaa = SimplifyTerm(*it); + if (BVCONST == aaa.GetKind()) + { + constkids.push_back(aaa); + } + else + { + nonconstkids.push_back(aaa); + } + } + + ASTNode one = CreateOneConst(inputValueWidth); + ASTNode max = CreateMaxConst(inputValueWidth); + ASTNode zero = CreateZeroConst(inputValueWidth); + + //initialize constoutput to zero, in case there are no elements + //in constkids + ASTNode constoutput = (k == BVPLUS) ? zero : one; + + if (1 == constkids.size()) + { + //only one element in constkids + constoutput = constkids[0]; + } + else if (1 < constkids.size()) + { + //many elements in constkids. simplify it + constoutput = CreateTerm(k, inputterm.GetValueWidth(), constkids); + constoutput = BVConstEvaluator(constoutput); + } + + if (BVMULT == k && zero == constoutput) + { + output = zero; + } + else if (BVMULT == k && 1 == nonconstkids.size() && constoutput == max) + { + //useful special case opt: when input is BVMULT(max_const,t), + //then output = BVUMINUS(t). this is easier on the bitblaster + output = CreateTerm(BVUMINUS, inputValueWidth, nonconstkids); + } + else + { + if (0 < nonconstkids.size()) + { + //nonconstkids is not empty. First, combine const and + //nonconstkids + if (BVPLUS == k && constoutput != zero) + { + nonconstkids.push_back(constoutput); + } + else if (BVMULT == k && constoutput != one) + { + nonconstkids.push_back(constoutput); + } + + if (1 == nonconstkids.size()) + { + //exactly one element in nonconstkids. output is exactly + //nonconstkids[0] + output = nonconstkids[0]; + } + else + { + //more than 1 element in nonconstkids. create BVPLUS term + SortByArith(nonconstkids); + output = CreateTerm(k, inputValueWidth, nonconstkids); + output = FlattenOneLevel(output); + output = DistributeMultOverPlus(output, true); + output = CombineLikeTerms(output); + } + } + else + { + //nonconstkids was empty, all childnodes were constant, hence + //constoutput is the output. + output = constoutput; + } + } + if (BVMULT == output.GetKind() || BVPLUS == output.GetKind()) + { + ASTVec d = output.GetChildren(); + SortByArith(d); + output = CreateTerm(output.GetKind(), output.GetValueWidth(), d); + } + break; + } + case BVSUB: + { + ASTVec c = inputterm.GetChildren(); + ASTNode a0 = SimplifyTerm(inputterm[0]); + ASTNode a1 = SimplifyTerm(inputterm[1]); + unsigned int l = inputValueWidth; + if (a0 == a1) + output = CreateZeroConst(l); + else + { + //covert x-y into x+(-y) and simplify. this transformation + //triggers more simplifications + // + a1 = SimplifyTerm(CreateTerm(BVUMINUS, l, a1)); + output = SimplifyTerm(CreateTerm(BVPLUS, l, a0, a1)); + } + break; + } + case BVUMINUS: + { + //important to treat BVUMINUS as a special case, because it + //helps in arithmetic transformations. e.g. x + BVUMINUS(x) is + //actually 0. One way to reveal this fact is to strip bvuminus + //out, and replace with something else so that combineliketerms + //can catch this fact. + ASTNode a0 = SimplifyTerm(inputterm[0]); + Kind k1 = a0.GetKind(); + unsigned int l = a0.GetValueWidth(); + ASTNode one = CreateOneConst(l); + switch (k1) + { + case BVUMINUS: + output = a0[0]; + break; + case BVCONST: + { + output = BVConstEvaluator(CreateTerm(BVUMINUS, l, a0)); + break; + } + case BVNEG: + { + output = SimplifyTerm(CreateTerm(BVPLUS, l, a0[0], one)); + break; + } + case BVMULT: + { + if (BVUMINUS == a0[0].GetKind()) + { + output = CreateTerm(BVMULT, l, a0[0][0], a0[1]); + } + else if (BVUMINUS == a0[1].GetKind()) + { + output = CreateTerm(BVMULT, l, a0[0], a0[1][0]); + } + else + { + ASTNode a00 = SimplifyTerm(CreateTerm(BVUMINUS, l, a0[0])); + output = CreateTerm(BVMULT, l, a00, a0[1]); + } + break; + } + case BVPLUS: + { + //push BVUMINUS over all the monomials of BVPLUS. Simplify + //along the way + // + //BVUMINUS(a1x1 + a2x2 + ...) <=> BVPLUS(BVUMINUS(a1x1) + + //BVUMINUS(a2x2) + ... + ASTVec c = a0.GetChildren(); + ASTVec o; + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + //Simplify(BVUMINUS(a1x1)) + ASTNode aaa = SimplifyTerm(CreateTerm(BVUMINUS, l, *it)); + o.push_back(aaa); + } + //simplify the bvplus + output = SimplifyTerm(CreateTerm(BVPLUS, l, o)); + break; + } + case BVSUB: + { + //BVUMINUS(BVSUB(x,y)) <=> BVSUB(y,x) + output = SimplifyTerm(CreateTerm(BVSUB, l, a0[1], a0[0])); + break; + } + case ITE: + { + //BVUMINUS(ITE(c,t1,t2)) <==> ITE(c,BVUMINUS(t1),BVUMINUS(t2)) + ASTNode c = a0[0]; + ASTNode t1 = SimplifyTerm(CreateTerm(BVUMINUS, l, a0[1])); + ASTNode t2 = SimplifyTerm(CreateTerm(BVUMINUS, l, a0[2])); + output = CreateSimplifiedTermITE(c, t1, t2); + break; + } + default: + { + output = CreateTerm(BVUMINUS, l, a0); + break; + } + } + break; + } + case BVEXTRACT: + { + //it is important to take care of wordlevel transformation in + //BVEXTRACT. it exposes oppurtunities for later simplification + //and solving (variable elimination) + ASTNode a0 = SimplifyTerm(inputterm[0]); + Kind k1 = a0.GetKind(); + unsigned int a_len = inputValueWidth; + + //indices for BVEXTRACT + ASTNode i = inputterm[1]; + ASTNode j = inputterm[2]; + ASTNode zero = CreateBVConst(32, 0); + //recall that the indices of BVEXTRACT are always 32 bits + //long. therefore doing a GetBVUnsigned is ok. + unsigned int i_val = GetUnsignedConst(i); + unsigned int j_val = GetUnsignedConst(j); + + // a0[i:0] and len(a0)=i+1, then return a0 + if (0 == j_val && a_len == a0.GetValueWidth()) + return a0; + + switch (k1) + { + case BVCONST: + { + //extract the constant + output = BVConstEvaluator(CreateTerm(BVEXTRACT, a_len, a0, i, j)); + break; + } + case BVCONCAT: + { + //assumes concatenation is binary + // + //input is of the form a0[i:j] + // + //a0 is the conatentation t@u, and a0[0] is t, and a0[1] is u + ASTNode t = a0[0]; + ASTNode u = a0[1]; + unsigned int len_a0 = a0.GetValueWidth(); + unsigned int len_u = u.GetValueWidth(); + + if (len_u > i_val) + { + //Apply the following rule: + // (t@u)[i:j] <==> u[i:j], if len(u) > i + // + output = SimplifyTerm(CreateTerm(BVEXTRACT, a_len, u, i, j)); + } + else if (len_a0 > i_val && j_val >= len_u) + { + //Apply the rule: + // (t@u)[i:j] <==> t[i-len_u:j-len_u], if len(t@u) > i >= j >= len(u) + i = CreateBVConst(32, i_val - len_u); + j = CreateBVConst(32, j_val - len_u); + output = SimplifyTerm(CreateTerm(BVEXTRACT, a_len, t, i, j)); + } + else + { + //Apply the rule: + // (t@u)[i:j] <==> t[i-len_u:0] @ u[len_u-1:j] + i = CreateBVConst(32, i_val - len_u); + ASTNode m = CreateBVConst(32, len_u - 1); + t = SimplifyTerm(CreateTerm(BVEXTRACT, i_val - len_u + 1, t, i, zero)); + u = SimplifyTerm(CreateTerm(BVEXTRACT, len_u - j_val, u, m, j)); + output = CreateTerm(BVCONCAT, a_len, t, u); + } + break; + } + case BVPLUS: + case BVMULT: + { + // (BVMULT(n,t,u))[i:j] <==> BVMULT(i+1,t[i:0],u[i:0])[i:j] + //similar rule for BVPLUS + ASTVec c = a0.GetChildren(); + ASTVec o; + for (ASTVec::iterator jt = c.begin(), jtend = c.end(); jt != jtend; jt++) + { + ASTNode aaa = *jt; + aaa = SimplifyTerm(CreateTerm(BVEXTRACT, i_val + 1, aaa, i, zero)); + o.push_back(aaa); + } + output = CreateTerm(a0.GetKind(), i_val + 1, o); + if (j_val != 0) + { + //add extraction only if j is not zero + output = CreateTerm(BVEXTRACT, a_len, output, i, j); + } + break; + } + case BVAND: + case BVOR: + case BVXOR: + { + //assumes these operators are binary + // + // (t op u)[i:j] <==> t[i:j] op u[i:j] + ASTNode t = a0[0]; + ASTNode u = a0[1]; + t = SimplifyTerm(CreateTerm(BVEXTRACT, a_len, t, i, j)); + u = SimplifyTerm(CreateTerm(BVEXTRACT, a_len, u, i, j)); + BVTypeCheck(t); + BVTypeCheck(u); + output = CreateTerm(k1, a_len, t, u); + break; + } + case BVNEG: + { + // (~t)[i:j] <==> ~(t[i:j]) + ASTNode t = a0[0]; + t = SimplifyTerm(CreateTerm(BVEXTRACT, a_len, t, i, j)); + output = CreateTerm(BVNEG, a_len, t); + break; + } + // case BVSX:{ + // //(BVSX(t,n)[i:j] <==> BVSX(t,i+1), if n >= i+1 and j=0 + // ASTNode t = a0[0]; + // unsigned int bvsx_len = a0.GetValueWidth(); + // if(bvsx_len < a_len) { + // FatalError("SimplifyTerm: BVEXTRACT over BVSX:" + // "the length of BVSX term must be greater than extract-len",inputterm); + // } + // if(j != zero) { + // output = CreateTerm(BVEXTRACT,a_len,a0,i,j); + // } + // else { + // output = CreateTerm(BVSX,a_len,t,CreateBVConst(32,a_len)); + // } + // break; + // } + case ITE: + { + ASTNode t0 = a0[0]; + ASTNode t1 = SimplifyTerm(CreateTerm(BVEXTRACT, a_len, a0[1], i, j)); + ASTNode t2 = SimplifyTerm(CreateTerm(BVEXTRACT, a_len, a0[2], i, j)); + output = CreateSimplifiedTermITE(t0, t1, t2); + break; + } + default: + { + output = CreateTerm(BVEXTRACT, a_len, a0, i, j); + break; + } + } + break; + } + case BVNEG: + { + ASTNode a0 = SimplifyTerm(inputterm[0]); + unsigned len = inputValueWidth; + switch (a0.GetKind()) + { + case BVCONST: + output = BVConstEvaluator(CreateTerm(BVNEG, len, a0)); + break; + case BVNEG: + output = a0[0]; + break; + // case ITE: { + // ASTNode cond = a0[0]; + // ASTNode thenpart = SimplifyTerm(CreateTerm(BVNEG,len,a0[1])); + // ASTNode elsepart = SimplifyTerm(CreateTerm(BVNEG,len,a0[2])); + // output = CreateSimplifiedTermITE(cond,thenpart,elsepart); + // break; + // } + default: + output = CreateTerm(BVNEG, len, a0); + break; + } + break; + } + case BVZX: + { + //a0 is the expr which is being zero extended + ASTNode a0 = SimplifyTerm(inputterm[0]); + //a1 represents the length of the term BVZX(a0) + ASTNode a1 = inputterm[1]; + //output length of the BVSX term + unsigned len = inputValueWidth; + + output = CreateTerm(BVZX, len, a0, a1); + break; + } + break; + + case BVSX: + { + //a0 is the expr which is being sign extended + ASTNode a0 = SimplifyTerm(inputterm[0]); + //a1 represents the length of the term BVSX(a0) + ASTNode a1 = inputterm[1]; + //output length of the BVSX term + unsigned len = inputValueWidth; + + if (a0.GetValueWidth() == len) + { + //nothing to signextend + return a0; + } + + switch (a0.GetKind()) + { + case BVCONST: + output = BVConstEvaluator(CreateTerm(BVSX, len, a0, a1)); + break; + case BVNEG: + output = CreateTerm(a0.GetKind(), len, CreateTerm(BVSX, len, a0[0], a1)); + break; + case BVAND: + case BVOR: + //assuming BVAND and BVOR are binary + output = CreateTerm(a0.GetKind(), len, CreateTerm(BVSX, len, a0[0], a1), CreateTerm(BVSX, len, a0[1], a1)); + break; + case BVPLUS: + { + //BVSX(m,BVPLUS(n,BVSX(t1),BVSX(t2))) <==> BVPLUS(m,BVSX(m,t1),BVSX(m,t2)) + ASTVec c = a0.GetChildren(); + bool returnflag = false; + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + if (BVSX != it->GetKind()) + { + returnflag = true; + break; + } + } + if (returnflag) + { + output = CreateTerm(BVSX, len, a0, a1); + } + else + { + ASTVec o; + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + ASTNode aaa = SimplifyTerm(CreateTerm(BVSX, len, *it, a1)); + o.push_back(aaa); + } + output = CreateTerm(a0.GetKind(), len, o); + } + break; + } + case BVSX: + { + //if you have BVSX(m,BVSX(n,a)) then you can drop the inner + //BVSX provided m is greater than n. + a0 = SimplifyTerm(a0[0]); + output = CreateTerm(BVSX, len, a0, a1); + break; + } + case ITE: + { + ASTNode cond = a0[0]; + ASTNode thenpart = SimplifyTerm(CreateTerm(BVSX, len, a0[1], a1)); + ASTNode elsepart = SimplifyTerm(CreateTerm(BVSX, len, a0[2], a1)); + output = CreateSimplifiedTermITE(cond, thenpart, elsepart); + break; + } + default: + output = CreateTerm(BVSX, len, a0, a1); + break; + } + break; + } + case BVAND: + case BVOR: + { + ASTNode max = CreateMaxConst(inputValueWidth); + ASTNode zero = CreateZeroConst(inputValueWidth); + + ASTNode identity = (BVAND == k) ? max : zero; + ASTNode annihilator = (BVAND == k) ? zero : max; + ASTVec c = FlattenOneLevel(inputterm).GetChildren(); + SortByArith(c); + ASTVec o; + bool constant = true; + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + ASTNode aaa = SimplifyTerm(*it); + if (BVCONST != aaa.GetKind()) + { + constant = false; + } + + if (aaa == annihilator) + { + output = annihilator; + return output; + } + + if (aaa != identity) + { + o.push_back(aaa); + } + } + + switch (o.size()) + { + case 0: + output = identity; + break; + case 1: + output = o[0]; + break; + default: + SortByArith(o); + output = CreateTerm(k, inputValueWidth, o); + if (constant) + { + output = BVConstEvaluator(output); + } + break; + } + break; + } + case BVCONCAT: + { + ASTNode t = SimplifyTerm(inputterm[0]); + ASTNode u = SimplifyTerm(inputterm[1]); + Kind tkind = t.GetKind(); + Kind ukind = u.GetKind(); + + if (BVCONST == tkind && BVCONST == ukind) + { + output = BVConstEvaluator(CreateTerm(BVCONCAT, inputValueWidth, t, u)); + } + else if (BVEXTRACT == tkind && BVEXTRACT == ukind && t[0] == u[0]) + { + //to handle the case x[m:n]@x[n-1:k] <==> x[m:k] + ASTNode t_hi = t[1]; + ASTNode t_low = t[2]; + ASTNode u_hi = u[1]; + ASTNode u_low = u[2]; + ASTNode c = BVConstEvaluator(CreateTerm(BVPLUS, 32, u_hi, CreateOneConst(32))); + if (t_low == c) + { + output = CreateTerm(BVEXTRACT, inputValueWidth, t[0], t_hi, u_low); + } + else + { + output = CreateTerm(BVCONCAT, inputValueWidth, t, u); + } + } + else + { + output = CreateTerm(BVCONCAT, inputValueWidth, t, u); + } + break; + } + case BVXOR: + case BVXNOR: + case BVNAND: + case BVNOR: + case BVLEFTSHIFT: + case BVRIGHTSHIFT: + case BVVARSHIFT: + case BVSRSHIFT: + case BVDIV: + case BVMOD: + { + ASTVec c = inputterm.GetChildren(); + ASTVec o; + bool constant = true; + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + ASTNode aaa = SimplifyTerm(*it); + if (BVCONST != aaa.GetKind()) + { + constant = false; + } + o.push_back(aaa); + } + output = CreateTerm(k, inputValueWidth, o); + if (constant) + output = BVConstEvaluator(output); + break; + } + case READ: + { + ASTNode out1; + //process only if not in the substitution map. simplifymap + //has been checked already + if (!CheckSubstitutionMap(inputterm, out1)) + { + if (WRITE == inputterm[0].GetKind()) + { + //get rid of all writes + ASTNode nowrites = RemoveWrites_TopLevel(inputterm); + out1 = nowrites; + } + else if (ITE == inputterm[0].GetKind()) + { + ASTNode cond = SimplifyFormula(inputterm[0][0], false); + ASTNode index = SimplifyTerm(inputterm[1]); + + ASTNode read1 = CreateTerm(READ, inputValueWidth, inputterm[0][1], index); + ASTNode read2 = CreateTerm(READ, inputValueWidth, inputterm[0][2], index); + + read1 = SimplifyTerm(read1); + read2 = SimplifyTerm(read2); + out1 = CreateSimplifiedTermITE(cond, read1, read2); + } + else + { + //arr is a SYMBOL for sure + ASTNode arr = inputterm[0]; + ASTNode index = SimplifyTerm(inputterm[1]); + out1 = CreateTerm(READ, inputValueWidth, arr, index); + } + } + //it is possible that after all the procesing the READ term + //reduces to READ(Symbol,const) and hence we should check the + //substitutionmap once again. + if (!CheckSubstitutionMap(out1, output)) + output = out1; + break; + } + case ITE: + { + ASTNode t0 = SimplifyFormula(inputterm[0], false); + ASTNode t1 = SimplifyTerm(inputterm[1]); + ASTNode t2 = SimplifyTerm(inputterm[2]); + output = CreateSimplifiedTermITE(t0, t1, t2); + break; + } + case SBVREM: + case SBVMOD: + case SBVDIV: + { + ASTVec c = inputterm.GetChildren(); + ASTVec o; + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + ASTNode aaa = SimplifyTerm(*it); + o.push_back(aaa); + } + output = CreateTerm(k, inputValueWidth, o); + break; + } + case WRITE: + default: + FatalError("SimplifyTermAux: Control should never reach here:", inputterm, k); + return inputterm; + break; + } + + return output; +} + +//At the end of each simplification call, we want the output to be +//always smaller or equal to the input in size. +void BeevMgr::CheckSimplifyInvariant(const ASTNode& a, const ASTNode& output) +{ + + if (NodeSize(a, true) + 1 < NodeSize(output, true)) + { + cerr << "lhs := " << a << endl; + cerr << "NodeSize of lhs is: " << NodeSize(a, true) << endl; + cerr << endl; + cerr << "rhs := " << output << endl; + cerr << "NodeSize of rhs is: " << NodeSize(output, true) << endl; + // FatalError("SimplifyFormula: The nodesize shoudl decrease from lhs to rhs: ",ASTUndefined); + } +} + +//this function assumes that the input is a vector of childnodes of +//a BVPLUS term. it combines like terms and returns a bvplus +//term. e.g. 1.x + 2.x is converted to 3.x +ASTNode BeevMgr::CombineLikeTerms(const ASTNode& a) +{ + if (BVPLUS != a.GetKind()) + return a; + + ASTNode output; + if (CheckSimplifyMap(a, output, false)) + { + //check memo table + //cerr << "output of SimplifyTerm Cache: " << output << endl; + return output; + } + + const ASTVec& c = a.GetChildren(); + //map from variables to vector of constants + ASTNodeToVecMap vars_to_consts; + //vector to hold constants + ASTVec constkids; + ASTVec outputvec; + + //useful constants + unsigned int len = c[0].GetValueWidth(); + ASTNode one = CreateOneConst(len); + ASTNode zero = CreateZeroConst(len); + ASTNode max = CreateMaxConst(len); + + //go over the childnodes of the input bvplus, and collect like + //terms in a map. the key of the map are the variables, and the + //values are stored in a ASTVec + for (ASTVec::const_iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + ASTNode aaa = *it; + if (SYMBOL == aaa.GetKind()) + { + vars_to_consts[aaa].push_back(one); + } + else if (BVMULT == aaa.GetKind() && BVUMINUS == aaa[0].GetKind() && BVCONST == aaa[0][0].GetKind()) + { + //(BVUMINUS(c))*(y) <==> compute(BVUMINUS(c))*y + ASTNode compute_const = BVConstEvaluator(aaa[0]); + vars_to_consts[aaa[1]].push_back(compute_const); + } + else if (BVMULT == aaa.GetKind() && BVUMINUS == aaa[1].GetKind() && BVCONST == aaa[0].GetKind()) + { + //c*(BVUMINUS(y)) <==> compute(BVUMINUS(c))*y + ASTNode cccc = BVConstEvaluator(CreateTerm(BVUMINUS, len, aaa[0])); + vars_to_consts[aaa[1][0]].push_back(cccc); + } + else if (BVMULT == aaa.GetKind() && BVCONST == aaa[0].GetKind()) + { + //assumes that BVMULT is binary + vars_to_consts[aaa[1]].push_back(aaa[0]); + } + else if (BVMULT == aaa.GetKind() && BVUMINUS == aaa[0].GetKind()) + { + //(-1*x)*(y) <==> -1*(xy) + ASTNode cccc = CreateTerm(BVMULT, len, aaa[0][0], aaa[1]); + ASTVec cNodes = cccc.GetChildren(); + SortByArith(cNodes); + vars_to_consts[cccc].push_back(max); + } + else if (BVMULT == aaa.GetKind() && BVUMINUS == aaa[1].GetKind()) + { + //x*(-1*y) <==> -1*(xy) + ASTNode cccc = CreateTerm(BVMULT, len, aaa[0], aaa[1][0]); + ASTVec cNodes = cccc.GetChildren(); + SortByArith(cNodes); + vars_to_consts[cccc].push_back(max); + } + else if (BVCONST == aaa.GetKind()) + { + constkids.push_back(aaa); + } + else if (BVUMINUS == aaa.GetKind()) + { + //helps to convert BVUMINUS into a BVMULT. here the max + //constant represents -1. this transformation allows us to + //conclude that x + BVUMINUS(x) is 0. + vars_to_consts[aaa[0]].push_back(max); + } + else + vars_to_consts[aaa].push_back(one); + } //end of for loop + + //go over the map from variables to vector of values. combine the + //vector of values, multiply to the variable, and put the + //resultant monomial in the output BVPLUS. + for (ASTNodeToVecMap::iterator it = vars_to_consts.begin(), itend = vars_to_consts.end(); it != itend; it++) + { + ASTVec ccc = it->second; + + ASTNode constant; + if (1 < ccc.size()) + { + constant = CreateTerm(BVPLUS, ccc[0].GetValueWidth(), ccc); + constant = BVConstEvaluator(constant); + } + else + constant = ccc[0]; + + //constant * var + ASTNode monom; + if (zero == constant) + monom = zero; + else if (one == constant) + monom = it->first; + else + { + monom = SimplifyTerm(CreateTerm(BVMULT, constant.GetValueWidth(), constant, it->first)); + } + if (zero != monom) + { + outputvec.push_back(monom); + } + } //end of for loop + + if (constkids.size() > 1) + { + ASTNode output = CreateTerm(BVPLUS, constkids[0].GetValueWidth(), constkids); + output = BVConstEvaluator(output); + if (output != zero) + outputvec.push_back(output); + } + else if (constkids.size() == 1) + { + if (constkids[0] != zero) + outputvec.push_back(constkids[0]); + } + + if (outputvec.size() > 1) + { + output = CreateTerm(BVPLUS, len, outputvec); + } + else if (outputvec.size() == 1) + { + output = outputvec[0]; + } + else + { + output = zero; + } + + //memoize + //UpdateSimplifyMap(a,output,false); + return output; +} //end of CombineLikeTerms() + +//accepts lhs and rhs, and returns lhs - rhs = 0. The function +//assumes that lhs and rhs have already been simplified. although +//this assumption is not needed for correctness, it is essential for +//performance. The function also assumes that lhs is a BVPLUS +ASTNode BeevMgr::LhsMinusRhs(const ASTNode& eq) +{ + //if input is not an equality, simply return it + if (EQ != eq.GetKind()) + return eq; + + ASTNode lhs = eq[0]; + ASTNode rhs = eq[1]; + Kind k_lhs = lhs.GetKind(); + Kind k_rhs = rhs.GetKind(); + //either the lhs has to be a BVPLUS or the rhs has to be a + //BVPLUS + if (!(BVPLUS == k_lhs || BVPLUS == k_rhs || (BVMULT == k_lhs && BVMULT == k_rhs))) + { + return eq; + } + + ASTNode output; + if (CheckSimplifyMap(eq, output, false)) + { + //check memo table + //cerr << "output of SimplifyTerm Cache: " << output << endl; + return output; + } + + //if the lhs is not a BVPLUS, but the rhs is a BVPLUS, then swap + //the lhs and rhs + bool swap_flag = false; + if (BVPLUS != k_lhs && BVPLUS == k_rhs) + { + ASTNode swap = lhs; + lhs = rhs; + rhs = swap; + swap_flag = true; + } + + unsigned int len = lhs.GetValueWidth(); + ASTNode zero = CreateZeroConst(len); + //right is -1*(rhs): Simplify(-1*rhs) + rhs = SimplifyTerm(CreateTerm(BVUMINUS, len, rhs)); + + ASTVec lvec = lhs.GetChildren(); + ASTVec rvec = rhs.GetChildren(); + ASTNode lhsplusrhs; + if (BVPLUS != lhs.GetKind() && BVPLUS != rhs.GetKind()) + { + lhsplusrhs = CreateTerm(BVPLUS, len, lhs, rhs); + } + else if (BVPLUS == lhs.GetKind() && BVPLUS == rhs.GetKind()) + { + //combine the childnodes of the left and the right + lvec.insert(lvec.end(), rvec.begin(), rvec.end()); + lhsplusrhs = CreateTerm(BVPLUS, len, lvec); + } + else if (BVPLUS == lhs.GetKind() && BVPLUS != rhs.GetKind()) + { + lvec.push_back(rhs); + lhsplusrhs = CreateTerm(BVPLUS, len, lvec); + } + else + { + //Control should never reach here + FatalError("LhsMinusRhs: Control should never reach here\n"); + } + + //combine like terms + output = CombineLikeTerms(lhsplusrhs); + output = SimplifyTerm(output); + // + //Now make output into: lhs-rhs = 0 + output = CreateSimplifiedEQ(output, zero); + //sort if BVPLUS + if (BVPLUS == output.GetKind()) + { + ASTVec outv = output.GetChildren(); + SortByArith(outv); + output = CreateTerm(BVPLUS, len, outv); + } + + //memoize + //UpdateSimplifyMap(eq,output,false); + return output; +} //end of LhsMinusRHS() + +//THis function accepts a BVMULT(t1,t2) and distributes the mult +//over plus if either or both t1 and t2 are BVPLUSes. +// +// x*(y1 + y2 + ...+ yn) <==> x*y1 + x*y2 + ... + x*yn +// +// (y1 + y2 + ...+ yn)*x <==> x*y1 + x*y2 + ... + x*yn +// +// The function assumes that the BVPLUSes have been flattened +ASTNode BeevMgr::DistributeMultOverPlus(const ASTNode& a, bool startdistribution) +{ + if (!startdistribution) + return a; + Kind k = a.GetKind(); + if (BVMULT != k) + return a; + + ASTNode left = a[0]; + ASTNode right = a[1]; + Kind left_kind = left.GetKind(); + Kind right_kind = right.GetKind(); + + ASTNode output; + if (CheckSimplifyMap(a, output, false)) + { + //check memo table + //cerr << "output of SimplifyTerm Cache: " << output << endl; + return output; + } + + //special case optimization: c1*(c2*t1) <==> (c1*c2)*t1 + if (BVCONST == left_kind && BVMULT == right_kind && BVCONST == right[0].GetKind()) + { + ASTNode c = BVConstEvaluator(CreateTerm(BVMULT, a.GetValueWidth(), left, right[0])); + c = CreateTerm(BVMULT, a.GetValueWidth(), c, right[1]); + return c; + left = c[0]; + right = c[1]; + left_kind = left.GetKind(); + right_kind = right.GetKind(); + } + + //special case optimization: c1*(t1*c2) <==> (c1*c2)*t1 + if (BVCONST == left_kind && BVMULT == right_kind && BVCONST == right[1].GetKind()) + { + ASTNode c = BVConstEvaluator(CreateTerm(BVMULT, a.GetValueWidth(), left, right[1])); + c = CreateTerm(BVMULT, a.GetValueWidth(), c, right[0]); + return c; + left = c[0]; + right = c[1]; + left_kind = left.GetKind(); + right_kind = right.GetKind(); + } + + //atleast one of left or right have to be BVPLUS + if (!(BVPLUS == left_kind || BVPLUS == right_kind)) + { + return a; + } + + //if left is BVPLUS and right is not, then swap left and right. we + //can do this since BVMULT is communtative + ASTNode swap; + if (BVPLUS == left_kind && BVPLUS != right_kind) + { + swap = left; + left = right; + right = swap; + } + left_kind = left.GetKind(); + right_kind = right.GetKind(); + + //by this point we are gauranteed that right is a BVPLUS, but left + //may not be + ASTVec rightnodes = right.GetChildren(); + ASTVec outputvec; + unsigned len = a.GetValueWidth(); + ASTNode zero = CreateZeroConst(len); + ASTNode one = CreateOneConst(len); + if (BVPLUS != left_kind) + { + //if the multiplier is not a BVPLUS then we have a special case + // x*(y1 + y2 + ...+ yn) <==> x*y1 + x*y2 + ... + x*yn + if (zero == left) + { + outputvec.push_back(zero); + } + else if (one == left) + { + outputvec.push_back(left); + } + else + { + for (ASTVec::iterator j = rightnodes.begin(), jend = rightnodes.end(); j != jend; j++) + { + ASTNode out = SimplifyTerm(CreateTerm(BVMULT, len, left, *j)); + outputvec.push_back(out); + } + } + } + else + { + ASTVec leftnodes = left.GetChildren(); + // (x1 + x2 + ... + xm)*(y1 + y2 + ...+ yn) <==> x1*y1 + x1*y2 + + // ... + x2*y1 + ... + xm*yn + for (ASTVec::iterator i = leftnodes.begin(), iend = leftnodes.end(); i != iend; i++) + { + ASTNode multiplier = *i; + for (ASTVec::iterator j = rightnodes.begin(), jend = rightnodes.end(); j != jend; j++) + { + ASTNode out = SimplifyTerm(CreateTerm(BVMULT, len, multiplier, *j)); + outputvec.push_back(out); + } + } + } + + //compute output here + if (outputvec.size() > 1) + { + output = CombineLikeTerms(CreateTerm(BVPLUS, len, outputvec)); + output = SimplifyTerm(output); + } + else + output = SimplifyTerm(outputvec[0]); + + //memoize + //UpdateSimplifyMap(a,output,false); + return output; +} //end of distributemultoverplus() + +//converts the BVSX(len, a0) operator into ITE( check top bit, +//extend a0 by 1, extend a0 by 0) +ASTNode BeevMgr::ConvertBVSXToITE(const ASTNode& a) +{ + if (BVSX != a.GetKind()) + return a; + + ASTNode output; + if (CheckSimplifyMap(a, output, false)) + { + //check memo table + //cerr << "output of ConvertBVSXToITE Cache: " << output << endl; + return output; + } + + ASTNode a0 = a[0]; + unsigned a_len = a.GetValueWidth(); + unsigned a0_len = a0.GetValueWidth(); + + if (a0_len > a_len) + { + FatalError("Trying to sign_extend a larger BV into a smaller BV"); + return ASTUndefined; //to stop the compiler from producing bogus warnings + } + + //sign extend + unsigned extensionlen = a_len - a0_len; + if (0 == extensionlen) + { + UpdateSimplifyMap(a, output, false); + return a; + } + + std::string ones; + for (unsigned c = 0; c < extensionlen; c++) + ones += '1'; + std::string zeros; + for (unsigned c = 0; c < extensionlen; c++) + zeros += '0'; + + //string of oness of length extensionlen + BEEV::ASTNode BVOnes = CreateBVConst(ones.c_str(), 2); + //string of zeros of length extensionlen + BEEV::ASTNode BVZeros = CreateBVConst(zeros.c_str(), 2); + + //string of ones BVCONCAT a0 + BEEV::ASTNode concatOnes = CreateTerm(BEEV::BVCONCAT, a_len, BVOnes, a0); + //string of zeros BVCONCAT a0 + BEEV::ASTNode concatZeros = CreateTerm(BEEV::BVCONCAT, a_len, BVZeros, a0); + + //extract top bit of a0 + BEEV::ASTNode hi = CreateBVConst(32, a0_len - 1); + BEEV::ASTNode low = CreateBVConst(32, a0_len - 1); + BEEV::ASTNode topBit = CreateTerm(BEEV::BVEXTRACT, 1, a0, hi, low); + + //compare topBit of a0 with 0bin1 + BEEV::ASTNode condition = CreateSimplifiedEQ(CreateBVConst(1, 1), topBit); + + //ITE(topbit = 0bin1, 0bin1111...a0, 0bin000...a0) + output = CreateSimplifiedTermITE(condition, concatOnes, concatZeros); + UpdateSimplifyMap(a, output, false); + return output; +} //end of ConvertBVSXToITE() + + +ASTNode BeevMgr::RemoveWrites_TopLevel(const ASTNode& term) +{ + if (READ != term.GetKind() && WRITE != term[0].GetKind()) + { + FatalError("RemovesWrites: Input must be a READ over a WRITE", term); + } + + if (!Begin_RemoveWrites && !SimplifyWrites_InPlace_Flag && !start_abstracting) + { + return term; + } + else if (!Begin_RemoveWrites && SimplifyWrites_InPlace_Flag && !start_abstracting) + { + //return term; + return SimplifyWrites_InPlace(term); + } + else + { + return RemoveWrites(term); + } +} //end of RemoveWrites_TopLevel() + +ASTNode BeevMgr::SimplifyWrites_InPlace(const ASTNode& term) +{ + ASTNodeMultiSet WriteIndicesSeenSoFar; + bool SeenNonConstWriteIndex = false; + + if (READ != term.GetKind() && WRITE != term[0].GetKind()) + { + FatalError("RemovesWrites: Input must be a READ over a WRITE", term); + } + + ASTNode output; + if (CheckSimplifyMap(term, output, false)) + { + return output; + } + + ASTVec writeIndices, writeValues; + unsigned int width = term.GetValueWidth(); + ASTNode write = term[0]; + unsigned indexwidth = write.GetIndexWidth(); + ASTNode readIndex = SimplifyTerm(term[1]); + + do + { + ASTNode writeIndex = SimplifyTerm(write[1]); + ASTNode writeVal = SimplifyTerm(write[2]); + + //compare the readIndex and the current writeIndex and see if they + //simplify to TRUE or FALSE or UNDETERMINABLE at this stage + ASTNode compare_readwrite_indices = SimplifyFormula(CreateSimplifiedEQ(writeIndex, readIndex), false); + + //if readIndex and writeIndex are equal + if (ASTTrue == compare_readwrite_indices && !SeenNonConstWriteIndex) + { + UpdateSimplifyMap(term, writeVal, false); + return writeVal; + } + + if (!(ASTTrue == compare_readwrite_indices || ASTFalse == compare_readwrite_indices)) + { + SeenNonConstWriteIndex = true; + } + + //if (readIndex=writeIndex <=> FALSE) + if (ASTFalse == compare_readwrite_indices || (WriteIndicesSeenSoFar.find(writeIndex) != WriteIndicesSeenSoFar.end())) + { + //drop the current level write + //do nothing + } + else + { + writeIndices.push_back(writeIndex); + writeValues.push_back(writeVal); + } + + //record the write indices seen so far + //if(BVCONST == writeIndex.GetKind()) { + WriteIndicesSeenSoFar.insert(writeIndex); + //} + + //Setup the write for the new iteration, one level inner write + write = write[0]; + } while (SYMBOL != write.GetKind()); + + ASTVec::reverse_iterator it_index = writeIndices.rbegin(); + ASTVec::reverse_iterator itend_index = writeIndices.rend(); + ASTVec::reverse_iterator it_values = writeValues.rbegin(); + ASTVec::reverse_iterator itend_values = writeValues.rend(); + + //"write" must be a symbol at the control point before the + //begining of the "for loop" + + for (; it_index != itend_index; it_index++, it_values++) + { + write = CreateTerm(WRITE, width, write, *it_index, *it_values); + write.SetIndexWidth(indexwidth); + } + + output = CreateTerm(READ, width, write, readIndex); + UpdateSimplifyMap(term, output, false); + return output; +} //end of SimplifyWrites_In_Place() + +//accepts a read over a write and returns a term without the write +//READ(WRITE(A i val) j) <==> ITE(i=j,val,READ(A,j)). We use a memo +//table for this function called RemoveWritesMemoMap +ASTNode BeevMgr::RemoveWrites(const ASTNode& input) +{ + //unsigned int width = input.GetValueWidth(); + if (READ != input.GetKind() || WRITE != input[0].GetKind()) + { + FatalError("RemovesWrites: Input must be a READ over a WRITE", input); + } + + ASTNodeMap::iterator it; + ASTNode output = input; + if (CheckSimplifyMap(input, output, false)) + { + return output; + } + + if (!start_abstracting && Begin_RemoveWrites) + { + output = ReadOverWrite_To_ITE(input); + } + + if (start_abstracting) + { + ASTNode newVar; + if (!CheckSimplifyMap(input, newVar, false)) + { + newVar = NewVar(input.GetValueWidth()); + ReadOverWrite_NewName_Map[input] = newVar; + NewName_ReadOverWrite_Map[newVar] = input; + + UpdateSimplifyMap(input, newVar, false); + ASTNodeStats("New Var Name which replace Read_Over_Write: ", newVar); + } + output = newVar; + } //end of start_abstracting if condition + + //memoize + UpdateSimplifyMap(input, output, false); + return output; +} //end of RemoveWrites() + +ASTNode BeevMgr::ReadOverWrite_To_ITE(const ASTNode& term) +{ + unsigned int width = term.GetValueWidth(); + ASTNode input = term; + if (READ != term.GetKind() || WRITE != term[0].GetKind()) + { + FatalError("RemovesWrites: Input must be a READ over a WRITE", term); + } + + ASTNodeMap::iterator it; + ASTNode output; + // if(CheckSimplifyMap(term,output,false)) { + // return output; + // } + + ASTNode partialITE = term; + ASTNode writeA = ASTTrue; + ASTNode oldRead = term; + //iteratively expand read-over-write + do + { + ASTNode write = input[0]; + ASTNode readIndex = SimplifyTerm(input[1]); + //DO NOT CALL SimplifyTerm() on write[0]. You will go into an + //infinite loop + writeA = write[0]; + ASTNode writeIndex = SimplifyTerm(write[1]); + ASTNode writeVal = SimplifyTerm(write[2]); + + ASTNode cond = SimplifyFormula(CreateSimplifiedEQ(writeIndex, readIndex), false); + ASTNode newRead = CreateTerm(READ, width, writeA, readIndex); + ASTNode newRead_memoized = newRead; + if (CheckSimplifyMap(newRead, newRead_memoized, false)) + { + newRead = newRead_memoized; + } + + if (ASTTrue == cond && (term == partialITE)) + { + //found the write-value in the first iteration itself. return + //it + output = writeVal; + UpdateSimplifyMap(term, output, false); + return output; + } + + if (READ == partialITE.GetKind() && WRITE == partialITE[0].GetKind()) + { + //first iteration or (previous cond==ASTFALSE and partialITE is a "READ over WRITE") + partialITE = CreateSimplifiedTermITE(cond, writeVal, newRead); + } + else if (ITE == partialITE.GetKind()) + { + //ITE(i1 = j, v1, R(A,j)) + ASTNode ElseITE = CreateSimplifiedTermITE(cond, writeVal, newRead); + //R(W(A,i1,v1),j) <==> ITE(i1 = j, v1, R(A,j)) + UpdateSimplifyMap(oldRead, ElseITE, false); + //ITE(i2 = j, v2, R(W(A,i1,v1),j)) <==> ITE(i2 = j, v2, ITE(i1 = j, v1, R(A,j))) + partialITE = SimplifyTerm(partialITE); + } + else + { + FatalError("RemoveWrites: Control should not reach here\n"); + } + + if (ASTTrue == cond) + { + //no more iterations required + output = partialITE; + UpdateSimplifyMap(term, output, false); + return output; + } + + input = newRead; + oldRead = newRead; + } while (READ == input.GetKind() && WRITE == input[0].GetKind()); + + output = partialITE; + + //memoize + //UpdateSimplifyMap(term,output,false); + return output; +} //ReadOverWrite_To_ITE() + +//compute the multiplicative inverse of the input +ASTNode BeevMgr::MultiplicativeInverse(const ASTNode& d) +{ + ASTNode c = d; + if (BVCONST != c.GetKind()) + { + FatalError("Input must be a constant", c); + } + + if (!BVConstIsOdd(c)) + { + FatalError("MultiplicativeInverse: Input must be odd: ", c); + } + + //cerr << "input to multinverse function is: " << d << endl; + ASTNode inverse; + if (CheckMultInverseMap(d, inverse)) + { + //cerr << "found the inverse of: " << d << "and it is: " << inverse << endl; + return inverse; + } + + inverse = c; + unsigned inputwidth = c.GetValueWidth(); + +#ifdef NATIVE_C_ARITH + ASTNode one = CreateOneConst(inputwidth); + while(c != one) + { + //c = c*c + c = BVConstEvaluator(CreateTerm(BVMULT,inputwidth,c,c)); + //inverse = invsere*c + inverse = BVConstEvaluator(CreateTerm(BVMULT,inputwidth,inverse,c)); + } +#else + //Compute the multiplicative inverse of c using the extended + //euclidian algorithm + // + //create a '0' which is 1 bit long + ASTNode onebit_zero = CreateZeroConst(1); + //zero pad t0, i.e. 0 @ t0 + c = BVConstEvaluator(CreateTerm(BVCONCAT, inputwidth + 1, onebit_zero, c)); + + //construct 2^(inputwidth), i.e. a bitvector of length + //'inputwidth+1', which is max(inputwidth)+1 + // + //all 1's + ASTNode max = CreateMaxConst(inputwidth); + //zero pad max + max = BVConstEvaluator(CreateTerm(BVCONCAT, inputwidth + 1, onebit_zero, max)); + //Create a '1' which has leading zeros of length 'inputwidth' + ASTNode inputwidthplusone_one = CreateOneConst(inputwidth + 1); + //add 1 to max + max = CreateTerm(BVPLUS, inputwidth + 1, max, inputwidthplusone_one); + max = BVConstEvaluator(max); + + ASTNode zero = CreateZeroConst(inputwidth + 1); + ASTNode max_bvgt_0 = CreateNode(BVGT, max, zero); + ASTNode quotient, remainder; + ASTNode x, x1, x2; + + //x1 initialized to zero + x1 = zero; + //x2 initialized to one + x2 = CreateOneConst(inputwidth + 1); + while (ASTTrue == BVConstEvaluator(max_bvgt_0)) + { + //quotient = (c divided by max) + quotient = BVConstEvaluator(CreateTerm(BVDIV, inputwidth + 1, c, max)); + + //remainder of (c divided by max) + remainder = BVConstEvaluator(CreateTerm(BVMOD, inputwidth + 1, c, max)); + + //x = x2 - q*x1 + x = CreateTerm(BVSUB, inputwidth + 1, x2, CreateTerm(BVMULT, inputwidth + 1, quotient, x1)); + x = BVConstEvaluator(x); + + //fix the inputs to the extended euclidian algo + c = max; + max = remainder; + max_bvgt_0 = CreateNode(BVGT, max, zero); + + x2 = x1; + x1 = x; + } + + ASTNode hi = CreateBVConst(32, inputwidth - 1); + ASTNode low = CreateZeroConst(32); + inverse = CreateTerm(BVEXTRACT, inputwidth, x2, hi, low); + inverse = BVConstEvaluator(inverse); +#endif + + UpdateMultInverseMap(d, inverse); + //cerr << "output of multinverse function is: " << inverse << endl; + return inverse; +} //end of MultiplicativeInverse() + +//returns true if the input is odd +bool BeevMgr::BVConstIsOdd(const ASTNode& c) +{ + if (BVCONST != c.GetKind()) + { + FatalError("Input must be a constant", c); + } + + ASTNode zero = CreateZeroConst(1); + ASTNode hi = CreateZeroConst(32); + ASTNode low = hi; + ASTNode lowestbit = CreateTerm(BVEXTRACT, 1, c, hi, low); + lowestbit = BVConstEvaluator(lowestbit); + + if (lowestbit == zero) + { + return false; + } + else + { + return true; + } +} //end of BVConstIsOdd() + +//The big substitution function +ASTNode BeevMgr::CreateSubstitutionMap(const ASTNode& a) +{ + if (!optimize) + return a; + + ASTNode output = a; + //if the variable has been solved for, then simply return it + if (CheckSolverMap(a, output)) + return output; + + //traverse a and populate the SubstitutionMap + Kind k = a.GetKind(); + if (SYMBOL == k && BOOLEAN_TYPE == a.GetType()) + { + bool updated = UpdateSubstitutionMap(a, ASTTrue); + output = updated ? ASTTrue : a; + return output; + } + if (NOT == k && SYMBOL == a[0].GetKind()) + { + bool updated = UpdateSubstitutionMap(a[0], ASTFalse); + output = updated ? ASTTrue : a; + return output; + } + + if (IFF == k) + { + ASTVec c = a.GetChildren(); + SortByArith(c); + if (SYMBOL != c[0].GetKind() || VarSeenInTerm(c[0], SimplifyFormula_NoRemoveWrites(c[1], false))) + { + return a; + } + bool updated = UpdateSubstitutionMap(c[0], SimplifyFormula(c[1], false)); + output = updated ? ASTTrue : a; + return output; + } + + if (EQ == k) + { + //fill the arrayname readindices vector if e0 is a + //READ(Arr,index) and index is a BVCONST + ASTVec c = a.GetChildren(); + SortByArith(c); + FillUp_ArrReadIndex_Vec(c[0], c[1]); + + if (SYMBOL == c[0].GetKind() && VarSeenInTerm(c[0], SimplifyTermAux(c[1]))) + { + return a; + } + + if (1 == TermOrder(c[0], c[1]) && READ == c[0].GetKind() && VarSeenInTerm(c[0][0], SimplifyTermAux(c[1]))) + { + return a; + } + bool updated = UpdateSubstitutionMap(c[0], SimplifyTermAux(c[1])); + output = updated ? ASTTrue : a; + return output; + } + + if (AND == k) + { + ASTVec o; + ASTVec c = a.GetChildren(); + for (ASTVec::iterator it = c.begin(), itend = c.end(); it != itend; it++) + { + UpdateAlwaysTrueFormMap(*it); + ASTNode aaa = CreateSubstitutionMap(*it); + + if (ASTTrue != aaa) + { + if (ASTFalse == aaa) + return ASTFalse; + else + o.push_back(aaa); + } + } + if (o.size() == 0) + return ASTTrue; + + if (o.size() == 1) + return o[0]; + + return CreateNode(AND, o); + } + + //printf("I gave up on kind: %d node: %d\n", k, a.GetNodeNum()); + return output; +} //end of CreateSubstitutionMap() + + +bool BeevMgr::VarSeenInTerm(const ASTNode& var, const ASTNode& term) +{ + if (READ == term.GetKind() && WRITE == term[0].GetKind() && !Begin_RemoveWrites) + { + return false; + } + + if (READ == term.GetKind() && WRITE == term[0].GetKind() && Begin_RemoveWrites) + { + return true; + } + + ASTNodeMap::iterator it; + if ((it = TermsAlreadySeenMap.find(term)) != TermsAlreadySeenMap.end()) + { + if (it->second == var) + { + return false; + } + } + + if (var == term) + { + return true; + } + + for (ASTVec::const_iterator it = term.begin(), itend = term.end(); it != itend; it++) + { + if (VarSeenInTerm(var, *it)) + { + return true; + } + else + { + TermsAlreadySeenMap[*it] = var; + } + } + + TermsAlreadySeenMap[term] = var; + return false; +} + +// in ext/hash_map, and tr/unordered_map, there is no provision to shrink down +// the number of buckets in a hash map. If the hash_map has previously held a +// lot of data, then it will have a lot of buckets. Slowing down iterators and +// clears() in particular. +void BeevMgr::ResetSimplifyMaps() +{ + delete SimplifyMap; + SimplifyMap = new ASTNodeMap(INITIAL_SIMPLIFY_MAP_SIZE); + + delete SimplifyNegMap; + SimplifyNegMap = new ASTNodeMap(INITIAL_SIMPLIFY_MAP_SIZE); +} + +} +;//end of namespace -- 2.47.3