From: vijay_ganesh Date: Thu, 3 Sep 2009 19:22:47 +0000 (+0000) Subject: added scripts to do emacs formatting X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=9a639ab1fea939f864d201197fe3c41c36da506e;p=francis%2Fstp.git added scripts to do emacs formatting git-svn-id: https://stp-fast-prover.svn.sourceforge.net/svnroot/stp-fast-prover/trunk/stp@174 e59a4935-1847-0410-ae03-e826735625c1 --- diff --git a/scripts/emacs-format-file b/scripts/emacs-format-file new file mode 100644 index 0000000..ba8754f --- /dev/null +++ b/scripts/emacs-format-file @@ -0,0 +1,11 @@ +;;; File: emacs-format-file +;;; Stan Warford +;;; 17 May 2006 + +(defun emacs-format-function () + "Format the whole buffer." + (c-set-style "gnu") + (indent-region (point-min) (point-max) nil) + (untabify (point-min) (point-max)) + (save-buffer) +) diff --git a/scripts/emacs-format.sh b/scripts/emacs-format.sh new file mode 100755 index 0000000..7a5a6fa --- /dev/null +++ b/scripts/emacs-format.sh @@ -0,0 +1,36 @@ +#!/bin/sh +# File: my-indent +# Opens a set of files in emacs and executes the emacs-format-function. +# Assumes the function named emacs-format-function is defined in the +# file named emacs-format-file. + +loadpath=`pwd` +if [ $# == 0 ] +then + echo "my-indent requires at least one argument." 1>&2 + echo "Usage: my-indent files-to-indent" 1>&2 + exit 1 +fi + +while [ $# -ge 1 ] +do + if [ -d $1 ] + then + echo "Argument of my-indent $1 cannot be a directory." 1>&2 + exit 1 + fi + + # Check for existence of file: + ls $1 2> /dev/null | grep $1 > /dev/null + if [ $? != 0 ] + then + echo "my-indent: $1 not found." 1>&2 + exit 1 + fi + echo "Indenting $1 with emacs in batch mode" + emacs -batch $1 -l $loadpath/scripts/emacs-format-file -f emacs-format-function + echo + shift 1 +done +exit 0 + diff --git a/src/AST/AST.cpp b/src/AST/AST.cpp index 4ecef9d..7ecd09c 100644 --- a/src/AST/AST.cpp +++ b/src/AST/AST.cpp @@ -14,1300 +14,1300 @@ 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_flag = false; -//print DAG nodes -bool print_nodes_flag = false; -//run STP in optimized mode -bool optimize_flag = 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_flag = true; -//flag to control write refinement -bool arraywrite_refinement_flag = true; -//check the counterexample against the original input to STP -bool check_counterexample_flag = false; -//construct the counterexample in terms of original variable based -//on the counterexample returned by SAT solver -bool construct_counterexample_flag = true; -bool print_counterexample_flag = false; -bool print_binary_flag = 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_flag = false; -//flag to decide whether to print "valid/invalid" or not -bool print_output_flag = false; -//print the variable order chosen by the sat solver while it is -//solving. -bool print_sat_varorder_flag = false; -//turn on word level bitvector solver -bool wordlevel_solve_flag = true; -//turn off XOR flattening -bool xor_flatten_flag = false; -//Flag to switch on the smtlib parser -bool smtlib_parser_flag = false; -//print the input back -bool print_STPinput_back_flag = false; - -// If enabled. division, mod and remainder by zero will evaluate to 1. -bool division_by_zero_returns_one = false; - -enum 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); - } -} - - - -//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() - - - -//////////////////////////////////////////////////////////////// -// 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; -} - -//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 - - int shift_amount = (sizeof(unsigned long) << 3); - while (copied + (sizeof(unsigned long) << 3) < width) - { - CONSTANTBV::BitVector_Chunk_Store(bv, shift_amount, copied, c_val); - bvconst = bvconst >> shift_amount; - c_val = (~((unsigned long) 0)) & bvconst; - copied += shift_amount; - } - 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(); -} - -// 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) -{ - if (n._int_node_ptr) - { - n._int_node_ptr->IncRef(); - } -} - -// If there is a lot of sharing in the graph, this will take a long -// time. it doesn't mark subgraphs as already having been -// typechecked. -bool BeevMgr::BVTypeCheckRecursive(const ASTNode& n) -{ - const ASTVec& c = n.GetChildren(); - - BVTypeCheck(n); - - for (ASTVec::const_iterator it = c.begin(), itend = c.end(); it != itend; it++) - BVTypeCheckRecursive(*it); - - return true; -} - - - -/* 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. - * - * If this returns, this ALWAYS returns true. If there is an error it - * will call FatalError() and abort. - */ - - -bool 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 true; - 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.GetChildren().size() !=2) - FatalError("2 params to 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); - } - if (ARRAY_TYPE != n[0].GetType()) - FatalError("First parameter to read should be an array", n[0]); - if (BITVECTOR_TYPE != n[1].GetType()) - FatalError("Second parameter to read should be a bitvector", n[1]); - break; - case WRITE: - if (n.GetChildren().size() !=3) - FatalError("3 params to 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); - if (ARRAY_TYPE != n[0].GetType()) - FatalError("First parameter to read should be an array", n[0]); - if (BITVECTOR_TYPE != n[1].GetType()) - FatalError("Second parameter to read should be a bitvector", n[1]); - if (BITVECTOR_TYPE != n[2].GetType()) - FatalError("Third parameter to read should be a bitvector", n[2]); - - 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); - } - if ((v.size() != 2)) - FatalError("BVTypeCheck:BVSX must have two arguments. The second is the new width\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); - } - if ((v.size() != 2)) - FatalError("BVTypeCheck:BVZX must have two arguments. The second is the new width\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 true; - 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; - case FOR: - //FIXME: Todo - break; - default: - FatalError("BVTypeCheck: Unrecognized kind: ", ASTUndefined); - break; - } - } - return true; -} //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_flag) - return; - - StatInfoSet.clear(); - //print node size: - cout << endl << "Printing: " << c; - if (print_nodes_flag) - { - //a.PL_Print(cout,0); - //cout << endl; - cout << a << endl; - } - cout << "Node size is: "; - cout << NodeSize(a) << endl << endl; -} - -ostream &ASTNode::LispPrint(ostream &os, int indentation) const -{ - printer::Lisp_Print(os, *this, indentation); -} - -ostream &ASTNode::LispPrint_indent(ostream &os, int indentation) const -{ - printer::Lisp_Print_indent(os, *this, indentation); -} - -ostream& ASTNode::PL_Print(ostream &os, int indentation) const -{ - printer::PL_Print(os, *this, indentation); -} - -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(); - ReferenceCount->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(); - ReferenceCount->clear(); - SolverMap.clear(); - AlwaysTrueFormMap.clear(); - _arrayread_ite.clear(); - _arrayread_symbol.clear(); - _introduced_symbols.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 << "!"; - } - printer::PL_Print(cout,vv, 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 ReferenceCount; -} + //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_flag = false; + //print DAG nodes + bool print_nodes_flag = false; + //run STP in optimized mode + bool optimize_flag = 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_flag = true; + //flag to control write refinement + bool arraywrite_refinement_flag = true; + //check the counterexample against the original input to STP + bool check_counterexample_flag = false; + //construct the counterexample in terms of original variable based + //on the counterexample returned by SAT solver + bool construct_counterexample_flag = true; + bool print_counterexample_flag = false; + bool print_binary_flag = 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_flag = false; + //flag to decide whether to print "valid/invalid" or not + bool print_output_flag = false; + //print the variable order chosen by the sat solver while it is + //solving. + bool print_sat_varorder_flag = false; + //turn on word level bitvector solver + bool wordlevel_solve_flag = true; + //turn off XOR flattening + bool xor_flatten_flag = false; + //Flag to switch on the smtlib parser + bool smtlib_parser_flag = false; + //print the input back + bool print_STPinput_back_flag = false; + + // If enabled. division, mod and remainder by zero will evaluate to 1. + bool division_by_zero_returns_one = false; + + enum 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); + } + } + + + + //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() + + + + //////////////////////////////////////////////////////////////// + // 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; + } + + //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 + + int shift_amount = (sizeof(unsigned long) << 3); + while (copied + (sizeof(unsigned long) << 3) < width) + { + CONSTANTBV::BitVector_Chunk_Store(bv, shift_amount, copied, c_val); + bvconst = bvconst >> shift_amount; + c_val = (~((unsigned long) 0)) & bvconst; + copied += shift_amount; + } + 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(); + } + + // 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) + { + if (n._int_node_ptr) + { + n._int_node_ptr->IncRef(); + } + } + + // If there is a lot of sharing in the graph, this will take a long + // time. it doesn't mark subgraphs as already having been + // typechecked. + bool BeevMgr::BVTypeCheckRecursive(const ASTNode& n) + { + const ASTVec& c = n.GetChildren(); + + BVTypeCheck(n); + + for (ASTVec::const_iterator it = c.begin(), itend = c.end(); it != itend; it++) + BVTypeCheckRecursive(*it); + + return true; + } + + + + /* 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. + * + * If this returns, this ALWAYS returns true. If there is an error it + * will call FatalError() and abort. + */ + + + bool 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 true; + 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.GetChildren().size() !=2) + FatalError("2 params to 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); + } + if (ARRAY_TYPE != n[0].GetType()) + FatalError("First parameter to read should be an array", n[0]); + if (BITVECTOR_TYPE != n[1].GetType()) + FatalError("Second parameter to read should be a bitvector", n[1]); + break; + case WRITE: + if (n.GetChildren().size() !=3) + FatalError("3 params to 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); + if (ARRAY_TYPE != n[0].GetType()) + FatalError("First parameter to read should be an array", n[0]); + if (BITVECTOR_TYPE != n[1].GetType()) + FatalError("Second parameter to read should be a bitvector", n[1]); + if (BITVECTOR_TYPE != n[2].GetType()) + FatalError("Third parameter to read should be a bitvector", n[2]); + + 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); + } + if ((v.size() != 2)) + FatalError("BVTypeCheck:BVSX must have two arguments. The second is the new width\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); + } + if ((v.size() != 2)) + FatalError("BVTypeCheck:BVZX must have two arguments. The second is the new width\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 true; + 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; + case FOR: + //FIXME: Todo + break; + default: + FatalError("BVTypeCheck: Unrecognized kind: ", ASTUndefined); + break; + } + } + return true; + } //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_flag) + return; + + StatInfoSet.clear(); + //print node size: + cout << endl << "Printing: " << c; + if (print_nodes_flag) + { + //a.PL_Print(cout,0); + //cout << endl; + cout << a << endl; + } + cout << "Node size is: "; + cout << NodeSize(a) << endl << endl; + } + + ostream &ASTNode::LispPrint(ostream &os, int indentation) const + { + printer::Lisp_Print(os, *this, indentation); + } + + ostream &ASTNode::LispPrint_indent(ostream &os, int indentation) const + { + printer::Lisp_Print_indent(os, *this, indentation); + } + + ostream& ASTNode::PL_Print(ostream &os, int indentation) const + { + printer::PL_Print(os, *this, indentation); + } + + 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(); + ReferenceCount->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(); + ReferenceCount->clear(); + SolverMap.clear(); + AlwaysTrueFormMap.clear(); + _arrayread_ite.clear(); + _arrayread_symbol.clear(); + _introduced_symbols.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 << "!"; + } + printer::PL_Print(cout,vv, 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 ReferenceCount; + } } ; // end namespace diff --git a/src/AST/AST.h b/src/AST/AST.h index 9e568b0..6caaefe 100644 --- a/src/AST/AST.h +++ b/src/AST/AST.h @@ -52,1773 +52,1773 @@ *****************************************************************************/ namespace BEEV { -using namespace std; -using namespace MINISAT; + 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; - - // 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 - const CBV GetBVConst() const; - - /*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; - ostream &LispPrint_indent(ostream &os, int indentation) const; - - - //Presentation Language Printer - ostream& PL_Print(ostream &os, int indentation = 0) 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 -{ + //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; + + // 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 + const CBV GetBVConst() const; + + /*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; + ostream &LispPrint_indent(ostream &os, int indentation) const; + + + //Presentation Language Printer + ostream& PL_Print(ostream &os, int indentation = 0) 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. + void IncRef() + { + ++_ref_count; + } + + // 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(); - 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. - void IncRef() - { - ++_ref_count; - } - - // 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? -/*************************************************************************** + // 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 -{ + ***************************************************************************/ + 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 - { + 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 */ -/***************************************************************************/ -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(print_binary_flag) { - res = CONSTANTBV::BitVector_to_Bin(_bvconst); - if (c_friendly) - { - prefix = "0b"; - } - else - { - prefix = "0bin"; - } - } - else 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 - -/*************************************************************************** - * Typedef ASTNodeMap: This is a hash table from ASTNodes to ASTNodes. - * It is very convenient for attributes that are not speed-critical - **************************************************************************/ -// These are generally useful for storing ASTNodes or attributes thereof -// Hash table from ASTNodes to ASTNodes -typedef hash_map ASTNodeMap; - -typedef hash_map ASTNodeCountMap; - - -// Function to dump contents of ASTNodeMap -ostream &operator<<(ostream &os, const ASTNodeMap &nmap); - -/*************************************************************************** + 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 */ + /***************************************************************************/ + 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(print_binary_flag) { + res = CONSTANTBV::BitVector_to_Bin(_bvconst); + if (c_friendly) + { + prefix = "0b"; + } + else + { + prefix = "0bin"; + } + } + else 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 + + /*************************************************************************** + * Typedef ASTNodeMap: This is a hash table from ASTNodes to ASTNodes. + * It is very convenient for attributes that are not speed-critical + **************************************************************************/ + // These are generally useful for storing ASTNodes or attributes thereof + // Hash table from ASTNodes to ASTNodes + typedef hash_map ASTNodeMap; + + typedef hash_map ASTNodeCountMap; + + + // 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_set ASTNodeSet; -typedef hash_multiset ASTNodeMultiSet; + typedef hash_multiset ASTNodeMultiSet; -//external parser table for declared symbols. -//FIXME: move to a more appropriate place -extern ASTNodeSet _parser_symbol_table; + //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 -{ + ***************************************************************************/ + class LispPrinter + { -public: - ASTNode _node; + public: + ASTNode _node; - // number of spaces to print before first real character of - // object. - int _indentation; + // 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) - { - } + // 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); - } - ; + friend ostream &operator<<(ostream &os, const LispPrinter &lp) + { + return lp._node.LispPrint(os, lp._indentation); + } + ; -}; //End of ListPrinter + }; //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 -{ + //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; + } -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; -} - -/*************************************************************************** - * 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; - - 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; - -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 BBRSignedShift(ASTVec& x, unsigned int shift); - 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, ASTNodeMap* VarConstMap=NULL); - ASTNode SimplifyFormula_TopLevel(const ASTNode& a, bool pushNeg); - ASTNode SimplifyTerm_TopLevel(const ASTNode& b); - - ASTNode SimplifyFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap=NULL); - ASTNode SimplifyTerm(const ASTNode& inputterm, ASTNodeMap* VarConstMap=NULL); - void CheckSimplifyInvariant(const ASTNode& a, const ASTNode& output); - void BuildReferenceCountMap(const ASTNode& b); - -private: - //memo table for simplifcation - ASTNodeMap *SimplifyMap; - ASTNodeMap *SimplifyNegMap; - ASTNodeMap SolverMap; - ASTNodeSet AlwaysTrueFormMap; - ASTNodeMap MultInverseMap; - - - // The number of direct parents of each node. i.e. the number - // of times the pointer is in "children". When we simplify we - // want to be careful sometimes about using the context of a - // node. For example, given ((x + 23) = 2), the obvious - // simplification is to join the constants. However, if there - // are lots of references to the plus node. Then each time we - // simplify, we'll create an additional plus. - // nextpoweroftwo064.smt is the motivating benchmark. The - // splitting increased the number of pluses from 1 to 65. - ASTNodeCountMap *ReferenceCount; - -public: - ASTNode SimplifyAtomicFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap=NULL); - ASTNode CreateSimplifiedEQ(const ASTNode& t1, const ASTNode& t2); - ASTNode ITEOpt_InEqs(const ASTNode& in1, ASTNodeMap* VarConstMap=NULL); - ASTNode PullUpITE(const ASTNode& in); - ASTNode RemoveContradictionsFromAND(const ASTNode& in); - 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, ASTNodeMap* VarConstMap=NULL); - ASTNode SimplifyAndOrFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap=NULL); - ASTNode SimplifyXorFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap=NULL); - ASTNode SimplifyNandFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap=NULL); - ASTNode SimplifyNorFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap=NULL); - ASTNode SimplifyImpliesFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap=NULL); - ASTNode SimplifyIffFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap=NULL); - ASTNode SimplifyIteFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap=NULL); - ASTNode SimplifyForFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap=NULL); - 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); - - int SATBased_FiniteLoop_Refinement(MINISAT::Solver& newS, const ASTNode& orig_input); - int Expand_FiniteLoop(const ASTNode& finiteloop, ASTNodeMap* ParamToCurrentValMap); - ASTNode FiniteLoop_Extract_SingleFormula(const ASTNode& finiteloop_formulabody, - ASTNodeMap* VarConstMap); - - //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); - - void printCacheStatus(); - - //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; - - //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. TransformArray should be a non-member function, - // but it accesses private elements. Move it later. - ASTNode TransformFormula_TopLevel(const ASTNode& form); - ASTNode TransformArray(const ASTNode& term); - ASTNode TransformFiniteFor(const ASTNode& form); - - - //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, ASTNodeMap* VarConstMap=NULL); - ASTNode ReadOverWrite_To_ITE(const ASTNode& term, ASTNodeMap* VarConstMap=NULL); - - 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; - - //For finiteloop construct - // - //A list of all finiteloop constructs in the input formula - ASTVec List_Of_FiniteLoops; -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 - - // NB: The boolean value is always true! - bool BVTypeCheck(const ASTNode& n); - - // Checks recursively all the way down. - bool BVTypeCheckRecursive(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); - - //Check the map passed to SimplifyTerm - bool CheckMap(ASTNodeMap* VarConstMap, const ASTNode& key, ASTNode& output); - - - //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); - ReferenceCount = new ASTNodeCountMap(INITIAL_SIMPLIFY_MAP_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 of Class CompleteCounterExample - - -/***************************************************************** - * 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(); -} + /***************************************************************************/ + /* Class LispVecPrinter:iomanipulator for printing vector of ASTNodes */ + /***************************************************************************/ + class LispVecPrinter + { -// 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(); -} + public: + const ASTVec * _vec; + // number of spaces to print before first real + // character of object. + int _indentation; -// Access node number -inline int ASTNode::GetNodeNum() const -{ - return _int_node_ptr->_node_num; -} + // Constructor to build the LispPrinter object + LispVecPrinter(const ASTVec &vec, int indentation) + { + _vec = &vec; + _indentation = indentation; + } -inline unsigned int ASTNode::GetIndexWidth() const -{ - return _int_node_ptr->_index_width; -} + 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 void ASTNode::SetIndexWidth(unsigned int iw) const -{ - _int_node_ptr->_index_width = iw; -} + /*************************************************************************** + * 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; + + 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; + + 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 BBRSignedShift(ASTVec& x, unsigned int shift); + 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; + } -inline unsigned int ASTNode::GetValueWidth() const -{ - return _int_node_ptr->_value_width; -} + // Table for DAG printing. + ASTNodeSet AlreadyPrintedSet; -inline void ASTNode::SetValueWidth(unsigned int vw) const -{ - _int_node_ptr->_value_width = vw; -} + //Tables for Presentation language printing -//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. -inline ASTNode::ASTNode(ASTInternal *in) : - _int_node_ptr(in) -{ - if (in) - in->IncRef(); -} + //Nodes seen so far + ASTNodeSet PLPrintNodeSet; -// 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. + //Map from ASTNodes to LetVars + ASTNodeMap NodeLetVarMap; -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 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(); - } -} + //This is a vector which stores the Node to LetVars pairs. It + //allows for sorted printing, as opposed to NodeLetVarMap + std::vector > NodeLetVarVec; -inline BeevMgr& ASTNode::GetBeevMgr() const -{ - return _int_node_ptr->_bm; -} + //a partial Map from ASTNodes to LetVars. Needed in order to + //correctly print shared subterms inside the LET itself + ASTNodeMap NodeLetVarMap1; -//Return the unsigned constant value of the input 'n' -inline unsigned int GetUnsignedConst(const ASTNode n) -{ - if(BVCONST != n.GetKind()){ - FatalError("GetUnsignedConst: cannot extract an "\ - "unsigned value from a non-bvconst"); + //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, ASTNodeMap* VarConstMap=NULL); + ASTNode SimplifyFormula_TopLevel(const ASTNode& a, bool pushNeg); + ASTNode SimplifyTerm_TopLevel(const ASTNode& b); + + ASTNode SimplifyFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap=NULL); + ASTNode SimplifyTerm(const ASTNode& inputterm, ASTNodeMap* VarConstMap=NULL); + void CheckSimplifyInvariant(const ASTNode& a, const ASTNode& output); + void BuildReferenceCountMap(const ASTNode& b); + + private: + //memo table for simplifcation + ASTNodeMap *SimplifyMap; + ASTNodeMap *SimplifyNegMap; + ASTNodeMap SolverMap; + ASTNodeSet AlwaysTrueFormMap; + ASTNodeMap MultInverseMap; + + + // The number of direct parents of each node. i.e. the number + // of times the pointer is in "children". When we simplify we + // want to be careful sometimes about using the context of a + // node. For example, given ((x + 23) = 2), the obvious + // simplification is to join the constants. However, if there + // are lots of references to the plus node. Then each time we + // simplify, we'll create an additional plus. + // nextpoweroftwo064.smt is the motivating benchmark. The + // splitting increased the number of pluses from 1 to 65. + ASTNodeCountMap *ReferenceCount; + + public: + ASTNode SimplifyAtomicFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap=NULL); + ASTNode CreateSimplifiedEQ(const ASTNode& t1, const ASTNode& t2); + ASTNode ITEOpt_InEqs(const ASTNode& in1, ASTNodeMap* VarConstMap=NULL); + ASTNode PullUpITE(const ASTNode& in); + ASTNode RemoveContradictionsFromAND(const ASTNode& in); + 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, ASTNodeMap* VarConstMap=NULL); + ASTNode SimplifyAndOrFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap=NULL); + ASTNode SimplifyXorFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap=NULL); + ASTNode SimplifyNandFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap=NULL); + ASTNode SimplifyNorFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap=NULL); + ASTNode SimplifyImpliesFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap=NULL); + ASTNode SimplifyIffFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap=NULL); + ASTNode SimplifyIteFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap=NULL); + ASTNode SimplifyForFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap=NULL); + 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); + + int SATBased_FiniteLoop_Refinement(MINISAT::Solver& newS, const ASTNode& orig_input); + int Expand_FiniteLoop(const ASTNode& finiteloop, ASTNodeMap* ParamToCurrentValMap); + ASTNode FiniteLoop_Extract_SingleFormula(const ASTNode& finiteloop_formulabody, + ASTNodeMap* VarConstMap); + + //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); + + void printCacheStatus(); + + //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; + + //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. TransformArray should be a non-member function, + // but it accesses private elements. Move it later. + ASTNode TransformFormula_TopLevel(const ASTNode& form); + ASTNode TransformArray(const ASTNode& term); + ASTNode TransformFiniteFor(const ASTNode& form); + + + //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, ASTNodeMap* VarConstMap=NULL); + ASTNode ReadOverWrite_To_ITE(const ASTNode& term, ASTNodeMap* VarConstMap=NULL); + + 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; + + //For finiteloop construct + // + //A list of all finiteloop constructs in the input formula + ASTVec List_Of_FiniteLoops; + 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 + + // NB: The boolean value is always true! + bool BVTypeCheck(const ASTNode& n); + + // Checks recursively all the way down. + bool BVTypeCheckRecursive(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); + + //Check the map passed to SimplifyTerm + bool CheckMap(ASTNodeMap* VarConstMap, const ASTNode& key, ASTNode& output); + + + //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); + ReferenceCount = new ASTNodeCountMap(INITIAL_SIMPLIFY_MAP_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 of Class CompleteCounterExample + + + /***************************************************************** + * 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(); } - 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"); - } + // 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. + inline ASTNode::ASTNode(ASTInternal *in) : + _int_node_ptr(in) + { + if (in) + in->IncRef(); + } + + // 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. + + 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 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 BeevMgr& ASTNode::GetBeevMgr() const + { + return _int_node_ptr->_bm; + } + + //Return the unsigned constant value of the input 'n' + inline unsigned int GetUnsignedConst(const ASTNode n) + { + if(BVCONST != n.GetKind()){ + FatalError("GetUnsignedConst: cannot extract an "\ + "unsigned value from a non-bvconst"); } - return (unsigned int) *((unsigned int *) n.GetBVConst()); -} //end of GetUnsignedConst + + 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()); + } //end of GetUnsignedConst }; // end namespace BEEV #endif diff --git a/src/AST/ASTUtil.cpp b/src/AST/ASTUtil.cpp index 435c8e0..c860d5c 100644 --- a/src/AST/ASTUtil.cpp +++ b/src/AST/ASTUtil.cpp @@ -10,42 +10,42 @@ #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; -} + 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; + //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 (stats_flag) - { + if (stats_flag) + { - 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 (!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/src/AST/ASTUtil.h b/src/AST/ASTUtil.h index e0c8827..e6df5a5 100644 --- a/src/AST/ASTUtil.h +++ b/src/AST/ASTUtil.h @@ -77,10 +77,10 @@ namespace BEEV { enum inputStatus { - NOT_DECLARED =0, // Not included in the input file / stream - TO_BE_SATISFIABLE, - TO_BE_UNSATISFIABLE, - TO_BE_UNKNOWN // Specified in the input file as unknown. + NOT_DECLARED =0, // Not included in the input file / stream + TO_BE_SATISFIABLE, + TO_BE_UNSATISFIABLE, + TO_BE_UNKNOWN // Specified in the input file as unknown. }; extern enum inputStatus input_status; @@ -110,10 +110,10 @@ namespace BEEV { // Table for storing function count stats. #ifdef TR1_UNORDERED_MAP typedef tr1::unordered_map,eqstr> function_counters; + tr1::hash,eqstr> function_counters; #else typedef hash_map,eqstr> function_counters; + hash,eqstr> function_counters; #endif void CountersAndStats(const char * functionname); @@ -121,6 +121,6 @@ namespace BEEV { //global function which accepts an integer and looks up the //corresponding ASTNode and prints a char* of that ASTNode void Convert_MINISATVar_To_ASTNode_Print(int minisat_var, - int decision, int polarity=0); + int decision, int polarity=0); }; // end namespace. #endif diff --git a/src/AST/AbstractionRefinement.cpp b/src/AST/AbstractionRefinement.cpp index 8e074dc..02375fe 100644 --- a/src/AST/AbstractionRefinement.cpp +++ b/src/AST/AbstractionRefinement.cpp @@ -13,211 +13,210 @@ namespace BEEV { - /****************************************************************** * Abstraction Refinement related functions - ******************************************************************/ - -//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_flag) - FatalError("SATBased_ArrayReadRefinement: Control should not reach here"); + ******************************************************************/ + + int BeevMgr::SATBased_ArrayReadRefinement(MINISAT::Solver& newS, + const ASTNode& q, const ASTNode& orig_input) { + //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). + + //printf("doing array read refinement\n"); + if (!arrayread_refinement_flag) + FatalError("SATBased_ArrayReadRefinement: Control should not reach here"); + + ASTVec FalseAxiomsVec, RemainingAxiomsVec; + RemainingAxiomsVec.push_back(ASTTrue); + FalseAxiomsVec.push_back(ASTTrue); + unsigned int oldFalseAxiomsSize = 0; - 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; + } - //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); - 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; - //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); - //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 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() > 0) + 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 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() > 0) - 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 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() - 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(); -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_TopLevel(writeAxiom); + FalseAxioms.push_back(writeAxiom); + } + else + { + writeAxiom = TransformFormula_TopLevel(writeAxiom); + RemainingAxioms.push_back(writeAxiom); + } + } - 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_TopLevel(writeAxiom); - FalseAxioms.push_back(writeAxiom); - } - else - { - writeAxiom = TransformFormula_TopLevel(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 = (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; + } - 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 - return 2; -} //end of SATBased_ArrayWriteRefinement - -//Expands all finite-for-loops using counterexample-guided -//abstraction-refinement. -int BeevMgr::SATBased_FiniteLoop_Refinement(MINISAT::Solver& newS, - const ASTNode& orig_input) -{ - /* - * For each 'finiteloop' in the global list 'List_Of_FiniteLoops' - * - * Expand_FiniteLoop(finiteloop); - * - * The 'Expand_FiniteLoop' function expands the 'finiteloop' in a - * counterexample-guided refinement fashion - * - * Once all the finiteloops have been expanded, we need to go back - * and recheck that every discarded constraint is true with the - * final model. A flag 'done' is set to false if atleast one - * constraint is false during model-check, and is set to true if all - * constraints are true during model-check. - * - * if the 'done' flag is true, then we terminate this refinement - * loop. - */ -} + //Expands all finite-for-loops using counterexample-guided + //abstraction-refinement. + int BeevMgr::SATBased_FiniteLoop_Refinement(MINISAT::Solver& newS, + const ASTNode& orig_input) + { + /* + * For each 'finiteloop' in the global list 'List_Of_FiniteLoops' + * + * Expand_FiniteLoop(finiteloop); + * + * The 'Expand_FiniteLoop' function expands the 'finiteloop' in a + * counterexample-guided refinement fashion + * + * Once all the finiteloops have been expanded, we need to go back + * and recheck that every discarded constraint is true with the + * final model. A flag 'done' is set to false if atleast one + * constraint is false during model-check, and is set to true if all + * constraints are true during model-check. + * + * if the 'done' flag is true, then we terminate this refinement + * loop. + */ + } -int BeevMgr::Expand_FiniteLoop(const ASTNode& finiteloop, - ASTNodeMap* ParamToCurrentValMap) { /* * 'finiteloop' is the finite loop to be expanded * @@ -267,63 +266,64 @@ int BeevMgr::Expand_FiniteLoop(const ASTNode& finiteloop, * * 3.2: We have SAT, and it is indeed a satisfying model */ + int BeevMgr::Expand_FiniteLoop(const ASTNode& finiteloop, + ASTNodeMap* ParamToCurrentValMap) { + //Make sure that the parameter is a variable + ASTNode parameter = finiteloop[0]; + int paramInit = GetUnsignedConst(finiteloop[1]); + int paramLimit = GetUnsignedConst(finiteloop[2]); + int paramIncrement = GetUnsignedConst(finiteloop[3]); + ASTNode formulabody = finiteloop[4]; + int paramCurrentValue = paramInit; - //Make sure that the parameter is a variable - ASTNode parameter = finiteloop[0]; - int paramInit = GetUnsignedConst(finiteloop[1]); - int paramLimit = GetUnsignedConst(finiteloop[2]); - int paramIncrement = GetUnsignedConst(finiteloop[3]); - ASTNode formulabody = finiteloop[4]; - int paramCurrentValue = paramInit; - - //Update ParamToCurrentValMap with parameter and its current - //value. Here paramCurrentValue is the initial value - unsigned width = 32; - (*ParamToCurrentValMap)[parameter] = CreateBVConst(32,paramCurrentValue); + //Update ParamToCurrentValMap with parameter and its current + //value. Here paramCurrentValue is the initial value + unsigned width = 32; + (*ParamToCurrentValMap)[parameter] = CreateBVConst(32,paramCurrentValue); - //Go recursively thru' all the FOR-constructs. - if(FOR == formulabody.GetKind()) { - while(paramCurrentValue < paramLimit) { - Expand_FiniteLoop(formulabody, ParamToCurrentValMap); - paramCurrentValue = paramCurrentValue + paramIncrement; + //Go recursively thru' all the FOR-constructs. + if(FOR == formulabody.GetKind()) { + while(paramCurrentValue < paramLimit) { + Expand_FiniteLoop(formulabody, ParamToCurrentValMap); + paramCurrentValue = paramCurrentValue + paramIncrement; - //Update ParamToCurrentValMap with parameter and its current - //value - // - //FIXME: Possible leak since I am not freeing the previous - //'value' for the same 'key' - (*ParamToCurrentValMap)[parameter] = CreateBVConst(32,paramCurrentValue); - } //end of While - } - else { - //Expand the leaf level FOR-construct completely - for(; - paramCurrentValue < paramLimit; - paramCurrentValue = paramCurrentValue + paramIncrement) { - ASTNode currentformula = - FiniteLoop_Extract_SingleFormula(formulabody, ParamToCurrentValMap); + //Update ParamToCurrentValMap with parameter and its current + //value + // + //FIXME: Possible leak since I am not freeing the previous + //'value' for the same 'key' + (*ParamToCurrentValMap)[parameter] = CreateBVConst(32,paramCurrentValue); + } //end of While + } + else { + //Expand the leaf level FOR-construct completely + for(; + paramCurrentValue < paramLimit; + paramCurrentValue = paramCurrentValue + paramIncrement) { + ASTNode currentformula = + FiniteLoop_Extract_SingleFormula(formulabody, ParamToCurrentValMap); - //Check the currentformula against the model, and add it to the - //SAT solver if it is false against the model + //Check the currentformula against the model, and add it to the + //SAT solver if it is false against the model - //Update ParamToCurrentValMap with parameter and its current - //value - // - //FIXME: Possible leak since I am not freeing the previous - //'value' for the same 'key' - (*ParamToCurrentValMap)[parameter] = CreateBVConst(32,paramCurrentValue); - } - } //end of else -} //end of the Expand_FiniteLoop() + //Update ParamToCurrentValMap with parameter and its current + //value + // + //FIXME: Possible leak since I am not freeing the previous + //'value' for the same 'key' + (*ParamToCurrentValMap)[parameter] = CreateBVConst(32,paramCurrentValue); + } + } //end of else + } //end of the Expand_FiniteLoop() -ASTNode BeevMgr::FiniteLoop_Extract_SingleFormula(const ASTNode& formulabody, - ASTNodeMap* VarToConstantMap) -{ - /* - * Takes a formula 'formulabody', and simplifies it against - * variable-to-constant map 'VarToConstantMap' - */ - return SimplifyFormula(formulabody, VarToConstantMap); -} //end of FiniteLoop_Extract_SingleFormula() + ASTNode BeevMgr::FiniteLoop_Extract_SingleFormula(const ASTNode& formulabody, + ASTNodeMap* VarToConstantMap) + { + /* + * Takes a formula 'formulabody', and simplifies it against + * variable-to-constant map 'VarToConstantMap' + */ + return SimplifyFormula(formulabody, VarToConstantMap); + } //end of FiniteLoop_Extract_SingleFormula() };// end of namespace BEEV diff --git a/src/AST/BitBlast.cpp b/src/AST/BitBlast.cpp index ad882b6..f18d330 100644 --- a/src/AST/BitBlast.cpp +++ b/src/AST/BitBlast.cpp @@ -21,1153 +21,1153 @@ #include "AST.h" 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. -// FIXME: Check resource limits and generate an exception when exceeded. -// FIXME: THis does a lot of unnecessary copying of vectors. -// Had to be careful not to modify memoized vectors! -// FIXME: Might be some redundant variables. - -// accepts a term, and returns a vector of bitblasted bits(ASTVec) - - -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++) - { - 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; - } - - case BVRIGHTSHIFT: - case BVSRSHIFT: - { - 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. - - if (BVRIGHTSHIFT == k) - BBRShift(children, shift); - else - BBRSignedShift(children, shift); - - result = CreateNode(BOOLVEC, children); - } - else - { - // Barrel shifter - const ASTVec& bbarg1 = BBTerm(term[0]).GetChildren(); - const ASTVec& bbarg2 = BBTerm(term[1]).GetChildren(); - - - // Signed right shift, need to copy the sign bit. - ASTNode toFill; - if (BVRIGHTSHIFT == k) - toFill = ASTFalse; - else - toFill = bbarg1.back(); - - 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], toFill, 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 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); - CBV bv = term.GetBVConst(); - for (unsigned int i = 0; i < num_bits; i++) - { - tmp_res[i] = - CONSTANTBV::BitVector_bit_test(bv, i) ? ASTTrue : ASTFalse; - } - 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); -} - -// 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; - -} - -// Stores result - x in result, destructively -void BeevMgr::BBSub(ASTVec& result, const ASTVec& y) -{ - 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; -} - -// Increment bit-blasted vector and return result. -ASTVec BeevMgr::BBInc(ASTVec& x) -{ - 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) -{ - // 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; -} - -// Compute unary minus -ASTVec BeevMgr::BBUminus(const ASTVec& x) -{ - 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; -} - -// This implements a variant of binary long division. -// q and r are "out" parameters. rwidth puts a bound on the -// 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); - } -} - -// 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; -} -// 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; -} - -// 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 -// to this by swapping args or complementing the result bit. -// FIXME: If this were done MSB first, it would enable a fast exit sometimes -// when the MSB is constant, deciding the result without looking at the rest -// 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; -} - -// Left shift by 1 within fixed field inserting zeros at LSB. -// Writes result into first argument. -// 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 within fixed field inserting zeros at LSB. -// Writes result into first argument. -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. - } -} - -// Right shift within fixed field inserting zeros at MSB. -// Writes result into first argument. -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 within fixed field copying the MSB. -// Writes result into first argument. -void BeevMgr::BBRSignedShift(ASTVec& x, unsigned int shift) -{ - // right shift x (destructively) within width. - ASTNode & MSB = x.back(); - ASTVec::iterator xend = x.end(); - ASTVec::iterator xit = x.begin(); - for (; xit < xend; xit++) - { - if (xit + shift < xend) - *xit = *(xit + shift); - else - *xit = MSB; // 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. -} - -// 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; -} - -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); -} + // extern void lpvec(ASTVec &vec); + + // FIXME: Assert no zero-length bit vectors!!! + // FIXME: Need top-level functions that create and destroy the memo tables. + // FIXME: Check resource limits and generate an exception when exceeded. + // FIXME: THis does a lot of unnecessary copying of vectors. + // Had to be careful not to modify memoized vectors! + // FIXME: Might be some redundant variables. + + // accepts a term, and returns a vector of bitblasted bits(ASTVec) + + + 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++) + { + 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; + } + + case BVRIGHTSHIFT: + case BVSRSHIFT: + { + 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. + + if (BVRIGHTSHIFT == k) + BBRShift(children, shift); + else + BBRSignedShift(children, shift); + + result = CreateNode(BOOLVEC, children); + } + else + { + // Barrel shifter + const ASTVec& bbarg1 = BBTerm(term[0]).GetChildren(); + const ASTVec& bbarg2 = BBTerm(term[1]).GetChildren(); + + + // Signed right shift, need to copy the sign bit. + ASTNode toFill; + if (BVRIGHTSHIFT == k) + toFill = ASTFalse; + else + toFill = bbarg1.back(); + + 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], toFill, 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 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); + CBV bv = term.GetBVConst(); + for (unsigned int i = 0; i < num_bits; i++) + { + tmp_res[i] = + CONSTANTBV::BitVector_bit_test(bv, i) ? ASTTrue : ASTFalse; + } + 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); + } + + // 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; + + } + + // Stores result - x in result, destructively + void BeevMgr::BBSub(ASTVec& result, const ASTVec& y) + { + 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; + } + + // Increment bit-blasted vector and return result. + ASTVec BeevMgr::BBInc(ASTVec& x) + { + 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) + { + // 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; + } + + // Compute unary minus + ASTVec BeevMgr::BBUminus(const ASTVec& x) + { + 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; + } + + // This implements a variant of binary long division. + // q and r are "out" parameters. rwidth puts a bound on the + // 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); + } + } + + // 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; + } + // 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; + } + + // 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 + // to this by swapping args or complementing the result bit. + // FIXME: If this were done MSB first, it would enable a fast exit sometimes + // when the MSB is constant, deciding the result without looking at the rest + // 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; + } + + // Left shift by 1 within fixed field inserting zeros at LSB. + // Writes result into first argument. + // 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 within fixed field inserting zeros at LSB. + // Writes result into first argument. + 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. + } + } + + // Right shift within fixed field inserting zeros at MSB. + // Writes result into first argument. + 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 within fixed field copying the MSB. + // Writes result into first argument. + void BeevMgr::BBRSignedShift(ASTVec& x, unsigned int shift) + { + // right shift x (destructively) within width. + ASTNode & MSB = x.back(); + ASTVec::iterator xend = x.end(); + ASTVec::iterator xit = x.begin(); + for (; xit < xend; xit++) + { + if (xit + shift < xend) + *xit = *(xit + shift); + else + *xit = MSB; // 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. + } + + // 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; + } + + 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); + } } // BEEV namespace diff --git a/src/AST/SimpBool.cpp b/src/AST/SimpBool.cpp index 1e06da0..ea486c0 100644 --- a/src/AST/SimpBool.cpp +++ b/src/AST/SimpBool.cpp @@ -27,480 +27,480 @@ static bool _disable_simpbool = 0; 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_flag) - { - 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; -} - -// 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_flag) - { - 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; -} - -// 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; -} + 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_flag) + { + 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; + } + + // 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_flag) + { + 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; + } + + // 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; + } } // BEEV namespace diff --git a/src/AST/ToCNF.cpp b/src/AST/ToCNF.cpp index 4045087..7b3b516 100644 --- a/src/AST/ToCNF.cpp +++ b/src/AST/ToCNF.cpp @@ -4,1855 +4,1855 @@ namespace BEEV { -class CNFMgr -{ + class CNFMgr + { -public: - - //######################################## - //######################################## - // constructor - - CNFMgr(BeevMgr *bmgr) - { - bm = bmgr; - } - - //######################################## - //######################################## - // destructor - - ~CNFMgr() - { - ASTNodeToASTNodePtrMap::const_iterator it1 = store.begin(); - for (; it1 != store.end(); it1++) - { - delete it1->second; - } - - store.clear(); - - } - - //######################################## - //######################################## - // 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; - } - - void DELETE(BeevMgr::ClauseList* varphi) - { - BeevMgr::ClauseList::const_iterator it = varphi->begin(); - for (; it != varphi->end(); it++) - { - delete *it; - } - - delete varphi; - } - -private: - - //######################################## - //######################################## - // 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; - } - - 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(); - psi->reserve(varphi1.size() * varphi2.size()); - - 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->reserve(clause1->size() + clause2->size()); - 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) - { - ASTVec::const_iterator it = varphi.GetChildren().begin(); - for (; it != varphi.GetChildren().end(); it++) - { - convertFormulaToCNF(*it, defs); // make pos and neg clause sets - } - BeevMgr::ClauseList* psi = convertFormulaToCNFPosXORAux(varphi, 0, defs); - info[varphi]->clausespos = psi; - ASTVec::const_iterator it2 = varphi.GetChildren().begin(); - for (; it2 != varphi.GetChildren().end(); it2++){ - reduceMemoryFootprintPos(*it2); - reduceMemoryFootprintNeg(*it2); - } - } - - 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]) - //**************************************** - 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]]); - } - - 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); - - 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]]); - } - - psi1 = PRODUCT(*(info[varphi[idx]]->clausespos), *theta1); - psi2 = PRODUCT(*(info[varphi[idx]]->clausesneg), *theta2); - DELETE(theta1); - DELETE(theta2); - NOCOPY_INPLACE_UNION(psi1, psi2); - - 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) - { - ASTVec::const_iterator it = varphi.GetChildren().begin(); - for (; it != varphi.GetChildren().end(); it++) - { - convertFormulaToCNF(*it, defs); // make pos and neg clause sets - } - BeevMgr::ClauseList* psi = convertFormulaToCNFNegXORAux(varphi, 0, defs); - info[varphi]->clausesneg = psi; - ASTVec::const_iterator it2 = varphi.GetChildren().begin(); - for (; it2 != varphi.GetChildren().end(); it2++){ - reduceMemoryFootprintPos(*it2); - reduceMemoryFootprintNeg(*it2); - } - } - - 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], defs); - renamesibs = (info[varphi[idx]]->clausespos)->size() > 1 ? true : false; - if (renamesibs) - { - setDoSibRenamingNeg(*info[varphi[idx + 1]]); - } - - 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); - - 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]]); - } - - psi1 = PRODUCT(*(info[varphi[idx]]->clausesneg), *theta1); - psi2 = PRODUCT(*(info[varphi[idx]]->clausespos), *theta2); - DELETE(theta1); - DELETE(theta2); - NOCOPY_INPLACE_UNION(psi1, psi2); - - 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; - CNFInfo* toDelete = info[varphi]; // get the thing to delete. - info.erase(varphi); // remove it from the hashtable - delete toDelete; - - - 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) -{ + public: - ASTNode q = CreateNode(AND, inputasserts, CreateNode(NOT, query)); - return TopLevelSATAux(q); -} + //######################################## + //######################################## + // constructor -//############################################################ -//############################################################ + CNFMgr(BeevMgr *bmgr) + { + bm = bmgr; + } + //######################################## + //######################################## + // destructor -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_flag) - 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_flag && print_nodes_flag) - { - 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_flag && print_nodes_flag) - { - cout << "Supposedly bogus one: \n"; - bool tmp = print_counterexample_flag; - print_counterexample_flag = true; - PrintCounterExample(true); - print_counterexample_flag = tmp; - } - - return 2; - } - } - else - { - PrintOutput(true); - return -100; - } -} //end of CALLSAT_ResultCheck + ~CNFMgr() + { + ASTNodeToASTNodePtrMap::const_iterator it1 = store.begin(); + for (; it1 != store.end(); it1++) + { + delete it1->second; + } + + store.clear(); + + } + + //######################################## + //######################################## + // 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; + } + + void DELETE(BeevMgr::ClauseList* varphi) + { + BeevMgr::ClauseList::const_iterator it = varphi->begin(); + for (; it != varphi->end(); it++) + { + delete *it; + } + + delete varphi; + } + + private: + + //######################################## + //######################################## + // 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; + } + + 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(); + psi->reserve(varphi1.size() * varphi2.size()); + + 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->reserve(clause1->size() + clause2->size()); + 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) + { + ASTVec::const_iterator it = varphi.GetChildren().begin(); + for (; it != varphi.GetChildren().end(); it++) + { + convertFormulaToCNF(*it, defs); // make pos and neg clause sets + } + BeevMgr::ClauseList* psi = convertFormulaToCNFPosXORAux(varphi, 0, defs); + info[varphi]->clausespos = psi; + ASTVec::const_iterator it2 = varphi.GetChildren().begin(); + for (; it2 != varphi.GetChildren().end(); it2++){ + reduceMemoryFootprintPos(*it2); + reduceMemoryFootprintNeg(*it2); + } + } + + 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]) + //**************************************** + 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]]); + } + + 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); + + 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]]); + } + + psi1 = PRODUCT(*(info[varphi[idx]]->clausespos), *theta1); + psi2 = PRODUCT(*(info[varphi[idx]]->clausesneg), *theta2); + DELETE(theta1); + DELETE(theta2); + NOCOPY_INPLACE_UNION(psi1, psi2); + + 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) + { + ASTVec::const_iterator it = varphi.GetChildren().begin(); + for (; it != varphi.GetChildren().end(); it++) + { + convertFormulaToCNF(*it, defs); // make pos and neg clause sets + } + BeevMgr::ClauseList* psi = convertFormulaToCNFNegXORAux(varphi, 0, defs); + info[varphi]->clausesneg = psi; + ASTVec::const_iterator it2 = varphi.GetChildren().begin(); + for (; it2 != varphi.GetChildren().end(); it2++){ + reduceMemoryFootprintPos(*it2); + reduceMemoryFootprintNeg(*it2); + } + } + + 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], defs); + renamesibs = (info[varphi[idx]]->clausespos)->size() > 1 ? true : false; + if (renamesibs) + { + setDoSibRenamingNeg(*info[varphi[idx + 1]]); + } + + 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); + + 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]]); + } + + psi1 = PRODUCT(*(info[varphi[idx]]->clausesneg), *theta1); + psi2 = PRODUCT(*(info[varphi[idx]]->clausespos), *theta2); + DELETE(theta1); + DELETE(theta2); + NOCOPY_INPLACE_UNION(psi1, psi2); + + 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; + CNFInfo* toDelete = info[varphi]; // get the thing to delete. + info.erase(varphi); // remove it from the hashtable + delete toDelete; + + + 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_flag) + 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_flag && print_nodes_flag) + { + 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_flag && print_nodes_flag) + { + cout << "Supposedly bogus one: \n"; + bool tmp = print_counterexample_flag; + print_counterexample_flag = true; + PrintCounterExample(true); + print_counterexample_flag = tmp; + } + + return 2; + } + } + else + { + PrintOutput(true); + return -100; + } + } //end of CALLSAT_ResultCheck } // end namespace diff --git a/src/AST/ToSAT.cpp b/src/AST/ToSAT.cpp index 6e67b1d..6d5265d 100644 --- a/src/AST/ToSAT.cpp +++ b/src/AST/ToSAT.cpp @@ -13,1303 +13,1303 @@ 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(); - 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_flag) - return; - double cpu_time = MINISAT::cpuTime(); - uint64_t mem_used = MINISAT::memUsed(); - reportf("restarts : %llu\n", s.starts); - reportf("conflicts : %llu (%.0f /sec)\n", s.conflicts , s.conflicts /cpu_time); - reportf("decisions : %llu (%.0f /sec)\n", s.decisions , s.decisions /cpu_time); - reportf("propagations : %llu (%.0f /sec)\n", s.propagations, s.propagations/cpu_time); - reportf("conflict literals : %llu (%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_flag && print_nodes_flag)) - 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); - } - 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; - } - - } - } - - 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_flag) - 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; - } - } - } - } - } - } - - //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); - } - 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); - } - - - if (WRITE == arrName.GetKind()) //READ over a WRITE - { - 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); - assert(ArrayReadFlag || (BVCONST == rtterm.GetKind())); - return rtterm; - } - else if (ITE == arrName.GetKind()) //READ over an ITE - { - // The "then" and "else" branch are arrays. - ASTNode indexVal = TermToConstTermUsingModel(index, ArrayReadFlag); - - ASTNode condcompute = ComputeFormulaUsingModel(arrName[0]); // Get the truth value. - if (ASTTrue == condcompute) - { - const ASTNode & result = TermToConstTermUsingModel(CreateTerm(READ, arrName.GetValueWidth(), arrName[1], indexVal), ArrayReadFlag); - assert(ArrayReadFlag || (BVCONST == result.GetKind())); - return result; - } - else if (ASTFalse == condcompute) - { - const ASTNode & result = TermToConstTermUsingModel(CreateTerm(READ, arrName.GetValueWidth(), arrName[2], indexVal), ArrayReadFlag); - assert(ArrayReadFlag || (BVCONST == result.GetKind())); - return result; - } - else - { - cerr << "TermToConstTermUsingModel: termITE: value of conditional is wrong: " << condcompute << endl; - FatalError(" TermToConstTermUsingModel: termITE: cannot compute ITE conditional against model: ", term); - } - FatalError("bn23143 Never Here"); - } - - 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; - } - } - - assert(ArrayReadFlag || (BVCONST == output.GetKind())); - - //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; -} //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_flag) - { - 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_flag) - { - 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_flag) - { - 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; - } - } - //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_flag) - 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_flag) - 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"; - } - } - } - 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 - -//################################################## -//################################################## - - -void BeevMgr::printCacheStatus() -{ - cerr << SimplifyMap->size() << endl; - cerr << SimplifyNegMap->size() << endl; - cerr << ReferenceCount->size() << endl; - cerr << TermsAlreadySeenMap.size() << endl; - - cerr << SimplifyMap->bucket_count() << endl; - cerr << SimplifyNegMap->bucket_count() << endl; - cerr << ReferenceCount->bucket_count() << endl; - cerr << TermsAlreadySeenMap.bucket_count() << endl; - - - -} - -// 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_flag) ? 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_TopLevel(newq); - ASTNodeStats("after transformation: ", newq); - TermsAlreadySeenMap.clear(); - - //if(stats_flag) - // printCacheStatus(); - - int res; - //solver instantiated here - MINISAT::Solver newS; - //MINISAT::SimpSolver newS; - //MINISAT::UnsoundSimpSolver newS; - if (arrayread_refinement_flag) - { - 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("TopLevelSATAux: 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 - -/******************************************************************* - * Helper Functions - *******************************************************************/ -//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); -} - -//This function prints the output of the STP solver -void BeevMgr::PrintOutput(bool true_iff_valid) -{ + /* 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(); + 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_flag) + return; + double cpu_time = MINISAT::cpuTime(); + uint64_t mem_used = MINISAT::memUsed(); + reportf("restarts : %llu\n", s.starts); + reportf("conflicts : %llu (%.0f /sec)\n", s.conflicts , s.conflicts /cpu_time); + reportf("decisions : %llu (%.0f /sec)\n", s.decisions , s.decisions /cpu_time); + reportf("propagations : %llu (%.0f /sec)\n", s.propagations, s.propagations/cpu_time); + reportf("conflict literals : %llu (%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_flag && print_nodes_flag)) + 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); + } + 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; + } + + } + } + + 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_flag) + 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; + } + } + } + } + } + } + + //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); + } + 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); + } + + + if (WRITE == arrName.GetKind()) //READ over a WRITE + { + 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); + assert(ArrayReadFlag || (BVCONST == rtterm.GetKind())); + return rtterm; + } + else if (ITE == arrName.GetKind()) //READ over an ITE + { + // The "then" and "else" branch are arrays. + ASTNode indexVal = TermToConstTermUsingModel(index, ArrayReadFlag); + + ASTNode condcompute = ComputeFormulaUsingModel(arrName[0]); // Get the truth value. + if (ASTTrue == condcompute) + { + const ASTNode & result = TermToConstTermUsingModel(CreateTerm(READ, arrName.GetValueWidth(), arrName[1], indexVal), ArrayReadFlag); + assert(ArrayReadFlag || (BVCONST == result.GetKind())); + return result; + } + else if (ASTFalse == condcompute) + { + const ASTNode & result = TermToConstTermUsingModel(CreateTerm(READ, arrName.GetValueWidth(), arrName[2], indexVal), ArrayReadFlag); + assert(ArrayReadFlag || (BVCONST == result.GetKind())); + return result; + } + else + { + cerr << "TermToConstTermUsingModel: termITE: value of conditional is wrong: " << condcompute << endl; + FatalError(" TermToConstTermUsingModel: termITE: cannot compute ITE conditional against model: ", term); + } + FatalError("bn23143 Never Here"); + } + + 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; + } + } + + assert(ArrayReadFlag || (BVCONST == output.GetKind())); + + //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; + } //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_flag) + { + 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_flag) + { + 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_flag) + { + 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; + } + } + //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_flag) + 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_flag) + 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"; + } + } + } + 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 + + //################################################## + //################################################## + + + void BeevMgr::printCacheStatus() + { + cerr << SimplifyMap->size() << endl; + cerr << SimplifyNegMap->size() << endl; + cerr << ReferenceCount->size() << endl; + cerr << TermsAlreadySeenMap.size() << endl; + + cerr << SimplifyMap->bucket_count() << endl; + cerr << SimplifyNegMap->bucket_count() << endl; + cerr << ReferenceCount->bucket_count() << endl; + cerr << TermsAlreadySeenMap.bucket_count() << endl; + + + + } + + // 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_flag) ? 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_TopLevel(newq); + ASTNodeStats("after transformation: ", newq); + TermsAlreadySeenMap.clear(); + + //if(stats_flag) + // printCacheStatus(); + + int res; + //solver instantiated here + MINISAT::Solver newS; + //MINISAT::SimpSolver newS; + //MINISAT::UnsoundSimpSolver newS; + if (arrayread_refinement_flag) + { + 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("TopLevelSATAux: 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 + + /******************************************************************* + * Helper Functions + *******************************************************************/ + //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); + } + + //This function prints the output of the STP solver + void BeevMgr::PrintOutput(bool true_iff_valid) + { + if (print_output_flag) + { + if (smtlib_parser_flag) + { + 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_flag) - { - if (smtlib_parser_flag) - { - 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_flag) - { - if (smtlib_parser_flag) - cout << "unsat\n"; - else - cout << "Valid.\n"; - } - } - else - { - ValidFlag = false; - if (print_output_flag) - { - if (smtlib_parser_flag) - cout << "sat\n"; - else - cout << "Invalid.\n"; - } - } -} + { + if (smtlib_parser_flag) + cout << "unsat\n"; + else + cout << "Valid.\n"; + } + } + else + { + ValidFlag = false; + if (print_output_flag) + { + if (smtlib_parser_flag) + cout << "sat\n"; + else + cout << "Invalid.\n"; + } + } + } } ; //end of namespace BEEV diff --git a/src/AST/Transform.cpp b/src/AST/Transform.cpp index 84b3988..11265b0 100644 --- a/src/AST/Transform.cpp +++ b/src/AST/Transform.cpp @@ -22,603 +22,603 @@ namespace BEEV { -ASTNode TransformFormula(const ASTNode& form); -ASTNode TranslateSignedDivModRem(const ASTNode& in); -ASTNode TransformTerm(const ASTNode& inputterm); -void assertTransformPostConditions(const ASTNode & term); - -ASTNodeMap* TransformMap; - -const bool debug_transform = false; - -// NB: This is the only function that should be called externally. It sets -// up the cache that the others use. -ASTNode BeevMgr::TransformFormula_TopLevel(const ASTNode& form) -{ - assert(TransformMap == NULL); - TransformMap = new ASTNodeMap(100); - ASTNode result = TransformFormula(form); - if (debug_transform) - assertTransformPostConditions(result); - TransformMap->clear(); - delete TransformMap; - TransformMap = NULL; - return result; -} - -//Translates signed BVDIV,BVMOD and BVREM into unsigned variety -ASTNode TranslateSignedDivModRem(const ASTNode& in) -{ - BeevMgr& bm = in.GetBeevMgr(); - assert(in.GetChildren().size() ==2); - - ASTNode dividend = in[0]; - ASTNode divisor = in[1]; - unsigned len = in.GetValueWidth(); - - ASTNode hi1 = bm.CreateBVConst(32, len - 1); - ASTNode one = bm.CreateOneConst(1); - ASTNode zero = bm.CreateZeroConst(1); - // create the condition for the dividend - ASTNode cond_dividend = bm.CreateNode(EQ, one, bm.CreateTerm(BVEXTRACT, 1, dividend, hi1, hi1)); - // create the condition for the divisor - ASTNode cond_divisor = bm.CreateNode(EQ, one, bm.CreateTerm(BVEXTRACT, 1, divisor, hi1, hi1)); - - if (SBVREM == in.GetKind()) - { - //BVMOD is an expensive operation. So have the fewest bvmods possible. Just one. - - //Take absolute value. - ASTNode pos_dividend = bm.CreateTerm(ITE, len, cond_dividend, bm.CreateTerm(BVUMINUS, len, dividend), dividend); - ASTNode pos_divisor = bm.CreateTerm(ITE, len, cond_divisor, bm.CreateTerm(BVUMINUS, len, divisor), divisor); - - //create the modulus term - ASTNode modnode = bm.CreateTerm(BVMOD, len, pos_dividend, pos_divisor); - - //If the dividend is <0 take the unary minus. - ASTNode n = bm.CreateTerm(ITE, len, cond_dividend, bm.CreateTerm(BVUMINUS, len, modnode), modnode); - - //put everything together, simplify, and return - return bm.SimplifyTerm_TopLevel(n); - } - - // This is the modulus of dividing rounding to -infinity. - // Except if the signs are different, and it perfectly divides - // the modulus is the divisor (not zero). - else 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))))))) - - //Take absolute value. - ASTNode pos_dividend = bm.CreateTerm(ITE, len, cond_dividend, bm.CreateTerm(BVUMINUS, len, dividend), dividend); - ASTNode pos_divisor = bm.CreateTerm(ITE, len, cond_divisor, bm.CreateTerm(BVUMINUS, len, divisor), divisor); - - ASTNode urem_node = bm.CreateTerm(BVMOD, len, pos_dividend, pos_divisor); - - // If the dividend is <0, then we negate the whole thing. - ASTNode rev_node = bm.CreateTerm(ITE, len, cond_dividend, bm.CreateTerm(BVUMINUS, len, urem_node), urem_node); - - // if It's XOR <0 then add t (not its absolute value). - ASTNode xor_node = bm.CreateNode(XOR, cond_dividend, cond_divisor); - ASTNode n = bm.CreateTerm(ITE, len, xor_node, bm.CreateTerm(BVPLUS, len, rev_node, divisor), rev_node); - - return bm.SimplifyTerm_TopLevel(n); - } - else if (SBVDIV == in.GetKind()) - { - //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) - - //Take absolute value. - ASTNode pos_dividend = bm.CreateTerm(ITE, len, cond_dividend, bm.CreateTerm(BVUMINUS, len, dividend), dividend); - ASTNode pos_divisor = bm.CreateTerm(ITE, len, cond_divisor, bm.CreateTerm(BVUMINUS, len, divisor), divisor); - - ASTNode divnode = bm.CreateTerm(BVDIV, len, pos_dividend, pos_divisor); - - // A little confusing. Only negate the result if they are XOR <0. - ASTNode xor_node = bm.CreateNode(XOR, cond_dividend, cond_divisor); - ASTNode n = bm.CreateTerm(ITE, len, xor_node, bm.CreateTerm(BVUMINUS, len, divnode), divnode); - - return bm.SimplifyTerm_TopLevel(n); - } - - FatalError("TranslateSignedDivModRem: input must be signed DIV/MOD/REM", in); - return bm.CreateNode(UNDEFINED); - -}//end of TranslateSignedDivModRem() - -// Check that the transformations have occurred. -void assertTransformPostConditions(const ASTNode & term) -{ - const Kind k = term.GetKind(); - - // Check the signed operations have been removed. - assert( SBVDIV != k); - assert( SBVMOD != k); - assert( SBVREM !=k); - - // Check the array reads / writes have been removed - assert( READ !=k ); - assert( WRITE !=k); - - // There should be no nodes left of type array. - assert(0 == term.GetIndexWidth()); - - ASTVec c = term.GetChildren(); - ASTVec::iterator it = c.begin(); - ASTVec::iterator itend = c.end(); - ASTVec o; - for (; it != itend; it++) - { - assertTransformPostConditions(*it); - } -} - -ASTNode TransformFormula(const ASTNode& form) -{ - BeevMgr& bm = form.GetBeevMgr(); - - assert(TransformMap != null); - - 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 = bm.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 = bm.CreateNode(k, c); - break; - } - case EQ: - { - ASTNode term1 = TransformTerm(simpleForm[0]); - ASTNode term2 = TransformTerm(simpleForm[1]); - result = bm.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 = bm.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: ", bm.CreateNode(UNDEFINED), k); - } - break; - } - - if (simpleForm.GetChildren().size() > 0) - (*TransformMap)[simpleForm] = result; - return result; -} //End of TransformFormula - -ASTNode TransformTerm(const ASTNode& inputterm) -{ - assert(TransformMap != null); - - BeevMgr& bm = inputterm.GetBeevMgr(); - - 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 = bm.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 = bm.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 = bm.CreateTerm(k, width, o); - result.SetIndexWidth(indexwidth); - - Kind k = result.GetKind(); - - if (BVDIV == k || BVMOD == k || SBVDIV == k || SBVREM == k || SBVMOD == k) - { - ASTNode bottom = result[1]; - - if (SBVDIV == result.GetKind() || SBVREM == result.GetKind() || SBVMOD == result.GetKind()) - { - result = TranslateSignedDivModRem(result); - } - - if (division_by_zero_returns_one) - { - // This is a difficult rule to introduce in other places because it's recursive. i.e. - // result is embedded unchanged inside the result. - - unsigned inputValueWidth = result.GetValueWidth(); - ASTNode zero = bm.CreateZeroConst(inputValueWidth); - ASTNode one = bm.CreateOneConst(inputValueWidth); - result = bm.CreateTerm(ITE, inputValueWidth, bm.CreateNode(EQ, zero, bottom), one, result); - } - } - } - //////////////////////////////////////////////////////////////////////////////////// - - - break; - } - - if (term.GetChildren().size() > 0) - (*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) - * - */ -ASTNode BeevMgr::TransformArray(const ASTNode& term) -{ - assert(TransformMap != null); - - ASTNode result = term; - - const unsigned int width = term.GetValueWidth(); - - if (READ != term.GetKind()) - FatalError("TransformArray: input term is of wrong kind: ", ASTUndefined); - - ASTNodeMap::iterator iter; - if ((iter = TransformMap->find(term)) != TransformMap->end()) - return iter->second; - - //'term' is of the form READ(arrName, readIndex) - const ASTNode & arrName = term[0]; - const ASTNode & readIndex = TransformTerm(term[1]); - - 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 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. - const ASTVec & readIndices = _arrayname_readindices[arrName]; - - //construct the ITE structure for this array-read - ASTNode ite = CurrentSymbol; - _introduced_symbols.insert(CurrentSymbol); - assert(BVTypeCheck(ite)); - - if (arrayread_refinement_flag) - { - // ite is really a variable here; it is an ite in the - // else-branch - result = ite; - } - else - { - // Full Array transform if we're not doing read refinement. - ASTVec::const_reverse_iterator it2 = readIndices.rbegin(); - ASTVec::const_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); - assert(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 writeIndex = TransformTerm(arrName[1]); - ASTNode writeVal = TransformTerm(arrName[2]); - - if (ARRAY_TYPE != arrName[0].GetType()) - FatalError("TransformArray: An array write is being attempted on a non-array:", term); - - if ((SYMBOL == arrName[0].GetKind() || WRITE == arrName[0].GetKind())) - { - ASTNode cond = CreateSimplifiedEQ(writeIndex, readIndex); - BVTypeCheck(cond); - - ASTNode readTerm = CreateTerm(READ, width, arrName[0], readIndex); - BVTypeCheck(readTerm); - - ASTNode readPushedIn = TransformArray(readTerm); - BVTypeCheck(readPushedIn); - - result = CreateSimplifiedTermITE(cond, writeVal, readPushedIn); - - BVTypeCheck(result); - } - else if (ITE == arrName[0].GetKind()) - { - // pull out the ite from the write // pushes the write through. - ASTNode writeTrue = CreateNode(WRITE, (arrName[0][1]), writeIndex, writeVal); - writeTrue.SetIndexWidth(writeIndex.GetValueWidth()); - writeTrue.SetValueWidth(writeVal.GetValueWidth()); - assert(ARRAY_TYPE == writeTrue.GetType()); - - ASTNode writeFalse = CreateNode(WRITE, (arrName[0][2]), writeIndex, writeVal); - writeFalse.SetIndexWidth(writeIndex.GetValueWidth()); - writeFalse.SetValueWidth(writeVal.GetValueWidth()); - assert(ARRAY_TYPE == writeFalse.GetType()); - - result = CreateSimplifiedTermITE(TransformFormula(arrName[0][0]), writeTrue, writeFalse); - result.SetIndexWidth(writeIndex.GetValueWidth()); - result.SetValueWidth(writeVal.GetValueWidth()); - assert(ARRAY_TYPE == result.GetType()); - - result = CreateTerm(READ, writeVal.GetValueWidth(), result, readIndex); - BVTypeCheck(result); - result = TransformArray(result); - } - else - FatalError("TransformArray: Write over bad type."); - 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)) - */ - - // pull out the ite from the read // pushes the read through. - - //(ITE cond thn els) - - ASTNode cond = arrName[0]; - cond = TransformFormula(cond); - - const ASTNode& thn = arrName[1]; - const ASTNode& els = arrName[2]; - - //(READ thn j) - ASTNode thnRead = CreateTerm(READ, width, thn, readIndex); - BVTypeCheck(thnRead); - thnRead = TransformArray(thnRead); - - //(READ els j) - ASTNode elsRead = CreateTerm(READ, width, els, readIndex); - 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; - } - - (*TransformMap)[term] = result; - return result; -} //end of TransformArray() - -ASTNode BeevMgr::TransformFiniteFor(const ASTNode& form) -{ - return form; -} + ASTNode TransformFormula(const ASTNode& form); + ASTNode TranslateSignedDivModRem(const ASTNode& in); + ASTNode TransformTerm(const ASTNode& inputterm); + void assertTransformPostConditions(const ASTNode & term); + + ASTNodeMap* TransformMap; + + const bool debug_transform = false; + + // NB: This is the only function that should be called externally. It sets + // up the cache that the others use. + ASTNode BeevMgr::TransformFormula_TopLevel(const ASTNode& form) + { + assert(TransformMap == NULL); + TransformMap = new ASTNodeMap(100); + ASTNode result = TransformFormula(form); + if (debug_transform) + assertTransformPostConditions(result); + TransformMap->clear(); + delete TransformMap; + TransformMap = NULL; + return result; + } + + //Translates signed BVDIV,BVMOD and BVREM into unsigned variety + ASTNode TranslateSignedDivModRem(const ASTNode& in) + { + BeevMgr& bm = in.GetBeevMgr(); + assert(in.GetChildren().size() ==2); + + ASTNode dividend = in[0]; + ASTNode divisor = in[1]; + unsigned len = in.GetValueWidth(); + + ASTNode hi1 = bm.CreateBVConst(32, len - 1); + ASTNode one = bm.CreateOneConst(1); + ASTNode zero = bm.CreateZeroConst(1); + // create the condition for the dividend + ASTNode cond_dividend = bm.CreateNode(EQ, one, bm.CreateTerm(BVEXTRACT, 1, dividend, hi1, hi1)); + // create the condition for the divisor + ASTNode cond_divisor = bm.CreateNode(EQ, one, bm.CreateTerm(BVEXTRACT, 1, divisor, hi1, hi1)); + + if (SBVREM == in.GetKind()) + { + //BVMOD is an expensive operation. So have the fewest bvmods possible. Just one. + + //Take absolute value. + ASTNode pos_dividend = bm.CreateTerm(ITE, len, cond_dividend, bm.CreateTerm(BVUMINUS, len, dividend), dividend); + ASTNode pos_divisor = bm.CreateTerm(ITE, len, cond_divisor, bm.CreateTerm(BVUMINUS, len, divisor), divisor); + + //create the modulus term + ASTNode modnode = bm.CreateTerm(BVMOD, len, pos_dividend, pos_divisor); + + //If the dividend is <0 take the unary minus. + ASTNode n = bm.CreateTerm(ITE, len, cond_dividend, bm.CreateTerm(BVUMINUS, len, modnode), modnode); + + //put everything together, simplify, and return + return bm.SimplifyTerm_TopLevel(n); + } + + // This is the modulus of dividing rounding to -infinity. + // Except if the signs are different, and it perfectly divides + // the modulus is the divisor (not zero). + else 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))))))) + + //Take absolute value. + ASTNode pos_dividend = bm.CreateTerm(ITE, len, cond_dividend, bm.CreateTerm(BVUMINUS, len, dividend), dividend); + ASTNode pos_divisor = bm.CreateTerm(ITE, len, cond_divisor, bm.CreateTerm(BVUMINUS, len, divisor), divisor); + + ASTNode urem_node = bm.CreateTerm(BVMOD, len, pos_dividend, pos_divisor); + + // If the dividend is <0, then we negate the whole thing. + ASTNode rev_node = bm.CreateTerm(ITE, len, cond_dividend, bm.CreateTerm(BVUMINUS, len, urem_node), urem_node); + + // if It's XOR <0 then add t (not its absolute value). + ASTNode xor_node = bm.CreateNode(XOR, cond_dividend, cond_divisor); + ASTNode n = bm.CreateTerm(ITE, len, xor_node, bm.CreateTerm(BVPLUS, len, rev_node, divisor), rev_node); + + return bm.SimplifyTerm_TopLevel(n); + } + else if (SBVDIV == in.GetKind()) + { + //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) + + //Take absolute value. + ASTNode pos_dividend = bm.CreateTerm(ITE, len, cond_dividend, bm.CreateTerm(BVUMINUS, len, dividend), dividend); + ASTNode pos_divisor = bm.CreateTerm(ITE, len, cond_divisor, bm.CreateTerm(BVUMINUS, len, divisor), divisor); + + ASTNode divnode = bm.CreateTerm(BVDIV, len, pos_dividend, pos_divisor); + + // A little confusing. Only negate the result if they are XOR <0. + ASTNode xor_node = bm.CreateNode(XOR, cond_dividend, cond_divisor); + ASTNode n = bm.CreateTerm(ITE, len, xor_node, bm.CreateTerm(BVUMINUS, len, divnode), divnode); + + return bm.SimplifyTerm_TopLevel(n); + } + + FatalError("TranslateSignedDivModRem: input must be signed DIV/MOD/REM", in); + return bm.CreateNode(UNDEFINED); + + }//end of TranslateSignedDivModRem() + + // Check that the transformations have occurred. + void assertTransformPostConditions(const ASTNode & term) + { + const Kind k = term.GetKind(); + + // Check the signed operations have been removed. + assert( SBVDIV != k); + assert( SBVMOD != k); + assert( SBVREM !=k); + + // Check the array reads / writes have been removed + assert( READ !=k ); + assert( WRITE !=k); + + // There should be no nodes left of type array. + assert(0 == term.GetIndexWidth()); + + ASTVec c = term.GetChildren(); + ASTVec::iterator it = c.begin(); + ASTVec::iterator itend = c.end(); + ASTVec o; + for (; it != itend; it++) + { + assertTransformPostConditions(*it); + } + } + + ASTNode TransformFormula(const ASTNode& form) + { + BeevMgr& bm = form.GetBeevMgr(); + + assert(TransformMap != null); + + 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 = bm.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 = bm.CreateNode(k, c); + break; + } + case EQ: + { + ASTNode term1 = TransformTerm(simpleForm[0]); + ASTNode term2 = TransformTerm(simpleForm[1]); + result = bm.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 = bm.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: ", bm.CreateNode(UNDEFINED), k); + } + break; + } + + if (simpleForm.GetChildren().size() > 0) + (*TransformMap)[simpleForm] = result; + return result; + } //End of TransformFormula + + ASTNode TransformTerm(const ASTNode& inputterm) + { + assert(TransformMap != null); + + BeevMgr& bm = inputterm.GetBeevMgr(); + + 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 = bm.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 = bm.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 = bm.CreateTerm(k, width, o); + result.SetIndexWidth(indexwidth); + + Kind k = result.GetKind(); + + if (BVDIV == k || BVMOD == k || SBVDIV == k || SBVREM == k || SBVMOD == k) + { + ASTNode bottom = result[1]; + + if (SBVDIV == result.GetKind() || SBVREM == result.GetKind() || SBVMOD == result.GetKind()) + { + result = TranslateSignedDivModRem(result); + } + + if (division_by_zero_returns_one) + { + // This is a difficult rule to introduce in other places because it's recursive. i.e. + // result is embedded unchanged inside the result. + + unsigned inputValueWidth = result.GetValueWidth(); + ASTNode zero = bm.CreateZeroConst(inputValueWidth); + ASTNode one = bm.CreateOneConst(inputValueWidth); + result = bm.CreateTerm(ITE, inputValueWidth, bm.CreateNode(EQ, zero, bottom), one, result); + } + } + } + //////////////////////////////////////////////////////////////////////////////////// + + + break; + } + + if (term.GetChildren().size() > 0) + (*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) + * + */ + ASTNode BeevMgr::TransformArray(const ASTNode& term) + { + assert(TransformMap != null); + + ASTNode result = term; + + const unsigned int width = term.GetValueWidth(); + + if (READ != term.GetKind()) + FatalError("TransformArray: input term is of wrong kind: ", ASTUndefined); + + ASTNodeMap::iterator iter; + if ((iter = TransformMap->find(term)) != TransformMap->end()) + return iter->second; + + //'term' is of the form READ(arrName, readIndex) + const ASTNode & arrName = term[0]; + const ASTNode & readIndex = TransformTerm(term[1]); + + 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 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. + const ASTVec & readIndices = _arrayname_readindices[arrName]; + + //construct the ITE structure for this array-read + ASTNode ite = CurrentSymbol; + _introduced_symbols.insert(CurrentSymbol); + assert(BVTypeCheck(ite)); + + if (arrayread_refinement_flag) + { + // ite is really a variable here; it is an ite in the + // else-branch + result = ite; + } + else + { + // Full Array transform if we're not doing read refinement. + ASTVec::const_reverse_iterator it2 = readIndices.rbegin(); + ASTVec::const_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); + assert(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 writeIndex = TransformTerm(arrName[1]); + ASTNode writeVal = TransformTerm(arrName[2]); + + if (ARRAY_TYPE != arrName[0].GetType()) + FatalError("TransformArray: An array write is being attempted on a non-array:", term); + + if ((SYMBOL == arrName[0].GetKind() || WRITE == arrName[0].GetKind())) + { + ASTNode cond = CreateSimplifiedEQ(writeIndex, readIndex); + BVTypeCheck(cond); + + ASTNode readTerm = CreateTerm(READ, width, arrName[0], readIndex); + BVTypeCheck(readTerm); + + ASTNode readPushedIn = TransformArray(readTerm); + BVTypeCheck(readPushedIn); + + result = CreateSimplifiedTermITE(cond, writeVal, readPushedIn); + + BVTypeCheck(result); + } + else if (ITE == arrName[0].GetKind()) + { + // pull out the ite from the write // pushes the write through. + ASTNode writeTrue = CreateNode(WRITE, (arrName[0][1]), writeIndex, writeVal); + writeTrue.SetIndexWidth(writeIndex.GetValueWidth()); + writeTrue.SetValueWidth(writeVal.GetValueWidth()); + assert(ARRAY_TYPE == writeTrue.GetType()); + + ASTNode writeFalse = CreateNode(WRITE, (arrName[0][2]), writeIndex, writeVal); + writeFalse.SetIndexWidth(writeIndex.GetValueWidth()); + writeFalse.SetValueWidth(writeVal.GetValueWidth()); + assert(ARRAY_TYPE == writeFalse.GetType()); + + result = CreateSimplifiedTermITE(TransformFormula(arrName[0][0]), writeTrue, writeFalse); + result.SetIndexWidth(writeIndex.GetValueWidth()); + result.SetValueWidth(writeVal.GetValueWidth()); + assert(ARRAY_TYPE == result.GetType()); + + result = CreateTerm(READ, writeVal.GetValueWidth(), result, readIndex); + BVTypeCheck(result); + result = TransformArray(result); + } + else + FatalError("TransformArray: Write over bad type."); + 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)) + */ + + // pull out the ite from the read // pushes the read through. + + //(ITE cond thn els) + + ASTNode cond = arrName[0]; + cond = TransformFormula(cond); + + const ASTNode& thn = arrName[1]; + const ASTNode& els = arrName[2]; + + //(READ thn j) + ASTNode thnRead = CreateTerm(READ, width, thn, readIndex); + BVTypeCheck(thnRead); + thnRead = TransformArray(thnRead); + + //(READ els j) + ASTNode elsRead = CreateTerm(READ, width, els, readIndex); + 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; + } + + (*TransformMap)[term] = result; + return result; + } //end of TransformArray() + + ASTNode BeevMgr::TransformFiniteFor(const ASTNode& form) + { + return form; + } } //end of namespace BEEV diff --git a/src/AST/asttest.cpp b/src/AST/asttest.cpp index f2a8c60..1baafe5 100644 --- a/src/AST/asttest.cpp +++ b/src/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/src/AST/bbtest.cpp b/src/AST/bbtest.cpp index 7fd5c95..900ddc3 100644 --- a/src/AST/bbtest.cpp +++ b/src/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/src/AST/cnftest.cpp b/src/AST/cnftest.cpp index 2c337c4..7db6166 100644 --- a/src/AST/cnftest.cpp +++ b/src/AST/cnftest.cpp @@ -8,40 +8,40 @@ using namespace BEEV; int main() { - const int size = 1; + const int size = 1; - BeevMgr *bm = new BeevMgr(); - ASTNode s1 = bm->CreateSymbol("x"); - s1.SetValueWidth(size); + 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 << "s1" << s1 << endl; + ASTNode s2 = bm->CreateSymbol("y"); + s2.SetValueWidth(size); - cout << "s2" << s2 << endl; - ASTNode s3 = bm->CreateSymbol("z"); - s3.SetValueWidth(size); + cout << "s2" << s2 << endl; + ASTNode s3 = bm->CreateSymbol("z"); + s3.SetValueWidth(size); - cout << "s3" << s3 << endl; + cout << "s3" << s3 << endl; - ASTNode bbs1 = bm->BBForm(s1); - cout << "bitblasted s1" << endl << bbs1 << endl; - bm->PrintClauseList(cout, bm->ToCNF(bbs1)); + 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 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 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; + ASTNode a4 = bm->CreateNode(EQ, s1, s2); + ASTNode bba4 = bm->BBForm(a4); + cout << "bitblasted a4 " << endl << bba4 << endl; - bm->PrintClauseList(cout, bm->ToCNF(bba4)); + bm->PrintClauseList(cout, bm->ToCNF(bba4)); } diff --git a/src/bitvec/consteval.cpp b/src/bitvec/consteval.cpp index 2a54a80..adacde6 100644 --- a/src/bitvec/consteval.cpp +++ b/src/bitvec/consteval.cpp @@ -12,559 +12,559 @@ 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); -} - -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: - case BVSRSHIFT: - { - bool msb = CONSTANTBV::BitVector_msb_(tmp0); - - 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); - - if (BVSRSHIFT == k && msb) - { - // signed shift, and the number was originally negative. - // Shift may be larger than the inputwidth. - for (unsigned int i = 0; i < min(shift, inputwidth); i++) - { - CONSTANTBV::BitVector_Bit_On(output, (inputwidth - 1 - i)); - } - assert(CONSTANTBV::BitVector_Sign(output) == -1); //must be negative. - } - - 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; - } - - // SBVREM : Result of rounding the quotient towards zero. i.e. (-10)/3, has a remainder of -1 - // SBVMOD : Result of rounding the quotient towards -infinity. i.e. (-10)/3, has a modulus of 2. - // EXCEPT THAT if it divides exactly and the signs are different, then it's equal to the dividend. - case SBVDIV: - case SBVREM: - { - CBV quotient = CONSTANTBV::BitVector_Create(inputwidth, true); - CBV remainder = CONSTANTBV::BitVector_Create(inputwidth, true); - - if (division_by_zero_returns_one && CONSTANTBV::BitVector_is_empty(tmp1)) - { - // Expecting a division by zero. Just return one. - OutputNode = CreateOneConst(outputwidth); - } - else - { - CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Divide(quotient, tmp0, tmp1, remainder); - - if (e != 0) - { - cerr << "WARNING" << endl; - FatalError((const char*) CONSTANTBV::BitVector_Error(e)); - } - - if (SBVDIV == k) - { - OutputNode = CreateBVConst(quotient, outputwidth); - CONSTANTBV::BitVector_Destroy(remainder); - } - else - { - OutputNode = CreateBVConst(remainder, outputwidth); - CONSTANTBV::BitVector_Destroy(quotient); - - } - } - break; - } - - case SBVMOD: - { - /* Definition taken from the SMTLIB website - (bvsmod s t) abbreviates - (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))))))) - */ - - assert(t[0].GetValueWidth() == t[1].GetValueWidth()); - - bool isNegativeS = CONSTANTBV::BitVector_msb_(tmp0); - bool isNegativeT = CONSTANTBV::BitVector_msb_(tmp1); - - CBV quotient = CONSTANTBV::BitVector_Create(inputwidth, true); - CBV remainder = CONSTANTBV::BitVector_Create(inputwidth, true); - tmp0 = CONSTANTBV::BitVector_Clone(tmp0); - tmp1 = CONSTANTBV::BitVector_Clone(tmp1); - - if (division_by_zero_returns_one && CONSTANTBV::BitVector_is_empty(tmp1)) - { - // Expecting a division by zero. Just return one. - OutputNode = CreateOneConst(outputwidth); - - } - else - { - if (!isNegativeS && !isNegativeT) - { - // Signs are both positive - CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Div_Pos(quotient, tmp0, tmp1, remainder); - if (e != CONSTANTBV::ErrCode_Ok) - { - cerr << "Error code was:" << e << endl; - assert(e == CONSTANTBV::ErrCode_Ok); - } - OutputNode = CreateBVConst(remainder, outputwidth); - } - else if (isNegativeS && !isNegativeT) - { - // S negative, T positive. - CBV tmp0b = CONSTANTBV::BitVector_Create(inputwidth, true); - CONSTANTBV::BitVector_Negate(tmp0b, tmp0); - - CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Div_Pos(quotient, tmp0b, tmp1, remainder); - - assert(e == CONSTANTBV::ErrCode_Ok); - - CBV remb = CONSTANTBV::BitVector_Create(inputwidth, true); - CONSTANTBV::BitVector_Negate(remb, remainder); - - bool carry = false; - CBV res = CONSTANTBV::BitVector_Create(inputwidth, true); - CONSTANTBV::BitVector_add(res, remb, tmp1, &carry); - - OutputNode = CreateBVConst(res, outputwidth); - - CONSTANTBV::BitVector_Destroy(tmp0b); - CONSTANTBV::BitVector_Destroy(remb); - CONSTANTBV::BitVector_Destroy(remainder); - } - else if (!isNegativeS && isNegativeT) - { - // If s is positive and t is negative - CBV tmp1b = CONSTANTBV::BitVector_Create(inputwidth, true); - CONSTANTBV::BitVector_Negate(tmp1b, tmp1); - - CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Div_Pos(quotient, tmp0, tmp1b, remainder); - - assert(e == CONSTANTBV::ErrCode_Ok); - - bool carry = false; - CBV res = CONSTANTBV::BitVector_Create(inputwidth, true); - CONSTANTBV::BitVector_add(res, remainder, tmp1, &carry); - - OutputNode = CreateBVConst(res, outputwidth); - - CONSTANTBV::BitVector_Destroy(tmp1b); - CONSTANTBV::BitVector_Destroy(remainder); - } - else if (isNegativeS && isNegativeT) - { - // Signs are both negative - CBV tmp0b = CONSTANTBV::BitVector_Create(inputwidth, true); - CBV tmp1b = CONSTANTBV::BitVector_Create(inputwidth, true); - CONSTANTBV::BitVector_Negate(tmp0b, tmp0); - CONSTANTBV::BitVector_Negate(tmp1b, tmp1); - - CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Div_Pos(quotient, tmp0b, tmp1b, remainder); - assert(e == CONSTANTBV::ErrCode_Ok); - - CBV remb = CONSTANTBV::BitVector_Create(inputwidth, true); - CONSTANTBV::BitVector_Negate(remb, remainder); - - OutputNode = CreateBVConst(remb, outputwidth); - CONSTANTBV::BitVector_Destroy(tmp0b); - CONSTANTBV::BitVector_Destroy(tmp1b); - CONSTANTBV::BitVector_Destroy(remainder); - } - else - { - FatalError("never get called"); - } - } - - CONSTANTBV::BitVector_Destroy(tmp0); - CONSTANTBV::BitVector_Destroy(tmp1); - CONSTANTBV::BitVector_Destroy(quotient); - } - break; - - case BVDIV: - case BVMOD: - { - CBV quotient = CONSTANTBV::BitVector_Create(inputwidth, true); - CBV remainder = CONSTANTBV::BitVector_Create(inputwidth, true); - - if (division_by_zero_returns_one && CONSTANTBV::BitVector_is_empty(tmp1)) - { - // Expecting a division by zero. Just return one. - OutputNode = CreateOneConst(outputwidth); - } - else - { - - // 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: - { - ASTNode tmp0 = t[0]; // Should this run BVConstEvaluator?? - - if (ASTTrue == tmp0) - OutputNode = BVConstEvaluator(t[1]); - else if (ASTFalse == tmp0) - OutputNode = BVConstEvaluator(t[2]); - else - { - cerr << tmp0; - 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<= 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<GetKind())) + if(!BEEV::is_Form_kind(a->GetKind())) BEEV::FatalError("CInterface: Trying to QUERY a NON formula: ",*a); - //printf("kill all humans\n"); - //a->LispPrint(cout, 0); - //printf("##################################################\n"); + //printf("kill all humans\n"); + //a->LispPrint(cout, 0); + //printf("##################################################\n"); b->BVTypeCheck(*a); b->AddQuery(*a); @@ -481,7 +481,7 @@ int vc_getBVLength(VC vc, Expr ex) { //! Create a variable with a given name and type /*! The type cannot be a function type. */ Expr vc_varExpr1(VC vc, char* name, - int indexwidth, int valuewidth) { + int indexwidth, int valuewidth) { bmstar b = (bmstar)vc; node o = b->CreateSymbol(name); @@ -729,7 +729,7 @@ Type vc_bvType(VC vc, int num_bits) { if(!(0 < num_bits)) BEEV::FatalError("CInterface: number of bits in a bvtype must be a positive integer:", - b->CreateNode(BEEV::UNDEFINED)); + b->CreateNode(BEEV::UNDEFINED)); node e = b->CreateBVConst(32, num_bits); nodestar output = new node(b->CreateNode(BEEV::BITVECTOR,e)); @@ -765,8 +765,8 @@ Expr vc_bvConstExprFromStr(VC vc, char* binary_repr) { } Expr vc_bvConstExprFromInt(VC vc, - int n_bits, - unsigned int value) { + int n_bits, + unsigned int value) { bmstar b = (bmstar)vc; unsigned long long int v = (unsigned long long int)value; @@ -778,8 +778,8 @@ Expr vc_bvConstExprFromInt(VC vc, } Expr vc_bvConstExprFromLL(VC vc, - int n_bits, - unsigned long long value) { + int n_bits, + unsigned long long value) { bmstar b = (bmstar)vc; node n = b->CreateBVConst(n_bits, value); @@ -798,7 +798,7 @@ Expr vc_bvConcatExpr(VC vc, Expr left, Expr right) { b->BVTypeCheck(*r); node o = b->CreateTerm(BEEV::BVCONCAT, - l->GetValueWidth()+ r->GetValueWidth(),*l,*r); + l->GetValueWidth()+ r->GetValueWidth(),*l,*r); b->BVTypeCheck(o); nodestar output = new node(o); //if(cinterface_exprdelete_on) created_exprs.push_back(output); @@ -1179,10 +1179,10 @@ Expr vc_bvVar32LeftShiftExpr(VC vc, Expr sh_amt, Expr child) { for(int count=32; count >= 0; count--){ if(count != 32) { ifpart = vc_eqExpr(vc, sh_amt, - vc_bvConstExprFromInt(vc, shift_width, count)); + vc_bvConstExprFromInt(vc, shift_width, count)); thenpart = vc_bvExtract(vc, - vc_bvLeftShiftExpr(vc, count, child), - child_width-1, 0); + vc_bvLeftShiftExpr(vc, count, child), + child_width-1, 0); ite = vc_iteExpr(vc,ifpart,thenpart,elsepart); elsepart = ite; @@ -1202,7 +1202,7 @@ Expr vc_bvVar32DivByPowOfTwoExpr(VC vc, Expr child, Expr rhs) { for(int count=32; count >= 0; count--){ if(count != 32) { ifpart = vc_eqExpr(vc, rhs, - vc_bvConstExprFromInt(vc, 32, 1 << count)); + vc_bvConstExprFromInt(vc, 32, 1 << count)); thenpart = vc_bvRightShiftExpr(vc, count, child); ite = vc_iteExpr(vc,ifpart,thenpart,elsepart); elsepart = ite; @@ -1227,7 +1227,7 @@ Expr vc_bvVar32RightShiftExpr(VC vc, Expr sh_amt, Expr child) { for(int count=32; count >= 0; count--){ if(count != 32) { ifpart = vc_eqExpr(vc, sh_amt, - vc_bvConstExprFromInt(vc, shift_width, count)); + vc_bvConstExprFromInt(vc, shift_width, count)); thenpart = vc_bvRightShiftExpr(vc, count, child); ite = vc_iteExpr(vc,ifpart,thenpart,elsepart); elsepart = ite; @@ -1325,7 +1325,7 @@ unsigned long long int getBVUnsignedLongLong(Expr e) { if(BEEV::BVCONST != a->GetKind()) BEEV::FatalError("getBVUnsigned: Attempting to extract int value"\ - "from a NON-constant BITVECTOR: ",*a); + "from a NON-constant BITVECTOR: ",*a); unsigned* bv = a->GetBVConst(); char * str_bv = (char *)CONSTANTBV::BitVector_to_Bin(bv); @@ -1369,8 +1369,8 @@ Expr vc_bvCreateMemoryArray(VC vc, char * arrayName) { } Expr vc_bvReadMemoryArray(VC vc, - Expr array, - Expr byteIndex, int numOfBytes) { + Expr array, + Expr byteIndex, int numOfBytes) { if(!(numOfBytes > 0)) BEEV::FatalError("numOfBytes must be greater than 0"); @@ -1381,10 +1381,10 @@ Expr vc_bvReadMemoryArray(VC vc, Expr a = vc_readExpr(vc,array,byteIndex); while(--numOfBytes > 0) { Expr b = vc_readExpr(vc,array, - /*vc_simplify(vc, */ - vc_bvPlusExpr(vc, 32, - byteIndex, - vc_bvConstExprFromInt(vc,32,count)))/*)*/; + /*vc_simplify(vc, */ + vc_bvPlusExpr(vc, 32, + byteIndex, + vc_bvConstExprFromInt(vc,32,count)))/*)*/; a = vc_bvConcatExpr(vc,b,a); count++; } @@ -1393,11 +1393,11 @@ Expr vc_bvReadMemoryArray(VC vc, } Expr vc_bvWriteToMemoryArray(VC vc, - Expr array, Expr byteIndex, - Expr element, int numOfBytes) { + Expr array, Expr byteIndex, + Expr element, int numOfBytes) { if(!(numOfBytes > 0)) BEEV::FatalError("numOfBytes must be greater than 0"); - + int newBitsPerElem = numOfBytes*8; if(numOfBytes == 1) return vc_writeExpr(vc, array, byteIndex, element); @@ -1418,9 +1418,9 @@ Expr vc_bvWriteToMemoryArray(VC vc, c = vc_bvExtract(vc, element, hi_elem, low_elem); newarray = - vc_writeExpr(vc, newarray, - vc_bvPlusExpr(vc, 32, byteIndex, vc_bvConstExprFromInt(vc,32,count)), - c); + vc_writeExpr(vc, newarray, + vc_bvPlusExpr(vc, 32, byteIndex, vc_bvConstExprFromInt(vc,32,count)), + c); count++; } return newarray; @@ -1434,17 +1434,17 @@ Expr vc_bv32ConstExprFromInt(VC vc, unsigned int value){ #if 0 static char *val_to_binary_str(unsigned nbits, unsigned long long val) { - char s[65]; - - assert(nbits < sizeof s); - strcpy(s, ""); - while(nbits-- > 0) { - if((val >> nbits) & 1) - strcat(s, "1"); - else - strcat(s, "0"); - } - return strdup(s); + char s[65]; + + assert(nbits < sizeof s); + strcpy(s, ""); + while(nbits-- > 0) { + if((val >> nbits) & 1) + strcat(s, "1"); + else + strcat(s, "0"); + } + return strdup(s); } #endif @@ -1569,7 +1569,7 @@ int vc_isBool(Expr e) { void vc_Destroy(VC vc) { bmstar b = (bmstar)vc; // for(std::vector::iterator it=created_exprs.begin(), - // itend=created_exprs.end();it!=itend;it++) { + // itend=created_exprs.end();it!=itend;it++) { // BEEV::ASTNode * aaa = *it; // delete aaa; // } @@ -1631,11 +1631,11 @@ void vc_printCounterExampleFile(VC vc, int fd) { } const char* exprName(Expr e){ - return ((nodestar)e)->GetName(); + return ((nodestar)e)->GetName(); } int getExprID (Expr ex) { - BEEV::ASTNode q = (*(nodestar)ex); + BEEV::ASTNode q = (*(nodestar)ex); - return q.GetNodeNum(); + return q.GetNodeNum(); } diff --git a/src/c_interface/c_interface.h b/src/c_interface/c_interface.h index 78ebf4a..0f4d1d5 100644 --- a/src/c_interface/c_interface.h +++ b/src/c_interface/c_interface.h @@ -65,7 +65,7 @@ extern "C" { //The var name can contain only variables, numerals and //underscore. If you use any other symbol, you will get a segfault. Expr vc_varExpr1(VC vc, char* name, - int indexwidth, int valuewidth); + int indexwidth, int valuewidth); //! Get the expression and type associated with a name. /*! If there is no such Expr, a NULL Expr is returned. */ @@ -120,7 +120,7 @@ extern "C" { //! Prints 'e' to stdout as C code void vc_printExprCCode(VC vc, Expr e); - //! print in smtlib format + //! print in smtlib format char * vc_printSMTLIB(VC vc, Expr e); //! Prints 'e' into an open file descriptor 'fd' @@ -152,7 +152,7 @@ extern "C" { //simplify_print must be set to "1" if you wish simplification to //occur dring printing. It must be set to "0" otherwise void vc_printQueryStateToBuffer(VC vc, Expr e, - char **buf, unsigned long *len, int simplify_print); + char **buf, unsigned long *len, int simplify_print); //! Similar to vc_printQueryStateToBuffer() void vc_printCounterExampleToBuffer(VC vc, char **buf,unsigned long *len); @@ -206,7 +206,7 @@ extern "C" { Type vc_bvType(VC vc, int no_bits); Type vc_bv32Type(VC vc); - Expr vc_bvConstExprFromDecStr(VC vc, const size_t width, char* decimalInput ); + Expr vc_bvConstExprFromDecStr(VC vc, const size_t width, char* decimalInput ); Expr vc_bvConstExprFromStr(VC vc, char* binary_repr); Expr vc_bvConstExprFromInt(VC vc, int n_bits, unsigned int value); Expr vc_bvConstExprFromLL(VC vc, int n_bits, unsigned long long value); @@ -268,10 +268,10 @@ extern "C" { /*C pointer support: C interface to support C memory arrays in CVCL */ Expr vc_bvCreateMemoryArray(VC vc, char * arrayName); Expr vc_bvReadMemoryArray(VC vc, - Expr array, Expr byteIndex, int numOfBytes); + Expr array, Expr byteIndex, int numOfBytes); Expr vc_bvWriteToMemoryArray(VC vc, - Expr array, Expr byteIndex, - Expr element, int numOfBytes); + Expr array, Expr byteIndex, + Expr element, int numOfBytes); Expr vc_bv32ConstExprFromInt(VC vc, unsigned int value); // return a string representation of the Expr e. The caller is responsible @@ -310,68 +310,68 @@ extern "C" { //Kinds of Expr enum exprkind_t{ - UNDEFINED, - SYMBOL, - BVCONST, - BVNEG, - BVCONCAT, - BVOR, - BVAND, - BVXOR, - BVNAND, - BVNOR, - BVXNOR, - BVEXTRACT, - BVLEFTSHIFT, - BVRIGHTSHIFT, - BVSRSHIFT, - BVVARSHIFT, - BVPLUS, - BVSUB, - BVUMINUS, - BVMULTINVERSE, - BVMULT, - BVDIV, - BVMOD, - SBVDIV, - SBVREM, - BVSX, - BOOLVEC, - ITE, - BVGETBIT, - BVLT, - BVLE, - BVGT, - BVGE, - BVSLT, - BVSLE, - BVSGT, - BVSGE, - EQ, - NEQ, - FALSE, - TRUE, - NOT, - AND, - OR, - NAND, - NOR, - XOR, - IFF, - IMPLIES, - READ, - WRITE, - ARRAY, - BITVECTOR, - BOOLEAN, + UNDEFINED, + SYMBOL, + BVCONST, + BVNEG, + BVCONCAT, + BVOR, + BVAND, + BVXOR, + BVNAND, + BVNOR, + BVXNOR, + BVEXTRACT, + BVLEFTSHIFT, + BVRIGHTSHIFT, + BVSRSHIFT, + BVVARSHIFT, + BVPLUS, + BVSUB, + BVUMINUS, + BVMULTINVERSE, + BVMULT, + BVDIV, + BVMOD, + SBVDIV, + SBVREM, + BVSX, + BOOLVEC, + ITE, + BVGETBIT, + BVLT, + BVLE, + BVGT, + BVGE, + BVSLT, + BVSLE, + BVSGT, + BVSGE, + EQ, + NEQ, + FALSE, + TRUE, + NOT, + AND, + OR, + NAND, + NOR, + XOR, + IFF, + IMPLIES, + READ, + WRITE, + ARRAY, + BITVECTOR, + BOOLEAN, }; // type of expression enum type_t { - BOOLEAN_TYPE = 0, - BITVECTOR_TYPE, - ARRAY_TYPE, - UNKNOWN_TYPE + BOOLEAN_TYPE = 0, + BITVECTOR_TYPE, + ARRAY_TYPE, + UNKNOWN_TYPE }; // get the kind of the expression diff --git a/src/c_interface/fdstream.h b/src/c_interface/fdstream.h index 2cff613..0c7bfdf 100644 --- a/src/c_interface/fdstream.h +++ b/src/c_interface/fdstream.h @@ -53,13 +53,13 @@ namespace std { -/************************************************************ - * fdostream - * - a stream that writes on a file descriptor - ************************************************************/ + /************************************************************ + * fdostream + * - a stream that writes on a file descriptor + ************************************************************/ -class fdoutbuf : public std::streambuf { + class fdoutbuf : public std::streambuf { protected: int fd; // file descriptor public: @@ -69,38 +69,38 @@ class fdoutbuf : public std::streambuf { protected: // write one character virtual int_type overflow (int_type c) { - if (c != EOF) { - char z = c; - if (write (fd, &z, 1) != 1) { - return EOF; - } + if (c != EOF) { + char z = c; + if (write (fd, &z, 1) != 1) { + return EOF; } - return c; + } + return c; } // write multiple characters virtual - std::streamsize xsputn (const char* s, - std::streamsize num) { - return write(fd,s,num); + std::streamsize xsputn (const char* s, + std::streamsize num) { + return write(fd,s,num); } -}; + }; -class fdostream : public std::ostream { + class fdostream : public std::ostream { protected: fdoutbuf buf; public: fdostream (int fd) : std::ostream(0), buf(fd) { - rdbuf(&buf); + rdbuf(&buf); } -}; + }; -/************************************************************ - * fdistream - * - a stream that reads on a file descriptor - ************************************************************/ + /************************************************************ + * fdistream + * - a stream that reads on a file descriptor + ************************************************************/ -class fdinbuf : public std::streambuf { + class fdinbuf : public std::streambuf { protected: int fd; // file descriptor protected: @@ -120,65 +120,65 @@ class fdinbuf : public std::streambuf { * => force underflow() */ fdinbuf (int _fd) : fd(_fd) { - setg (buffer+pbSize, // beginning of putback area - buffer+pbSize, // read position - buffer+pbSize); // end position + setg (buffer+pbSize, // beginning of putback area + buffer+pbSize, // read position + buffer+pbSize); // end position } protected: // insert new characters into the buffer virtual int_type underflow () { #ifndef _MSC_VER - using std::memmove; + using std::memmove; #endif - // is read position before end of buffer? - if (gptr() < egptr()) { - return traits_type::to_int_type(*gptr()); - } - - /* process size of putback area - * - use number of characters read - * - but at most size of putback area - */ - int numPutback; - numPutback = gptr() - eback(); - if (numPutback > pbSize) { - numPutback = pbSize; - } - - /* copy up to pbSize characters previously read into - * the putback area - */ - memmove (buffer+(pbSize-numPutback), gptr()-numPutback, - numPutback); - - // read at most bufSize new characters - int num; - num = read (fd, buffer+pbSize, bufSize); - if (num <= 0) { - // ERROR or EOF - return EOF; - } - - // reset buffer pointers - setg (buffer+(pbSize-numPutback), // beginning of putback area - buffer+pbSize, // read position - buffer+pbSize+num); // end of buffer - - // return next character + // is read position before end of buffer? + if (gptr() < egptr()) { return traits_type::to_int_type(*gptr()); + } + + /* process size of putback area + * - use number of characters read + * - but at most size of putback area + */ + int numPutback; + numPutback = gptr() - eback(); + if (numPutback > pbSize) { + numPutback = pbSize; + } + + /* copy up to pbSize characters previously read into + * the putback area + */ + memmove (buffer+(pbSize-numPutback), gptr()-numPutback, + numPutback); + + // read at most bufSize new characters + int num; + num = read (fd, buffer+pbSize, bufSize); + if (num <= 0) { + // ERROR or EOF + return EOF; + } + + // reset buffer pointers + setg (buffer+(pbSize-numPutback), // beginning of putback area + buffer+pbSize, // read position + buffer+pbSize+num); // end of buffer + + // return next character + return traits_type::to_int_type(*gptr()); } -}; + }; -class fdistream : public std::istream { + class fdistream : public std::istream { protected: fdinbuf buf; public: fdistream (int fd) : std::istream(0), buf(fd) { - rdbuf(&buf); + rdbuf(&buf); } -}; + }; } // END namespace boost diff --git a/src/constantbv/constantbv.cpp b/src/constantbv/constantbv.cpp index d874d43..cd05ed3 100644 --- a/src/constantbv/constantbv.cpp +++ b/src/constantbv/constantbv.cpp @@ -49,41 +49,41 @@ #include "constantbv.h" namespace CONSTANTBV { -/*****************************************************************************/ -/* MODULE IMPLEMENTATION: */ -/*****************************************************************************/ - /**********************************************/ - /* global implementation-intrinsic constants: */ - /**********************************************/ + /*****************************************************************************/ + /* MODULE IMPLEMENTATION: */ + /*****************************************************************************/ + /**********************************************/ + /* global implementation-intrinsic constants: */ + /**********************************************/ #define BIT_VECTOR_HIDDEN_WORDS 3 - /*****************************************************************/ - /* global machine-dependent constants (set by "BitVector_Boot"): */ - /*****************************************************************/ + /*****************************************************************/ + /* global machine-dependent constants (set by "BitVector_Boot"): */ + /*****************************************************************/ -static unsigned int BITS; /* = # of bits in machine word (must be power of 2) */ -static unsigned int MODMASK; /* = BITS - 1 (mask for calculating modulo BITS) */ -static unsigned int LOGBITS; /* = ld(BITS) (logarithmus dualis) */ -static unsigned int FACTOR; /* = ld(BITS / 8) (ld of # of bytes) */ + static unsigned int BITS; /* = # of bits in machine word (must be power of 2) */ + static unsigned int MODMASK; /* = BITS - 1 (mask for calculating modulo BITS) */ + static unsigned int LOGBITS; /* = ld(BITS) (logarithmus dualis) */ + static unsigned int FACTOR; /* = ld(BITS / 8) (ld of # of bytes) */ -static unsigned int LSB = 1; /* = mask for least significant bit */ -static unsigned int MSB; /* = mask for most significant bit */ + static unsigned int LSB = 1; /* = mask for least significant bit */ + static unsigned int MSB; /* = mask for most significant bit */ -static unsigned int LONGBITS; /* = # of bits in unsigned long */ + static unsigned int LONGBITS; /* = # of bits in unsigned long */ -static unsigned int LOG10; /* = logarithm to base 10 of BITS - 1 */ -static unsigned int EXP10; /* = largest possible power of 10 in signed int */ + static unsigned int LOG10; /* = logarithm to base 10 of BITS - 1 */ + static unsigned int EXP10; /* = largest possible power of 10 in signed int */ - /********************************************************************/ - /* global bit mask table for fast access (set by "BitVector_Boot"): */ - /********************************************************************/ + /********************************************************************/ + /* global bit mask table for fast access (set by "BitVector_Boot"): */ + /********************************************************************/ -static unsigned int BITMASKTAB[sizeof(unsigned int) << 3]; + static unsigned int BITMASKTAB[sizeof(unsigned int) << 3]; - /*****************************/ - /* global macro definitions: */ - /*****************************/ + /*****************************/ + /* global macro definitions: */ + /*****************************/ #define BIT_VECTOR_ZERO_WORDS(target,count) \ while (count-- > 0) *target++ = 0; @@ -118,97 +118,97 @@ static unsigned int BITMASKTAB[sizeof(unsigned int) << 3]; digit -= value * 10; \ digit += (type) '0'; - /*********************************************************/ - /* private low-level functions (potentially dangerous!): */ - /*********************************************************/ + /*********************************************************/ + /* private low-level functions (potentially dangerous!): */ + /*********************************************************/ -static unsigned int power10(unsigned int x) { + static unsigned int power10(unsigned int x) { unsigned int y = 1; while (x-- > 0) y *= 10; return(y); -} + } -static void BIT_VECTOR_zro_words(unsigned int * addr, unsigned int count) { + static void BIT_VECTOR_zro_words(unsigned int * addr, unsigned int count) { BIT_VECTOR_ZERO_WORDS(addr,count) -} + } -static void BIT_VECTOR_cpy_words(unsigned int * target, - unsigned int * source, unsigned int count) { + static void BIT_VECTOR_cpy_words(unsigned int * target, + unsigned int * source, unsigned int count) { BIT_VECTOR_COPY_WORDS(target,source,count) -} + } -static void BIT_VECTOR_mov_words(unsigned int * target, - unsigned int * source, unsigned int count) { + static void BIT_VECTOR_mov_words(unsigned int * target, + unsigned int * source, unsigned int count) { if (target != source) { - if (target < source) BIT_VECTOR_COPY_WORDS(target,source,count) - else BIT_VECTOR_BACK_WORDS(target,source,count) - } -} + if (target < source) BIT_VECTOR_COPY_WORDS(target,source,count) + else BIT_VECTOR_BACK_WORDS(target,source,count) + } + } -static void BIT_VECTOR_ins_words(unsigned int * addr, - unsigned int total, unsigned int count, boolean clear) { + static void BIT_VECTOR_ins_words(unsigned int * addr, + unsigned int total, unsigned int count, boolean clear) { unsigned int length; if ((total > 0) && (count > 0)) { - if (count > total) count = total; - length = total - count; - if (length > 0) BIT_VECTOR_mov_words(addr+count,addr,length); - if (clear) BIT_VECTOR_zro_words(addr,count); + if (count > total) count = total; + length = total - count; + if (length > 0) BIT_VECTOR_mov_words(addr+count,addr,length); + if (clear) BIT_VECTOR_zro_words(addr,count); } -} + } -static void BIT_VECTOR_del_words(unsigned int * addr, - unsigned int total, unsigned int count, boolean clear) { + static void BIT_VECTOR_del_words(unsigned int * addr, + unsigned int total, unsigned int count, boolean clear) { unsigned int length; if ((total > 0) && (count > 0)) { - if (count > total) count = total; - length = total - count; - if (length > 0) BIT_VECTOR_mov_words(addr,addr+count,length); - if (clear) BIT_VECTOR_zro_words(addr+length,count); + if (count > total) count = total; + length = total - count; + if (length > 0) BIT_VECTOR_mov_words(addr,addr+count,length); + if (clear) BIT_VECTOR_zro_words(addr+length,count); } -} + } -static void BIT_VECTOR_reverse(unsigned char * string, unsigned int length) { + static void BIT_VECTOR_reverse(unsigned char * string, unsigned int length) { unsigned char * last; unsigned char temp; if (length > 1) { - last = string + length - 1; - while (string < last) { - temp = *string; - *string = *last; - *last = temp; - string++; - last--; - } + last = string + length - 1; + while (string < last) { + temp = *string; + *string = *last; + *last = temp; + string++; + last--; + } } -} + } -static unsigned int BIT_VECTOR_int2str(unsigned char * string, unsigned int value) { + static unsigned int BIT_VECTOR_int2str(unsigned char * string, unsigned int value) { unsigned int length; unsigned int digit; unsigned char * work; work = string; if (value > 0) { - length = 0; - while (value > 0) { - BIT_VECTOR_DIGITIZE(unsigned int,value,digit) - *work++ = (unsigned char) digit; - length++; - } - BIT_VECTOR_reverse(string,length); + length = 0; + while (value > 0) { + BIT_VECTOR_DIGITIZE(unsigned int,value,digit) + *work++ = (unsigned char) digit; + length++; + } + BIT_VECTOR_reverse(string,length); } else { - length = 1; - *work++ = (unsigned char) '0'; + length = 1; + *work++ = (unsigned char) '0'; } return(length); -} + } -static unsigned int BIT_VECTOR_str2int(unsigned char * string, unsigned int *value) { + static unsigned int BIT_VECTOR_str2int(unsigned char * string, unsigned int *value) { unsigned int length; unsigned int digit; @@ -217,55 +217,55 @@ static unsigned int BIT_VECTOR_str2int(unsigned char * string, unsigned int *val digit = (unsigned int) *string++; /* separate because isdigit() is likely a macro! */ while (isdigit((int)digit) != 0) { - length++; - digit -= (unsigned int) '0'; - if (*value) *value *= 10; - *value += digit; - digit = (unsigned int) *string++; + length++; + digit -= (unsigned int) '0'; + if (*value) *value *= 10; + *value += digit; + digit = (unsigned int) *string++; } return(length); -} + } - /********************************************/ - /* routine to convert error code to string: */ - /********************************************/ + /********************************************/ + /* routine to convert error code to string: */ + /********************************************/ -unsigned char * BitVector_Error(ErrCode error) { + unsigned char * BitVector_Error(ErrCode error) { switch (error) { - case ErrCode_Ok: return( (unsigned char *) NULL ); break; - case ErrCode_Type: return( (unsigned char *) ERRCODE_TYPE ); break; - case ErrCode_Bits: return( (unsigned char *) ERRCODE_BITS ); break; - case ErrCode_Word: return( (unsigned char *) ERRCODE_WORD ); break; - case ErrCode_Long: return( (unsigned char *) ERRCODE_LONG ); break; - case ErrCode_Powr: return( (unsigned char *) ERRCODE_POWR ); break; - case ErrCode_Loga: return( (unsigned char *) ERRCODE_LOGA ); break; - case ErrCode_Null: return( (unsigned char *) ERRCODE_NULL ); break; - case ErrCode_Indx: return( (unsigned char *) ERRCODE_INDX ); break; - case ErrCode_Ordr: return( (unsigned char *) ERRCODE_ORDR ); break; - case ErrCode_Size: return( (unsigned char *) ERRCODE_SIZE ); break; - case ErrCode_Pars: return( (unsigned char *) ERRCODE_PARS ); break; - case ErrCode_Ovfl: return( (unsigned char *) ERRCODE_OVFL ); break; - case ErrCode_Same: return( (unsigned char *) ERRCODE_SAME ); break; - case ErrCode_Expo: return( (unsigned char *) ERRCODE_EXPO ); break; - case ErrCode_Zero: return( (unsigned char *) ERRCODE_ZERO ); break; - default: return( (unsigned char *) ERRCODE_OOPS ); break; + case ErrCode_Ok: return( (unsigned char *) NULL ); break; + case ErrCode_Type: return( (unsigned char *) ERRCODE_TYPE ); break; + case ErrCode_Bits: return( (unsigned char *) ERRCODE_BITS ); break; + case ErrCode_Word: return( (unsigned char *) ERRCODE_WORD ); break; + case ErrCode_Long: return( (unsigned char *) ERRCODE_LONG ); break; + case ErrCode_Powr: return( (unsigned char *) ERRCODE_POWR ); break; + case ErrCode_Loga: return( (unsigned char *) ERRCODE_LOGA ); break; + case ErrCode_Null: return( (unsigned char *) ERRCODE_NULL ); break; + case ErrCode_Indx: return( (unsigned char *) ERRCODE_INDX ); break; + case ErrCode_Ordr: return( (unsigned char *) ERRCODE_ORDR ); break; + case ErrCode_Size: return( (unsigned char *) ERRCODE_SIZE ); break; + case ErrCode_Pars: return( (unsigned char *) ERRCODE_PARS ); break; + case ErrCode_Ovfl: return( (unsigned char *) ERRCODE_OVFL ); break; + case ErrCode_Same: return( (unsigned char *) ERRCODE_SAME ); break; + case ErrCode_Expo: return( (unsigned char *) ERRCODE_EXPO ); break; + case ErrCode_Zero: return( (unsigned char *) ERRCODE_ZERO ); break; + default: return( (unsigned char *) ERRCODE_OOPS ); break; } -} - - /*****************************************/ - /* automatic self-configuration routine: */ - /*****************************************/ - - /*******************************************************/ - /* */ - /* MUST be called once prior to any other function */ - /* to initialize the machine dependent constants */ - /* of this package! (But call only ONCE, or you */ - /* will suffer memory leaks!) */ - /* */ - /*******************************************************/ - -ErrCode BitVector_Boot(void) { + } + + /*****************************************/ + /* automatic self-configuration routine: */ + /*****************************************/ + + /*******************************************************/ + /* */ + /* MUST be called once prior to any other function */ + /* to initialize the machine dependent constants */ + /* of this package! (But call only ONCE, or you */ + /* will suffer memory leaks!) */ + /* */ + /*******************************************************/ + + ErrCode BitVector_Boot(void) { unsigned long longsample = 1L; unsigned int sample = LSB; unsigned int lsb; @@ -288,8 +288,8 @@ ErrCode BitVector_Boot(void) { sample = BITS; lsb = (sample & LSB); while ((sample >>= 1) && (! lsb)) { - LOGBITS++; - lsb = (sample & LSB); + LOGBITS++; + lsb = (sample & LSB); } if (sample) return(ErrCode_Powr); /* # of bits is not a power of 2! */ @@ -301,90 +301,90 @@ ErrCode BitVector_Boot(void) { MSB = (LSB << MODMASK); for ( sample = 0; sample < BITS; sample++ ) { - BITMASKTAB[sample] = (LSB << sample); + BITMASKTAB[sample] = (LSB << sample); } LOG10 = (unsigned int) (MODMASK * 0.30103); /* = (BITS - 1) * ( ln 2 / ln 10 ) */ EXP10 = power10(LOG10); return(ErrCode_Ok); -} + } -unsigned int BitVector_Size(unsigned int bits) { /* bit vector size (# of words) */ + unsigned int BitVector_Size(unsigned int bits) { /* bit vector size (# of words) */ unsigned int size; size = bits >> LOGBITS; if (bits & MODMASK) size++; return(size); -} + } -unsigned int BitVector_Mask(unsigned int bits) /* bit vector mask (unused bits) */ -{ + unsigned int BitVector_Mask(unsigned int bits) /* bit vector mask (unused bits) */ + { unsigned int mask; mask = bits & MODMASK; if (mask) mask = (unsigned int) ~(~0L << mask); else mask = (unsigned int) ~0L; return(mask); -} + } -unsigned char * BitVector_Version(void) -{ + unsigned char * BitVector_Version(void) + { return((unsigned char *)"6.4"); -} + } -unsigned int BitVector_Word_Bits(void) -{ + unsigned int BitVector_Word_Bits(void) + { return(BITS); -} + } -unsigned int BitVector_Long_Bits(void) -{ + unsigned int BitVector_Long_Bits(void) + { return(LONGBITS); -} - -/********************************************************************/ -/* */ -/* WARNING: Do not "free()" constant character strings, i.e., */ -/* don't call "BitVector_Dispose()" for strings returned */ -/* by "BitVector_Error()" or "BitVector_Version()"! */ -/* */ -/* ONLY call this function for strings allocated with "malloc()", */ -/* i.e., the strings returned by the functions "BitVector_to_*()" */ -/* and "BitVector_Block_Read()"! */ -/* */ -/********************************************************************/ - -void BitVector_Dispose(unsigned char * string) /* free string */ -{ + } + + /********************************************************************/ + /* */ + /* WARNING: Do not "free()" constant character strings, i.e., */ + /* don't call "BitVector_Dispose()" for strings returned */ + /* by "BitVector_Error()" or "BitVector_Version()"! */ + /* */ + /* ONLY call this function for strings allocated with "malloc()", */ + /* i.e., the strings returned by the functions "BitVector_to_*()" */ + /* and "BitVector_Block_Read()"! */ + /* */ + /********************************************************************/ + + void BitVector_Dispose(unsigned char * string) /* free string */ + { if (string != NULL) free((void *) string); -} + } -void BitVector_Destroy(unsigned int * addr) /* free bitvec */ -{ + void BitVector_Destroy(unsigned int * addr) /* free bitvec */ + { if (addr != NULL) - { + { addr -= BIT_VECTOR_HIDDEN_WORDS; free((void *) addr); - } -} + } + } -void BitVector_Destroy_List(unsigned int * * list, unsigned int count) /* free list */ -{ + void BitVector_Destroy_List(unsigned int * * list, unsigned int count) /* free list */ + { unsigned int * * slot; if (list != NULL) - { + { slot = list; while (count-- > 0) - { + { BitVector_Destroy(*slot++); - } + } free((void *) list); - } -} + } + } -unsigned int * BitVector_Create(unsigned int bits, boolean clear) /* malloc */ -{ + unsigned int * BitVector_Create(unsigned int bits, boolean clear) /* malloc */ + { unsigned int size; unsigned int mask; unsigned int bytes; @@ -396,49 +396,49 @@ unsigned int * BitVector_Create(unsigned int bits, boolean clear) /* ma bytes = (size + BIT_VECTOR_HIDDEN_WORDS) << FACTOR; addr = (unsigned int * ) malloc((size_t) bytes); if (addr != NULL) - { + { *addr++ = bits; *addr++ = size; *addr++ = mask; if (clear) - { + { zero = addr; BIT_VECTOR_ZERO_WORDS(zero,size) - } - } + } + } return(addr); -} + } -unsigned int * * BitVector_Create_List(unsigned int bits, boolean clear, unsigned int count) -{ + unsigned int * * BitVector_Create_List(unsigned int bits, boolean clear, unsigned int count) + { unsigned int * * list = NULL; unsigned int * * slot; unsigned int * addr; unsigned int i; if (count > 0) - { + { list = (unsigned int * * ) malloc(sizeof(unsigned int * ) * count); if (list != NULL) - { + { slot = list; for ( i = 0; i < count; i++ ) - { + { addr = BitVector_Create(bits,clear); if (addr == NULL) - { + { BitVector_Destroy_List(list,i); return(NULL); - } + } *slot++ = addr; - } - } - } + } + } + } return(list); -} + } -unsigned int * BitVector_Resize(unsigned int * oldaddr, unsigned int bits) /* realloc */ -{ + unsigned int * BitVector_Resize(unsigned int * oldaddr, unsigned int bits) /* realloc */ + { unsigned int bytes; unsigned int oldsize; unsigned int oldmask; @@ -454,19 +454,19 @@ unsigned int * BitVector_Resize(unsigned int * oldaddr, unsigned int bits) newmask = BitVector_Mask(bits); if (oldsize > 0) *(oldaddr+oldsize-1) &= oldmask; if (newsize <= oldsize) - { + { newaddr = oldaddr; bits_(newaddr) = bits; size_(newaddr) = newsize; mask_(newaddr) = newmask; if (newsize > 0) *(newaddr+newsize-1) &= newmask; - } + } else - { + { bytes = (newsize + BIT_VECTOR_HIDDEN_WORDS) << FACTOR; newaddr = (unsigned int * ) malloc((size_t) bytes); if (newaddr != NULL) - { + { *newaddr++ = bits; *newaddr++ = newsize; *newaddr++ = newmask; @@ -474,32 +474,32 @@ unsigned int * BitVector_Resize(unsigned int * oldaddr, unsigned int bits) source = oldaddr; newsize -= oldsize; BIT_VECTOR_COPY_WORDS(target,source,oldsize) - BIT_VECTOR_ZERO_WORDS(target,newsize) - } + BIT_VECTOR_ZERO_WORDS(target,newsize) + } BitVector_Destroy(oldaddr); - } + } return(newaddr); -} + } -unsigned int * BitVector_Shadow(unsigned int * addr) /* makes new, same size but empty */ -{ + unsigned int * BitVector_Shadow(unsigned int * addr) /* makes new, same size but empty */ + { return( BitVector_Create(bits_(addr),true) ); -} + } -unsigned int * BitVector_Clone(unsigned int * addr) /* makes exact duplicate */ -{ + unsigned int * BitVector_Clone(unsigned int * addr) /* makes exact duplicate */ + { unsigned int bits; unsigned int * twin; bits = bits_(addr); twin = BitVector_Create(bits,false); if ((twin != NULL) && (bits > 0)) - BIT_VECTOR_cpy_words(twin,addr,size_(addr)); + BIT_VECTOR_cpy_words(twin,addr,size_(addr)); return(twin); -} + } -unsigned int * BitVector_Concat(unsigned int * X, unsigned int * Y) /* returns concatenation */ -{ + unsigned int * BitVector_Concat(unsigned int * X, unsigned int * Y) /* returns concatenation */ + { /* BEWARE that X = most significant part, Y = least significant part! */ unsigned int bitsX; @@ -512,16 +512,16 @@ unsigned int * BitVector_Concat(unsigned int * X, unsigned int * Y) /* r bitsZ = bitsX + bitsY; Z = BitVector_Create(bitsZ,false); if ((Z != NULL) && (bitsZ > 0)) - { + { BIT_VECTOR_cpy_words(Z,Y,size_(Y)); BitVector_Interval_Copy(Z,X,bitsY,0,bitsX); *(Z+size_(Z)-1) &= mask_(Z); - } + } return(Z); -} + } -void BitVector_Copy(unsigned int * X, unsigned int * Y) /* X = Y */ -{ + void BitVector_Copy(unsigned int * X, unsigned int * Y) /* X = Y */ + { unsigned int sizeX = size_(X); unsigned int sizeY = size_(Y); unsigned int maskX = mask_(X); @@ -531,65 +531,65 @@ void BitVector_Copy(unsigned int * X, unsigned int * Y) unsigned int * lastY; if ((X != Y) && (sizeX > 0)) - { + { lastX = X + sizeX - 1; if (sizeY > 0) - { + { lastY = Y + sizeY - 1; if ( (*lastY & (maskY & ~ (maskY >> 1))) == 0 ) *lastY &= maskY; else - { + { fill = (unsigned int) ~0L; *lastY |= ~ maskY; - } + } while ((sizeX > 0) && (sizeY > 0)) - { + { *X++ = *Y++; sizeX--; sizeY--; - } + } *lastY &= maskY; - } + } while (sizeX-- > 0) *X++ = fill; *lastX &= maskX; - } -} + } + } -void BitVector_Empty(unsigned int * addr) /* X = {} clr all */ -{ + void BitVector_Empty(unsigned int * addr) /* X = {} clr all */ + { unsigned int size = size_(addr); BIT_VECTOR_ZERO_WORDS(addr,size) -} + } -void BitVector_Fill(unsigned int * addr) /* X = ~{} set all */ -{ + void BitVector_Fill(unsigned int * addr) /* X = ~{} set all */ + { unsigned int size = size_(addr); unsigned int mask = mask_(addr); unsigned int fill = (unsigned int) ~0L; if (size > 0) - { + { BIT_VECTOR_FILL_WORDS(addr,fill,size) - *(--addr) &= mask; - } -} + *(--addr) &= mask; + } + } -void BitVector_Flip(unsigned int * addr) /* X = ~X flip all */ -{ + void BitVector_Flip(unsigned int * addr) /* X = ~X flip all */ + { unsigned int size = size_(addr); unsigned int mask = mask_(addr); unsigned int flip = (unsigned int) ~0L; if (size > 0) - { + { BIT_VECTOR_FLIP_WORDS(addr,flip,size) - *(--addr) &= mask; - } -} + *(--addr) &= mask; + } + } -void BitVector_Primes(unsigned int * addr) -{ + void BitVector_Primes(unsigned int * addr) + { unsigned int bits = bits_(addr); unsigned int size = size_(addr); unsigned int * work; @@ -597,69 +597,69 @@ void BitVector_Primes(unsigned int * addr) unsigned int i,j; if (size > 0) - { + { temp = 0xAAAA; i = BITS >> 4; while (--i > 0) - { + { temp <<= 16; temp |= 0xAAAA; - } + } i = size; work = addr; *work++ = temp ^ 0x0006; while (--i > 0) *work++ = temp; for ( i = 3; (j = i * i) < bits; i += 2 ) - { + { for ( ; j < bits; j += i ) BIT_VECTOR_CLR_BIT(addr,j) - } + } *(addr+size-1) &= mask_(addr); - } -} + } + } -void BitVector_Reverse(unsigned int * X, unsigned int * Y) -{ + void BitVector_Reverse(unsigned int * X, unsigned int * Y) + { unsigned int bits = bits_(X); unsigned int mask; unsigned int bit; unsigned int value; if (bits > 0) - { + { if (X == Y) BitVector_Interval_Reverse(X,0,bits-1); else if (bits == bits_(Y)) - { -/* mask = mask_(Y); */ -/* mask &= ~ (mask >> 1); */ + { + /* mask = mask_(Y); */ + /* mask &= ~ (mask >> 1); */ mask = BITMASKTAB[(bits-1) & MODMASK]; Y += size_(Y) - 1; value = 0; bit = LSB; while (bits-- > 0) - { + { if ((*Y & mask) != 0) - { + { value |= bit; - } + } if (! (mask >>= 1)) - { + { Y--; mask = MSB; - } + } if (! (bit <<= 1)) - { + { *X++ = value; value = 0; bit = LSB; - } - } + } + } if (bit > LSB) *X = value; - } - } -} + } + } + } -void BitVector_Interval_Empty(unsigned int * addr, unsigned int lower, unsigned int upper) -{ /* X = X \ [lower..upper] */ + void BitVector_Interval_Empty(unsigned int * addr, unsigned int lower, unsigned int upper) + { /* X = X \ [lower..upper] */ unsigned int bits = bits_(addr); unsigned int size = size_(addr); unsigned int * loaddr; @@ -671,7 +671,7 @@ void BitVector_Interval_Empty(unsigned int * addr, unsigned int lower, unsigned unsigned int diff; if ((size > 0) && (lower < bits) && (upper < bits) && (lower <= upper)) - { + { lobase = lower >> LOGBITS; hibase = upper >> LOGBITS; diff = hibase - lobase; @@ -682,23 +682,23 @@ void BitVector_Interval_Empty(unsigned int * addr, unsigned int lower, unsigned himask = (unsigned int) ~((~0L << (upper & MODMASK)) << 1); if (diff == 0) - { + { *loaddr &= ~ (lomask & himask); - } + } else - { + { *loaddr++ &= ~ lomask; while (--diff > 0) - { + { *loaddr++ = 0; - } + } *hiaddr &= ~ himask; - } - } -} + } + } + } -void BitVector_Interval_Fill(unsigned int * addr, unsigned int lower, unsigned int upper) -{ /* X = X + [lower..upper] */ + void BitVector_Interval_Fill(unsigned int * addr, unsigned int lower, unsigned int upper) + { /* X = X + [lower..upper] */ unsigned int bits = bits_(addr); unsigned int size = size_(addr); unsigned int fill = (unsigned int) ~0L; @@ -711,7 +711,7 @@ void BitVector_Interval_Fill(unsigned int * addr, unsigned int lower, unsigned unsigned int diff; if ((size > 0) && (lower < bits) && (upper < bits) && (lower <= upper)) - { + { lobase = lower >> LOGBITS; hibase = upper >> LOGBITS; diff = hibase - lobase; @@ -722,24 +722,24 @@ void BitVector_Interval_Fill(unsigned int * addr, unsigned int lower, unsigned himask = (unsigned int) ~((~0L << (upper & MODMASK)) << 1); if (diff == 0) - { + { *loaddr |= (lomask & himask); - } + } else - { + { *loaddr++ |= lomask; while (--diff > 0) - { + { *loaddr++ = fill; - } + } *hiaddr |= himask; - } + } *(addr+size-1) &= mask_(addr); - } -} + } + } -void BitVector_Interval_Flip(unsigned int * addr, unsigned int lower, unsigned int upper) -{ /* X = X ^ [lower..upper] */ + void BitVector_Interval_Flip(unsigned int * addr, unsigned int lower, unsigned int upper) + { /* X = X ^ [lower..upper] */ unsigned int bits = bits_(addr); unsigned int size = size_(addr); unsigned int flip = (unsigned int) ~0L; @@ -752,7 +752,7 @@ void BitVector_Interval_Flip(unsigned int * addr, unsigned int lower, unsigned unsigned int diff; if ((size > 0) && (lower < bits) && (upper < bits) && (lower <= upper)) - { + { lobase = lower >> LOGBITS; hibase = upper >> LOGBITS; diff = hibase - lobase; @@ -763,24 +763,24 @@ void BitVector_Interval_Flip(unsigned int * addr, unsigned int lower, unsigned himask = (unsigned int) ~((~0L << (upper & MODMASK)) << 1); if (diff == 0) - { + { *loaddr ^= (lomask & himask); - } + } else - { + { *loaddr++ ^= lomask; while (--diff > 0) - { + { *loaddr++ ^= flip; - } + } *hiaddr ^= himask; - } + } *(addr+size-1) &= mask_(addr); - } -} + } + } -void BitVector_Interval_Reverse(unsigned int * addr, unsigned int lower, unsigned int upper) -{ + void BitVector_Interval_Reverse(unsigned int * addr, unsigned int lower, unsigned int upper) + { unsigned int bits = bits_(addr); unsigned int * loaddr; unsigned int * hiaddr; @@ -788,35 +788,35 @@ void BitVector_Interval_Reverse(unsigned int * addr, unsigned int lower, unsign unsigned int himask; if ((bits > 0) && (lower < bits) && (upper < bits) && (lower < upper)) - { + { loaddr = addr + (lower >> LOGBITS); hiaddr = addr + (upper >> LOGBITS); lomask = BITMASKTAB[lower & MODMASK]; himask = BITMASKTAB[upper & MODMASK]; for ( bits = upper - lower + 1; bits > 1; bits -= 2 ) - { + { if (((*loaddr & lomask) != 0) ^ ((*hiaddr & himask) != 0)) - { + { *loaddr ^= lomask; /* swap bits only if they differ! */ *hiaddr ^= himask; - } + } if (! (lomask <<= 1)) - { + { lomask = LSB; loaddr++; - } + } if (! (himask >>= 1)) - { + { himask = MSB; hiaddr--; - } - } - } -} + } + } + } + } -boolean BitVector_interval_scan_inc(unsigned int * addr, unsigned int start, - unsigned int * min, unsigned int * max) -{ + boolean BitVector_interval_scan_inc(unsigned int * addr, unsigned int start, + unsigned int * min, unsigned int * max) + { unsigned int size = size_(addr); unsigned int mask = mask_(addr); unsigned int offset; @@ -841,56 +841,56 @@ boolean BitVector_interval_scan_inc(unsigned int * addr, unsigned int start, value = *addr++; if ((value & bitmask) == 0) - { + { value &= mask; if (value == 0) - { + { offset++; empty = true; while (empty && (--size > 0)) - { + { if ((value = *addr++)) empty = false; else offset++; - } + } if (empty) return(false); - } + } start = offset << LOGBITS; bitmask = LSB; mask = value; while (! (mask & LSB)) - { + { bitmask <<= 1; mask >>= 1; start++; - } + } mask = ~ (bitmask | (bitmask - 1)); *min = start; *max = start; - } + } value = ~ value; value &= mask; if (value == 0) - { + { offset++; empty = true; while (empty && (--size > 0)) - { + { if ((value = ~ *addr++)) empty = false; else offset++; - } + } if (empty) value = LSB; - } + } start = offset << LOGBITS; while (! (value & LSB)) - { + { value >>= 1; start++; - } + } *max = --start; return(true); -} + } -boolean BitVector_interval_scan_dec(unsigned int * addr, unsigned int start, - unsigned int * min, unsigned int * max) -{ + boolean BitVector_interval_scan_dec(unsigned int * addr, unsigned int start, + unsigned int * min, unsigned int * max) + { unsigned int size = size_(addr); unsigned int mask = mask_(addr); unsigned int offset; @@ -917,56 +917,56 @@ boolean BitVector_interval_scan_dec(unsigned int * addr, unsigned int start, value = *addr--; if ((value & bitmask) == 0) - { + { value &= mask; if (value == 0) - { + { offset--; empty = true; while (empty && (--size > 0)) - { + { if ((value = *addr--)) empty = false; else offset--; - } + } if (empty) return(false); - } + } start = offset << LOGBITS; bitmask = MSB; mask = value; while (! (mask & MSB)) - { + { bitmask >>= 1; mask <<= 1; start--; - } + } mask = (bitmask - 1); *max = --start; *min = start; - } + } value = ~ value; value &= mask; if (value == 0) - { + { offset--; empty = true; while (empty && (--size > 0)) - { + { if ((value = ~ *addr--)) empty = false; else offset--; - } + } if (empty) value = MSB; - } + } start = offset << LOGBITS; while (! (value & MSB)) - { + { value <<= 1; start--; - } + } *min = start; return(true); -} + } -void BitVector_Interval_Copy(unsigned int * X, unsigned int * Y, unsigned int Xoffset, - unsigned int Yoffset, unsigned int length) -{ + void BitVector_Interval_Copy(unsigned int * X, unsigned int * Y, unsigned int Xoffset, + unsigned int Yoffset, unsigned int length) + { unsigned int bitsX = bits_(X); unsigned int bitsY = bits_(Y); unsigned int source = 0; /* silence compiler warning */ @@ -998,7 +998,7 @@ void BitVector_Interval_Copy(unsigned int * X, unsigned int * Y, unsigned int unsigned int * Z = X; if ((length > 0) && (Xoffset < bitsX) && (Yoffset < bitsY)) - { + { if ((Xoffset + length) > bitsX) length = bitsX - Xoffset; if ((Yoffset + length) > bitsY) length = bitsY - Yoffset; @@ -1017,327 +1017,327 @@ void BitVector_Interval_Copy(unsigned int * X, unsigned int * Y, unsigned int t_hi_bit = Xoffset & MODMASK; if (ascending) - { + { s_base = s_lo_base; t_base = t_lo_base; - } + } else - { + { s_base = s_hi_base; t_base = t_hi_base; - } + } s_bits = 0; t_bits = 0; Y += s_base; X += t_base; notfirst = false; while (true) - { + { if (t_bits == 0) - { + { if (notfirst) - { + { *X = target; if (ascending) - { + { if (t_base == t_hi_base) break; t_base++; X++; - } + } else - { + { if (t_base == t_lo_base) break; t_base--; X--; - } - } + } + } select = ((t_base == t_hi_base) << 1) | (t_base == t_lo_base); switch (select) - { - case 0: - t_lower = 0; - t_upper = BITS - 1; - t_bits = BITS; - target = 0; - break; - case 1: - t_lower = t_lo_bit; - t_upper = BITS - 1; - t_bits = BITS - t_lo_bit; - mask = (unsigned int) (~0L << t_lower); - target = *X & ~ mask; - break; - case 2: - t_lower = 0; - t_upper = t_hi_bit; - t_bits = t_hi_bit + 1; - mask = (unsigned int) ((~0L << t_upper) << 1); - target = *X & mask; - break; - case 3: - t_lower = t_lo_bit; - t_upper = t_hi_bit; - t_bits = t_hi_bit - t_lo_bit + 1; - mask = (unsigned int) (~0L << t_lower); - mask &= (unsigned int) ~((~0L << t_upper) << 1); - target = *X & ~ mask; - break; - } - } + { + case 0: + t_lower = 0; + t_upper = BITS - 1; + t_bits = BITS; + target = 0; + break; + case 1: + t_lower = t_lo_bit; + t_upper = BITS - 1; + t_bits = BITS - t_lo_bit; + mask = (unsigned int) (~0L << t_lower); + target = *X & ~ mask; + break; + case 2: + t_lower = 0; + t_upper = t_hi_bit; + t_bits = t_hi_bit + 1; + mask = (unsigned int) ((~0L << t_upper) << 1); + target = *X & mask; + break; + case 3: + t_lower = t_lo_bit; + t_upper = t_hi_bit; + t_bits = t_hi_bit - t_lo_bit + 1; + mask = (unsigned int) (~0L << t_lower); + mask &= (unsigned int) ~((~0L << t_upper) << 1); + target = *X & ~ mask; + break; + } + } if (s_bits == 0) - { + { if (notfirst) - { + { if (ascending) - { + { if (s_base == s_hi_base) break; s_base++; Y++; - } + } else - { + { if (s_base == s_lo_base) break; s_base--; Y--; - } - } + } + } source = *Y; select = ((s_base == s_hi_base) << 1) | (s_base == s_lo_base); switch (select) - { - case 0: - s_lower = 0; - s_upper = BITS - 1; - s_bits = BITS; - break; - case 1: - s_lower = s_lo_bit; - s_upper = BITS - 1; - s_bits = BITS - s_lo_bit; - break; - case 2: - s_lower = 0; - s_upper = s_hi_bit; - s_bits = s_hi_bit + 1; - break; - case 3: - s_lower = s_lo_bit; - s_upper = s_hi_bit; - s_bits = s_hi_bit - s_lo_bit + 1; - break; - } - } + { + case 0: + s_lower = 0; + s_upper = BITS - 1; + s_bits = BITS; + break; + case 1: + s_lower = s_lo_bit; + s_upper = BITS - 1; + s_bits = BITS - s_lo_bit; + break; + case 2: + s_lower = 0; + s_upper = s_hi_bit; + s_bits = s_hi_bit + 1; + break; + case 3: + s_lower = s_lo_bit; + s_upper = s_hi_bit; + s_bits = s_hi_bit - s_lo_bit + 1; + break; + } + } notfirst = true; if (s_bits > t_bits) - { + { bits = t_bits - 1; if (ascending) - { + { s_min = s_lower; s_max = s_lower + bits; - } + } else - { + { s_max = s_upper; s_min = s_upper - bits; - } + } t_min = t_lower; - } + } else - { + { bits = s_bits - 1; if (ascending) t_min = t_lower; else t_min = t_upper - bits; s_min = s_lower; s_max = s_upper; - } + } bits++; mask = (unsigned int) (~0L << s_min); mask &= (unsigned int) ~((~0L << s_max) << 1); if (s_min == t_min) target |= (source & mask); else - { + { if (s_min < t_min) target |= (source & mask) << (t_min-s_min); else target |= (source & mask) >> (s_min-t_min); - } + } if (ascending) - { + { s_lower += bits; t_lower += bits; - } + } else - { + { s_upper -= bits; t_upper -= bits; - } + } s_bits -= bits; t_bits -= bits; - } + } *(Z+size_(Z)-1) &= mask_(Z); - } -} + } + } -unsigned int * BitVector_Interval_Substitute(unsigned int * X, unsigned int * Y, - unsigned int Xoffset, unsigned int Xlength, - unsigned int Yoffset, unsigned int Ylength) -{ + unsigned int * BitVector_Interval_Substitute(unsigned int * X, unsigned int * Y, + unsigned int Xoffset, unsigned int Xlength, + unsigned int Yoffset, unsigned int Ylength) + { unsigned int Xbits = bits_(X); unsigned int Ybits = bits_(Y); unsigned int limit; unsigned int diff; if ((Xoffset <= Xbits) && (Yoffset <= Ybits)) - { + { limit = Xoffset + Xlength; if (limit > Xbits) - { + { limit = Xbits; Xlength = Xbits - Xoffset; - } + } if ((Yoffset + Ylength) > Ybits) - { + { Ylength = Ybits - Yoffset; - } + } if (Xlength == Ylength) - { + { if ((Ylength > 0) && ((X != Y) || (Xoffset != Yoffset))) - { + { BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); - } - } + } + } else /* Xlength != Ylength */ - { + { if (Xlength > Ylength) - { + { diff = Xlength - Ylength; if (Ylength > 0) BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); if (limit < Xbits) BitVector_Delete(X,Xoffset+Ylength,diff,false); if ((X = BitVector_Resize(X,Xbits-diff)) == NULL) return(NULL); - } + } else /* Ylength > Xlength ==> Ylength > 0 */ - { + { diff = Ylength - Xlength; if (X != Y) - { + { if ((X = BitVector_Resize(X,Xbits+diff)) == NULL) return(NULL); if (limit < Xbits) BitVector_Insert(X,limit,diff,false); BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); - } + } else /* in-place */ - { + { if ((Y = X = BitVector_Resize(X,Xbits+diff)) == NULL) return(NULL); if (limit >= Xbits) - { + { BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); - } + } else /* limit < Xbits */ - { + { BitVector_Insert(X,limit,diff,false); if ((Yoffset+Ylength) <= limit) - { + { BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); - } + } else /* overlaps or lies above critical area */ - { + { if (limit <= Yoffset) - { + { Yoffset += diff; BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); - } + } else /* Yoffset < limit */ - { + { Xlength = limit - Yoffset; BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Xlength); Yoffset = Xoffset + Ylength; /* = limit + diff */ Xoffset += Xlength; Ylength -= Xlength; BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength); - } - } - } - } - } - } - } + } + } + } + } + } + } + } return(X); -} + } -boolean BitVector_is_empty(unsigned int * addr) /* X == {} ? */ -{ + boolean BitVector_is_empty(unsigned int * addr) /* X == {} ? */ + { unsigned int size = size_(addr); boolean r = true; if (size > 0) - { + { *(addr+size-1) &= mask_(addr); while (r && (size-- > 0)) r = ( *addr++ == 0 ); - } + } return(r); -} + } -boolean BitVector_is_full(unsigned int * addr) /* X == ~{} ? */ -{ + boolean BitVector_is_full(unsigned int * addr) /* X == ~{} ? */ + { unsigned int size = size_(addr); unsigned int mask = mask_(addr); boolean r = false; unsigned int * last; if (size > 0) - { + { r = true; last = addr + size - 1; *last |= ~ mask; while (r && (size-- > 0)) r = ( ~ *addr++ == 0 ); *last &= mask; - } + } return(r); -} + } -boolean BitVector_equal(unsigned int * X, unsigned int * Y) /* X == Y ? */ -{ + boolean BitVector_equal(unsigned int * X, unsigned int * Y) /* X == Y ? */ + { unsigned int size = size_(X); unsigned int mask = mask_(X); boolean r = false; if (bits_(X) == bits_(Y)) - { + { r = true; if (size > 0) - { + { *(X+size-1) &= mask; *(Y+size-1) &= mask; while (r && (size-- > 0)) r = (*X++ == *Y++); - } - } + } + } return(r); -} + } -/* X <,=,> Y ? : unsigned */ -signed int BitVector_Lexicompare(unsigned int * X, unsigned int * Y) { + /* X <,=,> Y ? : unsigned */ + signed int BitVector_Lexicompare(unsigned int * X, unsigned int * Y) { unsigned int bitsX = bits_(X); unsigned int bitsY = bits_(Y); unsigned int size = size_(X); boolean r = true; if (bitsX == bitsY) { - if (size > 0) { - X += size; - Y += size; - while (r && (size-- > 0)) r = (*(--X) == *(--Y)); - } - if (r) return((signed int) 0); - else { - if (*X < *Y) return((signed int) -1); else return((signed int) 1); - } + if (size > 0) { + X += size; + Y += size; + while (r && (size-- > 0)) r = (*(--X) == *(--Y)); + } + if (r) return((signed int) 0); + else { + if (*X < *Y) return((signed int) -1); else return((signed int) 1); + } } else { - if (bitsX < bitsY) return((signed int) -1); else return((signed int) 1); + if (bitsX < bitsY) return((signed int) -1); else return((signed int) 1); } -} + } -signed int BitVector_Compare(unsigned int * X, unsigned int * Y) /* X <,=,> Y ? */ -{ /* signed */ + signed int BitVector_Compare(unsigned int * X, unsigned int * Y) /* X <,=,> Y ? */ + { /* signed */ unsigned int bitsX = bits_(X); unsigned int bitsY = bits_(Y); unsigned int size = size_(X); @@ -1346,66 +1346,66 @@ signed int BitVector_Compare(unsigned int * X, unsigned int * Y) boolean r = true; if (bitsX == bitsY) - { + { if (size > 0) - { + { X += size; Y += size; mask &= ~ (mask >> 1); if ((sign = (*(X-1) & mask)) != (*(Y-1) & mask)) - { + { if (sign) return((signed int) -1); else return((signed int) 1); - } + } while (r && (size-- > 0)) r = (*(--X) == *(--Y)); - } + } if (r) return((signed int) 0); else - { + { if (*X < *Y) return((signed int) -1); else return((signed int) 1); - } - } + } + } else - { + { if (bitsX < bitsY) return((signed int) -1); else return((signed int) 1); - } -} - -size_t BitVector_Hash(unsigned int * addr) -{ - unsigned int bits = bits_(addr); - unsigned int size = size_(addr); - unsigned int value; - unsigned int count; - unsigned int digit; - unsigned int length; + } + } + + size_t BitVector_Hash(unsigned int * addr) + { + unsigned int bits = bits_(addr); + unsigned int size = size_(addr); + unsigned int value; + unsigned int count; + unsigned int digit; + unsigned int length; - size_t result = 0; - - length = bits >> 2; - if (bits & 0x0003) length++; - if (size > 0) - { - *(addr+size-1) &= mask_(addr); - while ((size-- > 0) && (length > 0)) - { - value = *addr++; - count = BITS >> 2; - while ((count-- > 0) && (length > 0)) - { - digit = value & 0x000F; - if (digit > 9) digit += (unsigned int) 'A' - 10; - else digit += (unsigned int) '0'; - result = 5*result + digit; length--; - if ((count > 0) && (length > 0)) value >>= 4; - } - } - } - return result; -} + size_t result = 0; + + length = bits >> 2; + if (bits & 0x0003) length++; + if (size > 0) + { + *(addr+size-1) &= mask_(addr); + while ((size-- > 0) && (length > 0)) + { + value = *addr++; + count = BITS >> 2; + while ((count-- > 0) && (length > 0)) + { + digit = value & 0x000F; + if (digit > 9) digit += (unsigned int) 'A' - 10; + else digit += (unsigned int) '0'; + result = 5*result + digit; length--; + if ((count > 0) && (length > 0)) value >>= 4; + } + } + } + return result; + } -unsigned char * BitVector_to_Hex(unsigned int * addr) -{ + unsigned char * BitVector_to_Hex(unsigned int * addr) + { unsigned int bits = bits_(addr); unsigned int size = size_(addr); unsigned int value; @@ -1421,27 +1421,27 @@ unsigned char * BitVector_to_Hex(unsigned int * addr) string += length; *string = (unsigned char) '\0'; if (size > 0) - { + { *(addr+size-1) &= mask_(addr); while ((size-- > 0) && (length > 0)) - { + { value = *addr++; count = BITS >> 2; while ((count-- > 0) && (length > 0)) - { + { digit = value & 0x000F; if (digit > 9) digit += (unsigned int) 'A' - 10; else digit += (unsigned int) '0'; *(--string) = (unsigned char) digit; length--; if ((count > 0) && (length > 0)) value >>= 4; - } - } - } + } + } + } return(string); -} + } -ErrCode BitVector_from_Hex(unsigned int * addr, unsigned char * string) -{ + ErrCode BitVector_from_Hex(unsigned int * addr, unsigned char * string) + { unsigned int size = size_(addr); unsigned int mask = mask_(addr); boolean ok = true; @@ -1451,34 +1451,34 @@ ErrCode BitVector_from_Hex(unsigned int * addr, unsigned char * string) int digit; if (size > 0) - { + { length = strlen((char *) string); string += length; while (size-- > 0) - { + { value = 0; for ( count = 0; (ok && (length > 0) && (count < BITS)); count += 4 ) - { + { digit = (int) *(--string); length--; /* separate because toupper() is likely a macro! */ digit = toupper(digit); if ((ok = (isxdigit(digit) != 0))) - { - if (digit >= (int) 'A') digit -= (int) 'A' - 10; - else digit -= (int) '0'; - value |= (((unsigned int) digit) << count); - } - } + { + if (digit >= (int) 'A') digit -= (int) 'A' - 10; + else digit -= (int) '0'; + value |= (((unsigned int) digit) << count); + } + } *addr++ = value; - } + } *(--addr) &= mask; - } + } if (ok) return(ErrCode_Ok); else return(ErrCode_Pars); -} + } -unsigned char * BitVector_to_Bin(unsigned int * addr) -{ + unsigned char * BitVector_to_Bin(unsigned int * addr) + { unsigned int size = size_(addr); unsigned int value; unsigned int count; @@ -1492,27 +1492,27 @@ unsigned char * BitVector_to_Bin(unsigned int * addr) string += length; *string = (unsigned char) '\0'; if (size > 0) - { + { *(addr+size-1) &= mask_(addr); while (size-- > 0) - { + { value = *addr++; count = BITS; if (count > length) count = length; while (count-- > 0) - { + { digit = value & 0x0001; digit += (unsigned int) '0'; *(--string) = (unsigned char) digit; length--; if (count > 0) value >>= 1; - } - } - } + } + } + } return(string); -} + } -ErrCode BitVector_from_Bin(unsigned int * addr, unsigned char * string) -{ + ErrCode BitVector_from_Bin(unsigned int * addr, unsigned char * string) + { unsigned int size = size_(addr); unsigned int mask = mask_(addr); boolean ok = true; @@ -1522,37 +1522,37 @@ ErrCode BitVector_from_Bin(unsigned int * addr, unsigned char * string) int digit; if (size > 0) - { + { length = strlen((char *) string); string += length; while (size-- > 0) - { + { value = 0; for ( count = 0; (ok && (length > 0) && (count < BITS)); count++ ) - { + { digit = (int) *(--string); length--; switch (digit) - { - case (int) '0': - break; - case (int) '1': - value |= BITMASKTAB[count]; - break; - default: - ok = false; - break; - } - } + { + case (int) '0': + break; + case (int) '1': + value |= BITMASKTAB[count]; + break; + default: + ok = false; + break; + } + } *addr++ = value; - } + } *(--addr) &= mask; - } + } if (ok) return(ErrCode_Ok); else return(ErrCode_Pars); -} + } -unsigned char * BitVector_to_Dec(unsigned int * addr) -{ + unsigned char * BitVector_to_Dec(unsigned int * addr) + { unsigned int bits = bits_(addr); unsigned int length; unsigned int digits; @@ -1575,98 +1575,98 @@ unsigned char * BitVector_to_Dec(unsigned int * addr) string = result; sign = BitVector_Sign(addr); if ((bits < 4) || (sign == 0)) - { + { if (bits > 0) digits = *addr; else digits = (unsigned int) 0; if (sign < 0) digits = ((unsigned int)(-((signed int)digits))) & mask_(addr); *string++ = (unsigned char) digits + (unsigned char) '0'; digits = 1; - } + } else - { + { quot = BitVector_Create(bits,false); if (quot == NULL) - { + { BitVector_Dispose(result); return(NULL); - } + } rest = BitVector_Create(bits,false); if (rest == NULL) - { + { BitVector_Dispose(result); BitVector_Destroy(quot); return(NULL); - } + } temp = BitVector_Create(bits,false); if (temp == NULL) - { + { BitVector_Dispose(result); BitVector_Destroy(quot); BitVector_Destroy(rest); return(NULL); - } + } base = BitVector_Create(bits,true); if (base == NULL) - { + { BitVector_Dispose(result); BitVector_Destroy(quot); BitVector_Destroy(rest); BitVector_Destroy(temp); return(NULL); - } + } if (sign < 0) BitVector_Negate(quot,addr); else BitVector_Copy(quot,addr); digits = 0; *base = EXP10; loop = (bits >= BITS); do - { + { if (loop) - { + { BitVector_Copy(temp,quot); if (BitVector_Div_Pos(quot,temp,base,rest)) - { + { BitVector_Dispose(result); /* emergency exit */ BitVector_Destroy(quot); BitVector_Destroy(rest); /* should never occur */ BitVector_Destroy(temp); /* under normal operation */ BitVector_Destroy(base); return(NULL); - } + } loop = ! BitVector_is_empty(quot); q = *rest; - } + } else q = *quot; count = LOG10; while (((loop && (count-- > 0)) || ((! loop) && (q != 0))) && - (digits < length)) - { + (digits < length)) + { if (q != 0) - { + { BIT_VECTOR_DIGITIZE(unsigned int,q,r) - } + } else r = (unsigned int) '0'; *string++ = (unsigned char) r; digits++; - } - } + } + } while (loop && (digits < length)); BitVector_Destroy(quot); BitVector_Destroy(rest); BitVector_Destroy(temp); BitVector_Destroy(base); - } + } if ((sign < 0) && (digits < length)) - { + { *string++ = (unsigned char) '-'; digits++; - } + } *string = (unsigned char) '\0'; BIT_VECTOR_reverse(result,digits); return(result); -} + } -ErrCode BitVector_from_Dec(unsigned int * addr, unsigned char * string) -{ + ErrCode BitVector_from_Dec(unsigned int * addr, unsigned char * string) + { ErrCode error = ErrCode_Ok; unsigned int bits = bits_(addr); unsigned int mask = mask_(addr); @@ -1686,127 +1686,127 @@ ErrCode BitVector_from_Dec(unsigned int * addr, unsigned char * string) int digit; if (bits > 0) - { + { length = strlen((char *) string); if (length == 0) return(ErrCode_Pars); digit = (int) *string; if ((minus = (digit == (int) '-')) || - (digit == (int) '+')) - { + (digit == (int) '+')) + { string++; if (--length == 0) return(ErrCode_Pars); - } + } string += length; term = BitVector_Create(BITS,false); if (term == NULL) - { + { return(ErrCode_Null); - } + } base = BitVector_Create(BITS,false); if (base == NULL) - { + { BitVector_Destroy(term); return(ErrCode_Null); - } + } prod = BitVector_Create(bits,init); if (prod == NULL) - { + { BitVector_Destroy(term); BitVector_Destroy(base); return(ErrCode_Null); - } + } rank = BitVector_Create(bits,init); if (rank == NULL) - { + { BitVector_Destroy(term); BitVector_Destroy(base); BitVector_Destroy(prod); return(ErrCode_Null); - } + } temp = BitVector_Create(bits,false); if (temp == NULL) - { + { BitVector_Destroy(term); BitVector_Destroy(base); BitVector_Destroy(prod); BitVector_Destroy(rank); return(ErrCode_Null); - } + } BitVector_Empty(addr); *base = EXP10; shift = false; while ((! error) && (length > 0)) - { + { accu = 0; powr = 1; count = LOG10; while ((! error) && (length > 0) && (count-- > 0)) - { + { digit = (int) *(--string); length--; /* separate because isdigit() is likely a macro! */ if (isdigit(digit) != 0) - { + { accu += ((unsigned int) digit - (unsigned int) '0') * powr; powr *= 10; - } + } else error = ErrCode_Pars; - } + } if (! error) - { + { if (shift) - { + { *term = accu; BitVector_Copy(temp,rank); error = BitVector_Mul_Pos(prod,temp,term,false); - } + } else - { + { *prod = accu; if ((! init) && ((accu & ~ mask) != 0)) error = ErrCode_Ovfl; - } + } if (! error) - { + { carry = false; BitVector_compute(addr,addr,prod,false,&carry); /* ignores sign change (= overflow) but ! */ /* numbers too large (= carry) for resulting bit vector */ if (carry) error = ErrCode_Ovfl; else - { + { if (length > 0) - { + { if (shift) - { + { BitVector_Copy(temp,rank); error = BitVector_Mul_Pos(rank,temp,base,false); - } + } else - { + { *rank = *base; shift = true; - } - } - } - } - } - } + } + } + } + } + } + } BitVector_Destroy(term); BitVector_Destroy(base); BitVector_Destroy(prod); BitVector_Destroy(rank); BitVector_Destroy(temp); if (! error && minus) - { + { BitVector_Negate(addr,addr); if ((*(addr + size_(addr) - 1) & mask & ~ (mask >> 1)) == 0) - error = ErrCode_Ovfl; - } - } + error = ErrCode_Ovfl; + } + } return(error); -} + } -unsigned char * BitVector_to_Enum(unsigned int * addr) -{ + unsigned char * BitVector_to_Enum(unsigned int * addr) + { unsigned int bits = bits_(addr); unsigned int sample; unsigned int length; @@ -1821,26 +1821,26 @@ unsigned char * BitVector_to_Enum(unsigned int * addr) boolean comma; if (bits > 0) - { + { sample = bits - 1; /* greatest possible index */ length = 2; /* account for index 0 && terminating '\0' */ digits = 1; /* account for intervening dashes && commas */ factor = 1; power = 10; while (sample >= (power-1)) - { + { length += ++digits * factor * 6; /* 9,90,900,9000,... (9*2/3 = 6) */ factor = power; power *= 10; - } + } if (sample > --factor) - { + { sample -= factor; factor = (unsigned int) ( sample / 3 ); factor = (factor << 1) + (sample - (factor * 3)); length += ++digits * factor; - } - } + } + } else length = 1; string = (unsigned char *) malloc((size_t) length); if (string == NULL) return(NULL); @@ -1848,36 +1848,36 @@ unsigned char * BitVector_to_Enum(unsigned int * addr) comma = false; target = string; while ((start < bits) && BitVector_interval_scan_inc(addr,start,&min,&max)) - { + { start = max + 2; if (comma) *target++ = (unsigned char) ','; if (min == max) - { + { target += BIT_VECTOR_int2str(target,min); - } + } else - { + { if (min+1 == max) - { + { target += BIT_VECTOR_int2str(target,min); *target++ = (unsigned char) ','; target += BIT_VECTOR_int2str(target,max); - } + } else - { + { target += BIT_VECTOR_int2str(target,min); *target++ = (unsigned char) '-'; target += BIT_VECTOR_int2str(target,max); - } - } + } + } comma = true; - } + } *target = (unsigned char) '\0'; return(string); -} + } -ErrCode BitVector_from_Enum(unsigned int * addr, unsigned char * string) -{ + ErrCode BitVector_from_Enum(unsigned int * addr, unsigned char * string) + { ErrCode error = ErrCode_Ok; unsigned int bits = bits_(addr); unsigned int state = 1; @@ -1886,176 +1886,176 @@ ErrCode BitVector_from_Enum(unsigned int * addr, unsigned char * string) unsigned int start = 0; /* silence compiler warning */ if (bits > 0) - { + { BitVector_Empty(addr); while ((! error) && (state != 0)) - { + { token = (unsigned int) *string; /* separate because isdigit() is likely a macro! */ if (isdigit((int)token) != 0) - { + { string += BIT_VECTOR_str2int(string,&index); if (index < bits) token = (unsigned int) '0'; else error = ErrCode_Indx; - } + } else string++; if (! error) - switch (state) - { + switch (state) + { case 1: - switch (token) + switch (token) { - case (unsigned int) '0': - state = 2; - break; - case (unsigned int) '\0': - state = 0; - break; - default: - error = ErrCode_Pars; - break; + case (unsigned int) '0': + state = 2; + break; + case (unsigned int) '\0': + state = 0; + break; + default: + error = ErrCode_Pars; + break; } - break; + break; case 2: - switch (token) + switch (token) { - case (unsigned int) '-': - start = index; - state = 3; - break; - case (unsigned int) ',': - BIT_VECTOR_SET_BIT(addr,index) - state = 5; - break; - case (unsigned int) '\0': - BIT_VECTOR_SET_BIT(addr,index) - state = 0; - break; - default: - error = ErrCode_Pars; - break; + case (unsigned int) '-': + start = index; + state = 3; + break; + case (unsigned int) ',': + BIT_VECTOR_SET_BIT(addr,index) + state = 5; + break; + case (unsigned int) '\0': + BIT_VECTOR_SET_BIT(addr,index) + state = 0; + break; + default: + error = ErrCode_Pars; + break; } - break; + break; case 3: - switch (token) + switch (token) { - case (unsigned int) '0': - if (start < index) - BitVector_Interval_Fill(addr,start,index); - else if (start == index) - BIT_VECTOR_SET_BIT(addr,index) - else error = ErrCode_Ordr; - state = 4; - break; - default: - error = ErrCode_Pars; - break; + case (unsigned int) '0': + if (start < index) + BitVector_Interval_Fill(addr,start,index); + else if (start == index) + BIT_VECTOR_SET_BIT(addr,index) + else error = ErrCode_Ordr; + state = 4; + break; + default: + error = ErrCode_Pars; + break; } - break; + break; case 4: - switch (token) + switch (token) { - case (unsigned int) ',': - state = 5; - break; - case (unsigned int) '\0': - state = 0; - break; - default: - error = ErrCode_Pars; - break; + case (unsigned int) ',': + state = 5; + break; + case (unsigned int) '\0': + state = 0; + break; + default: + error = ErrCode_Pars; + break; } - break; + break; case 5: - switch (token) + switch (token) { - case (unsigned int) '0': - state = 2; - break; - default: - error = ErrCode_Pars; - break; + case (unsigned int) '0': + state = 2; + break; + default: + error = ErrCode_Pars; + break; } - break; - } - } - } + break; + } + } + } return(error); -} + } -void BitVector_Bit_Off(unsigned int * addr, unsigned int index) /* X = X \ {x} */ -{ + void BitVector_Bit_Off(unsigned int * addr, unsigned int index) /* X = X \ {x} */ + { if (index < bits_(addr)) BIT_VECTOR_CLR_BIT(addr,index) -} + } -void BitVector_Bit_On(unsigned int * addr, unsigned int index) /* X = X + {x} */ -{ + void BitVector_Bit_On(unsigned int * addr, unsigned int index) /* X = X + {x} */ + { if (index < bits_(addr)) BIT_VECTOR_SET_BIT(addr,index) -} + } -boolean BitVector_bit_flip(unsigned int * addr, unsigned int index) /* X=(X+{x})\(X*{x}) */ -{ + boolean BitVector_bit_flip(unsigned int * addr, unsigned int index) /* X=(X+{x})\(X*{x}) */ + { unsigned int mask; if (index < bits_(addr)) return( BIT_VECTOR_FLP_BIT(addr,index,mask) ); else return( false ); -} + } -boolean BitVector_bit_test(unsigned int * addr, unsigned int index) /* {x} in X ? */ -{ + boolean BitVector_bit_test(unsigned int * addr, unsigned int index) /* {x} in X ? */ + { if (index < bits_(addr)) return( BIT_VECTOR_TST_BIT(addr,index) ); else return( false ); -} + } -void BitVector_Bit_Copy(unsigned int * addr, unsigned int index, boolean bit) -{ + void BitVector_Bit_Copy(unsigned int * addr, unsigned int index, boolean bit) + { if (index < bits_(addr)) - { + { if (bit) BIT_VECTOR_SET_BIT(addr,index) - else BIT_VECTOR_CLR_BIT(addr,index) - } -} + else BIT_VECTOR_CLR_BIT(addr,index) + } + } -void BitVector_LSB(unsigned int * addr, boolean bit) -{ + void BitVector_LSB(unsigned int * addr, boolean bit) + { if (bits_(addr) > 0) - { + { if (bit) *addr |= LSB; else *addr &= ~ LSB; - } -} + } + } -void BitVector_MSB(unsigned int * addr, boolean bit) -{ + void BitVector_MSB(unsigned int * addr, boolean bit) + { unsigned int size = size_(addr); unsigned int mask = mask_(addr); if (size-- > 0) - { + { if (bit) *(addr+size) |= mask & ~ (mask >> 1); else *(addr+size) &= ~ mask | (mask >> 1); - } -} + } + } -boolean BitVector_lsb_(unsigned int * addr) -{ + boolean BitVector_lsb_(unsigned int * addr) + { if (size_(addr) > 0) return( (*addr & LSB) != 0 ); else return( false ); -} + } -boolean BitVector_msb_(unsigned int * addr) -{ + boolean BitVector_msb_(unsigned int * addr) + { unsigned int size = size_(addr); unsigned int mask = mask_(addr); if (size-- > 0) - return( (*(addr+size) & (mask & ~ (mask >> 1))) != 0 ); + return( (*(addr+size) & (mask & ~ (mask >> 1))) != 0 ); else - return( false ); -} + return( false ); + } -boolean BitVector_rotate_left(unsigned int * addr) -{ + boolean BitVector_rotate_left(unsigned int * addr) + { unsigned int size = size_(addr); unsigned int mask = mask_(addr); unsigned int msb; @@ -2063,27 +2063,27 @@ boolean BitVector_rotate_left(unsigned int * addr) boolean carry_out = false; if (size > 0) - { + { msb = mask & ~ (mask >> 1); carry_in = ((*(addr+size-1) & msb) != 0); while (size-- > 1) - { + { carry_out = ((*addr & MSB) != 0); *addr <<= 1; if (carry_in) *addr |= LSB; carry_in = carry_out; addr++; - } + } carry_out = ((*addr & msb) != 0); *addr <<= 1; if (carry_in) *addr |= LSB; *addr &= mask; - } + } return(carry_out); -} + } -boolean BitVector_rotate_right(unsigned int * addr) -{ + boolean BitVector_rotate_right(unsigned int * addr) + { unsigned int size = size_(addr); unsigned int mask = mask_(addr); unsigned int msb; @@ -2091,7 +2091,7 @@ boolean BitVector_rotate_right(unsigned int * addr) boolean carry_out = false; if (size > 0) - { + { msb = mask & ~ (mask >> 1); carry_in = ((*addr & LSB) != 0); addr += size-1; @@ -2103,52 +2103,52 @@ boolean BitVector_rotate_right(unsigned int * addr) addr--; size--; while (size-- > 0) - { + { carry_out = ((*addr & LSB) != 0); *addr >>= 1; if (carry_in) *addr |= MSB; carry_in = carry_out; addr--; - } - } + } + } return(carry_out); -} + } -boolean BitVector_shift_left(unsigned int * addr, boolean carry_in) -{ + boolean BitVector_shift_left(unsigned int * addr, boolean carry_in) + { unsigned int size = size_(addr); unsigned int mask = mask_(addr); unsigned int msb; boolean carry_out = carry_in; if (size > 0) - { + { msb = mask & ~ (mask >> 1); while (size-- > 1) - { + { carry_out = ((*addr & MSB) != 0); *addr <<= 1; if (carry_in) *addr |= LSB; carry_in = carry_out; addr++; - } + } carry_out = ((*addr & msb) != 0); *addr <<= 1; if (carry_in) *addr |= LSB; *addr &= mask; - } + } return(carry_out); -} + } -boolean BitVector_shift_right(unsigned int * addr, boolean carry_in) -{ + boolean BitVector_shift_right(unsigned int * addr, boolean carry_in) + { unsigned int size = size_(addr); unsigned int mask = mask_(addr); unsigned int msb; boolean carry_out = carry_in; if (size > 0) - { + { msb = mask & ~ (mask >> 1); addr += size-1; *addr &= mask; @@ -2159,128 +2159,128 @@ boolean BitVector_shift_right(unsigned int * addr, boolean carry_in) addr--; size--; while (size-- > 0) - { + { carry_out = ((*addr & LSB) != 0); *addr >>= 1; if (carry_in) *addr |= MSB; carry_in = carry_out; addr--; - } - } + } + } return(carry_out); -} + } -void BitVector_Move_Left(unsigned int * addr, unsigned int bits) -{ + void BitVector_Move_Left(unsigned int * addr, unsigned int bits) + { unsigned int count; unsigned int words; if (bits > 0) - { + { count = bits & MODMASK; words = bits >> LOGBITS; if (bits >= bits_(addr)) BitVector_Empty(addr); else - { + { while (count-- > 0) BitVector_shift_left(addr,0); BitVector_Word_Insert(addr,0,words,true); - } - } -} + } + } + } -void BitVector_Move_Right(unsigned int * addr, unsigned int bits) -{ + void BitVector_Move_Right(unsigned int * addr, unsigned int bits) + { unsigned int count; unsigned int words; if (bits > 0) - { + { count = bits & MODMASK; words = bits >> LOGBITS; if (bits >= bits_(addr)) BitVector_Empty(addr); else - { + { while (count-- > 0) BitVector_shift_right(addr,0); BitVector_Word_Delete(addr,0,words,true); - } - } -} + } + } + } -void BitVector_Insert(unsigned int * addr, unsigned int offset, unsigned int count, boolean clear) -{ + void BitVector_Insert(unsigned int * addr, unsigned int offset, unsigned int count, boolean clear) + { unsigned int bits = bits_(addr); unsigned int last; if ((count > 0) && (offset < bits)) - { + { last = offset + count; if (last < bits) - { + { BitVector_Interval_Copy(addr,addr,last,offset,(bits-last)); - } + } else last = bits; if (clear) BitVector_Interval_Empty(addr,offset,(last-1)); - } -} + } + } -void BitVector_Delete(unsigned int * addr, unsigned int offset, unsigned int count, boolean clear) -{ + void BitVector_Delete(unsigned int * addr, unsigned int offset, unsigned int count, boolean clear) + { unsigned int bits = bits_(addr); unsigned int last; if ((count > 0) && (offset < bits)) - { + { last = offset + count; if (last < bits) - { + { BitVector_Interval_Copy(addr,addr,offset,last,(bits-last)); - } + } else count = bits - offset; if (clear) BitVector_Interval_Empty(addr,(bits-count),(bits-1)); - } -} + } + } -boolean BitVector_increment(unsigned int * addr) /* X++ */ -{ + boolean BitVector_increment(unsigned int * addr) /* X++ */ + { unsigned int size = size_(addr); unsigned int mask = mask_(addr); unsigned int * last = addr + size - 1; boolean carry = true; if (size > 0) - { + { *last |= ~ mask; while (carry && (size-- > 0)) - { + { carry = (++(*addr++) == 0); - } + } *last &= mask; - } + } return(carry); -} + } -boolean BitVector_decrement(unsigned int * addr) /* X-- */ -{ + boolean BitVector_decrement(unsigned int * addr) /* X-- */ + { unsigned int size = size_(addr); unsigned int mask = mask_(addr); unsigned int * last = addr + size - 1; boolean carry = true; if (size > 0) - { + { *last &= mask; while (carry && (size-- > 0)) - { + { carry = (*addr == 0); --(*addr++); - } + } *last &= mask; - } + } return(carry); -} + } -boolean BitVector_compute(unsigned int * X, unsigned int * Y, unsigned int * Z, boolean minus, boolean *carry) -{ + boolean BitVector_compute(unsigned int * X, unsigned int * Y, unsigned int * Z, boolean minus, boolean *carry) + { unsigned int size = size_(X); unsigned int mask = mask_(X); unsigned int vv = 0; @@ -2292,12 +2292,12 @@ boolean BitVector_compute(unsigned int * X, unsigned int * Y, unsigned int * unsigned int hi; if (size > 0) - { + { if (minus) cc = (*carry == 0); else cc = (*carry != 0); /* deal with (size-1) least significant full words first: */ while (--size > 0) - { + { yy = *Y++; if (minus) zz = (unsigned int) ~ ( Z ? *Z++ : 0 ); else zz = (unsigned int) ( Z ? *Z++ : 0 ); @@ -2305,24 +2305,24 @@ boolean BitVector_compute(unsigned int * X, unsigned int * Y, unsigned int * hi = (yy >> 1) + (zz >> 1) + (lo >> 1); cc = ((hi & MSB) != 0); *X++ = (hi << 1) | (lo & LSB); - } + } /* deal with most significant word (may be used only partially): */ yy = *Y & mask; if (minus) zz = (unsigned int) ~ ( Z ? *Z : 0 ); else zz = (unsigned int) ( Z ? *Z : 0 ); zz &= mask; if (mask == LSB) /* special case, only one bit used */ - { + { vv = cc; lo = yy + zz + cc; cc = (lo >> 1); vv ^= cc; *X = lo & LSB; - } + } else - { + { if (~ mask) /* not all bits are used, but more than one */ - { + { mm = (mask >> 1); vv = (yy & mm) + (zz & mm) + cc; mm = mask & ~ mm; @@ -2332,9 +2332,9 @@ boolean BitVector_compute(unsigned int * X, unsigned int * Y, unsigned int * vv &= mm; cc &= mm; *X = lo & mask; - } + } else /* other special case, all bits are used */ - { + { mm = ~ MSB; lo = (yy & mm) + (zz & mm) + cc; vv = lo & MSB; @@ -2342,95 +2342,95 @@ boolean BitVector_compute(unsigned int * X, unsigned int * Y, unsigned int * cc = hi & MSB; vv ^= cc; *X = (hi << 1) | (lo & mm); - } - } + } + } if (minus) *carry = (cc == 0); else *carry = (cc != 0); - } + } return(vv != 0); -} + } -boolean BitVector_add(unsigned int * X, unsigned int * Y, unsigned int * Z, boolean *carry) -{ + boolean BitVector_add(unsigned int * X, unsigned int * Y, unsigned int * Z, boolean *carry) + { return(BitVector_compute(X,Y,Z,false,carry)); -} + } -boolean BitVector_sub(unsigned int * X, unsigned int * Y, unsigned int * Z, boolean *carry) -{ + boolean BitVector_sub(unsigned int * X, unsigned int * Y, unsigned int * Z, boolean *carry) + { return(BitVector_compute(X,Y,Z,true,carry)); -} + } -boolean BitVector_inc(unsigned int * X, unsigned int * Y) -{ + boolean BitVector_inc(unsigned int * X, unsigned int * Y) + { boolean carry = true; return(BitVector_compute(X,Y,NULL,false,&carry)); -} + } -boolean BitVector_dec(unsigned int * X, unsigned int * Y) -{ + boolean BitVector_dec(unsigned int * X, unsigned int * Y) + { boolean carry = true; return(BitVector_compute(X,Y,NULL,true,&carry)); -} + } -void BitVector_Negate(unsigned int * X, unsigned int * Y) -{ + void BitVector_Negate(unsigned int * X, unsigned int * Y) + { unsigned int size = size_(X); unsigned int mask = mask_(X); boolean carry = true; if (size > 0) - { + { while (size-- > 0) - { + { *X = ~ *Y++; if (carry) - { + { carry = (++(*X) == 0); - } + } X++; - } + } *(--X) &= mask; - } -} + } + } -void BitVector_Absolute(unsigned int * X, unsigned int * Y) -{ + void BitVector_Absolute(unsigned int * X, unsigned int * Y) + { unsigned int size = size_(Y); unsigned int mask = mask_(Y); if (size > 0) - { + { if (*(Y+size-1) & (mask & ~ (mask >> 1))) BitVector_Negate(X,Y); else BitVector_Copy(X,Y); - } -} + } + } -// FIXME: What the hell does the return value of this mean? -// It returns 0, 1, or -1 under mysterious circumstances. -signed int BitVector_Sign(unsigned int * addr) -{ + // FIXME: What the hell does the return value of this mean? + // It returns 0, 1, or -1 under mysterious circumstances. + signed int BitVector_Sign(unsigned int * addr) + { unsigned int size = size_(addr); unsigned int mask = mask_(addr); unsigned int * last = addr + size - 1; boolean r = true; if (size > 0) - { + { *last &= mask; while (r && (size-- > 0)) r = ( *addr++ == 0 ); - } + } if (r) return((signed int) 0); else - { + { if (*last & (mask & ~ (mask >> 1))) return((signed int) -1); else return((signed int) 1); - } -} + } + } -ErrCode BitVector_Mul_Pos(unsigned int * X, unsigned int * Y, unsigned int * Z, boolean strict) -{ + ErrCode BitVector_Mul_Pos(unsigned int * X, unsigned int * Y, unsigned int * Z, boolean strict) + { unsigned int mask; unsigned int limit; unsigned int count; @@ -2441,13 +2441,13 @@ ErrCode BitVector_Mul_Pos(unsigned int * X, unsigned int * Y, unsigned int * boolean ok = true; /* - Requirements: - - X, Y && Z must be distinct - - X && Y must have equal sizes (whereas Z may be any size!) - - Z should always contain the SMALLER of the two factors Y && Z - Constraints: - - The contents of Y (&& of X, of course) are destroyed - (only Z is preserved!) + Requirements: + - X, Y && Z must be distinct + - X && Y must have equal sizes (whereas Z may be any size!) + - Z should always contain the SMALLER of the two factors Y && Z + Constraints: + - The contents of Y (&& of X, of course) are destroyed + (only Z is preserved!) */ if ((X == Y) || (X == Z) || (Y == Z)) return(ErrCode_Same); @@ -2461,30 +2461,30 @@ ErrCode BitVector_Mul_Pos(unsigned int * X, unsigned int * Y, unsigned int * *sign &= mask; mask &= ~ (mask >> 1); for ( count = 0; (ok && (count <= limit)); count++ ) - { + { if ( BIT_VECTOR_TST_BIT(Z,count) ) - { + { carry = false; overflow = BitVector_compute(X,X,Y,false,&carry); if (strict) ok = ! (carry || overflow); else ok = ! carry; - } + } if (ok && (count < limit)) - { + { carry = BitVector_shift_left(Y,0); if (strict) - { + { overflow = ((*sign & mask) != 0); ok = ! (carry || overflow); - } + } else ok = ! carry; - } - } + } + } if (ok) return(ErrCode_Ok); else return(ErrCode_Ovfl); -} + } -ErrCode BitVector_Multiply(unsigned int * X, unsigned int * Y, unsigned int * Z) -{ + ErrCode BitVector_Multiply(unsigned int * X, unsigned int * Y, unsigned int * Z) + { ErrCode error = ErrCode_Ok; unsigned int bit_x = bits_(X); unsigned int bit_y = bits_(Y); @@ -2502,22 +2502,22 @@ ErrCode BitVector_Multiply(unsigned int * X, unsigned int * Y, unsigned int * unsigned int * B; /* - Requirements: - - Y && Z must have equal sizes - - X must have at least the same size as Y && Z but may be larger (!) - Features: - - The contents of Y && Z are preserved - - X may be identical with Y or Z (or both!) - (in-place multiplication is possible!) + Requirements: + - Y && Z must have equal sizes + - X must have at least the same size as Y && Z but may be larger (!) + Features: + - The contents of Y && Z are preserved + - X may be identical with Y or Z (or both!) + (in-place multiplication is possible!) */ if ((bit_y != bit_z) || (bit_x < bit_y)) return(ErrCode_Size); if (BitVector_is_empty(Y) || BitVector_is_empty(Z)) - { + { BitVector_Empty(X); - } + } else - { + { A = BitVector_Create(bit_y,false); if (A == NULL) return(ErrCode_Null); B = BitVector_Create(bit_z,false); @@ -2534,37 +2534,37 @@ ErrCode BitVector_Multiply(unsigned int * X, unsigned int * Y, unsigned int * ptr_z = B + size; zero = true; while (zero && (size-- > 0)) - { + { zero &= (*(--ptr_y) == 0); zero &= (*(--ptr_z) == 0); - } + } if (*ptr_y > *ptr_z) - { + { if (bit_x > bit_y) - { + { A = BitVector_Resize(A,bit_x); if (A == NULL) { BitVector_Destroy(B); return(ErrCode_Null); } - } + } error = BitVector_Mul_Pos(X,A,B,true); - } + } else - { + { if (bit_x > bit_z) - { + { B = BitVector_Resize(B,bit_x); if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); } - } + } error = BitVector_Mul_Pos(X,B,A,true); - } + } if ((! error) && sgn_x) BitVector_Negate(X,X); BitVector_Destroy(A); BitVector_Destroy(B); - } + } return(error); -} + } -ErrCode BitVector_Div_Pos(unsigned int * Q, unsigned int * X, unsigned int * Y, unsigned int * R) -{ + ErrCode BitVector_Div_Pos(unsigned int * Q, unsigned int * X, unsigned int * Y, unsigned int * R) + { unsigned int bits = bits_(Q); unsigned int mask; unsigned int * addr; @@ -2573,56 +2573,56 @@ ErrCode BitVector_Div_Pos(unsigned int * Q, unsigned int * X, unsigned int * boolean copy = false; /* flags whether valid rest is in R (0) || X (1) */ /* - Requirements: - - All bit vectors must have equal sizes - - Q, X, Y && R must all be distinct bit vectors - - Y must be non-zero (of course!) - Constraints: - - The contents of X (&& Q && R, of course) are destroyed - (only Y is preserved!) + Requirements: + - All bit vectors must have equal sizes + - Q, X, Y && R must all be distinct bit vectors + - Y must be non-zero (of course!) + Constraints: + - The contents of X (&& Q && R, of course) are destroyed + (only Y is preserved!) */ if ((bits != bits_(X)) || (bits != bits_(Y)) || (bits != bits_(R))) - return(ErrCode_Size); + return(ErrCode_Size); if ((Q == X) || (Q == Y) || (Q == R) || (X == Y) || (X == R) || (Y == R)) - return(ErrCode_Same); + return(ErrCode_Same); if (BitVector_is_empty(Y)) - return(ErrCode_Zero); + return(ErrCode_Zero); BitVector_Empty(R); BitVector_Copy(Q,X); if ((last = Set_Max(Q)) < 0L) return(ErrCode_Ok); bits = (unsigned int) ++last; while (bits-- > 0) - { + { addr = Q + (bits >> LOGBITS); mask = BITMASKTAB[bits & MODMASK]; flag = ((*addr & mask) != 0); if (copy) - { + { BitVector_shift_left(X,flag); flag = false; BitVector_compute(R,X,Y,true,&flag); - } + } else - { + { BitVector_shift_left(R,flag); flag = false; BitVector_compute(X,R,Y,true,&flag); - } + } if (flag) *addr &= ~ mask; else - { + { *addr |= mask; copy = ! copy; - } - } + } + } if (copy) BitVector_Copy(R,X); return(ErrCode_Ok); -} + } -ErrCode BitVector_Divide(unsigned int * Q, unsigned int * X, unsigned int * Y, unsigned int * R) -{ + ErrCode BitVector_Divide(unsigned int * Q, unsigned int * X, unsigned int * Y, unsigned int * R) + { ErrCode error = ErrCode_Ok; unsigned int bits = bits_(Q); unsigned int size = size_(Q); @@ -2635,32 +2635,32 @@ ErrCode BitVector_Divide(unsigned int * Q, unsigned int * X, unsigned int * Y unsigned int * B; /* - Requirements: - - All bit vectors must have equal sizes - - Q && R must be two distinct bit vectors - - Y must be non-zero (of course!) - Features: - - The contents of X && Y are preserved - - Q may be identical with X || Y (or both) - (in-place division is possible!) - - R may be identical with X || Y (or both) - (but not identical with Q!) + Requirements: + - All bit vectors must have equal sizes + - Q && R must be two distinct bit vectors + - Y must be non-zero (of course!) + Features: + - The contents of X && Y are preserved + - Q may be identical with X || Y (or both) + (in-place division is possible!) + - R may be identical with X || Y (or both) + (but not identical with Q!) */ if ((bits != bits_(X)) || (bits != bits_(Y)) || (bits != bits_(R))) - return(ErrCode_Size); + return(ErrCode_Size); if (Q == R) - return(ErrCode_Same); + return(ErrCode_Same); if (BitVector_is_empty(Y)) - return(ErrCode_Zero); + return(ErrCode_Zero); if (BitVector_is_empty(X)) - { + { BitVector_Empty(Q); BitVector_Empty(R); - } + } else - { + { A = BitVector_Create(bits,false); if (A == NULL) return(ErrCode_Null); B = BitVector_Create(bits,false); @@ -2672,18 +2672,18 @@ ErrCode BitVector_Divide(unsigned int * Q, unsigned int * X, unsigned int * Y if (sgn_x) BitVector_Negate(A,X); else BitVector_Copy(A,X); if (sgn_y) BitVector_Negate(B,Y); else BitVector_Copy(B,Y); if (! (error = BitVector_Div_Pos(Q,A,B,R))) - { + { if (sgn_q) BitVector_Negate(Q,Q); if (sgn_x) BitVector_Negate(R,R); - } + } BitVector_Destroy(A); BitVector_Destroy(B); - } + } return(error); -} + } -ErrCode BitVector_GCD(unsigned int * X, unsigned int * Y, unsigned int * Z) -{ + ErrCode BitVector_GCD(unsigned int * X, unsigned int * Y, unsigned int * Z) + { ErrCode error = ErrCode_Ok; unsigned int bits = bits_(X); unsigned int size = size_(X); @@ -2699,82 +2699,82 @@ ErrCode BitVector_GCD(unsigned int * X, unsigned int * Y, unsigned int * Z) unsigned int * T; /* - Requirements: - - All bit vectors must have equal sizes - Features: - - The contents of Y && Z are preserved - - X may be identical with Y || Z (or both) - (in-place is possible!) - - GCD(0,z) == GCD(z,0) == z - - negative values are h&&led correctly + Requirements: + - All bit vectors must have equal sizes + Features: + - The contents of Y && Z are preserved + - X may be identical with Y || Z (or both) + (in-place is possible!) + - GCD(0,z) == GCD(z,0) == z + - negative values are h&&led correctly */ if ((bits != bits_(Y)) || (bits != bits_(Z))) return(ErrCode_Size); if (BitVector_is_empty(Y)) - { + { if (X != Z) BitVector_Copy(X,Z); return(ErrCode_Ok); - } + } if (BitVector_is_empty(Z)) - { + { if (X != Y) BitVector_Copy(X,Y); return(ErrCode_Ok); - } + } Q = BitVector_Create(bits,false); if (Q == NULL) - { + { return(ErrCode_Null); - } + } R = BitVector_Create(bits,false); if (R == NULL) - { + { BitVector_Destroy(Q); return(ErrCode_Null); - } + } A = BitVector_Create(bits,false); if (A == NULL) - { + { BitVector_Destroy(Q); BitVector_Destroy(R); return(ErrCode_Null); - } + } B = BitVector_Create(bits,false); if (B == NULL) - { + { BitVector_Destroy(Q); BitVector_Destroy(R); BitVector_Destroy(A); return(ErrCode_Null); - } + } size--; sgn_a = (((*(Y+size) &= mask) & msb) != 0); sgn_b = (((*(Z+size) &= mask) & msb) != 0); if (sgn_a) BitVector_Negate(A,Y); else BitVector_Copy(A,Y); if (sgn_b) BitVector_Negate(B,Z); else BitVector_Copy(B,Z); while (! error) - { + { if (! (error = BitVector_Div_Pos(Q,A,B,R))) - { + { if (BitVector_is_empty(R)) break; T = A; sgn_r = sgn_a; A = B; sgn_a = sgn_b; B = R; sgn_b = sgn_r; R = T; - } - } + } + } if (! error) - { + { if (sgn_b) BitVector_Negate(X,B); else BitVector_Copy(X,B); - } + } BitVector_Destroy(Q); BitVector_Destroy(R); BitVector_Destroy(A); BitVector_Destroy(B); return(error); -} + } -ErrCode BitVector_GCD2(unsigned int * U, unsigned int * V, unsigned int * W, unsigned int * X, unsigned int * Y) -{ + ErrCode BitVector_GCD2(unsigned int * U, unsigned int * V, unsigned int * W, unsigned int * X, unsigned int * Y) + { ErrCode error = ErrCode_Ok; unsigned int bits = bits_(U); unsigned int size = size_(U); @@ -2803,49 +2803,49 @@ ErrCode BitVector_GCD2(unsigned int * U, unsigned int * V, unsigned int * W, unsigned int * Z; /* - Requirements: - - All bit vectors must have equal sizes - - U, V, && W must all be distinct bit vectors - Features: - - The contents of X && Y are preserved - - U, V && W may be identical with X || Y (or both, - provided that U, V && W are mutually distinct) - (i.e., in-place is possible!) - - GCD(0,z) == GCD(z,0) == z - - negative values are h&&led correctly + Requirements: + - All bit vectors must have equal sizes + - U, V, && W must all be distinct bit vectors + Features: + - The contents of X && Y are preserved + - U, V && W may be identical with X || Y (or both, + provided that U, V && W are mutually distinct) + (i.e., in-place is possible!) + - GCD(0,z) == GCD(z,0) == z + - negative values are h&&led correctly */ if ((bits != bits_(V)) || (bits != bits_(W)) || (bits != bits_(X)) || (bits != bits_(Y))) - { + { return(ErrCode_Size); - } + } if ((U == V) || (U == W) || (V == W)) - { + { return(ErrCode_Same); - } + } if (BitVector_is_empty(X)) - { + { if (U != Y) BitVector_Copy(U,Y); BitVector_Empty(V); BitVector_Empty(W); *W = 1; return(ErrCode_Ok); - } + } if (BitVector_is_empty(Y)) - { + { if (U != X) BitVector_Copy(U,X); BitVector_Empty(V); BitVector_Empty(W); *V = 1; return(ErrCode_Ok); - } + } if ((L = BitVector_Create_List(bits,false,11)) == NULL) - { + { return(ErrCode_Null); - } + } Q = L[0]; R = L[1]; A = L[2]; @@ -2871,43 +2871,43 @@ ErrCode BitVector_GCD2(unsigned int * U, unsigned int * V, unsigned int * W, sgn_x = false; sgn_y = false; while (! error) - { + { if ((error = BitVector_Div_Pos(Q,A,B,R))) - { + { break; - } + } if (BitVector_is_empty(R)) - { + { break; - } + } sgn_q = sgn_a ^ sgn_b; if (sgn_x) BitVector_Negate(Z,X2); else BitVector_Copy(Z,X2); if ((error = BitVector_Mul_Pos(X3,Z,Q,true))) - { + { break; - } + } minus = ! (sgn_x ^ sgn_q); carry = 0; if (BitVector_compute(X3,X1,X3,minus,&carry)) - { + { error = ErrCode_Ovfl; break; - } + } sgn_x = (((*(X3+size) &= mask) & msb) != 0); if (sgn_y) BitVector_Negate(Z,Y2); else BitVector_Copy(Z,Y2); if ((error = BitVector_Mul_Pos(Y3,Z,Q,true))) - { + { break; - } + } minus = ! (sgn_y ^ sgn_q); carry = 0; if (BitVector_compute(Y3,Y1,Y3,minus,&carry)) - { + { error = ErrCode_Ovfl; break; - } + } sgn_y = (((*(Y3+size) &= mask) & msb) != 0); T = A; sgn_r = sgn_a; @@ -2924,19 +2924,19 @@ ErrCode BitVector_GCD2(unsigned int * U, unsigned int * V, unsigned int * W, Y1 = Y2; Y2 = Y3; Y3 = T; - } + } if (! error) - { + { if (sgn_b) BitVector_Negate(U,B); else BitVector_Copy(U,B); BitVector_Copy(V,X2); BitVector_Copy(W,Y2); - } + } BitVector_Destroy_List(L,11); return(error); -} + } -ErrCode BitVector_Power(unsigned int * X, unsigned int * Y, unsigned int * Z) -{ + ErrCode BitVector_Power(unsigned int * X, unsigned int * Y, unsigned int * Z) + { ErrCode error = ErrCode_Ok; unsigned int bits = bits_(X); boolean first = true; @@ -2946,56 +2946,56 @@ ErrCode BitVector_Power(unsigned int * X, unsigned int * Y, unsigned int * Z) unsigned int * T; /* - Requirements: - - X must have at least the same size as Y but may be larger (!) - - X may not be identical with Z - - Z must be positive - Features: - - The contents of Y && Z are preserved + Requirements: + - X must have at least the same size as Y but may be larger (!) + - X may not be identical with Z + - Z must be positive + Features: + - The contents of Y && Z are preserved */ if (X == Z) return(ErrCode_Same); if (bits < bits_(Y)) return(ErrCode_Size); if (BitVector_msb_(Z)) return(ErrCode_Expo); if ((last = Set_Max(Z)) < 0L) - { + { if (bits < 2) return(ErrCode_Ovfl); BitVector_Empty(X); *X |= LSB; return(ErrCode_Ok); /* anything ^ 0 == 1 */ - } + } if (BitVector_is_empty(Y)) - { + { if (X != Y) BitVector_Empty(X); return(ErrCode_Ok); /* 0 ^ anything ! zero == 0 */ - } + } T = BitVector_Create(bits,false); if (T == NULL) return(ErrCode_Null); limit = (unsigned int) last; for ( count = 0; ((!error) && (count <= limit)); count++ ) - { + { if ( BIT_VECTOR_TST_BIT(Z,count) ) - { + { if (first) - { + { first = false; if (count) { BitVector_Copy(X,T); } else { if (X != Y) BitVector_Copy(X,Y); } - } + } else error = BitVector_Multiply(X,T,X); /* order important because T > X */ - } + } if ((!error) && (count < limit)) - { + { if (count) error = BitVector_Multiply(T,T,T); else error = BitVector_Multiply(T,Y,Y); - } - } + } + } BitVector_Destroy(T); return(error); -} + } -void BitVector_Block_Store(unsigned int * addr, unsigned char * buffer, unsigned int length) -{ + void BitVector_Block_Store(unsigned int * addr, unsigned char * buffer, unsigned int length) + { unsigned int size = size_(addr); unsigned int mask = mask_(addr); unsigned int value; @@ -3003,22 +3003,22 @@ void BitVector_Block_Store(unsigned int * addr, unsigned char * buffer, unsigne /* provide translation for independence of endian-ness: */ if (size > 0) - { + { while (size-- > 0) - { + { value = 0; for ( count = 0; (length > 0) && (count < BITS); count += 8 ) - { + { value |= (((unsigned int) *buffer++) << count); length--; - } + } *addr++ = value; - } + } *(--addr) &= mask; - } -} + } + } -unsigned char * BitVector_Block_Read(unsigned int * addr, unsigned int * length) -{ + unsigned char * BitVector_Block_Read(unsigned int * addr, unsigned int * length) + { unsigned int size = size_(addr); unsigned int value; unsigned int count; @@ -3031,100 +3031,100 @@ unsigned char * BitVector_Block_Read(unsigned int * addr, unsigned int * length if (buffer == NULL) return(NULL); target = buffer; if (size > 0) - { + { *(addr+size-1) &= mask_(addr); while (size-- > 0) - { + { value = *addr++; count = BITS >> 3; while (count-- > 0) - { + { *target++ = (unsigned char) (value & 0x00FF); if (count > 0) value >>= 8; - } - } - } + } + } + } *target = (unsigned char) '\0'; return(buffer); -} + } -void BitVector_Word_Store(unsigned int * addr, unsigned int offset, unsigned int value) -{ + void BitVector_Word_Store(unsigned int * addr, unsigned int offset, unsigned int value) + { unsigned int size = size_(addr); if (size > 0) - { + { if (offset < size) *(addr+offset) = value; *(addr+size-1) &= mask_(addr); - } -} + } + } -unsigned int BitVector_Word_Read(unsigned int * addr, unsigned int offset) -{ + unsigned int BitVector_Word_Read(unsigned int * addr, unsigned int offset) + { unsigned int size = size_(addr); if (size > 0) - { + { *(addr+size-1) &= mask_(addr); if (offset < size) return( *(addr+offset) ); - } + } return( (unsigned int) 0 ); -} + } -void BitVector_Word_Insert(unsigned int * addr, unsigned int offset, unsigned int count, - boolean clear) -{ + void BitVector_Word_Insert(unsigned int * addr, unsigned int offset, unsigned int count, + boolean clear) + { unsigned int size = size_(addr); unsigned int mask = mask_(addr); unsigned int * last = addr+size-1; if (size > 0) - { + { *last &= mask; if (offset > size) offset = size; BIT_VECTOR_ins_words(addr+offset,size-offset,count,clear); *last &= mask; - } -} + } + } -void BitVector_Word_Delete(unsigned int * addr, unsigned int offset, unsigned int count, - boolean clear) -{ + void BitVector_Word_Delete(unsigned int * addr, unsigned int offset, unsigned int count, + boolean clear) + { unsigned int size = size_(addr); unsigned int mask = mask_(addr); unsigned int * last = addr+size-1; if (size > 0) - { + { *last &= mask; if (offset > size) offset = size; BIT_VECTOR_del_words(addr+offset,size-offset,count,clear); *last &= mask; - } -} + } + } -void BitVector_Chunk_Store(unsigned int * addr, unsigned int chunksize, unsigned int offset, - unsigned long value) -{ + void BitVector_Chunk_Store(unsigned int * addr, unsigned int chunksize, unsigned int offset, + unsigned long value) + { unsigned int bits = bits_(addr); unsigned int mask; unsigned int temp; if ((chunksize > 0) && (offset < bits)) - { + { if (chunksize > LONGBITS) chunksize = LONGBITS; if ((offset + chunksize) > bits) chunksize = bits - offset; addr += offset >> LOGBITS; offset &= MODMASK; while (chunksize > 0) - { + { mask = (unsigned int) (~0L << offset); bits = offset + chunksize; if (bits < BITS) - { + { mask &= (unsigned int) ~(~0L << bits); bits = chunksize; - } + } else bits = BITS - offset; temp = (unsigned int) (value << offset); temp &= mask; @@ -3133,12 +3133,12 @@ void BitVector_Chunk_Store(unsigned int * addr, unsigned int chunksize, unsigne value >>= bits; chunksize -= bits; offset = 0; - } - } -} + } + } + } -unsigned long BitVector_Chunk_Read(unsigned int * addr, unsigned int chunksize, unsigned int offset) -{ + unsigned long BitVector_Chunk_Read(unsigned int * addr, unsigned int chunksize, unsigned int offset) + { unsigned int bits = bits_(addr); unsigned int chunkbits = 0; unsigned long value = 0L; @@ -3146,121 +3146,121 @@ unsigned long BitVector_Chunk_Read(unsigned int * addr, unsigned int chunksize, unsigned int mask; if ((chunksize > 0) && (offset < bits)) - { + { if (chunksize > LONGBITS) chunksize = LONGBITS; if ((offset + chunksize) > bits) chunksize = bits - offset; addr += offset >> LOGBITS; offset &= MODMASK; while (chunksize > 0) - { + { bits = offset + chunksize; if (bits < BITS) - { + { mask = (unsigned int) ~(~0L << bits); bits = chunksize; - } + } else - { + { mask = (unsigned int) ~0L; bits = BITS - offset; - } + } temp = (unsigned long) ((*addr++ & mask) >> offset); value |= temp << chunkbits; chunkbits += bits; chunksize -= bits; offset = 0; - } - } + } + } return(value); -} + } - /*******************/ - /* set operations: */ - /*******************/ + /*******************/ + /* set operations: */ + /*******************/ -void Set_Union(unsigned int * X, unsigned int * Y, unsigned int * Z) /* X = Y + Z */ -{ + void Set_Union(unsigned int * X, unsigned int * Y, unsigned int * Z) /* X = Y + Z */ + { unsigned int bits = bits_(X); unsigned int size = size_(X); unsigned int mask = mask_(X); if ((size > 0) && (bits == bits_(Y)) && (bits == bits_(Z))) - { + { while (size-- > 0) *X++ = *Y++ | *Z++; *(--X) &= mask; - } -} + } + } -void Set_Intersection(unsigned int * X, unsigned int * Y, unsigned int * Z) /* X = Y * Z */ -{ + void Set_Intersection(unsigned int * X, unsigned int * Y, unsigned int * Z) /* X = Y * Z */ + { unsigned int bits = bits_(X); unsigned int size = size_(X); unsigned int mask = mask_(X); if ((size > 0) && (bits == bits_(Y)) && (bits == bits_(Z))) - { + { while (size-- > 0) *X++ = *Y++ & *Z++; *(--X) &= mask; - } -} + } + } -void Set_Difference(unsigned int * X, unsigned int * Y, unsigned int * Z) /* X = Y \ Z */ -{ + void Set_Difference(unsigned int * X, unsigned int * Y, unsigned int * Z) /* X = Y \ Z */ + { unsigned int bits = bits_(X); unsigned int size = size_(X); unsigned int mask = mask_(X); if ((size > 0) && (bits == bits_(Y)) && (bits == bits_(Z))) - { + { while (size-- > 0) *X++ = *Y++ & ~ *Z++; *(--X) &= mask; - } -} + } + } -void Set_ExclusiveOr(unsigned int * X, unsigned int * Y, unsigned int * Z) /* X=(Y+Z)\(Y*Z) */ -{ + void Set_ExclusiveOr(unsigned int * X, unsigned int * Y, unsigned int * Z) /* X=(Y+Z)\(Y*Z) */ + { unsigned int bits = bits_(X); unsigned int size = size_(X); unsigned int mask = mask_(X); if ((size > 0) && (bits == bits_(Y)) && (bits == bits_(Z))) - { + { while (size-- > 0) *X++ = *Y++ ^ *Z++; *(--X) &= mask; - } -} + } + } -void Set_Complement(unsigned int * X, unsigned int * Y) /* X = ~Y */ -{ + void Set_Complement(unsigned int * X, unsigned int * Y) /* X = ~Y */ + { unsigned int size = size_(X); unsigned int mask = mask_(X); if ((size > 0) && (bits_(X) == bits_(Y))) - { + { while (size-- > 0) *X++ = ~ *Y++; *(--X) &= mask; - } -} + } + } - /******************/ - /* set functions: */ - /******************/ + /******************/ + /* set functions: */ + /******************/ -boolean Set_subset(unsigned int * X, unsigned int * Y) /* X subset Y ? */ -{ + boolean Set_subset(unsigned int * X, unsigned int * Y) /* X subset Y ? */ + { unsigned int size = size_(X); boolean r = false; if ((size > 0) && (bits_(X) == bits_(Y))) - { + { r = true; while (r && (size-- > 0)) r = ((*X++ & ~ *Y++) == 0); - } + } return(r); -} + } -unsigned int Set_Norm(unsigned int * addr) /* = | X | */ -{ + unsigned int Set_Norm(unsigned int * addr) /* = | X | */ + { unsigned char * byte; unsigned int bytes; unsigned int n; @@ -3269,76 +3269,76 @@ unsigned int Set_Norm(unsigned int * addr) /* = bytes = size_(addr) << FACTOR; n = 0; while (bytes-- > 0) - { + { n += BitVector_BYTENORM[*byte++]; - } + } return(n); -} + } -unsigned int Set_Norm2(unsigned int * addr) /* = | X | */ -{ + unsigned int Set_Norm2(unsigned int * addr) /* = | X | */ + { unsigned int size = size_(addr); unsigned int w0,w1; unsigned int n,k; n = 0; while (size-- > 0) - { + { k = 0; w1 = ~ (w0 = *addr++); while (w0 && w1) - { + { w0 &= w0 - 1; w1 &= w1 - 1; k++; - } + } if (w0 == 0) n += k; else n += BITS - k; - } + } return(n); -} + } -unsigned int Set_Norm3(unsigned int * addr) /* = | X | */ -{ + unsigned int Set_Norm3(unsigned int * addr) /* = | X | */ + { unsigned int size = size_(addr); unsigned int count = 0; unsigned int c; while (size-- > 0) - { + { c = *addr++; while (c) - { + { c &= c - 1; count++; - } - } + } + } return(count); -} + } -signed long Set_Min(unsigned int * addr) /* = min(X) */ -{ + signed long Set_Min(unsigned int * addr) /* = min(X) */ + { boolean empty = true; unsigned int size = size_(addr); unsigned int i = 0; unsigned int c = 0; /* silence compiler warning */ while (empty && (size-- > 0)) - { + { if ((c = *addr++)) empty = false; else i++; - } + } if (empty) return((signed long) LONG_MAX); /* plus infinity */ i <<= LOGBITS; while (! (c & LSB)) - { + { c >>= 1; i++; - } + } return((signed long) i); -} + } -signed long Set_Max(unsigned int * addr) /* = max(X) */ -{ + signed long Set_Max(unsigned int * addr) /* = max(X) */ + { boolean empty = true; unsigned int size = size_(addr); unsigned int i = size; @@ -3346,27 +3346,27 @@ signed long Set_Max(unsigned int * addr) /* = ma addr += size-1; while (empty && (size-- > 0)) - { + { if ((c = *addr--)) empty = false; else i--; - } + } if (empty) return((signed long) LONG_MIN); /* minus infinity */ i <<= LOGBITS; while (! (c & MSB)) - { + { c <<= 1; i--; - } + } return((signed long) --i); -} + } - /**********************************/ - /* matrix-of-booleans operations: */ - /**********************************/ + /**********************************/ + /* matrix-of-booleans operations: */ + /**********************************/ -void Matrix_Multiplication(unsigned int * X, unsigned int rowsX, unsigned int colsX, - unsigned int * Y, unsigned int rowsY, unsigned int colsY, - unsigned int * Z, unsigned int rowsZ, unsigned int colsZ) -{ + void Matrix_Multiplication(unsigned int * X, unsigned int rowsX, unsigned int colsX, + unsigned int * Y, unsigned int rowsY, unsigned int colsY, + unsigned int * Z, unsigned int rowsZ, unsigned int colsZ) + { unsigned int i; unsigned int j; unsigned int k; @@ -3377,37 +3377,37 @@ void Matrix_Multiplication(unsigned int * X, unsigned int rowsX, unsigned int c unsigned int termY; unsigned int sum; - if ((colsY == rowsZ) && (rowsX == rowsY) && (colsX == colsZ) && - (bits_(X) == rowsX*colsX) && - (bits_(Y) == rowsY*colsY) && - (bits_(Z) == rowsZ*colsZ)) - { - for ( i = 0; i < rowsY; i++ ) - { - termX = i * colsX; - termY = i * colsY; - for ( j = 0; j < colsZ; j++ ) - { - indxX = termX + j; - sum = 0; - for ( k = 0; k < colsY; k++ ) - { - indxY = termY + k; - indxZ = k * colsZ + j; - if ( BIT_VECTOR_TST_BIT(Y,indxY) & - BIT_VECTOR_TST_BIT(Z,indxZ) ) sum ^= 1; - } - if (sum) BIT_VECTOR_SET_BIT(X,indxX) - else BIT_VECTOR_CLR_BIT(X,indxX) - } - } + if ((colsY == rowsZ) && (rowsX == rowsY) && (colsX == colsZ) && + (bits_(X) == rowsX*colsX) && + (bits_(Y) == rowsY*colsY) && + (bits_(Z) == rowsZ*colsZ)) + { + for ( i = 0; i < rowsY; i++ ) + { + termX = i * colsX; + termY = i * colsY; + for ( j = 0; j < colsZ; j++ ) + { + indxX = termX + j; + sum = 0; + for ( k = 0; k < colsY; k++ ) + { + indxY = termY + k; + indxZ = k * colsZ + j; + if ( BIT_VECTOR_TST_BIT(Y,indxY) & + BIT_VECTOR_TST_BIT(Z,indxZ) ) sum ^= 1; + } + if (sum) BIT_VECTOR_SET_BIT(X,indxX) + else BIT_VECTOR_CLR_BIT(X,indxX) + } + } + } } -} -void Matrix_Product(unsigned int * X, unsigned int rowsX, unsigned int colsX, - unsigned int * Y, unsigned int rowsY, unsigned int colsY, - unsigned int * Z, unsigned int rowsZ, unsigned int colsZ) -{ + void Matrix_Product(unsigned int * X, unsigned int rowsX, unsigned int colsX, + unsigned int * Y, unsigned int rowsY, unsigned int colsY, + unsigned int * Z, unsigned int rowsZ, unsigned int colsZ) + { unsigned int i; unsigned int j; unsigned int k; @@ -3418,35 +3418,35 @@ void Matrix_Product(unsigned int * X, unsigned int rowsX, unsigned int colsX, unsigned int termY; unsigned int sum; - if ((colsY == rowsZ) && (rowsX == rowsY) && (colsX == colsZ) && - (bits_(X) == rowsX*colsX) && - (bits_(Y) == rowsY*colsY) && - (bits_(Z) == rowsZ*colsZ)) - { - for ( i = 0; i < rowsY; i++ ) - { - termX = i * colsX; - termY = i * colsY; - for ( j = 0; j < colsZ; j++ ) - { - indxX = termX + j; - sum = 0; - for ( k = 0; k < colsY; k++ ) - { - indxY = termY + k; - indxZ = k * colsZ + j; - if ( BIT_VECTOR_TST_BIT(Y,indxY) & - BIT_VECTOR_TST_BIT(Z,indxZ) ) sum |= 1; - } - if (sum) BIT_VECTOR_SET_BIT(X,indxX) - else BIT_VECTOR_CLR_BIT(X,indxX) - } - } + if ((colsY == rowsZ) && (rowsX == rowsY) && (colsX == colsZ) && + (bits_(X) == rowsX*colsX) && + (bits_(Y) == rowsY*colsY) && + (bits_(Z) == rowsZ*colsZ)) + { + for ( i = 0; i < rowsY; i++ ) + { + termX = i * colsX; + termY = i * colsY; + for ( j = 0; j < colsZ; j++ ) + { + indxX = termX + j; + sum = 0; + for ( k = 0; k < colsY; k++ ) + { + indxY = termY + k; + indxZ = k * colsZ + j; + if ( BIT_VECTOR_TST_BIT(Y,indxY) & + BIT_VECTOR_TST_BIT(Z,indxZ) ) sum |= 1; + } + if (sum) BIT_VECTOR_SET_BIT(X,indxX) + else BIT_VECTOR_CLR_BIT(X,indxX) + } + } + } } -} -void Matrix_Closure(unsigned int * addr, unsigned int rows, unsigned int cols) -{ + void Matrix_Closure(unsigned int * addr, unsigned int rows, unsigned int cols) + { unsigned int i; unsigned int j; unsigned int k; @@ -3457,36 +3457,36 @@ void Matrix_Closure(unsigned int * addr, unsigned int rows, unsigned int cols) unsigned int termi; unsigned int termk; - if ((rows == cols) && (bits_(addr) == rows*cols)) - { - for ( i = 0; i < rows; i++ ) - { - ii = i * cols + i; - BIT_VECTOR_SET_BIT(addr,ii) - } - for ( k = 0; k < rows; k++ ) - { - termk = k * cols; + if ((rows == cols) && (bits_(addr) == rows*cols)) + { for ( i = 0; i < rows; i++ ) - { - termi = i * cols; - ik = termi + k; - for ( j = 0; j < rows; j++ ) - { - ij = termi + j; - kj = termk + j; - if ( BIT_VECTOR_TST_BIT(addr,ik) & - BIT_VECTOR_TST_BIT(addr,kj) ) - BIT_VECTOR_SET_BIT(addr,ij) - } - } - } + { + ii = i * cols + i; + BIT_VECTOR_SET_BIT(addr,ii) + } + for ( k = 0; k < rows; k++ ) + { + termk = k * cols; + for ( i = 0; i < rows; i++ ) + { + termi = i * cols; + ik = termi + k; + for ( j = 0; j < rows; j++ ) + { + ij = termi + j; + kj = termk + j; + if ( BIT_VECTOR_TST_BIT(addr,ik) & + BIT_VECTOR_TST_BIT(addr,kj) ) + BIT_VECTOR_SET_BIT(addr,ij) + } + } + } + } } -} -void Matrix_Transpose(unsigned int * X, unsigned int rowsX, unsigned int colsX, - unsigned int * Y, unsigned int rowsY, unsigned int colsY) -{ + void Matrix_Transpose(unsigned int * X, unsigned int rowsX, unsigned int colsX, + unsigned int * Y, unsigned int rowsY, unsigned int colsY) + { unsigned int i; unsigned int j; unsigned int ii; @@ -3502,66 +3502,66 @@ void Matrix_Transpose(unsigned int * X, unsigned int rowsX, unsigned int colsX, unsigned int termj; boolean swap; - /* BEWARE that "in-place" is ONLY possible if the matrix is quadratic!! */ - - if ((rowsX == colsY) && (colsX == rowsY) && - (bits_(X) == rowsX*colsX) && - (bits_(Y) == rowsY*colsY)) - { - if (rowsY == colsY) /* in-place is possible! */ - { - for ( i = 0; i < rowsY; i++ ) - { - termi = i * colsY; - for ( j = 0; j < i; j++ ) - { - termj = j * colsX; - ij = termi + j; - ji = termj + i; - addij = ij >> LOGBITS; - addji = ji >> LOGBITS; - bitij = BITMASKTAB[ij & MODMASK]; - bitji = BITMASKTAB[ji & MODMASK]; - swap = ((*(Y+addij) & bitij) != 0); - if ((*(Y+addji) & bitji) != 0) - *(X+addij) |= bitij; - else - *(X+addij) &= ~ bitij; - if (swap) - *(X+addji) |= bitji; - else - *(X+addji) &= ~ bitji; - } - ii = termi + i; - addii = ii >> LOGBITS; - bitii = BITMASKTAB[ii & MODMASK]; - if ((*(Y+addii) & bitii) != 0) - *(X+addii) |= bitii; - else - *(X+addii) &= ~ bitii; - } - } - else /* rowsX != colsX, in-place is ~ possible! */ - { - for ( i = 0; i < rowsY; i++ ) - { - termi = i * colsY; - for ( j = 0; j < colsY; j++ ) - { - termj = j * colsX; - ij = termi + j; - ji = termj + i; - addij = ij >> LOGBITS; - addji = ji >> LOGBITS; - bitij = BITMASKTAB[ij & MODMASK]; - bitji = BITMASKTAB[ji & MODMASK]; - if ((*(Y+addij) & bitij) != 0) - *(X+addji) |= bitji; + /* BEWARE that "in-place" is ONLY possible if the matrix is quadratic!! */ + + if ((rowsX == colsY) && (colsX == rowsY) && + (bits_(X) == rowsX*colsX) && + (bits_(Y) == rowsY*colsY)) + { + if (rowsY == colsY) /* in-place is possible! */ + { + for ( i = 0; i < rowsY; i++ ) + { + termi = i * colsY; + for ( j = 0; j < i; j++ ) + { + termj = j * colsX; + ij = termi + j; + ji = termj + i; + addij = ij >> LOGBITS; + addji = ji >> LOGBITS; + bitij = BITMASKTAB[ij & MODMASK]; + bitji = BITMASKTAB[ji & MODMASK]; + swap = ((*(Y+addij) & bitij) != 0); + if ((*(Y+addji) & bitji) != 0) + *(X+addij) |= bitij; + else + *(X+addij) &= ~ bitij; + if (swap) + *(X+addji) |= bitji; + else + *(X+addji) &= ~ bitji; + } + ii = termi + i; + addii = ii >> LOGBITS; + bitii = BITMASKTAB[ii & MODMASK]; + if ((*(Y+addii) & bitii) != 0) + *(X+addii) |= bitii; else - *(X+addji) &= ~ bitji; - } - } - } + *(X+addii) &= ~ bitii; + } + } + else /* rowsX != colsX, in-place is ~ possible! */ + { + for ( i = 0; i < rowsY; i++ ) + { + termi = i * colsY; + for ( j = 0; j < colsY; j++ ) + { + termj = j * colsX; + ij = termi + j; + ji = termj + i; + addij = ij >> LOGBITS; + addji = ji >> LOGBITS; + bitij = BITMASKTAB[ij & MODMASK]; + bitji = BITMASKTAB[ji & MODMASK]; + if ((*(Y+addij) & bitij) != 0) + *(X+addji) |= bitji; + else + *(X+addji) &= ~ bitji; + } + } + } + } } -} }; //end of namespace CONSTANTBV diff --git a/src/constantbv/constantbv.h b/src/constantbv/constantbv.h index 47e0c56..3241b45 100644 --- a/src/constantbv/constantbv.h +++ b/src/constantbv/constantbv.h @@ -62,23 +62,23 @@ namespace CONSTANTBV { #endif typedef enum { - ErrCode_Ok = 0, /* everything went allright */ - ErrCode_Type, /* types word and size_t have incompatible sizes */ - ErrCode_Bits, /* bits of word and sizeof(word) are inconsistent */ - ErrCode_Word, /* size of word is less than 16 bits */ - ErrCode_Long, /* size of word is greater than size of long */ - ErrCode_Powr, /* number of bits of word is not a power of two */ - ErrCode_Loga, /* error in calculation of logarithm */ - ErrCode_Null, /* unable to allocate memory */ - ErrCode_Indx, /* index out of range */ - ErrCode_Ordr, /* minimum > maximum index */ - ErrCode_Size, /* bit vector size mismatch */ - ErrCode_Pars, /* input string syntax error */ - ErrCode_Ovfl, /* numeric overflow error */ - ErrCode_Same, /* operands must be distinct */ - ErrCode_Expo, /* exponent must be positive */ - ErrCode_Zero /* division by zero error */ - } ErrCode; + ErrCode_Ok = 0, /* everything went allright */ + ErrCode_Type, /* types word and size_t have incompatible sizes */ + ErrCode_Bits, /* bits of word and sizeof(word) are inconsistent */ + ErrCode_Word, /* size of word is less than 16 bits */ + ErrCode_Long, /* size of word is greater than size of long */ + ErrCode_Powr, /* number of bits of word is not a power of two */ + ErrCode_Loga, /* error in calculation of logarithm */ + ErrCode_Null, /* unable to allocate memory */ + ErrCode_Indx, /* index out of range */ + ErrCode_Ordr, /* minimum > maximum index */ + ErrCode_Size, /* bit vector size mismatch */ + ErrCode_Pars, /* input string syntax error */ + ErrCode_Ovfl, /* numeric overflow error */ + ErrCode_Same, /* operands must be distinct */ + ErrCode_Expo, /* exponent must be positive */ + ErrCode_Zero /* division by zero error */ + } ErrCode; /* ===> MISCELLANEOUS BASIC FUNCTIONS: <=== */ @@ -129,14 +129,14 @@ namespace CONSTANTBV { void BitVector_Interval_Reverse (unsigned int * addr, unsigned int lower, unsigned int upper); boolean BitVector_interval_scan_inc (unsigned int * addr, unsigned int start, - unsigned int * min, unsigned int * max); + unsigned int * min, unsigned int * max); boolean BitVector_interval_scan_dec (unsigned int * addr, unsigned int start, - unsigned int * min, unsigned int * max); + unsigned int * min, unsigned int * max); void BitVector_Interval_Copy (unsigned int * X, unsigned int * Y, - unsigned int Xoffset, unsigned int Yoffset, unsigned int length); + unsigned int Xoffset, unsigned int Yoffset, unsigned int length); unsigned int * BitVector_Interval_Substitute(unsigned int * X, unsigned int * Y, - unsigned int Xoffset, unsigned int Xlength, - unsigned int Yoffset, unsigned int Ylength); + unsigned int Xoffset, unsigned int Xlength, + unsigned int Yoffset, unsigned int Ylength); /* ===> bit vector test functions: */ boolean BitVector_is_empty (unsigned int * addr); /* X == {} ? */ @@ -176,19 +176,19 @@ namespace CONSTANTBV { /* ===> bit vector insert/delete bits: */ void BitVector_Insert (unsigned int * addr, - unsigned int offset, unsigned int count, boolean clear); + unsigned int offset, unsigned int count, boolean clear); void BitVector_Delete (unsigned int * addr, - unsigned int offset, unsigned int count, boolean clear); + unsigned int offset, unsigned int count, boolean clear); /* ===> bit vector arithmetic: */ boolean BitVector_increment (unsigned int * addr); /* X++ */ boolean BitVector_decrement (unsigned int * addr); /* X-- */ boolean BitVector_compute (unsigned int * X, unsigned int * Y, - unsigned int * Z, boolean minus, boolean *carry); + unsigned int * Z, boolean minus, boolean *carry); boolean BitVector_add (unsigned int * X, - unsigned int * Y, unsigned int * Z, boolean *carry); + unsigned int * Y, unsigned int * Z, boolean *carry); boolean BitVector_sub (unsigned int * X, - unsigned int * Y, unsigned int * Z, boolean *carry); /* X = Y-Z*/ + unsigned int * Y, unsigned int * Z, boolean *carry); /* X = Y-Z*/ boolean BitVector_inc (unsigned int * X, unsigned int * Y); boolean BitVector_dec (unsigned int * X, unsigned int * Y); @@ -196,33 +196,33 @@ namespace CONSTANTBV { void BitVector_Absolute (unsigned int * X, unsigned int * Y); signed int BitVector_Sign (unsigned int * addr); ErrCode BitVector_Mul_Pos (unsigned int * X, - unsigned int * Y, unsigned int * Z, boolean strict); + unsigned int * Y, unsigned int * Z, boolean strict); ErrCode BitVector_Multiply (unsigned int * X, unsigned int * Y, unsigned int * Z); ErrCode BitVector_Div_Pos (unsigned int * Q, unsigned int * X, unsigned int * Y, unsigned int * R); ErrCode BitVector_Divide (unsigned int * Q, unsigned int * X, unsigned int * Y, unsigned int * R); ErrCode BitVector_GCD (unsigned int * X, unsigned int * Y, unsigned int * Z); ErrCode BitVector_GCD2 (unsigned int * U, unsigned int * V, unsigned int * W, /* O */ - unsigned int * X, unsigned int * Y); /* I */ + unsigned int * X, unsigned int * Y); /* I */ ErrCode BitVector_Power (unsigned int * X, unsigned int * Y, unsigned int * Z); /* ===> direct memory access functions: */ void BitVector_Block_Store (unsigned int * addr, - unsigned char * buffer, unsigned int length); + unsigned char * buffer, unsigned int length); unsigned char * BitVector_Block_Read (unsigned int * addr, unsigned int * length); /* ===> word array functions: */ void BitVector_Word_Store (unsigned int * addr, unsigned int offset, unsigned int value); unsigned int BitVector_Word_Read (unsigned int * addr, unsigned int offset); void BitVector_Word_Insert (unsigned int * addr, - unsigned int offset, unsigned int count, boolean clear); + unsigned int offset, unsigned int count, boolean clear); void BitVector_Word_Delete (unsigned int * addr, - unsigned int offset, unsigned int count, boolean clear); + unsigned int offset, unsigned int count, boolean clear); /* ===> arbitrary size chunk functions: */ void BitVector_Chunk_Store (unsigned int * addr, unsigned int chunksize, - unsigned int offset, unsigned long value); + unsigned int offset, unsigned long value); unsigned long BitVector_Chunk_Read (unsigned int * addr, - unsigned int chunksize,unsigned int offset); + unsigned int chunksize,unsigned int offset); /* ===> set operations: */ void Set_Union (unsigned int * X, unsigned int * Y, unsigned int * Z); /* X = Y + Z */ @@ -241,14 +241,14 @@ namespace CONSTANTBV { /* ===> matrix-of-booleans operations: */ void Matrix_Multiplication (unsigned int * X, unsigned int rowsX, unsigned int colsX, - unsigned int * Y, unsigned int rowsY, unsigned int colsY, - unsigned int * Z, unsigned int rowsZ, unsigned int colsZ); + unsigned int * Y, unsigned int rowsY, unsigned int colsY, + unsigned int * Z, unsigned int rowsZ, unsigned int colsZ); void Matrix_Product (unsigned int * X, unsigned int rowsX, unsigned int colsX, - unsigned int * Y, unsigned int rowsY, unsigned int colsY, - unsigned int * Z, unsigned int rowsZ, unsigned int colsZ); + unsigned int * Y, unsigned int rowsY, unsigned int colsY, + unsigned int * Z, unsigned int rowsZ, unsigned int colsZ); void Matrix_Closure (unsigned int * addr, unsigned int rows, unsigned int cols); void Matrix_Transpose (unsigned int * X, unsigned int rowsX, unsigned int colsX, - unsigned int * Y, unsigned int rowsY, unsigned int colsY); + unsigned int * Y, unsigned int rowsY, unsigned int colsY); /*****************************************************************************/ /* MODULE RESOURCES: */ diff --git a/src/parser/let-funcs.cpp b/src/parser/let-funcs.cpp index 659a91c..0f65e21 100644 --- a/src/parser/let-funcs.cpp +++ b/src/parser/let-funcs.cpp @@ -44,7 +44,7 @@ namespace BEEV { //returns the var. ASTNode BeevMgr::ResolveID(const ASTNode& v) { if (_letid_expr_map == NULL) - InitializeLetIDMap(); + InitializeLetIDMap(); if(v.GetKind() != SYMBOL) { return v; @@ -57,9 +57,9 @@ namespace BEEV { ASTNodeMap::iterator it; if((it =_letid_expr_map->find(v)) != _letid_expr_map->end()) { if(it->second == ASTUndefined) - FatalError("Unresolved Identifier: ",v); + FatalError("Unresolved Identifier: ",v); else - return it->second; + return it->second; } //this is to mark the let-var as undefined. the let var is defined @@ -76,28 +76,28 @@ namespace BEEV { // This function simply cleans up the LetID -> LetExpr Map. void BeevMgr::CleanupLetIDMap(void) { - // ext/hash_map::clear() is very expensive on big empty lists. shortcut. + // ext/hash_map::clear() is very expensive on big empty lists. shortcut. if (_letid_expr_map->size() ==0) - return; + return; ASTNodeMap::iterator it = _letid_expr_map->begin(); ASTNodeMap::iterator itend = _letid_expr_map->end(); for(;it!=itend;it++) { if(it->second != ASTUndefined) { - it->first.SetValueWidth(0); - it->first.SetIndexWidth(0); + it->first.SetValueWidth(0); + it->first.SetIndexWidth(0); } } - // May contain lots of buckets, so reset. + // May contain lots of buckets, so reset. delete _letid_expr_map; _letid_expr_map = new ASTNodeMap(); } - void BeevMgr::InitializeLetIDMap(void) + void BeevMgr::InitializeLetIDMap(void) { - _letid_expr_map = new ASTNodeMap(); + _letid_expr_map = new ASTNodeMap(); } }; diff --git a/src/parser/main.cpp b/src/parser/main.cpp index 73d87cc..0cb181e 100644 --- a/src/parser/main.cpp +++ b/src/parser/main.cpp @@ -24,7 +24,7 @@ #include #ifdef EXT_HASH_MAP - using namespace __gnu_cxx; +using namespace __gnu_cxx; #endif /* GLOBAL FUNCTION: parser @@ -35,8 +35,8 @@ extern int cvcparse(); namespace BEEV { -extern BEEV::ASTNode SingleBitOne; -extern BEEV::ASTNode SingleBitZero; + extern BEEV::ASTNode SingleBitOne; + extern BEEV::ASTNode SingleBitZero; } const string version = "$Id$"; @@ -99,96 +99,96 @@ int main(int argc, char ** argv) { if(argv[i][0] == '-') { switch(argv[i][1]) { case 'a' : - BEEV::optimize_flag = false; - break; + BEEV::optimize_flag = false; + break; case 'b': - BEEV::print_STPinput_back_flag = true; - break; + BEEV::print_STPinput_back_flag = true; + break; case 'c': - BEEV::construct_counterexample_flag = true; - break; + BEEV::construct_counterexample_flag = true; + break; case 'd': - BEEV::construct_counterexample_flag = true; - BEEV::check_counterexample_flag = true; - break; + BEEV::construct_counterexample_flag = true; + BEEV::check_counterexample_flag = true; + break; case 'h': - fprintf(stderr,usage,prog); - cout << helpstring; - //BEEV::FatalError(""); - return -1; - break; + fprintf(stderr,usage,prog); + cout << helpstring; + //BEEV::FatalError(""); + return -1; + break; case 'n': - BEEV::print_output_flag = true; - break; + BEEV::print_output_flag = true; + break; case 'm': - BEEV::smtlib_parser_flag=true; - BEEV::division_by_zero_returns_one = true; - break; + BEEV::smtlib_parser_flag=true; + BEEV::division_by_zero_returns_one = true; + break; case 'p': - BEEV::print_counterexample_flag = true; - break; + BEEV::print_counterexample_flag = true; + break; case 'y': - BEEV::print_binary_flag = true; - break; + BEEV::print_binary_flag = true; + break; case 'q': - BEEV::print_arrayval_declaredorder_flag = true; - break; + BEEV::print_arrayval_declaredorder_flag = true; + break; case 'r': - BEEV::arrayread_refinement_flag = false; - break; + BEEV::arrayread_refinement_flag = false; + break; case 's' : - BEEV::stats_flag = true; - break; + BEEV::stats_flag = true; + break; case 'u': - BEEV::arraywrite_refinement_flag = false; - break; + BEEV::arraywrite_refinement_flag = false; + break; case 'v' : - BEEV::print_nodes_flag = true; - break; + BEEV::print_nodes_flag = true; + break; case 'w': - BEEV::wordlevel_solve_flag = false; - break; + BEEV::wordlevel_solve_flag = false; + break; case 'x': - BEEV::xor_flatten_flag = true; - break; + BEEV::xor_flatten_flag = true; + break; case 'z': - BEEV::print_sat_varorder_flag = true; - break; + BEEV::print_sat_varorder_flag = true; + break; default: - fprintf(stderr,usage,prog); - cout << helpstring; - //BEEV::FatalError(""); - return -1; - break; + fprintf(stderr,usage,prog); + cout << helpstring; + //BEEV::FatalError(""); + return -1; + break; } if(argv[i][2]) { - fprintf(stderr, "Multiple character options are not allowed.\n"); - fprintf(stderr, "(for example: -ab is not an abbreviation for -a -b)\n"); - fprintf(stderr,usage,prog); - cout << helpstring; - return -1; + fprintf(stderr, "Multiple character options are not allowed.\n"); + fprintf(stderr, "(for example: -ab is not an abbreviation for -a -b)\n"); + fprintf(stderr,usage,prog); + cout << helpstring; + return -1; } } else { infile = argv[i]; if (BEEV::smtlib_parser_flag) - { - smtin = fopen(infile,"r"); - if(smtin == NULL) - { - fprintf(stderr,"%s: Error: cannot open %s\n",prog,infile); - BEEV::FatalError(""); - } - } + { + smtin = fopen(infile,"r"); + if(smtin == NULL) + { + fprintf(stderr,"%s: Error: cannot open %s\n",prog,infile); + BEEV::FatalError(""); + } + } else - { - cvcin = fopen(infile,"r"); - if(cvcin == NULL) - { - fprintf(stderr,"%s: Error: cannot open %s\n",prog,infile); - BEEV::FatalError(""); - } - } + { + cvcin = fopen(infile,"r"); + if(cvcin == NULL) + { + fprintf(stderr,"%s: Error: cannot open %s\n",prog,infile); + BEEV::FatalError(""); + } + } } } diff --git a/src/simplifier/bvsolver.cpp b/src/simplifier/bvsolver.cpp index cd1ff6c..4d68ab6 100644 --- a/src/simplifier/bvsolver.cpp +++ b/src/simplifier/bvsolver.cpp @@ -36,757 +36,757 @@ //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 - { - 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; - } - } - 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; - } - 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_flag && 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 READ: -// { -// if(BVCONST != lhs[1].GetKind() || READ != rhs.GetKind() || -// BVCONST != rhs[1].GetKind() || lhs == rhs) -// { -// return eq; -// } -// else -// { -// 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_flag) - { - 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; - //_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_flag && 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 CheckEvenEqn - -//solve an eqn whose monomials have only even coefficients -ASTNode BVSolver::BVSolve_Even(const ASTNode& input) -{ - if (!wordlevel_solve_flag) - { - 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; - } - - //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() + //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 + { + 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; + } + } + 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; + } + 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_flag && 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 READ: + // { + // if(BVCONST != lhs[1].GetKind() || READ != rhs.GetKind() || + // BVCONST != rhs[1].GetKind() || lhs == rhs) + // { + // return eq; + // } + // else + // { + // 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_flag) + { + 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; + //_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_flag && 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 CheckEvenEqn + + //solve an eqn whose monomials have only even coefficients + ASTNode BVSolver::BVSolve_Even(const ASTNode& input) + { + if (!wordlevel_solve_flag) + { + 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; + } + + //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/src/simplifier/bvsolver.h b/src/simplifier/bvsolver.h index 1d4409b..49adb53 100644 --- a/src/simplifier/bvsolver.h +++ b/src/simplifier/bvsolver.h @@ -12,132 +12,132 @@ 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 + //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/src/simplifier/simplifier.cpp b/src/simplifier/simplifier.cpp index 44e5237..b4920d3 100644 --- a/src/simplifier/simplifier.cpp +++ b/src/simplifier/simplifier.cpp @@ -12,3023 +12,3023 @@ namespace BEEV { -bool BeevMgr::CheckMap(ASTNodeMap* VarConstMap, - const ASTNode& key, ASTNode& output) -{ - if(NULL == VarConstMap) - { - return false; - } - ASTNodeMap::iterator it; - if ((it = VarConstMap->find(key)) != VarConstMap->end()) - { - output = it->second; - return true; - } - return false; -} - - -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; -} - -// Push any reference count used by the key to the value. -void BeevMgr::UpdateSimplifyMap(const ASTNode& key, const ASTNode& value, bool pushNeg) -{ - // If there are references to the key, add them to the references of the value. - ASTNodeCountMap::const_iterator itKey, itValue; - itKey = ReferenceCount->find(key); - if (itKey != ReferenceCount->end()) - { - itValue = ReferenceCount->find(value); - if (itValue != ReferenceCount->end()) - (*ReferenceCount)[value] = itValue->second + itKey->second; - else - (*ReferenceCount)[value] = itKey->second; - } - - - 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; - - assert(e0 != e1); // One side should be a variable, the other a constant. - - //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)) - { - assert((e1.GetKind() == TRUE) || (e1.GetKind() == FALSE) || (e1.GetKind() == BVCONST)); - 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)) - { - assert((e0.GetKind() == TRUE) || (e0.GetKind() == FALSE) || (e0.GetKind() == BVCONST)); - 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))) - // || - // k2 == READ && b[0].GetKind() == SYMBOL && b[1].GetKind() == 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, ASTNodeMap* VarConstMap) -{ - Begin_RemoveWrites = false; - ASTNode out = SimplifyFormula(b, pushNeg, VarConstMap); - return out; -} - -void BeevMgr::BuildReferenceCountMap(const ASTNode& b) -{ - if (b.GetChildren().size() == 0) - return; - - ASTNodeCountMap::iterator it, itend; - - it = ReferenceCount->find(b); - if (it == ReferenceCount->end()) - { - (*ReferenceCount)[b] = 1; - } - else - { - (*ReferenceCount)[b] = it->second + 1; - return; - } - - const ASTVec& c = b.GetChildren(); - ASTVec::const_iterator itC = c.begin(); - ASTVec::const_iterator itendC = c.end(); - for (; itC != itendC; itC++) - { - BuildReferenceCountMap(*itC); - } -} - -ASTNode BeevMgr::SimplifyFormula_TopLevel(const ASTNode& b, bool pushNeg) -{ - ResetSimplifyMaps(); - BuildReferenceCountMap(b); - ASTNode out = SimplifyFormula(b, pushNeg); - ResetSimplifyMaps(); - return out; -} - -ASTNode BeevMgr::SimplifyFormula(const ASTNode& b, bool pushNeg, ASTNodeMap* VarConstMap) -{ - if (!optimize_flag) - 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 || FOR == kind || isAtomic(kind))) - { - SortByArith(ca); - a = CreateNode(kind, ca); - } - - ASTNode output; - if (CheckSimplifyMap(a, output, pushNeg)) - return output; - - a = PullUpITE(a); - kind = a.GetKind(); // pullUpITE can change the Kind of the node. - - 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; - case FOR: - output = SimplifyForFormula(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::SimplifyForFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap) { - //FIXME: Code this up properly later. Mainly pushing the negation down + bool BeevMgr::CheckMap(ASTNodeMap* VarConstMap, + const ASTNode& key, ASTNode& output) + { + if(NULL == VarConstMap) + { + return false; + } + ASTNodeMap::iterator it; + if ((it = VarConstMap->find(key)) != VarConstMap->end()) + { + output = it->second; + return true; + } + return false; + } + + + 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; + } + + // Push any reference count used by the key to the value. + void BeevMgr::UpdateSimplifyMap(const ASTNode& key, const ASTNode& value, bool pushNeg) + { + // If there are references to the key, add them to the references of the value. + ASTNodeCountMap::const_iterator itKey, itValue; + itKey = ReferenceCount->find(key); + if (itKey != ReferenceCount->end()) + { + itValue = ReferenceCount->find(value); + if (itValue != ReferenceCount->end()) + (*ReferenceCount)[value] = itValue->second + itKey->second; + else + (*ReferenceCount)[value] = itKey->second; + } + + + 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; + + assert(e0 != e1); // One side should be a variable, the other a constant. + + //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)) + { + assert((e1.GetKind() == TRUE) || (e1.GetKind() == FALSE) || (e1.GetKind() == BVCONST)); + 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)) + { + assert((e0.GetKind() == TRUE) || (e0.GetKind() == FALSE) || (e0.GetKind() == BVCONST)); + 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))) + // || + // k2 == READ && b[0].GetKind() == SYMBOL && b[1].GetKind() == 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, ASTNodeMap* VarConstMap) + { + Begin_RemoveWrites = false; + ASTNode out = SimplifyFormula(b, pushNeg, VarConstMap); + return out; + } + + void BeevMgr::BuildReferenceCountMap(const ASTNode& b) + { + if (b.GetChildren().size() == 0) + return; + + ASTNodeCountMap::iterator it, itend; + + it = ReferenceCount->find(b); + if (it == ReferenceCount->end()) + { + (*ReferenceCount)[b] = 1; + } + else + { + (*ReferenceCount)[b] = it->second + 1; + return; + } + + const ASTVec& c = b.GetChildren(); + ASTVec::const_iterator itC = c.begin(); + ASTVec::const_iterator itendC = c.end(); + for (; itC != itendC; itC++) + { + BuildReferenceCountMap(*itC); + } + } + + ASTNode BeevMgr::SimplifyFormula_TopLevel(const ASTNode& b, bool pushNeg) + { + ResetSimplifyMaps(); + BuildReferenceCountMap(b); + ASTNode out = SimplifyFormula(b, pushNeg); + ResetSimplifyMaps(); + return out; + } + + ASTNode BeevMgr::SimplifyFormula(const ASTNode& b, bool pushNeg, ASTNodeMap* VarConstMap) + { + if (!optimize_flag) + 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 || FOR == kind || isAtomic(kind))) + { + SortByArith(ca); + a = CreateNode(kind, ca); + } + + ASTNode output; + if (CheckSimplifyMap(a, output, pushNeg)) + return output; + + a = PullUpITE(a); + kind = a.GetKind(); // pullUpITE can change the Kind of the node. + + 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; + case FOR: + output = SimplifyForFormula(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::SimplifyForFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap) { + //FIXME: Code this up properly later. Mainly pushing the negation down + return a; + } + + ASTNode BeevMgr::SimplifyAtomicFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap) + { + if (!optimize_flag) + 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; + } + + //Look through the AND Node for terms that contradict. + //Should be made significantly more general.. + ASTNode BeevMgr::RemoveContradictionsFromAND(const ASTNode& in) + { + assert(AND == in.GetKind()); + const int childrenSize = in.GetChildren().size(); + + for (int i = 0; i < childrenSize; i++) + { + if (BVLT != in[i].GetKind()) + continue; + + for (int j = i + 1; j < childrenSize; j++) + { + if (BVLT != in[j].GetKind()) + continue; + if (in[i][0] == in[j][1] && in[i][1] == in[j][0]) // parameters are swapped. + return ASTFalse; + } + } + return in; + } + + // turns say (bvslt (ite a b c) (ite a d e)) INTO (ite a (bvslt b d) (bvslt c e)) + // Expensive. But makes some other simplifications possible. + ASTNode BeevMgr::PullUpITE(const ASTNode& in) + { + if (2 != in.GetChildren().size()) + return in; + if (ITE != in[0].GetKind()) + return in; + if (ITE != in[1].GetKind()) + return in; + if (in[0][0] != in[1][0]) // if the conditional is not equal. + return in; + + // Consider equals. It takes bitvectors and returns a boolean. + // Consider add. It takes bitvectors and returns bitvectors. + // Consider concat. The bitwidth of each side could vary. + + ASTNode l1; + ASTNode l2; + ASTNode result; + + if (in.GetType() == BOOLEAN_TYPE) + { + l1 = CreateNode(in.GetKind(), in[0][1], in[1][1]); + l2 = CreateNode(in.GetKind(), in[0][2], in[1][2]); + result = CreateNode(ITE, in[0][0], l1, l2); + } + else + { + l1 = CreateTerm(in.GetKind(), in.GetValueWidth(), in[0][1], in[1][1]); + l2 = CreateTerm(in.GetKind(), in.GetValueWidth(), in[0][2], in[1][2]); + result = CreateTerm(ITE, in.GetValueWidth(), in[0][0], l1, l2); + } + + assert(result.GetType() == in.GetType()); + assert(result.GetValueWidth() == in.GetValueWidth()); + assert(result.GetIndexWidth() == in.GetIndexWidth()); + assert(BVTypeCheck(result)); + + return result; + } + + //takes care of some simple ITE Optimizations in the context of equations + ASTNode BeevMgr::ITEOpt_InEqs(const ASTNode& in, ASTNodeMap* VarConstMap) + { + CountersAndStats("ITEOpts_InEqs"); + + if (!(EQ == in.GetKind() && optimize_flag)) + { + 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, VarConstMap); + 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, VarConstMap); + 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_flag) + // { + // 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_flag) + { + 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_flag) + { + 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; + } + } + ASTNode result = CreateNode(ITE, t0, t1, t2); + BVTypeCheck(result); + return result; + } + + ASTNode BeevMgr::SimplifyAndOrFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap) + { + 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, VarConstMap); + 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, VarConstMap); + } + 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, VarConstMap); + break; + } + default: + { + output = (isAnd) ? (pushNeg ? CreateNode(OR, outvec) : CreateNode(AND, outvec)) : (pushNeg ? CreateNode(AND, outvec) : CreateNode(OR, + outvec)); + //output = FlattenOneLevel(output); + break; + } + } + + // I haven't verified this is useful. + //if (output.GetKind() == AND) + // output = RemoveContradictionsFromAND(output); + + //memoize + UpdateSimplifyMap(a, output, pushNeg); + //cerr << "output:\n" << output << endl; + return output; + } //end of SimplifyAndOrFormula + + + ASTNode BeevMgr::SimplifyNotFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap) + { + 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, VarConstMap); + } + //memoize + UpdateSimplifyMap(o, output, pn); + UpdateSimplifyMap(a, output, pushNeg); + return output; + } + + ASTNode BeevMgr::SimplifyXorFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap) + { + 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, VarConstMap); + ASTNode a1 = SimplifyFormula(a[1], false, VarConstMap); + 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, ASTNodeMap* VarConstMap) + { + ASTNode output, a0, a1; + if (CheckSimplifyMap(a, output, pushNeg)) + return output; + + //the two NOTs cancel out + if (pushNeg) + { + a0 = SimplifyFormula(a[0], false, VarConstMap); + a1 = SimplifyFormula(a[1], false, VarConstMap); + output = CreateNode(AND, a0, a1); + } + else + { + //push the NOT implicit in the NAND + a0 = SimplifyFormula(a[0], true, VarConstMap); + a1 = SimplifyFormula(a[1], true, VarConstMap); + output = CreateNode(OR, a0, a1); + } + + //memoize + UpdateSimplifyMap(a, output, pushNeg); + return output; + } + + ASTNode BeevMgr::SimplifyNorFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap) + { + 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, VarConstMap); + output = CreateNode(OR, a0, a1); + } + else + { + //push the NOT implicit in the NAND + a0 = SimplifyFormula(a[0], true, VarConstMap); + a1 = SimplifyFormula(a[1], true, VarConstMap); + output = CreateNode(AND, a0, a1); + } + + //memoize + UpdateSimplifyMap(a, output, pushNeg); + return output; + } + + ASTNode BeevMgr::SimplifyImpliesFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap) + { + 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, VarConstMap); + c1 = SimplifyFormula(a[1], true, VarConstMap); + output = CreateNode(AND, c0, c1); + } + else + { + c0 = SimplifyFormula(a[0], false, VarConstMap); + c1 = SimplifyFormula(a[1], false, VarConstMap); + 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, ASTNodeMap* VarConstMap) + { + 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, VarConstMap); + + if (pushNeg) + c0 = SimplifyFormula(c0, true, VarConstMap); + else + c0 = SimplifyFormula(c0, false, VarConstMap); + + if (ASTTrue == c0) + { + output = c1; + } + else if (ASTFalse == c0) + { + output = SimplifyFormula(c1, true, VarConstMap); + } + else if (ASTTrue == c1) + { + output = c0; + } + else if (ASTFalse == c1) + { + output = SimplifyFormula(c0, true, VarConstMap); + } + 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, ASTNodeMap* VarConstMap) + { + if (!optimize_flag) + 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, VarConstMap); + ASTNode t1, t2; + if (pushNeg) + { + t1 = SimplifyFormula(a[1], true, VarConstMap); + t2 = SimplifyFormula(a[2], true, VarConstMap); + } + else + { + t1 = SimplifyFormula(a[1], false, VarConstMap); + t2 = SimplifyFormula(a[2], false, VarConstMap); + } + + 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, VarConstMap); + } + 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 BeevMgr::SimplifyAtomicFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap) -{ - if (!optimize_flag) - 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; -} - -//Look through the AND Node for terms that contradict. -//Should be made significantly more general.. -ASTNode BeevMgr::RemoveContradictionsFromAND(const ASTNode& in) -{ - assert(AND == in.GetKind()); - const int childrenSize = in.GetChildren().size(); - - for (int i = 0; i < childrenSize; i++) - { - if (BVLT != in[i].GetKind()) - continue; - - for (int j = i + 1; j < childrenSize; j++) - { - if (BVLT != in[j].GetKind()) - continue; - if (in[i][0] == in[j][1] && in[i][1] == in[j][0]) // parameters are swapped. - return ASTFalse; - } - } - return in; -} - -// turns say (bvslt (ite a b c) (ite a d e)) INTO (ite a (bvslt b d) (bvslt c e)) -// Expensive. But makes some other simplifications possible. -ASTNode BeevMgr::PullUpITE(const ASTNode& in) -{ - if (2 != in.GetChildren().size()) - return in; - if (ITE != in[0].GetKind()) - return in; - if (ITE != in[1].GetKind()) - return in; - if (in[0][0] != in[1][0]) // if the conditional is not equal. - return in; - - // Consider equals. It takes bitvectors and returns a boolean. - // Consider add. It takes bitvectors and returns bitvectors. - // Consider concat. The bitwidth of each side could vary. - - ASTNode l1; - ASTNode l2; - ASTNode result; - - if (in.GetType() == BOOLEAN_TYPE) - { - l1 = CreateNode(in.GetKind(), in[0][1], in[1][1]); - l2 = CreateNode(in.GetKind(), in[0][2], in[1][2]); - result = CreateNode(ITE, in[0][0], l1, l2); - } - else - { - l1 = CreateTerm(in.GetKind(), in.GetValueWidth(), in[0][1], in[1][1]); - l2 = CreateTerm(in.GetKind(), in.GetValueWidth(), in[0][2], in[1][2]); - result = CreateTerm(ITE, in.GetValueWidth(), in[0][0], l1, l2); - } - - assert(result.GetType() == in.GetType()); - assert(result.GetValueWidth() == in.GetValueWidth()); - assert(result.GetIndexWidth() == in.GetIndexWidth()); - assert(BVTypeCheck(result)); - - return result; -} - -//takes care of some simple ITE Optimizations in the context of equations -ASTNode BeevMgr::ITEOpt_InEqs(const ASTNode& in, ASTNodeMap* VarConstMap) -{ - CountersAndStats("ITEOpts_InEqs"); - - if (!(EQ == in.GetKind() && optimize_flag)) - { - 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, VarConstMap); - 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, VarConstMap); - 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_flag) - // { - // 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_flag) - { - 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_flag) - { - 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; - } - } - ASTNode result = CreateNode(ITE, t0, t1, t2); - BVTypeCheck(result); - return result; -} - -ASTNode BeevMgr::SimplifyAndOrFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap) -{ - 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, VarConstMap); - 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, VarConstMap); - } - 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, VarConstMap); - break; - } - default: - { - output = (isAnd) ? (pushNeg ? CreateNode(OR, outvec) : CreateNode(AND, outvec)) : (pushNeg ? CreateNode(AND, outvec) : CreateNode(OR, - outvec)); - //output = FlattenOneLevel(output); - break; - } - } - - // I haven't verified this is useful. - //if (output.GetKind() == AND) - // output = RemoveContradictionsFromAND(output); - - //memoize - UpdateSimplifyMap(a, output, pushNeg); - //cerr << "output:\n" << output << endl; - return output; -} //end of SimplifyAndOrFormula - - -ASTNode BeevMgr::SimplifyNotFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap) -{ - 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, VarConstMap); - } - //memoize - UpdateSimplifyMap(o, output, pn); - UpdateSimplifyMap(a, output, pushNeg); - return output; -} - -ASTNode BeevMgr::SimplifyXorFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap) -{ - 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, VarConstMap); - ASTNode a1 = SimplifyFormula(a[1], false, VarConstMap); - 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, ASTNodeMap* VarConstMap) -{ - ASTNode output, a0, a1; - if (CheckSimplifyMap(a, output, pushNeg)) - return output; - - //the two NOTs cancel out - if (pushNeg) - { - a0 = SimplifyFormula(a[0], false, VarConstMap); - a1 = SimplifyFormula(a[1], false, VarConstMap); - output = CreateNode(AND, a0, a1); - } - else - { - //push the NOT implicit in the NAND - a0 = SimplifyFormula(a[0], true, VarConstMap); - a1 = SimplifyFormula(a[1], true, VarConstMap); - output = CreateNode(OR, a0, a1); - } - - //memoize - UpdateSimplifyMap(a, output, pushNeg); - return output; -} - -ASTNode BeevMgr::SimplifyNorFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap) -{ - 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, VarConstMap); - output = CreateNode(OR, a0, a1); - } - else - { - //push the NOT implicit in the NAND - a0 = SimplifyFormula(a[0], true, VarConstMap); - a1 = SimplifyFormula(a[1], true, VarConstMap); - output = CreateNode(AND, a0, a1); - } - - //memoize - UpdateSimplifyMap(a, output, pushNeg); - return output; -} - -ASTNode BeevMgr::SimplifyImpliesFormula(const ASTNode& a, bool pushNeg, ASTNodeMap* VarConstMap) -{ - 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, VarConstMap); - c1 = SimplifyFormula(a[1], true, VarConstMap); - output = CreateNode(AND, c0, c1); - } - else - { - c0 = SimplifyFormula(a[0], false, VarConstMap); - c1 = SimplifyFormula(a[1], false, VarConstMap); - 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, ASTNodeMap* VarConstMap) -{ - 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, VarConstMap); - - if (pushNeg) - c0 = SimplifyFormula(c0, true, VarConstMap); - else - c0 = SimplifyFormula(c0, false, VarConstMap); - - if (ASTTrue == c0) - { - output = c1; - } - else if (ASTFalse == c0) - { - output = SimplifyFormula(c1, true, VarConstMap); - } - else if (ASTTrue == c1) - { - output = c0; - } - else if (ASTFalse == c1) - { - output = SimplifyFormula(c0, true, VarConstMap); - } - 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, ASTNodeMap* VarConstMap) -{ - if (!optimize_flag) - 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, VarConstMap); - ASTNode t1, t2; - if (pushNeg) - { - t1 = SimplifyFormula(a[1], true, VarConstMap); - t2 = SimplifyFormula(a[2], true, VarConstMap); - } - else - { - t1 = SimplifyFormula(a[1], false, VarConstMap); - t2 = SimplifyFormula(a[2], false, VarConstMap); - } - - 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, VarConstMap); - } - 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& actualInputterm, ASTNodeMap* VarConstMap) -{ - ASTNode inputterm(actualInputterm); // mutable local copy. - - //cout << "SimplifyTerm: input: " << a << endl; - if (!optimize_flag) - { - return inputterm; - } - - ASTNode output; - assert(BVTypeCheck(inputterm)); - - //######################################## - //######################################## - - if (CheckSubstitutionMap(inputterm, output)) - { - //cout << "SolverMap:" << inputterm << " output: " << output << endl; - return SimplifyTerm(output); - } - - if (CheckSimplifyMap(inputterm, output, false)) - { - //cerr << "SimplifierMap:" << inputterm << " output: " << 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(); - - inputterm = PullUpITE(inputterm); - k = inputterm.GetKind(); // pull up ITE can change the kind of the node - - switch (k) - { - case BVCONST: - output = inputterm; - break; - case SYMBOL: - if(CheckMap(VarConstMap, inputterm, output)) - { - return output; - } - 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, VarConstMap); - 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, VarConstMap); - ASTNode t1 = SimplifyTerm(inputterm[1]); - ASTNode t2 = SimplifyTerm(inputterm[2]); - output = CreateSimplifiedTermITE(t0, t1, t2); - break; - } - case SBVREM: - case SBVDIV: - case SBVMOD: - { - 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() - - -//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; - } - - ASTNodeCountMap::const_iterator it; - it = ReferenceCount->find(lhs); - if (it != ReferenceCount->end()) - { - if (it->second > 1) - return eq; - } - - 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, ASTNodeMap* VarConstMap) -{ - 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, VarConstMap); - - //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 (WRITE == 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(); - - // May be a symbol, or an ITE. - - 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, ASTNodeMap* VarConstMap) -{ - 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, VarConstMap); - 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(); - - //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); - - 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 (!wordlevel_solve_flag) - 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]); - - ASTNode c1 = SimplifyTerm(c[1]); - if (SYMBOL == c[0].GetKind() && VarSeenInTerm(c[0], c1)) - { - return a; - } - - if (1 == TermOrder(c[0], c[1]) && READ == c[0].GetKind() && VarSeenInTerm(c[0][1], c1)) - { - return a; - } - bool updated = UpdateSubstitutionMap(c[0], c1); - 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() -{ - SimplifyMap->clear(); - delete SimplifyMap; - SimplifyMap = new ASTNodeMap(INITIAL_SIMPLIFY_MAP_SIZE); - - SimplifyNegMap->clear(); - delete SimplifyNegMap; - SimplifyNegMap = new ASTNodeMap(INITIAL_SIMPLIFY_MAP_SIZE); - - ReferenceCount->clear(); - delete ReferenceCount; - ReferenceCount = new ASTNodeCountMap(INITIAL_SIMPLIFY_MAP_SIZE); -} + } + + 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& actualInputterm, ASTNodeMap* VarConstMap) + { + ASTNode inputterm(actualInputterm); // mutable local copy. + + //cout << "SimplifyTerm: input: " << a << endl; + if (!optimize_flag) + { + return inputterm; + } + + ASTNode output; + assert(BVTypeCheck(inputterm)); + + //######################################## + //######################################## + + if (CheckSubstitutionMap(inputterm, output)) + { + //cout << "SolverMap:" << inputterm << " output: " << output << endl; + return SimplifyTerm(output); + } + + if (CheckSimplifyMap(inputterm, output, false)) + { + //cerr << "SimplifierMap:" << inputterm << " output: " << 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(); + + inputterm = PullUpITE(inputterm); + k = inputterm.GetKind(); // pull up ITE can change the kind of the node + + switch (k) + { + case BVCONST: + output = inputterm; + break; + case SYMBOL: + if(CheckMap(VarConstMap, inputterm, output)) + { + return output; + } + 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, VarConstMap); + 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, VarConstMap); + ASTNode t1 = SimplifyTerm(inputterm[1]); + ASTNode t2 = SimplifyTerm(inputterm[2]); + output = CreateSimplifiedTermITE(t0, t1, t2); + break; + } + case SBVREM: + case SBVDIV: + case SBVMOD: + { + 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() + + + //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; + } + + ASTNodeCountMap::const_iterator it; + it = ReferenceCount->find(lhs); + if (it != ReferenceCount->end()) + { + if (it->second > 1) + return eq; + } + + 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, ASTNodeMap* VarConstMap) + { + 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, VarConstMap); + + //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 (WRITE == 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(); + + // May be a symbol, or an ITE. + + 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, ASTNodeMap* VarConstMap) + { + 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, VarConstMap); + 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(); + + //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); + + 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 (!wordlevel_solve_flag) + 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]); + + ASTNode c1 = SimplifyTerm(c[1]); + if (SYMBOL == c[0].GetKind() && VarSeenInTerm(c[0], c1)) + { + return a; + } + + if (1 == TermOrder(c[0], c[1]) && READ == c[0].GetKind() && VarSeenInTerm(c[0][1], c1)) + { + return a; + } + bool updated = UpdateSubstitutionMap(c[0], c1); + 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() + { + SimplifyMap->clear(); + delete SimplifyMap; + SimplifyMap = new ASTNodeMap(INITIAL_SIMPLIFY_MAP_SIZE); + + SimplifyNegMap->clear(); + delete SimplifyNegMap; + SimplifyNegMap = new ASTNodeMap(INITIAL_SIMPLIFY_MAP_SIZE); + + ReferenceCount->clear(); + delete ReferenceCount; + ReferenceCount = new ASTNodeCountMap(INITIAL_SIMPLIFY_MAP_SIZE); + } } ;//end of namespace