about summary refs log tree commit diff homepage
path: root/stp/AST/BitBlast.cpp
diff options
context:
space:
mode:
authorDaniel Dunbar <daniel@zuster.org>2009-05-21 04:36:41 +0000
committerDaniel Dunbar <daniel@zuster.org>2009-05-21 04:36:41 +0000
commit6f290d8f9e9d7faac295cb51fc96884a18f4ded4 (patch)
tree46e7d426abc0c9f06ac472ac6f7f9e661b5d78cb /stp/AST/BitBlast.cpp
parenta55960edd4dcd7535526de8d2277642522aa0209 (diff)
downloadklee-6f290d8f9e9d7faac295cb51fc96884a18f4ded4.tar.gz
Initial KLEE checkin.
 - Lots more tweaks, documentation, and web page content is needed,
   but this should compile & work on OS X & Linux.


git-svn-id: https://llvm.org/svn/llvm-project/klee/trunk@72205 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'stp/AST/BitBlast.cpp')
-rw-r--r--stp/AST/BitBlast.cpp812
1 files changed, 812 insertions, 0 deletions
diff --git a/stp/AST/BitBlast.cpp b/stp/AST/BitBlast.cpp
new file mode 100644
index 00000000..de78ec74
--- /dev/null
+++ b/stp/AST/BitBlast.cpp
@@ -0,0 +1,812 @@
+/********************************************************************
+ * AUTHORS: David L. Dill, Vijay Ganesh
+ *
+ * BEGIN DATE: November, 2005
+ *
+ * LICENSE: Please view LICENSE file in the home dir of this Program
+ ********************************************************************/
+// -*- c++ -*-
+
+// BitBlast -- convert bitvector terms and formulas to boolean
+// formulas.  A term is something that can represent a multi-bit
+// bitvector, such as BVPLUS or BVXOR (or a BV variable or constant).
+// A formula (form) represents a boolean value, such as EQ or BVLE.
+// Bit blasting a term representing an n-bit bitvector with BBTerm
+// yields a vector of n boolean formulas (returning ASTVec).
+// Bit blasting a formula returns a single boolean formula (type ASTNode).
+
+// A bitblasted term is a vector of ASTNodes for formulas.
+// The 0th element of the vector corresponds to bit 0 -- the low-order bit.
+
+#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;
+
+  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 BVSRSHIFT:
+  case BVVARSHIFT: 
+    FatalError("BBTerm: These kinds have not been implemented in the BitBlaster: ", term);
+    break;
+  case ITE: {
+    // Term version of ITE.
+
+    // Blast the args
+    // FIXME Uses temporary const ASTNodes and an ASTVec&
+    const ASTNode& cond = BBForm(term[0]);
+    const ASTNode& 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++, bb_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 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
+    const ASTNode& bbkids = BBTerm(term[0]); 
+    unsigned int high = GetUnsignedConst(term[1]);
+    unsigned int low = GetUnsignedConst(term[2]);
+
+    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));
+    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;
+    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);
+    break;
+  }
+  case BVCONST: {
+    ASTVec tmp_res(num_bits);
+#ifndef NATIVE_C_ARITH
+    CBV bv = term.GetBVConst();
+    for(unsigned int i = 0; i < num_bits; i++){
+      tmp_res[i] = CONSTANTBV::BitVector_bit_test(bv,i) ? ASTTrue : ASTFalse; 
+    }  
+#else
+    const unsigned long long int c = term.GetBVConst();
+    unsigned long long int bitmask = 0x00000000000000001LL;
+    for (unsigned int i = 0; i < num_bits; i++, bitmask <<= 1)
+      tmp_res[i] = ((c & (bitmask)) ? ASTTrue : ASTFalse);    
+#endif
+    result = CreateNode(BOOLVEC, tmp_res);
+    break;
+  }		  
+  case BOOLVEC: {
+    cerr << "Hit a boolvec! what to do?" << endl;
+    break;
+  }
+  default:
+    FatalError("BBTerm: Illegal kind to BBTerm",term);
+  }
+
+  //if(result == ASTJunk)
+  //  cout<<"result does not change"<<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:
+    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: {
+    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: {
+    // Common code for binary operations
+    // FIXME:  This ought to be in a semantic analysis phase.
+    const ASTNode left = BBTerm(form[0]);
+    const ASTNode right = BBTerm(form[1]);
+    if (left.Degree() != right.Degree()) {
+      cerr << "BBForm: Size mismatch" << endl << form[0] << endl << form[1] << endl;
+      FatalError("",ASTUndefined);
+    }
+    result = BBEQ(left.GetChildren(), right.GetChildren());
+    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);
+}
+
+// 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