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 BVAND: { output = CONSTANTBV::BitVector_Create(inputwidth,true); CONSTANTBV::Set_Intersection(output,tmp0,tmp1); OutputNode = CreateBVConst(output, outputwidth); break; } case BVOR: { output = CONSTANTBV::BitVector_Create(inputwidth,true); CONSTANTBV::Set_Union(output,tmp0,tmp1); OutputNode = CreateBVConst(output, outputwidth); break; } case BVXOR: { output = CONSTANTBV::BitVector_Create(inputwidth,true); CONSTANTBV::Set_ExclusiveOr(output,tmp0,tmp1); OutputNode = CreateBVConst(output, outputwidth); break; } case BVSUB: { output = CONSTANTBV::BitVector_Create(inputwidth,true); bool carry = false; CONSTANTBV::BitVector_sub(output,tmp0,tmp1,&carry); OutputNode = CreateBVConst(output, outputwidth); break; } case BVUMINUS: { output = CONSTANTBV::BitVector_Create(inputwidth,true); CONSTANTBV::BitVector_Negate(output, tmp0); OutputNode = CreateBVConst(output, outputwidth); break; } case BVEXTRACT: { output = CONSTANTBV::BitVector_Create(inputwidth,true); tmp0 = BVConstEvaluator(t[0]).GetBVConst(); unsigned int hi = GetUnsignedConst(BVConstEvaluator(t[1])); unsigned int low = GetUnsignedConst(BVConstEvaluator(t[2])); unsigned int len = hi-low+1; CONSTANTBV::BitVector_Destroy(output); output = CONSTANTBV::BitVector_Create(len, false); CONSTANTBV::BitVector_Interval_Copy(output, tmp0, 0, low, len); outputwidth = len; OutputNode = CreateBVConst(output, outputwidth); break; } //FIXME Only 2 inputs? case BVCONCAT: { output = CONSTANTBV::BitVector_Create(inputwidth,true); unsigned t0_width = t[0].GetValueWidth(); unsigned t1_width = t[1].GetValueWidth(); CONSTANTBV::BitVector_Destroy(output); output = CONSTANTBV::BitVector_Concat(tmp0, tmp1); outputwidth = t0_width + t1_width; OutputNode = CreateBVConst(output, outputwidth); break; } case BVMULT: { output = CONSTANTBV::BitVector_Create(inputwidth,true); CBV tmp = CONSTANTBV::BitVector_Create(2*inputwidth,true); CONSTANTBV::ErrCode e = CONSTANTBV::BitVector_Multiply(tmp,tmp0,tmp1); if(0 != e) { BVConstEvaluatorError(e,t); } //FIXME WHAT IS MY OUTPUT???? THE SECOND HALF of tmp? //CONSTANTBV::BitVector_Interval_Copy(output, tmp, 0, inputwidth, inputwidth); CONSTANTBV::BitVector_Interval_Copy(output, tmp, 0, 0, inputwidth); OutputNode = CreateBVConst(output, outputwidth); CONSTANTBV::BitVector_Destroy(tmp); break; } case BVPLUS: { output = CONSTANTBV::BitVector_Create(inputwidth,true); bool carry = false; ASTVec c = t.GetChildren(); for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { CBV kk = BVConstEvaluator(*it).GetBVConst(); CONSTANTBV::BitVector_add(output,output,kk,&carry); carry = false; //CONSTANTBV::BitVector_Destroy(kk); } OutputNode = CreateBVConst(output, outputwidth); break; } //FIXME ANOTHER SPECIAL CASE case SBVDIV: case SBVMOD:{ OutputNode = BVConstEvaluator(TranslateSignedDivMod(t)); break; } case BVDIV: case BVMOD: { CBV quotient = CONSTANTBV::BitVector_Create(inputwidth,true); CBV remainder = CONSTANTBV::BitVector_Create(inputwidth,true); // tmp0 is dividend, tmp1 is the divisor //All parameters to BitVector_Div_Pos must be distinct unlike BitVector_Divide //FIXME the contents of the second parameter to Div_Pos is destroyed //As tmp0 is currently the same as the copy belonging to an ASTNode t[0] //this must be copied. tmp0 = CONSTANTBV::BitVector_Clone(tmp0); CONSTANTBV::ErrCode e= CONSTANTBV::BitVector_Div_Pos(quotient,tmp0,tmp1,remainder); CONSTANTBV::BitVector_Destroy(tmp0); if(0 != e) { //error printing if(counterexample_checking_during_refinement) { output = CONSTANTBV::BitVector_Create(inputwidth,true); OutputNode = CreateBVConst(output, outputwidth); bvdiv_exception_occured = true; // CONSTANTBV::BitVector_Destroy(output); break; } else { BVConstEvaluatorError(e,t); } } //end of error printing //FIXME Not very standard in the current scheme if(BVDIV == k){ OutputNode = CreateBVConst(quotient, outputwidth); CONSTANTBV::BitVector_Destroy(remainder); }else{ OutputNode = CreateBVConst(remainder, outputwidth); CONSTANTBV::BitVector_Destroy(quotient); } break; } case ITE: if(ASTTrue == t[0]) OutputNode = BVConstEvaluator(t[1]); else if(ASTFalse == t[0]) OutputNode = BVConstEvaluator(t[2]); else FatalError("BVConstEvaluator: ITE condiional must be either TRUE or FALSE:",t); break; case EQ: if(CONSTANTBV::BitVector_equal(tmp0,tmp1)) OutputNode = ASTTrue; else OutputNode = ASTFalse; break; case NEQ: if(!CONSTANTBV::BitVector_equal(tmp0,tmp1)) OutputNode = ASTTrue; else OutputNode = ASTFalse; break; case BVLT: if(-1 == CONSTANTBV::BitVector_Lexicompare(tmp0,tmp1)) OutputNode = ASTTrue; else OutputNode = ASTFalse; break; case BVLE: { int comp = CONSTANTBV::BitVector_Lexicompare(tmp0,tmp1); if(comp <= 0) OutputNode = ASTTrue; else OutputNode = ASTFalse; break; } case BVGT: if(1 == CONSTANTBV::BitVector_Lexicompare(tmp0,tmp1)) OutputNode = ASTTrue; else OutputNode = ASTFalse; break; case BVGE: { int comp = CONSTANTBV::BitVector_Lexicompare(tmp0,tmp1); if(comp >= 0) OutputNode = ASTTrue; else OutputNode = ASTFalse; break; } case BVSLT: if(-1 == CONSTANTBV::BitVector_Compare(tmp0,tmp1)) OutputNode = ASTTrue; else OutputNode = ASTFalse; break; case BVSLE: { signed int comp = CONSTANTBV::BitVector_Compare(tmp0,tmp1); if(comp <= 0) OutputNode = ASTTrue; else OutputNode = ASTFalse; break; } case BVSGT: if(1 == CONSTANTBV::BitVector_Compare(tmp0,tmp1)) OutputNode = ASTTrue; else OutputNode = ASTFalse; break; case BVSGE: { int comp = CONSTANTBV::BitVector_Compare(tmp0,tmp1); if(comp >= 0) OutputNode = ASTTrue; else OutputNode = ASTFalse; break; } default: FatalError("BVConstEvaluator: The input kind is not supported yet:",t); break; } /* 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; }
//FIXME: Ideally I would like the ASTNodes to be able to operate on //themselves (add, sub, concat, etc.) rather than doing a //GetBVConst() and then do the operation externally. For now, //this is the fastest path to completion. ASTNode BeevMgr::BVConstEvaluator(const ASTNode& t) { //cerr << "inside begin bcconstevaluator: " << t << endl; ASTNode OutputNode; if(CheckSolverMap(t,OutputNode)) return OutputNode; OutputNode = ASTUndefined; Kind k = t.GetKind(); unsigned long long int output = 0; unsigned inputwidth = t.GetValueWidth(); ASTNode t0 = ASTUndefined; ASTNode t1 = ASTUndefined; if(2 == t.Degree()) { t0 = BVConstEvaluator(t[0]); t1 = BVConstEvaluator(t[1]); } switch(k) { case READ: case UNDEFINED: case WRITE: case SYMBOL: cerr << t; FatalError("BVConstEvaluator: term is not a constant-term",t); break; case BVCONST: return t; break; case BVNEG: //compute bitwise negation in C output = ~(BVConstEvaluator(t[0]).GetBVConst()); break; case BVSX: output = SXBVConst64(BVConstEvaluator(t[0])); break; case BVAND: output = t0.GetBVConst() & t1.GetBVConst(); break; case BVOR: output = t0.GetBVConst() | t1.GetBVConst(); break; case BVXOR: output = t0.GetBVConst() ^ t1.GetBVConst(); break; case BVSUB: output = t0.GetBVConst() - t1.GetBVConst(); break; case BVUMINUS: output = ~(BVConstEvaluator(t[0]).GetBVConst()) + 1; break; case BVEXTRACT: { unsigned long long int val = BVConstEvaluator(t[0]).GetBVConst(); unsigned int hi = GetUnsignedConst(BVConstEvaluator(t[1])); unsigned int low = GetUnsignedConst(BVConstEvaluator(t[2])); if(!(0 <= hi <= 64)) FatalError("ConstantEvaluator: hi bit in BVEXTRACT is > 32bits",t); if(!(0 <= low <= hi <= 64)) FatalError("ConstantEvaluator: low bit in BVEXTRACT is > 32bits or hi",t); //64 bit mask. unsigned long long int mask1 = 0xffffffffffffffffLL; mask1 >>= 64-(hi+1); //extract val[hi:0] val &= mask1; //extract val[hi:low] val >>= low; output = val; break; } case BVCONCAT: { unsigned long long int q = BVConstEvaluator(t0).GetBVConst(); unsigned long long int r = BVConstEvaluator(t1).GetBVConst(); unsigned int qlen = t[0].GetValueWidth(); unsigned int rlen = t[1].GetValueWidth(); unsigned int slen = t.GetValueWidth(); if(!(0 < qlen + rlen <= 64)) FatalError("BVConstEvaluator:" "lengths of childnodes of BVCONCAT are > 64:",t); //64 bit mask for q unsigned long long int qmask = 0xffffffffffffffffLL; qmask >>= 64-qlen; //zero the useless bits of q q &= qmask; //64 bit mask for r unsigned long long int rmask = 0xffffffffffffffffLL; rmask >>= 64-rlen; //zero the useless bits of r r &= rmask; //concatenate q <<= rlen; q |= r; //64 bit mask for output s unsigned long long int smask = 0xffffffffffffffffLL; smask >>= 64-slen; //currently q has the output output = q; output &= smask; break; } case BVMULT: { output = t0.GetBVConst() * t1.GetBVConst(); //64 bit mask unsigned long long int mask = 0xffffffffffffffffLL; mask = mask >> (64 - inputwidth); output &= mask; break; } case BVPLUS: { ASTVec c = t.GetChildren(); for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) output += BVConstEvaluator(*it).GetBVConst(); //64 bit mask unsigned long long int mask = 0xffffffffffffffffLL; mask = mask >> (64 -inputwidth); output &= mask; break; } case SBVDIV: case SBVMOD: { output = BVConstEvaluator(TranslateSignedDivMod(t)).GetBVConst(); break; } case BVDIV: { if(0 == t1.GetBVConst()) { //if denominator is 0 then // (if refinement is ON then output is set to 0) // (else produce a fatal error) if(counterexample_checking_during_refinement) { output = 0; bvdiv_exception_occured = true; break; } else { FatalError("BVConstEvaluator: divide by zero not allowed:",t); } } output = t0.GetBVConst() / t1.GetBVConst(); //64 bit mask unsigned long long int mask = 0xffffffffffffffffLL; mask = mask >> (64 - inputwidth); output &= mask; break; } case BVMOD: { if(0 == t1.GetBVConst()) { //if denominator is 0 then // (if refinement is ON then output is set to 0) // (else produce a fatal error) if(counterexample_checking_during_refinement) { output = 0; bvdiv_exception_occured = true; break; } else { FatalError("BVConstEvaluator: divide by zero not allowed:",t); } } output = t0.GetBVConst() % t1.GetBVConst(); //64 bit mask unsigned long long int mask = 0xffffffffffffffffLL; mask = mask >> (64 - inputwidth); output &= mask; break; } case ITE: if(ASTTrue == t[0]) OutputNode = BVConstEvaluator(t[1]); else if(ASTFalse == t[0]) OutputNode = BVConstEvaluator(t[2]); else FatalError("BVConstEvaluator:" "ITE condiional must be either TRUE or FALSE:",t); break; case EQ: if(t0.GetBVConst() == t1.GetBVConst()) OutputNode = ASTTrue; else OutputNode = ASTFalse; break; case NEQ: if(t0.GetBVConst() != t1.GetBVConst()) OutputNode = ASTTrue; else OutputNode = ASTFalse; break; break; case BVLT: { unsigned long long n0 = t0.GetBVConst(); unsigned long long n1 = t1.GetBVConst(); if(n0 < n1) OutputNode = ASTTrue; else OutputNode = ASTFalse; break; } case BVLE: if(t0.GetBVConst() <= t1.GetBVConst()) OutputNode = ASTTrue; else OutputNode = ASTFalse; break; case BVGT: if(t0.GetBVConst() > t1.GetBVConst()) OutputNode = ASTTrue; else OutputNode = ASTFalse; break; case BVGE: if(t0.GetBVConst() >= t1.GetBVConst()) OutputNode = ASTTrue; else OutputNode = ASTFalse; break; case BVSLT: { signed long long int n0 = SXBVConst64(t0); signed long long int n1 = SXBVConst64(t1); if(n0 < n1) OutputNode = ASTTrue; else OutputNode = ASTFalse; break; } case BVSLE: { signed long long int n0 = SXBVConst64(t0); signed long long int n1 = SXBVConst64(t1); if(n0 <= n1) OutputNode = ASTTrue; else OutputNode = ASTFalse; break; } case BVSGT: { signed long long int n0 = SXBVConst64(t0); signed long long int n1 = SXBVConst64(t1); if(n0 > n1) OutputNode = ASTTrue; else OutputNode = ASTFalse; break; } case BVSGE: { signed long long int n0 = SXBVConst64(t0); signed long long int n1 = SXBVConst64(t1); if(n0 >= n1) OutputNode = ASTTrue; else OutputNode = ASTFalse; break; } default: FatalError("BVConstEvaluator: The input kind is not supported yet:",t); break; } if(ASTTrue != OutputNode && ASTFalse != OutputNode) OutputNode = CreateBVConst(inputwidth, output); UpdateSolverMap(t,OutputNode); //UpdateSimplifyMap(t,OutputNode,false); return OutputNode; } //End of BVConstEvaluator
ASTNode SubstitutionMap::replace(const ASTNode& n, ASTNodeMap& fromTo, ASTNodeMap& cache, NodeFactory* nf, bool stopAtArrays, bool preventInfinite) { const Kind k = n.GetKind(); if (k == BVCONST || k == TRUE || k == FALSE) return n; ASTNodeMap::const_iterator it; if ((it = cache.find(n)) != cache.end()) return it->second; if ((it = fromTo.find(n)) != fromTo.end()) { const ASTNode& r = it->second; assert(r.GetIndexWidth() == n.GetIndexWidth()); if (preventInfinite) cache.insert(make_pair(n, r)); ASTNode replaced = replace(r, fromTo, cache, nf, stopAtArrays, preventInfinite); if (replaced != r) { fromTo.erase(n); fromTo[n] = replaced; } if (preventInfinite) cache.erase(n); cache.insert(make_pair(n, replaced)); return replaced; } // These can't be created like regular nodes are if (k == SYMBOL) return n; const unsigned int indexWidth = n.GetIndexWidth(); if (stopAtArrays && indexWidth > 0) // is an array. { return n; } const ASTVec& children = n.GetChildren(); assert(children.size() > 0); // Should have no leaves left here. ASTVec new_children; new_children.reserve(children.size()); for (ASTVec::const_iterator it = children.begin(); it != children.end(); it++) { new_children.push_back( replace(*it, fromTo, cache, nf, stopAtArrays, preventInfinite)); } assert(new_children.size() == children.size()); // This code short-cuts if the children are the same. Nodes with the same // children, // won't have necessarily given the same node if the simplifyingNodeFactory is // enabled // now, but wasn't enabled when the node was created. Shortcutting saves lots // of time. if (new_children == children) { cache.insert(make_pair(n, n)); return n; } ASTNode result; const unsigned int valueWidth = n.GetValueWidth(); if (valueWidth == 0) // n.GetType() == BOOLEAN_TYPE { result = nf->CreateNode(k, new_children); } else { // If the index and value width aren't saved, they are reset sometimes (??) result = nf->CreateArrayTerm(k, indexWidth, valueWidth, new_children); } // We may have created something that should be mapped. For instance, // if n is READ(A, x), and the fromTo is: {x==0, READ(A,0) == 1}, then // by here the result will be READ(A,0). Which needs to be mapped again.. // I hope that this makes it idempotent. if (fromTo.find(result) != fromTo.end()) { // map n->result, if running replace() on result gives us 'n', it will not // infinite loop. // This is only currently required for the bitblast equivalence stuff. if (preventInfinite) cache.insert(make_pair(n, result)); result = replace(result, fromTo, cache, nf, stopAtArrays, preventInfinite); } assert(result.GetValueWidth() == valueWidth); assert(result.GetIndexWidth() == indexWidth); // If there is already an "n" element in the cache, the maps semantics are to // ignore the next insertion. if (preventInfinite) cache.erase(n); cache.insert(make_pair(n, result)); return result; }