--- /dev/null
+;;; 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)
+)
--- /dev/null
+#!/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
+
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<ASTInteriorSet::const_iterator, bool> 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<ASTNode, ASTNode> 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<ASTBVConstSet::const_iterator, bool> 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<ASTSymbolSet::const_iterator, bool> 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<const ASTNode*> &v, int indentation)
-{
- // Print the children
- vector<const ASTNode*>::const_iterator iend = v.end();
- for (vector<const ASTNode*>::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<ASTVec *>::iterator it = _asserts.begin();
- vector<ASTVec *>::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<ASTVec *>::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<ASTInteriorSet::const_iterator, bool> 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<ASTNode, ASTNode> 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<ASTBVConstSet::const_iterator, bool> 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<ASTSymbolSet::const_iterator, bool> 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<const ASTNode*> &v, int indentation)
+ {
+ // Print the children
+ vector<const ASTNode*>::const_iterator iend = v.end();
+ for (vector<const ASTNode*>::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<ASTVec *>::iterator it = _asserts.begin();
+ vector<ASTVec *>::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<ASTVec *>::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
*****************************************************************************/
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<ASTNode> 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<ASTNode> ;
- //Print the arguments in lisp format.
- friend ostream &LispPrintVec(ostream &os,
- const ASTVec &v,
- int indentation = 0);
- friend ostream &LispPrintVecSpecial(ostream &os,
- const vector<const ASTNode*> &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<ASTNode> 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<ASTNode> ;
+ //Print the arguments in lisp format.
+ friend ostream &LispPrintVec(ostream &os,
+ const ASTVec &v,
+ int indentation = 0);
+ friend ostream &LispPrintVecSpecial(ostream &os,
+ const vector<const ASTNode*> &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<ASTInterior, ...>" 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<ASTInterior, ...>" 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<string> h;
+ tr1::hash<string> h;
#else
- hash<char*> h;
+ hash<char*> 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<ASTNode,
- ASTNode,
- ASTNode::ASTNodeHasher,
- ASTNode::ASTNodeEqual> ASTNodeMap;
-
-typedef hash_map<ASTNode,
- int32_t,
- ASTNode::ASTNodeHasher,
- ASTNode::ASTNodeEqual> 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<ASTNode,
+ ASTNode,
+ ASTNode::ASTNodeHasher,
+ ASTNode::ASTNodeEqual> ASTNodeMap;
+
+ typedef hash_map<ASTNode,
+ int32_t,
+ ASTNode::ASTNodeHasher,
+ ASTNode::ASTNodeEqual> 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<ASTNode,
- ASTNode::ASTNodeHasher,
- ASTNode::ASTNodeEqual> ASTNodeSet;
+ ***************************************************************************/
+ typedef hash_set<ASTNode,
+ ASTNode::ASTNodeHasher,
+ ASTNode::ASTNodeEqual> ASTNodeSet;
-typedef hash_multiset<ASTNode,
- ASTNode::ASTNodeHasher,
- ASTNode::ASTNodeEqual> ASTNodeMultiSet;
+ typedef hash_multiset<ASTNode,
+ ASTNode::ASTNodeHasher,
+ ASTNode::ASTNodeEqual> 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<ASTInterior *, ASTInterior::ASTInteriorHasher, ASTInterior::ASTInteriorEqual> ASTInteriorSet;
-
- // Typedef for unique Symbol node (leaf) table.
- typedef hash_set<ASTSymbol *, ASTSymbol::ASTSymbolHasher, ASTSymbol::ASTSymbolEqual> 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<ASTBVConst *, ASTBVConst::ASTBVConstHasher, ASTBVConst::ASTBVConstEqual> ASTBVConstSet;
-
- //table to uniquefy bvconst
- ASTBVConstSet _bvconst_unique_table;
-
- // type of memo table.
- typedef hash_map<ASTNode, ASTVec, ASTNode::ASTNodeHasher, ASTNode::ASTNodeEqual> ASTNodeToVecMap;
-
- typedef hash_map<ASTNode, ASTNodeSet, ASTNode::ASTNodeHasher, ASTNode::ASTNodeEqual> 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<const ASTNode*>* ClausePtr;
-
- // Datatype for Clauselists
- typedef vector<ClausePtr> 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<pair<ASTNode, ASTNode> > 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<ASTNode, MINISAT::Var, ASTNode::ASTNodeHasher, ASTNode::ASTNodeEqual> 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<ASTNode> _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, hash_map<unsigned int, bool> *, 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<unsigned, bool> * 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<ASTVec *> _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<ASTInterior *, ASTInterior::ASTInteriorHasher, ASTInterior::ASTInteriorEqual> ASTInteriorSet;
+
+ // Typedef for unique Symbol node (leaf) table.
+ typedef hash_set<ASTSymbol *, ASTSymbol::ASTSymbolHasher, ASTSymbol::ASTSymbolEqual> 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<ASTBVConst *, ASTBVConst::ASTBVConstHasher, ASTBVConst::ASTBVConstEqual> ASTBVConstSet;
+
+ //table to uniquefy bvconst
+ ASTBVConstSet _bvconst_unique_table;
+
+ // type of memo table.
+ typedef hash_map<ASTNode, ASTVec, ASTNode::ASTNodeHasher, ASTNode::ASTNodeEqual> ASTNodeToVecMap;
+
+ typedef hash_map<ASTNode, ASTNodeSet, ASTNode::ASTNodeHasher, ASTNode::ASTNodeEqual> 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<const ASTNode*>* ClausePtr;
+
+ // Datatype for Clauselists
+ typedef vector<ClausePtr> 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<pair<ASTNode, ASTNode> > 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<ASTNode, MINISAT::Var, ASTNode::ASTNodeHasher, ASTNode::ASTNodeEqual> 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<ASTNode> _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, hash_map<unsigned int, bool> *, 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<unsigned, bool> * 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<ASTVec *> _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
#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
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;
// Table for storing function count stats.
#ifdef TR1_UNORDERED_MAP
typedef tr1::unordered_map<const char*,int,
- tr1::hash<const char *>,eqstr> function_counters;
+ tr1::hash<const char *>,eqstr> function_counters;
#else
typedef hash_map<const char*,int,
- hash<char *>,eqstr> function_counters;
+ hash<char *>,eqstr> function_counters;
#endif
void CountersAndStats(const char * functionname);
//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
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
*
*
* 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
#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"<<endl;
- // cout << "================" << endl << "BBTerm:" << term << endl;
- // cout << "----------------" << endl << "BBTerm result:";
- // lpvec(result);
- // cout << endl;
-
- return (BBTermMemo[term] = result);
-
-}
-
-// bit blast a formula (boolean term). Result is one bit wide,
-// so it returns a single ASTNode.
-// FIXME: Add IsNegated flag.
-const ASTNode BeevMgr::BBForm(const ASTNode& form)
-{
-
- ASTNodeMap::iterator it = BBFormMemo.find(form);
- if (it != BBFormMemo.end())
- {
- // already there. Just return it.
- return it->second;
- }
-
- ASTNode result = ASTUndefined;
-
- Kind k = form.GetKind();
- if (!is_Form_kind(k))
- {
- FatalError("BBForm: Illegal kind: ", form);
- }
-
- // Not returning until end, and memoizing everything, makes it easier
- // to trace coherently.
-
- // Various special cases
- switch (k)
- {
- case TRUE:
- case FALSE:
- {
- result = form;
- break;
- }
-
- case SYMBOL:
- //printf("bit-blasting SYMBOL\n");
- if (form.GetType() != BOOLEAN_TYPE)
- {
- FatalError("BBForm: Symbol represents more than one bit", form);
- }
-
- result = form;
- break;
-
- case BVGETBIT:
- {
- // exactly two children
- const ASTNode bbchild = BBTerm(form[0]);
- unsigned int index = GetUnsignedConst(form[1]);
- result = bbchild[index];
- break;
- }
-
- case NOT:
- result = CreateSimpNot(BBForm(form[0]));
- break;
-
- case ITE:
- // FIXME: SHould this be CreateSimpITE?
- result = CreateNode(ITE, BBForm(form[0]), BBForm(form[1]), BBForm(form[2]));
- break;
-
- case AND:
- case OR:
- case NAND:
- case NOR:
- case IFF:
- case XOR:
- case IMPLIES:
- {
- //printf("bit-blasting AND or OR\n");
- ASTVec bbkids; // bit-blasted children (formulas)
-
- // FIXME: Put in fast exits for AND/OR/NAND/NOR/IMPLIES
- ASTVec::const_iterator kids_end = form.end();
- for (ASTVec::const_iterator it = form.begin(); it != kids_end; it++)
- {
- bbkids.push_back(BBForm(*it));
- }
- result = CreateSimpForm(k, bbkids);
- break;
- }
-
- case NEQ:
- {
- ASTNode bbkid = BBForm(CreateNode(EQ, form.GetChildren()));
- result = CreateSimpNot(bbkid);
- break;
- }
-
- case EQ:
- {
- //printf("bit-blasting EQ\n");
- //form.LispPrint(cout, 0);
- // Common code for binary operations
- // FIXME: This ought to be in a semantic analysis phase.
- //printf("spot01\n");
- const ASTNode left = BBTerm(form[0]);
- //printf("spot02\n");
- const ASTNode right = BBTerm(form[1]);
- //printf("spot03\n");
- if (left.Degree() != right.Degree())
- {
- cerr << "BBForm: Size mismatch" << endl << form[0] << endl << form[1] << endl;
- FatalError("", ASTUndefined);
- }
- result = BBEQ(left.GetChildren(), right.GetChildren());
- //printf("spot04\n");
- break;
- }
-
- case BVLE:
- case BVGE:
- case BVGT:
- case BVLT:
- case BVSLE:
- case BVSGE:
- case BVSGT:
- case BVSLT:
- {
- result = BBcompare(form);
- break;
- }
- default:
- FatalError("BBForm: Illegal kind: ", form);
- break;
- }
-
- // cout << "================" << endl
- // << "BBForm: " << form << endl
- // << "----------------" << endl
- // << "BBForm Result: " << result << endl;
-
- return (BBFormMemo[form] = result);
-}
-
-// Bit blast a sum of two equal length BVs.
-// Update sum vector destructively with new sum.
-void BeevMgr::BBPlus2(ASTVec& sum, const ASTVec& y, ASTNode cin)
-{
- // cout << "Bitblasting plus. Operand 1: " << endl;
- // lpvec(sum);
- // cout << endl << " operand 2: " << endl;
- // lpvec(y);
- // cout << endl << "carry: " << endl << cin << endl;
-
-
- int n = sum.size();
- // ASSERT: y.size() == x.size()
- // FIXME: Don't bother computing i+1 carry, which is discarded.
- for (int i = 0; i < n; i++)
- {
- ASTNode nextcin = Majority(sum[i], y[i], cin);
- sum[i] = CreateSimpForm(XOR, CreateSimpForm(XOR, sum[i], y[i]), cin);
- cin = nextcin;
- }
-
- // cout << "----------------" << endl << "Result: " << endl;
- // lpvec(sum);
- // cout << endl;
-
-}
-
-// 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"<<endl;
+ // cout << "================" << endl << "BBTerm:" << term << endl;
+ // cout << "----------------" << endl << "BBTerm result:";
+ // lpvec(result);
+ // cout << endl;
+
+ return (BBTermMemo[term] = result);
+
+ }
+
+ // bit blast a formula (boolean term). Result is one bit wide,
+ // so it returns a single ASTNode.
+ // FIXME: Add IsNegated flag.
+ const ASTNode BeevMgr::BBForm(const ASTNode& form)
+ {
+
+ ASTNodeMap::iterator it = BBFormMemo.find(form);
+ if (it != BBFormMemo.end())
+ {
+ // already there. Just return it.
+ return it->second;
+ }
+
+ ASTNode result = ASTUndefined;
+
+ Kind k = form.GetKind();
+ if (!is_Form_kind(k))
+ {
+ FatalError("BBForm: Illegal kind: ", form);
+ }
+
+ // Not returning until end, and memoizing everything, makes it easier
+ // to trace coherently.
+
+ // Various special cases
+ switch (k)
+ {
+ case TRUE:
+ case FALSE:
+ {
+ result = form;
+ break;
+ }
+
+ case SYMBOL:
+ //printf("bit-blasting SYMBOL\n");
+ if (form.GetType() != BOOLEAN_TYPE)
+ {
+ FatalError("BBForm: Symbol represents more than one bit", form);
+ }
+
+ result = form;
+ break;
+
+ case BVGETBIT:
+ {
+ // exactly two children
+ const ASTNode bbchild = BBTerm(form[0]);
+ unsigned int index = GetUnsignedConst(form[1]);
+ result = bbchild[index];
+ break;
+ }
+
+ case NOT:
+ result = CreateSimpNot(BBForm(form[0]));
+ break;
+
+ case ITE:
+ // FIXME: SHould this be CreateSimpITE?
+ result = CreateNode(ITE, BBForm(form[0]), BBForm(form[1]), BBForm(form[2]));
+ break;
+
+ case AND:
+ case OR:
+ case NAND:
+ case NOR:
+ case IFF:
+ case XOR:
+ case IMPLIES:
+ {
+ //printf("bit-blasting AND or OR\n");
+ ASTVec bbkids; // bit-blasted children (formulas)
+
+ // FIXME: Put in fast exits for AND/OR/NAND/NOR/IMPLIES
+ ASTVec::const_iterator kids_end = form.end();
+ for (ASTVec::const_iterator it = form.begin(); it != kids_end; it++)
+ {
+ bbkids.push_back(BBForm(*it));
+ }
+ result = CreateSimpForm(k, bbkids);
+ break;
+ }
+
+ case NEQ:
+ {
+ ASTNode bbkid = BBForm(CreateNode(EQ, form.GetChildren()));
+ result = CreateSimpNot(bbkid);
+ break;
+ }
+
+ case EQ:
+ {
+ //printf("bit-blasting EQ\n");
+ //form.LispPrint(cout, 0);
+ // Common code for binary operations
+ // FIXME: This ought to be in a semantic analysis phase.
+ //printf("spot01\n");
+ const ASTNode left = BBTerm(form[0]);
+ //printf("spot02\n");
+ const ASTNode right = BBTerm(form[1]);
+ //printf("spot03\n");
+ if (left.Degree() != right.Degree())
+ {
+ cerr << "BBForm: Size mismatch" << endl << form[0] << endl << form[1] << endl;
+ FatalError("", ASTUndefined);
+ }
+ result = BBEQ(left.GetChildren(), right.GetChildren());
+ //printf("spot04\n");
+ break;
+ }
+
+ case BVLE:
+ case BVGE:
+ case BVGT:
+ case BVLT:
+ case BVSLE:
+ case BVSGE:
+ case BVSGT:
+ case BVSLT:
+ {
+ result = BBcompare(form);
+ break;
+ }
+ default:
+ FatalError("BBForm: Illegal kind: ", form);
+ break;
+ }
+
+ // cout << "================" << endl
+ // << "BBForm: " << form << endl
+ // << "----------------" << endl
+ // << "BBForm Result: " << result << endl;
+
+ return (BBFormMemo[form] = result);
+ }
+
+ // Bit blast a sum of two equal length BVs.
+ // Update sum vector destructively with new sum.
+ void BeevMgr::BBPlus2(ASTVec& sum, const ASTVec& y, ASTNode cin)
+ {
+ // cout << "Bitblasting plus. Operand 1: " << endl;
+ // lpvec(sum);
+ // cout << endl << " operand 2: " << endl;
+ // lpvec(y);
+ // cout << endl << "carry: " << endl << cin << endl;
+
+
+ int n = sum.size();
+ // ASSERT: y.size() == x.size()
+ // FIXME: Don't bother computing i+1 carry, which is discarded.
+ for (int i = 0; i < n; i++)
+ {
+ ASTNode nextcin = Majority(sum[i], y[i], cin);
+ sum[i] = CreateSimpForm(XOR, CreateSimpForm(XOR, sum[i], y[i]), cin);
+ cin = nextcin;
+ }
+
+ // cout << "----------------" << endl << "Result: " << endl;
+ // lpvec(sum);
+ // cout << endl;
+
+ }
+
+ // 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
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
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<ASTNode, CNFInfo*, ASTNode::ASTNodeHasher, ASTNode::ASTNodeEqual> ASTNodeToCNFInfoMap;
-
- typedef hash_map<ASTNode, ASTNode*, ASTNode::ASTNodeHasher, ASTNode::ASTNodeEqual> ASTNodeToASTNodePtrMap;
-
- //########################################
- //########################################
- // this is the data
-
- BeevMgr *bm;
- ASTNodeToCNFInfoMap info;
- ASTNodeToASTNodePtrMap store;
-
- //########################################
- //########################################
- // utility predicates
-
- bool isAtom(const ASTNode& varphi)
- {
- bool result;
-
- Kind k = varphi.GetKind();
- switch (k)
- {
- case TRUE:
- {
- result = true;
- break;
- }
- case FALSE:
- {
- result = true;
- break;
- }
- case SYMBOL:
- {
- result = true;
- break;
- }
- case BVCONST:
- {
- result = true;
- break;
- }
- default:
- {
- result = false;
- break;
- }
- }
-
- return result;
- }
-
- bool isPred(const ASTNode& varphi)
- {
- bool result;
-
- Kind k = varphi.GetKind();
- switch (k)
- {
- case BVLT:
- {
- result = true;
- break;
- }
- case BVLE:
- {
- result = true;
- break;
- }
- case BVGT:
- {
- result = true;
- break;
- }
- case BVGE:
- {
- result = true;
- break;
- }
- case BVSLT:
- {
- result = true;
- break;
- }
- case BVSLE:
- {
- result = true;
- break;
- }
- case BVSGT:
- {
- result = true;
- break;
- }
- case BVSGE:
- {
- result = true;
- break;
- }
- case EQ:
- {
- result = true;
- break;
- }
- case NEQ:
- {
- result = true;
- break;
- }
- default:
- {
- result = false;
- break;
- }
- }
-
- return result;
- }
-
- bool isITE(const ASTNode& varphi)
- {
- bool result;
-
- Kind k = varphi.GetKind();
- switch (k)
- {
- case ITE:
- {
- result = true;
- break;
- }
- default:
- {
- result = false;
- break;
- }
- }
-
- return result;
- }
-
- bool onChildDoPos(const ASTNode& varphi, unsigned int idx)
- {
- bool result = true;
-
- Kind k = varphi.GetKind();
- switch (k)
- {
- case NOT:
- {
- result = false;
- break;
- }
- case NAND:
- {
- result = false;
- break;
- }
- case NOR:
- {
- result = false;
- break;
- }
- case IMPLIES:
- {
- if (idx == 0)
- {
- result = false;
- }
- break;
- }
- default:
- {
- break;
- }
- }
-
- return result;
- }
-
- bool onChildDoNeg(const ASTNode& varphi, unsigned int idx)
- {
- bool result = false;
-
- Kind k = varphi.GetKind();
- switch (k)
- {
- case NOT:
- {
- result = true;
- break;
- }
- case NAND:
- {
- result = true;
- break;
- }
- case NOR:
- {
- result = true;
- break;
- }
- case XOR:
- {
- result = true;
- break;
- }
- case IFF:
- {
- result = true;
- break;
- }
- case IMPLIES:
- {
- if (idx == 0)
- {
- result = true;
- }
- break;
- }
- case ITE:
- {
- if (idx == 0)
- {
- result = true;
- }
- break;
- }
- default:
- {
- break;
- }
- }
-
- return result;
- }
-
- //########################################
- //########################################
- //utilities for control bits.
-
- void initializeCNFInfo(CNFInfo& x)
- {
- x.control = 0;
- x.clausespos = NULL;
- x.clausesneg = NULL;
- }
-
- void incrementSharesPos(CNFInfo& x)
- {
- x.control += ((x.control & 3) < 2) ? 1 : 0;
- }
-
- int sharesPos(CNFInfo& x)
- {
- return (x.control & 3);
- }
-
- void incrementSharesNeg(CNFInfo& x)
- {
- x.control += ((x.control & 12) < 8) ? 4 : 0;
- }
-
- int sharesNeg(CNFInfo& x)
- {
- return ((x.control & 12) >> 2);
- }
-
- void setControlBit(CNFInfo& x, unsigned int idx)
- {
- x.control |= (1 << idx);
- }
-
- bool getControlBit(CNFInfo& x, unsigned int idx)
- {
- bool result = false;
-
- if (x.control & (1 << idx))
- {
-
- result = true;
- }
-
- return result;
- }
-
- void setIsTerm(CNFInfo& x)
- {
- setControlBit(x, 4);
- }
-
- bool isTerm(CNFInfo& x)
- {
- return getControlBit(x, 4);
- }
-
- void setDoRenamePos(CNFInfo& x)
- {
- setControlBit(x, 5);
- }
-
- bool doRenamePos(CNFInfo& x)
- {
- return getControlBit(x, 5);
- }
-
- void setWasRenamedPos(CNFInfo& x)
- {
- setControlBit(x, 6);
- }
-
- bool wasRenamedPos(CNFInfo& x)
- {
- return getControlBit(x, 6);
- }
-
- void setDoRenameNeg(CNFInfo& x)
- {
- setControlBit(x, 7);
- }
-
- bool doRenameNeg(CNFInfo& x)
- {
- return getControlBit(x, 7);
- }
-
- void setWasRenamedNeg(CNFInfo& x)
- {
- setControlBit(x, 8);
- }
-
- bool wasRenamedNeg(CNFInfo& x)
- {
- return getControlBit(x, 8);
- }
-
- void setDoSibRenamingPos(CNFInfo& x)
- {
- setControlBit(x, 9);
- }
-
- bool doSibRenamingPos(CNFInfo& x)
- {
- return getControlBit(x, 9);
- }
-
- void setDoSibRenamingNeg(CNFInfo& x)
- {
- setControlBit(x, 10);
- }
-
- 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<const ASTNode*> (**it));
- }
-
- return psi;
- }
-
- BeevMgr::ClauseList* SINGLETON(const ASTNode& varphi)
- {
- ASTNode* copy = ASTNodeToASTNodePtr(varphi);
-
- BeevMgr::ClausePtr clause = new vector<const ASTNode*> ();
- 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<const ASTNode*> ();
- 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<ASTNode, CNFInfo*, ASTNode::ASTNodeHasher, ASTNode::ASTNodeEqual> ASTNodeToCNFInfoMap;
+
+ typedef hash_map<ASTNode, ASTNode*, ASTNode::ASTNodeHasher, ASTNode::ASTNodeEqual> ASTNodeToASTNodePtrMap;
+
+ //########################################
+ //########################################
+ // this is the data
+
+ BeevMgr *bm;
+ ASTNodeToCNFInfoMap info;
+ ASTNodeToASTNodePtrMap store;
+
+ //########################################
+ //########################################
+ // utility predicates
+
+ bool isAtom(const ASTNode& varphi)
+ {
+ bool result;
+
+ Kind k = varphi.GetKind();
+ switch (k)
+ {
+ case TRUE:
+ {
+ result = true;
+ break;
+ }
+ case FALSE:
+ {
+ result = true;
+ break;
+ }
+ case SYMBOL:
+ {
+ result = true;
+ break;
+ }
+ case BVCONST:
+ {
+ result = true;
+ break;
+ }
+ default:
+ {
+ result = false;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ bool isPred(const ASTNode& varphi)
+ {
+ bool result;
+
+ Kind k = varphi.GetKind();
+ switch (k)
+ {
+ case BVLT:
+ {
+ result = true;
+ break;
+ }
+ case BVLE:
+ {
+ result = true;
+ break;
+ }
+ case BVGT:
+ {
+ result = true;
+ break;
+ }
+ case BVGE:
+ {
+ result = true;
+ break;
+ }
+ case BVSLT:
+ {
+ result = true;
+ break;
+ }
+ case BVSLE:
+ {
+ result = true;
+ break;
+ }
+ case BVSGT:
+ {
+ result = true;
+ break;
+ }
+ case BVSGE:
+ {
+ result = true;
+ break;
+ }
+ case EQ:
+ {
+ result = true;
+ break;
+ }
+ case NEQ:
+ {
+ result = true;
+ break;
+ }
+ default:
+ {
+ result = false;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ bool isITE(const ASTNode& varphi)
+ {
+ bool result;
+
+ Kind k = varphi.GetKind();
+ switch (k)
+ {
+ case ITE:
+ {
+ result = true;
+ break;
+ }
+ default:
+ {
+ result = false;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ bool onChildDoPos(const ASTNode& varphi, unsigned int idx)
+ {
+ bool result = true;
+
+ Kind k = varphi.GetKind();
+ switch (k)
+ {
+ case NOT:
+ {
+ result = false;
+ break;
+ }
+ case NAND:
+ {
+ result = false;
+ break;
+ }
+ case NOR:
+ {
+ result = false;
+ break;
+ }
+ case IMPLIES:
+ {
+ if (idx == 0)
+ {
+ result = false;
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ bool onChildDoNeg(const ASTNode& varphi, unsigned int idx)
+ {
+ bool result = false;
+
+ Kind k = varphi.GetKind();
+ switch (k)
+ {
+ case NOT:
+ {
+ result = true;
+ break;
+ }
+ case NAND:
+ {
+ result = true;
+ break;
+ }
+ case NOR:
+ {
+ result = true;
+ break;
+ }
+ case XOR:
+ {
+ result = true;
+ break;
+ }
+ case IFF:
+ {
+ result = true;
+ break;
+ }
+ case IMPLIES:
+ {
+ if (idx == 0)
+ {
+ result = true;
+ }
+ break;
+ }
+ case ITE:
+ {
+ if (idx == 0)
+ {
+ result = true;
+ }
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ //########################################
+ //########################################
+ //utilities for control bits.
+
+ void initializeCNFInfo(CNFInfo& x)
+ {
+ x.control = 0;
+ x.clausespos = NULL;
+ x.clausesneg = NULL;
+ }
+
+ void incrementSharesPos(CNFInfo& x)
+ {
+ x.control += ((x.control & 3) < 2) ? 1 : 0;
+ }
+
+ int sharesPos(CNFInfo& x)
+ {
+ return (x.control & 3);
+ }
+
+ void incrementSharesNeg(CNFInfo& x)
+ {
+ x.control += ((x.control & 12) < 8) ? 4 : 0;
+ }
+
+ int sharesNeg(CNFInfo& x)
+ {
+ return ((x.control & 12) >> 2);
+ }
+
+ void setControlBit(CNFInfo& x, unsigned int idx)
+ {
+ x.control |= (1 << idx);
+ }
+
+ bool getControlBit(CNFInfo& x, unsigned int idx)
+ {
+ bool result = false;
+
+ if (x.control & (1 << idx))
+ {
+
+ result = true;
+ }
+
+ return result;
+ }
+
+ void setIsTerm(CNFInfo& x)
+ {
+ setControlBit(x, 4);
+ }
+
+ bool isTerm(CNFInfo& x)
+ {
+ return getControlBit(x, 4);
+ }
+
+ void setDoRenamePos(CNFInfo& x)
+ {
+ setControlBit(x, 5);
+ }
+
+ bool doRenamePos(CNFInfo& x)
+ {
+ return getControlBit(x, 5);
+ }
+
+ void setWasRenamedPos(CNFInfo& x)
+ {
+ setControlBit(x, 6);
+ }
+
+ bool wasRenamedPos(CNFInfo& x)
+ {
+ return getControlBit(x, 6);
+ }
+
+ void setDoRenameNeg(CNFInfo& x)
+ {
+ setControlBit(x, 7);
+ }
+
+ bool doRenameNeg(CNFInfo& x)
+ {
+ return getControlBit(x, 7);
+ }
+
+ void setWasRenamedNeg(CNFInfo& x)
+ {
+ setControlBit(x, 8);
+ }
+
+ bool wasRenamedNeg(CNFInfo& x)
+ {
+ return getControlBit(x, 8);
+ }
+
+ void setDoSibRenamingPos(CNFInfo& x)
+ {
+ setControlBit(x, 9);
+ }
+
+ bool doSibRenamingPos(CNFInfo& x)
+ {
+ return getControlBit(x, 9);
+ }
+
+ void setDoSibRenamingNeg(CNFInfo& x)
+ {
+ setControlBit(x, 10);
+ }
+
+ 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<const ASTNode*> (**it));
+ }
+
+ return psi;
+ }
+
+ BeevMgr::ClauseList* SINGLETON(const ASTNode& varphi)
+ {
+ ASTNode* copy = ASTNodeToASTNodePtr(varphi);
+
+ BeevMgr::ClausePtr clause = new vector<const ASTNode*> ();
+ 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<const ASTNode*> ();
+ 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
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<const ASTNode*>*
- //****************************************
- for (; i != iend; i++)
- {
- //Clause for the SATSolver
- MINISAT::vec<MINISAT::Lit> satSolverClause;
-
- //now iterate through the internals of the ASTclause itself
- vector<const ASTNode*>::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<MINISAT::vec<MINISAT::Lit> >)(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<unsigned, bool> * v;
- if (_ASTNode_to_Bitvector.find(symbol) == _ASTNode_to_Bitvector.end())
- _ASTNode_to_Bitvector[symbol] = new hash_map<unsigned, bool> (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<unsigned, bool> * 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<int> 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<unsigned, bool> * 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<const ASTNode*>*
+ //****************************************
+ for (; i != iend; i++)
+ {
+ //Clause for the SATSolver
+ MINISAT::vec<MINISAT::Lit> satSolverClause;
+
+ //now iterate through the internals of the ASTclause itself
+ vector<const ASTNode*>::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<MINISAT::vec<MINISAT::Lit> >)(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<unsigned, bool> * v;
+ if (_ASTNode_to_Bitvector.find(symbol) == _ASTNode_to_Bitvector.end())
+ _ASTNode_to_Bitvector[symbol] = new hash_map<unsigned, bool> (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<unsigned, bool> * 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<int> 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<unsigned, bool> * 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
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
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;
}
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;
}
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));
}
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<<inputwidth<<endl;
- cerr<<"------------------------"<<endl;
- t.LispPrint(cerr);
- cerr<<endl;
- OutputNode.LispPrint(cerr);
- cerr<<endl<<"------------------------"<<endl;
- }
- */
- UpdateSolverMap(t, OutputNode);
- //UpdateSimplifyMap(t,OutputNode,false);
- return OutputNode;
-} //End of BVConstEvaluator
+ //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<<inputwidth<<endl;
+ cerr<<"------------------------"<<endl;
+ t.LispPrint(cerr);
+ cerr<<endl;
+ OutputNode.LispPrint(cerr);
+ cerr<<endl<<"------------------------"<<endl;
+ }
+ */
+ UpdateSolverMap(t, OutputNode);
+ //UpdateSimplifyMap(t,OutputNode,false);
+ return OutputNode;
+ } //End of BVConstEvaluator
}; //end of namespace BEEV
char * vc_printSMTLIB(VC vc, Expr e)
{
- stringstream ss;
- printer::SMTLIB_Print(ss,*((nodestar)e), 0);
+ stringstream ss;
+ printer::SMTLIB_Print(ss,*((nodestar)e), 0);
string s = ss.str();
char *copy = strdup(s.c_str());
return copy;
-
+
}
// prints Expr 'e' to stdout as C code
nodestar a = (nodestar)e;
bmstar b = (bmstar)vc;
- if(!BEEV::is_Form_kind(a->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);
//! 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);
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));
}
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;
}
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);
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);
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;
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;
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;
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);
}
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");
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++;
}
}
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);
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;
#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
void vc_Destroy(VC vc) {
bmstar b = (bmstar)vc;
// for(std::vector<BEEV::ASTNode *>::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;
// }
}
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();
}
//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. */
//! 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'
//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);
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);
/*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
//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
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:
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:
* => 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
#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;
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;
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;
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! */
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;
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;
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;
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;
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);
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;
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;
unsigned int diff;
if ((size > 0) && (lower < bits) && (upper < bits) && (lower <= upper))
- {
+ {
lobase = lower >> LOGBITS;
hibase = upper >> LOGBITS;
diff = hibase - lobase;
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;
unsigned int diff;
if ((size > 0) && (lower < bits) && (upper < bits) && (lower <= upper))
- {
+ {
lobase = lower >> LOGBITS;
hibase = upper >> LOGBITS;
diff = hibase - lobase;
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;
unsigned int diff;
if ((size > 0) && (lower < bits) && (upper < bits) && (lower <= upper))
- {
+ {
lobase = lower >> LOGBITS;
hibase = upper >> LOGBITS;
diff = hibase - lobase;
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;
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;
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;
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 */
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;
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);
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;
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;
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;
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;
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;
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);
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;
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);
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;
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;
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;
boolean carry_out = false;
if (size > 0)
- {
+ {
msb = mask & ~ (mask >> 1);
carry_in = ((*addr & LSB) != 0);
addr += size-1;
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;
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;
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 );
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;
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;
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;
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);
*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);
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);
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;
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);
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);
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);
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);
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];
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;
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;
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;
/* 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;
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;
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;
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;
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;
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;
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;
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;
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;
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
#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: <=== */
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 == {} ? */
/* ===> 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);
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 */
/* ===> 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: */
//returns the var.
ASTNode BeevMgr::ResolveID(const ASTNode& v) {
if (_letid_expr_map == NULL)
- InitializeLetIDMap();
+ InitializeLetIDMap();
if(v.GetKind() != SYMBOL) {
return v;
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
// 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();
}
};
#include <unistd.h>
#ifdef EXT_HASH_MAP
- using namespace __gnu_cxx;
+using namespace __gnu_cxx;
#endif
/* GLOBAL FUNCTION: parser
namespace BEEV
{
-extern BEEV::ASTNode SingleBitOne;
-extern BEEV::ASTNode SingleBitZero;
+ extern BEEV::ASTNode SingleBitOne;
+ extern BEEV::ASTNode SingleBitZero;
}
const string version = "$Id$";
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("");
+ }
+ }
}
}
//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
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
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