diff options
Diffstat (limited to 'stp/simplifier/simplifier.cpp')
-rw-r--r-- | stp/simplifier/simplifier.cpp | 2495 |
1 files changed, 2495 insertions, 0 deletions
diff --git a/stp/simplifier/simplifier.cpp b/stp/simplifier/simplifier.cpp new file mode 100644 index 00000000..2a627398 --- /dev/null +++ b/stp/simplifier/simplifier.cpp @@ -0,0 +1,2495 @@ +/******************************************************************** + * AUTHORS: Vijay Ganesh, David L. Dill + * + * BEGIN DATE: November, 2005 + * + * LICENSE: Please view LICENSE file in the home dir of this Program + ********************************************************************/ +// -*- c++ -*- + +#include "../AST/AST.h" +#include "../AST/ASTUtil.h" +namespace BEEV { + + bool BeevMgr::CheckSimplifyMap(const ASTNode& key, + ASTNode& output, bool pushNeg) { + ASTNodeMap::iterator it, itend; + it = pushNeg ? SimplifyNegMap.find(key) : SimplifyMap.find(key); + itend = pushNeg ? SimplifyNegMap.end() : SimplifyMap.end(); + + if(it != itend) { + output = it->second; + CountersAndStats("Successful_CheckSimplifyMap"); + return true; + } + + if(pushNeg && (it = SimplifyMap.find(key)) != SimplifyMap.end()) { + output = + (ASTFalse == it->second) ? + ASTTrue : + (ASTTrue == it->second) ? ASTFalse : CreateNode(NOT, it->second); + CountersAndStats("2nd_Successful_CheckSimplifyMap"); + return true; + } + + return false; + } + + void BeevMgr::UpdateSimplifyMap(const ASTNode& key, const ASTNode& value, bool pushNeg) { + if(pushNeg) + SimplifyNegMap[key] = value; + else + SimplifyMap[key] = value; + } + + bool BeevMgr::CheckSubstitutionMap(const ASTNode& key, ASTNode& output) { + ASTNodeMap::iterator it; + if((it = SolverMap.find(key)) != SolverMap.end()) { + output = it->second; + return true; + } + return false; + } + + bool BeevMgr::CheckSubstitutionMap(const ASTNode& key) { + if(SolverMap.find(key) != SolverMap.end()) + return true; + else + return false; + } + + bool BeevMgr::UpdateSubstitutionMap(const ASTNode& e0, const ASTNode& e1) { + int i = TermOrder(e0,e1); + if(0 == i) + return false; + + //e0 is of the form READ(Arr,const), and e1 is const, or + //e0 is of the form var, and e1 is const + if(1 == i && !CheckSubstitutionMap(e0)) { + SolverMap[e0] = e1; + return true; + } + + //e1 is of the form READ(Arr,const), and e0 is const, or + //e1 is of the form var, and e0 is const + if (-1 == i && !CheckSubstitutionMap(e1)) { + SolverMap[e1] = e0; + return true; + } + + return false; + } + + bool BeevMgr::CheckMultInverseMap(const ASTNode& key, ASTNode& output) { + ASTNodeMap::iterator it; + if((it = MultInverseMap.find(key)) != MultInverseMap.end()) { + output = it->second; + return true; + } + return false; + } + + void BeevMgr::UpdateMultInverseMap(const ASTNode& key, const ASTNode& value) { + MultInverseMap[key] = value; + } + + + bool BeevMgr::CheckAlwaysTrueFormMap(const ASTNode& key) { + ASTNodeSet::iterator it = AlwaysTrueFormMap.find(key); + ASTNodeSet::iterator itend = AlwaysTrueFormMap.end(); + + if(it != itend) { + //cerr << "found:" << *it << endl; + CountersAndStats("Successful_CheckAlwaysTrueFormMap"); + return true; + } + + return false; + } + + void BeevMgr::UpdateAlwaysTrueFormMap(const ASTNode& key) { + AlwaysTrueFormMap.insert(key); + } + + //if a is READ(Arr,const) or SYMBOL, and b is BVCONST then return 1 + //if b is READ(Arr,const) or SYMBOL, and a is BVCONST then return -1 + // + //else return 0 by default + int BeevMgr::TermOrder(const ASTNode& a, const ASTNode& b) { + Kind k1 = a.GetKind(); + Kind k2 = b.GetKind(); + + //a is of the form READ(Arr,const), and b is const, or + //a is of the form var, and b is const + if((k1 == READ + && + a[0].GetKind() == SYMBOL && + a[1].GetKind() == BVCONST + ) + && + (k2 == BVCONST) + ) + return 1; + + if(k1 == SYMBOL) + 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 + ) + || + k2 == SYMBOL + )) + return -1; + return 0; + } + + //This function records all the const-indices seen so far for each + //array. It populates the map '_arrayname_readindices' whose key is + //the arrayname, and vlaue is a vector of read-indices. + // + //fill the arrayname_readindices vector if e0 is a READ(Arr,index) + //and index is a BVCONST. + // + //Since these arrayreads are being nuked and recorded in the + //substitutionmap, we have to also record the fact that each + //arrayread (e0 is of the form READ(Arr,const) here is represented + //by a BVCONST (e1). This is necessary for later Leibnitz Axiom + //generation + void BeevMgr::FillUp_ArrReadIndex_Vec(const ASTNode& e0, const ASTNode& e1) { + int i = TermOrder(e0,e1); + if(0 == i) return; + + if(1 == i && e0.GetKind() != SYMBOL && !CheckSubstitutionMap(e0)) { + _arrayname_readindices[e0[0]].push_back(e0[1]); + //e0 is the array read : READ(A,i) and e1 is a bvconst + _arrayread_symbol[e0] = e1; + return; + } + if(-1 == i && e1.GetKind() != SYMBOL && !CheckSubstitutionMap(e1)) { + _arrayname_readindices[e1[0]].push_back(e1[1]); + //e0 is the array read : READ(A,i) and e1 is a bvconst + _arrayread_symbol[e1] = e0; + return; + } + } + + ASTNode BeevMgr::SimplifyFormula_NoRemoveWrites(const ASTNode& b, bool pushNeg) { + Begin_RemoveWrites = false; + ASTNode out = SimplifyFormula(b,pushNeg); + return out; + } + + ASTNode BeevMgr::SimplifyFormula_TopLevel(const ASTNode& b, bool pushNeg) { + SimplifyMap.clear(); + SimplifyNegMap.clear(); + ASTNode out = SimplifyFormula(b,pushNeg); + SimplifyMap.clear(); + SimplifyNegMap.clear(); + return out; + } + + ASTNode BeevMgr::SimplifyFormula(const ASTNode& b, bool pushNeg){ + if(!optimize) + return b; + + Kind kind = b.GetKind(); + if(BOOLEAN_TYPE != b.GetType()) { + FatalError(" SimplifyFormula: You have input a nonformula kind: ",ASTUndefined,kind); + } + + ASTNode a = b; + ASTVec ca = a.GetChildren(); + if(!(IMPLIES == kind || + ITE == kind || + isAtomic(kind))) { + SortByExprNum(ca); + a = CreateNode(kind,ca); + } + + ASTNode output; + if(CheckSimplifyMap(a,output,pushNeg)) + return output; + + switch(kind){ + case AND: + case OR: + output = SimplifyAndOrFormula(a,pushNeg); + break; + case NOT: + output = SimplifyNotFormula(a,pushNeg); + break; + case XOR: + output = SimplifyXorFormula(a,pushNeg); + break; + case NAND: + output = SimplifyNandFormula(a,pushNeg); + break; + case NOR: + output = SimplifyNorFormula(a,pushNeg); + break; + case IFF: + output = SimplifyIffFormula(a,pushNeg); + break; + case IMPLIES: + output = SimplifyImpliesFormula(a,pushNeg); + break; + case ITE: + output = SimplifyIteFormula(a,pushNeg); + break; + default: + //kind can be EQ,NEQ,BVLT,BVLE,... or a propositional variable + output = SimplifyAtomicFormula(a,pushNeg); + //output = pushNeg ? CreateNode(NOT,a) : a; + break; + } + + //memoize + UpdateSimplifyMap(a,output, pushNeg); + return output; + } + + ASTNode BeevMgr::SimplifyAtomicFormula(const ASTNode& a, bool pushNeg) { + if(!optimize) { + return a; + } + + ASTNode output; + if(CheckSimplifyMap(a,output,pushNeg)) { + return output; + } + + ASTNode left,right; + if(a.Degree() == 2) { + //cerr << "Input to simplifyterm: left: " << a[0] << endl; + left = SimplifyTerm(a[0]); + //cerr << "Output of simplifyterm:left: " << left << endl; + //cerr << "Input to simplifyterm: right: " << a[1] << endl; + right = SimplifyTerm(a[1]); + //cerr << "Output of simplifyterm:left: " << right << endl; + } + + Kind kind = a.GetKind(); + switch(kind) { + case TRUE: + output = pushNeg ? ASTFalse : ASTTrue; + break; + case FALSE: + output = pushNeg ? ASTTrue : ASTFalse; + break; + case SYMBOL: + if(!CheckSolverMap(a,output)) { + output = a; + } + output = pushNeg ? CreateNode(NOT,output) : output; + break; + case BVGETBIT: { + ASTNode term = SimplifyTerm(a[0]); + ASTNode thebit = a[1]; + ASTNode zero = CreateZeroConst(1); + ASTNode one = CreateOneConst(1); + ASTNode getthebit = SimplifyTerm(CreateTerm(BVEXTRACT,1,term,thebit,thebit)); + if(getthebit == zero) + output = pushNeg ? ASTTrue : ASTFalse; + else if(getthebit == one) + output = pushNeg ? ASTFalse : ASTTrue; + else { + output = CreateNode(BVGETBIT,term,thebit); + output = pushNeg ? CreateNode(NOT,output) : output; + } + break; + } + case EQ:{ + output = CreateSimplifiedEQ(left,right); + output = LhsMinusRhs(output); + output = ITEOpt_InEqs(output); + if(output == ASTTrue) + output = pushNeg ? ASTFalse : ASTTrue; + else if (output == ASTFalse) + output = pushNeg ? ASTTrue : ASTFalse; + else + output = pushNeg ? CreateNode(NOT,output) : output; + break; + } + case NEQ: { + output = CreateSimplifiedEQ(left,right); + output = LhsMinusRhs(output); + if(output == ASTTrue) + output = pushNeg ? ASTTrue : ASTFalse; + else if (output == ASTFalse) + output = pushNeg ? ASTFalse : ASTTrue; + else + output = pushNeg ? output : CreateNode(NOT,output); + break; + } + case BVLT: + case BVLE: + case BVGT: + case BVGE: + case BVSLT: + case BVSLE: + case BVSGT: + case BVSGE: { + //output = CreateNode(kind,left,right); + //output = pushNeg ? CreateNode(NOT,output) : output; + output = CreateSimplifiedINEQ(kind,left,right,pushNeg); + break; + } + default: + FatalError("SimplifyAtomicFormula: NO atomic formula of the kind: ",ASTUndefined,kind); + break; + } + + //memoize + UpdateSimplifyMap(a,output,pushNeg); + return output; + } //end of SimplifyAtomicFormula() + + ASTNode BeevMgr::CreateSimplifiedINEQ(Kind k, + const ASTNode& left, + const ASTNode& right, + bool pushNeg) { + ASTNode output; + if(BVCONST == left.GetKind() && BVCONST == right.GetKind()) { + output = BVConstEvaluator(CreateNode(k,left,right)); + output = pushNeg ? (ASTFalse == output) ? ASTTrue : ASTFalse : output; + return output; + } + + unsigned len = left.GetValueWidth(); + ASTNode zero = CreateZeroConst(len); + ASTNode one = CreateOneConst(len); + ASTNode max = CreateMaxConst(len); + switch(k){ + case BVLT: + if(right == zero) { + output = pushNeg ? ASTTrue : ASTFalse; + } + else if(left == right) { + output = pushNeg ? ASTTrue : ASTFalse; + } + else if(one == right) { + output = CreateSimplifiedEQ(left,zero); + output = pushNeg ? CreateNode(NOT,output) : output; + } + else { + output = pushNeg ? CreateNode(BVLE,right,left) : CreateNode(BVLT,left,right); + } + break; + case BVLE: + if(left == zero) { + output = pushNeg ? ASTFalse : ASTTrue; + } + else if(left == right) { + output = pushNeg ? ASTFalse : ASTTrue; + } + else if(max == right) { + output = pushNeg ? ASTFalse : ASTTrue; + } + else if(zero == right) { + output = CreateSimplifiedEQ(left,zero); + output = pushNeg ? CreateNode(NOT,output) : output; + } + else { + output = pushNeg ? CreateNode(BVLT,right,left) : CreateNode(BVLE,left,right); + } + break; + case BVGT: + if(left == zero) { + output = pushNeg ? ASTTrue : ASTFalse; + } + else if(left == right) { + output = pushNeg ? ASTTrue : ASTFalse; + } + else { + output = pushNeg ? CreateNode(BVLE,left,right) : CreateNode(BVLT,right,left); + } + break; + case BVGE: + if(right == zero) { + output = pushNeg ? ASTFalse : ASTTrue; + } + else if(left == right) { + output = pushNeg ? ASTFalse : ASTTrue; + } + else { + output = pushNeg ? CreateNode(BVLT,left,right) : CreateNode(BVLE,right,left); + } + break; + case BVSLT: + case BVSLE: + case BVSGE: + case BVSGT: { + output = CreateNode(k,left,right); + output = pushNeg ? CreateNode(NOT,output) : output; + } + break; + default: + FatalError("Wrong Kind"); + break; + } + + return output; + } + + //takes care of some simple ITE Optimizations in the context of equations + ASTNode BeevMgr::ITEOpt_InEqs(const ASTNode& in) { + CountersAndStats("ITEOpts_InEqs"); + + if(!(EQ == in.GetKind() && optimize)) { + return in; + } + + ASTNode output; + if(CheckSimplifyMap(in,output,false)) { + return output; + } + + ASTNode in1 = in[0]; + ASTNode in2 = in[1]; + Kind k1 = in1.GetKind(); + Kind k2 = in2.GetKind(); + if(in1 == in2) { + //terms are syntactically the same + output = ASTTrue; + } + else if(BVCONST == k1 && BVCONST == k2) { + //here the terms are definitely not syntactically equal but may + //be semantically equal. + output = ASTFalse; + } + else if(ITE == k1 && + BVCONST == in1[1].GetKind() && + BVCONST == in1[2].GetKind() && BVCONST == k2) { + //if one side is a BVCONST and the other side is an ITE over + //BVCONST then we can do the following optimization: + // + // c = ITE(cond,c,d) <=> cond + // + // similarly ITE(cond,c,d) = c <=> cond + // + // c = ITE(cond,d,c) <=> NOT(cond) + // + //similarly ITE(cond,d,c) = d <=> NOT(cond) + ASTNode cond = in1[0]; + if(in1[1] == in2) { + //ITE(cond, c, d) = c <=> cond + output = cond; + } + else if(in1[2] == in2) { + cond = SimplifyFormula(cond,true); + output = cond; + } + else { + //last resort is to CreateNode + output = CreateNode(EQ,in1,in2); + } + } + else if(ITE == k2 && + BVCONST == in2[1].GetKind() && + BVCONST == in2[2].GetKind() && BVCONST == k1) { + ASTNode cond = in2[0]; + if(in2[1] == in1) { + //ITE(cond, c, d) = c <=> cond + output = cond; + } + else if(in2[2] == in1) { + cond = SimplifyFormula(cond,true); + output = cond; + } + else { + //last resort is to CreateNode + output = CreateNode(EQ,in1,in2); + } + } + else { + //last resort is to CreateNode + output = CreateNode(EQ,in1,in2); + } + + UpdateSimplifyMap(in,output,false); + return output; + } //End of ITEOpts_InEqs() + + //Tries to simplify the input to TRUE/FALSE. if it fails, then + //return the constructed equality + ASTNode BeevMgr::CreateSimplifiedEQ(const ASTNode& in1, const ASTNode& in2) { + CountersAndStats("CreateSimplifiedEQ"); + Kind k1 = in1.GetKind(); + Kind k2 = in2.GetKind(); + + if(!optimize) { + return CreateNode(EQ,in1,in2); + } + + if(in1 == in2) + //terms are syntactically the same + return ASTTrue; + + //here the terms are definitely not syntactically equal but may be + //semantically equal. + if(BVCONST == k1 && BVCONST == k2) + return ASTFalse; + + //last resort is to CreateNode + return CreateNode(EQ,in1,in2); + } + + //accepts cond == t1, then part is t2, and else part is t3 + ASTNode BeevMgr::CreateSimplifiedTermITE(const ASTNode& in0, + const ASTNode& in1, const ASTNode& in2) { + ASTNode t0 = in0; + ASTNode t1 = in1; + ASTNode t2 = in2; + CountersAndStats("CreateSimplifiedITE"); + if(!optimize) { + if(t1.GetValueWidth() != t2.GetValueWidth()) { + cerr << "t2 is : = " << t2; + FatalError("CreateSimplifiedTermITE: the lengths of then and else branches don't match",t1); + } + if(t1.GetIndexWidth() != t2.GetIndexWidth()) { + cerr << "t2 is : = " << t2; + FatalError("CreateSimplifiedTermITE: the lengths of then and else branches don't match",t1); + } + return CreateTerm(ITE,t1.GetValueWidth(),t0,t1,t2); + } + + if(t0 == ASTTrue) + return t1; + if (t0 == ASTFalse) + return t2; + if(t1 == t2) + return t1; + if(CheckAlwaysTrueFormMap(t0)) { + return t1; + } + if(CheckAlwaysTrueFormMap(CreateNode(NOT,t0)) || + (NOT == t0.GetKind() && CheckAlwaysTrueFormMap(t0[0]))) { + return t2; + } + + return CreateTerm(ITE,t1.GetValueWidth(),t0,t1,t2); + } + + ASTNode BeevMgr::SimplifyAndOrFormula(const ASTNode& a, bool pushNeg) { + ASTNode output; + //cerr << "input:\n" << a << endl; + + if(CheckSimplifyMap(a,output,pushNeg)) + return output; + + ASTVec c, outvec; + c = a.GetChildren(); + ASTNode flat = FlattenOneLevel(a); + c = flat.GetChildren(); + SortByExprNum(c); + + Kind k = a.GetKind(); + bool isAnd = (k == AND) ? true : false; + + ASTNode annihilator = isAnd ? + (pushNeg ? ASTTrue : ASTFalse): + (pushNeg ? ASTFalse : ASTTrue); + + ASTNode identity = isAnd ? + (pushNeg ? ASTFalse : ASTTrue): + (pushNeg ? ASTTrue : ASTFalse); + + //do the work + ASTVec::const_iterator next_it; + for(ASTVec::const_iterator i=c.begin(),iend=c.end();i!=iend;i++) { + ASTNode aaa = *i; + next_it = i+1; + bool nextexists = (next_it < iend); + + aaa = SimplifyFormula(aaa,pushNeg); + if(annihilator == aaa) { + //memoize + UpdateSimplifyMap(*i,annihilator,pushNeg); + UpdateSimplifyMap(a, annihilator,pushNeg); + //cerr << "annihilator1: output:\n" << annihilator << endl; + return annihilator; + } + ASTNode bbb = ASTFalse; + if(nextexists) { + bbb = SimplifyFormula(*next_it,pushNeg); + } + if(nextexists && bbb == aaa) { + //skip the duplicate aaa. *next_it will be included + } + else if(nextexists && + ((bbb.GetKind() == NOT && bbb[0] == aaa))) { + //memoize + UpdateSimplifyMap(a, annihilator,pushNeg); + //cerr << "annihilator2: output:\n" << annihilator << endl; + return annihilator; + } + else if(identity == aaa) { + // //drop identites + } + else if((!isAnd && !pushNeg) || + (isAnd && pushNeg)) { + outvec.push_back(aaa); + } + else if((isAnd && !pushNeg) || + (!isAnd && pushNeg)) { + outvec.push_back(aaa); + } + else { + outvec.push_back(aaa); + } + } + + switch(outvec.size()) { + case 0: { + //only identities were dropped + output = identity; + break; + } + case 1: { + output = SimplifyFormula(outvec[0],false); + break; + } + default: { + output = (isAnd) ? + (pushNeg ? CreateNode(OR,outvec) : CreateNode(AND,outvec)): + (pushNeg ? CreateNode(AND,outvec) : CreateNode(OR,outvec)); + //output = FlattenOneLevel(output); + break; + } + } + //memoize + UpdateSimplifyMap(a,output,pushNeg); + //cerr << "output:\n" << output << endl; + return output; + } //end of SimplifyAndOrFormula + + + ASTNode BeevMgr::SimplifyNotFormula(const ASTNode& a, bool pushNeg) { + ASTNode output; + if(CheckSimplifyMap(a,output,pushNeg)) + return output; + + if(!(a.Degree() == 1 && NOT == a.GetKind())) + FatalError("SimplifyNotFormula: input vector with more than 1 node",ASTUndefined); + + //if pushNeg is set then there is NOT on top + unsigned int NotCount = pushNeg ? 1 : 0; + ASTNode o = a; + //count the number of NOTs in 'a' + while(NOT == o.GetKind()) { + o = o[0]; + NotCount++; + } + + //pushnegation if there are odd number of NOTs + bool pn = (NotCount % 2 == 0) ? false : true; + + if(CheckAlwaysTrueFormMap(o)) { + output = pn ? ASTFalse : ASTTrue; + return output; + } + + if(CheckSimplifyMap(o,output,pn)) { + return output; + } + + if (ASTTrue == o) { + output = pn ? ASTFalse : ASTTrue; + } + else if (ASTFalse == o) { + output = pn ? ASTTrue : ASTFalse; + } + else { + output = SimplifyFormula(o,pn); + } + //memoize + UpdateSimplifyMap(o,output,pn); + UpdateSimplifyMap(a,output,pushNeg); + return output; + } + + ASTNode BeevMgr::SimplifyXorFormula(const ASTNode& a, bool pushNeg) { + ASTNode output; + if(CheckSimplifyMap(a,output,pushNeg)) + return output; + + if (a.GetChildren().size() > 2) { + FatalError("Simplify got an XOR with more than two children."); + } + + ASTNode a0 = SimplifyFormula(a[0],false); + ASTNode a1 = SimplifyFormula(a[1],false); + output = pushNeg ? CreateNode(IFF,a0,a1) : CreateNode(XOR,a0,a1); + + if(XOR == output.GetKind()) { + a0 = output[0]; + a1 = output[1]; + if(a0 == a1) + output = ASTFalse; + else if((a0 == ASTTrue && a1 == ASTFalse) || + (a0 == ASTFalse && a1 == ASTTrue)) + output = ASTTrue; + } + + //memoize + UpdateSimplifyMap(a,output,pushNeg); + return output; + } + + ASTNode BeevMgr::SimplifyNandFormula(const ASTNode& a, bool pushNeg) { + ASTNode output,a0,a1; + if(CheckSimplifyMap(a,output,pushNeg)) + return output; + + //the two NOTs cancel out + if(pushNeg) { + a0 = SimplifyFormula(a[0],false); + a1 = SimplifyFormula(a[1],false); + output = CreateNode(AND,a0,a1); + } + else { + //push the NOT implicit in the NAND + a0 = SimplifyFormula(a[0],true); + a1 = SimplifyFormula(a[1],true); + output = CreateNode(OR,a0,a1); + } + + //memoize + UpdateSimplifyMap(a,output,pushNeg); + return output; + } + + ASTNode BeevMgr::SimplifyNorFormula(const ASTNode& a, bool pushNeg) { + ASTNode output,a0,a1; + if(CheckSimplifyMap(a,output,pushNeg)) + return output; + + //the two NOTs cancel out + if(pushNeg) { + a0 = SimplifyFormula(a[0],false); + a1 = SimplifyFormula(a[1],false); + output = CreateNode(OR,a0,a1); + } + else { + //push the NOT implicit in the NAND + a0 = SimplifyFormula(a[0],true); + a1 = SimplifyFormula(a[1],true); + output = CreateNode(AND,a0,a1); + } + + //memoize + UpdateSimplifyMap(a,output,pushNeg); + return output; + } + + ASTNode BeevMgr::SimplifyImpliesFormula(const ASTNode& a, bool pushNeg) { + ASTNode output; + if(CheckSimplifyMap(a,output,pushNeg)) + return output; + + if(!(a.Degree()==2 && IMPLIES==a.GetKind())) + FatalError("SimplifyImpliesFormula: vector with wrong num of nodes",ASTUndefined); + + ASTNode c0,c1; + if(pushNeg) { + c0 = SimplifyFormula(a[0],false); + c1 = SimplifyFormula(a[1],true); + output = CreateNode(AND,c0,c1); + } + else { + c0 = SimplifyFormula(a[0],false); + c1 = SimplifyFormula(a[1],false); + if(ASTFalse == c0) { + output = ASTTrue; + } + else if (ASTTrue == c0) { + output = c1; + } + else if (c0 == c1) { + output = ASTTrue; + } + else if(CheckAlwaysTrueFormMap(c0)) { + // c0 AND (~c0 OR c1) <==> c1 + // + //applying modus ponens + output = c1; + } + else if(CheckAlwaysTrueFormMap(c1) || + CheckAlwaysTrueFormMap(CreateNode(NOT,c0)) || + (NOT == c0.GetKind() && CheckAlwaysTrueFormMap(c0[0]))) { + //(~c0 AND (~c0 OR c1)) <==> TRUE + // + //(c0 AND ~c0->c1) <==> TRUE + output = ASTTrue; + } + else if (CheckAlwaysTrueFormMap(CreateNode(NOT,c1)) || + (NOT == c1.GetKind() && CheckAlwaysTrueFormMap(c1[0]))) { + //(~c1 AND c0->c1) <==> (~c1 AND ~c1->~c0) <==> ~c0 + //(c1 AND c0->~c1) <==> (c1 AND c1->~c0) <==> ~c0 + output = CreateNode(NOT,c0); + } + else { + if(NOT == c0.GetKind()) { + output = CreateNode(OR,c0[0],c1); + } + else { + output = CreateNode(OR,CreateNode(NOT,c0),c1); + } + } + } + + //memoize + UpdateSimplifyMap(a,output,pushNeg); + return output; + } + + ASTNode BeevMgr::SimplifyIffFormula(const ASTNode& a, bool pushNeg) { + ASTNode output; + if(CheckSimplifyMap(a,output,pushNeg)) + return output; + + if(!(a.Degree()==2 && IFF==a.GetKind())) + FatalError("SimplifyIffFormula: vector with wrong num of nodes",ASTUndefined); + + ASTNode c0 = a[0]; + ASTNode c1 = SimplifyFormula(a[1],false); + + if(pushNeg) + c0 = SimplifyFormula(c0,true); + else + c0 = SimplifyFormula(c0,false); + + if(ASTTrue == c0) { + output = c1; + } + else if (ASTFalse == c0) { + output = SimplifyFormula(c1,true); + } + else if (ASTTrue == c1) { + output = c0; + } + else if (ASTFalse == c1) { + output = SimplifyFormula(c0,true); + } + else if (c0 == c1) { + output = ASTTrue; + } + else if((NOT == c0.GetKind() && c0[0] == c1) || + (NOT == c1.GetKind() && c0 == c1[0])) { + output = ASTFalse; + } + else if(CheckAlwaysTrueFormMap(c0)) { + output = c1; + } + else if(CheckAlwaysTrueFormMap(c1)) { + output = c0; + } + else if(CheckAlwaysTrueFormMap(CreateNode(NOT,c0))) { + output = CreateNode(NOT,c1); + } + else if(CheckAlwaysTrueFormMap(CreateNode(NOT,c1))) { + output = CreateNode(NOT,c0); + } + else { + output = CreateNode(IFF,c0,c1); + } + + //memoize + UpdateSimplifyMap(a,output,pushNeg); + return output; + } + + ASTNode BeevMgr::SimplifyIteFormula(const ASTNode& b, bool pushNeg) { + if(!optimize) + return b; + + ASTNode output; + if(CheckSimplifyMap(b,output,pushNeg)) + return output; + + if(!(b.Degree() == 3 && ITE == b.GetKind())) + FatalError("SimplifyIteFormula: vector with wrong num of nodes",ASTUndefined); + + ASTNode a = b; + ASTNode t0 = SimplifyFormula(a[0],false); + ASTNode t1,t2; + if(pushNeg) { + t1 = SimplifyFormula(a[1],true); + t2 = SimplifyFormula(a[2],true); + } + else { + t1 = SimplifyFormula(a[1],false); + t2 = SimplifyFormula(a[2],false); + } + + if(ASTTrue == t0) { + output = t1; + } + else if (ASTFalse == t0) { + output = t2; + } + else if (t1 == t2) { + output = t1; + } + else if(ASTTrue == t1 && ASTFalse == t2) { + output = t0; + } + else if(ASTFalse == t1 && ASTTrue == t2) { + output = SimplifyFormula(t0,true); + } + else if(ASTTrue == t1) { + output = CreateNode(OR,t0,t2); + } + else if(ASTFalse == t1) { + output = CreateNode(AND,CreateNode(NOT,t0),t2); + } + else if(ASTTrue == t2) { + output = CreateNode(OR,CreateNode(NOT,t0),t1); + } + else if(ASTFalse == t2) { + output = CreateNode(AND,t0,t1); + } + else if(CheckAlwaysTrueFormMap(t0)) { + output = t1; + } + else if(CheckAlwaysTrueFormMap(CreateNode(NOT,t0)) || + (NOT == t0.GetKind() && CheckAlwaysTrueFormMap(t0[0]))) { + output = t2; + } + else { + output = CreateNode(ITE,t0,t1,t2); + } + + //memoize + UpdateSimplifyMap(a,output,pushNeg); + return output; + } + + //one level deep flattening + ASTNode BeevMgr::FlattenOneLevel(const ASTNode& a) { + Kind k = a.GetKind(); + if(!(BVPLUS == k || + AND == k || OR == k + //|| BVAND == k + //|| BVOR == k + ) + ) { + return a; + } + + ASTNode output; + // if(CheckSimplifyMap(a,output,false)) { + // //check memo table + // //cerr << "output of SimplifyTerm Cache: " << output << endl; + // return output; + // } + + ASTVec c = a.GetChildren(); + ASTVec o; + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { + ASTNode aaa = *it; + if(k == aaa.GetKind()) { + ASTVec ac = aaa.GetChildren(); + o.insert(o.end(),ac.begin(),ac.end()); + } + else + o.push_back(aaa); + } + + if(is_Form_kind(k)) + output = CreateNode(k,o); + else + output = CreateTerm(k,a.GetValueWidth(),o); + + //UpdateSimplifyMap(a,output,false); + return output; + //memoize + } //end of flattenonelevel() + + ASTNode BeevMgr::SimplifyTerm_TopLevel(const ASTNode& b) { + SimplifyMap.clear(); + SimplifyNegMap.clear(); + ASTNode out = SimplifyTerm(b); + SimplifyNegMap.clear(); + SimplifyMap.clear(); + return out; + } + + //This function simplifies terms based on their kind + ASTNode BeevMgr::SimplifyTerm(const ASTNode& inputterm) { + //cout << "SimplifyTerm: input: " << a << endl; + if(!optimize) { + return inputterm; + } + + BVTypeCheck(inputterm); + ASTNode output; + if(wordlevel_solve && CheckSolverMap(inputterm,output)) { + //cout << "SimplifyTerm: output: " << output << endl; + return SimplifyTerm(output); + } + + if(CheckSimplifyMap(inputterm,output,false)) { + //cerr << "output of SimplifyTerm Cache: " << output << endl; + return output; + } + + Kind k = inputterm.GetKind(); + if(!is_Term_kind(k)) { + FatalError("SimplifyTerm: You have input a Non-term",ASTUndefined); + } + + unsigned int inputValueWidth = inputterm.GetValueWidth(); + switch(k) { + case BVCONST: + output = inputterm; + break; + case SYMBOL: + if(CheckSolverMap(inputterm,output)) { + return SimplifyTerm(output); + } + output = inputterm; + break; + case BVMULT: + case BVPLUS:{ + if(BVMULT == k && 2 != inputterm.Degree()) { + FatalError("SimplifyTerm: We assume that BVMULT is binary",inputterm); + } + + ASTVec c = FlattenOneLevel(inputterm).GetChildren(); + SortByExprNum(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 + SortByExprNum(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(); + SortByExprNum(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 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(); + SortByExprNum(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: + SortByExprNum(o); + output = CreateTerm(k,inputValueWidth,o); + if(constant) { + output = BVConstEvaluator(output); + } + break; + } + break; + } + case BVCONCAT:{ + ASTNode t = SimplifyTerm(inputterm[0]); + ASTNode u = SimplifyTerm(inputterm[1]); + Kind tkind = t.GetKind(); + Kind ukind = u.GetKind(); + + + if(BVCONST == tkind && BVCONST == ukind) { + output = BVConstEvaluator(CreateTerm(BVCONCAT,inputValueWidth,t,u)); + } + else if(BVEXTRACT == tkind && + BVEXTRACT == ukind && + t[0] == u[0]) { + //to handle the case x[m:n]@x[n-1:k] <==> x[m:k] + ASTNode t_hi = t[1]; + ASTNode t_low = t[2]; + ASTNode u_hi = u[1]; + ASTNode u_low = u[2]; + ASTNode c = BVConstEvaluator(CreateTerm(BVPLUS,32,u_hi,CreateOneConst(32))); + if(t_low == c) { + output = CreateTerm(BVEXTRACT,inputValueWidth,t[0],t_hi,u_low); + } + else { + output = CreateTerm(BVCONCAT,inputValueWidth,t,u); + } + } + else { + output = CreateTerm(BVCONCAT,inputValueWidth,t,u); + } + break; + } + case BVXOR: + case BVXNOR: + case BVNAND: + case BVNOR: + case BVLEFTSHIFT: + case BVRIGHTSHIFT: + case BVVARSHIFT: + case BVSRSHIFT: + case BVDIV: + case BVMOD: { + ASTVec c = inputterm.GetChildren(); + ASTVec o; + bool constant = true; + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { + ASTNode aaa = SimplifyTerm(*it); + if(BVCONST != aaa.GetKind()) { + constant = false; + } + o.push_back(aaa); + } + output = CreateTerm(k,inputValueWidth,o); + if(constant) + output = BVConstEvaluator(output); + break; + } + case READ: { + ASTNode out1; + //process only if not in the substitution map. simplifymap + //has been checked already + if(!CheckSubstitutionMap(inputterm,out1)) { + if(WRITE == inputterm[0].GetKind()) { + //get rid of all writes + ASTNode nowrites = RemoveWrites_TopLevel(inputterm); + out1 = nowrites; + } + else if (ITE == inputterm[0].GetKind()){ + ASTNode cond = SimplifyFormula(inputterm[0][0],false); + ASTNode arr1 = SimplifyTerm(inputterm[0][1]); + ASTNode arr2 = SimplifyTerm(inputterm[0][2]); + + ASTNode index = SimplifyTerm(inputterm[1]); + + ASTNode read1 = CreateTerm(READ,inputValueWidth,arr1,index); + ASTNode read2 = CreateTerm(READ,inputValueWidth,arr2,index); + out1 = CreateSimplifiedTermITE(cond,read1,read2); + } + else { + //arr is a SYMBOL for sure + ASTNode arr = inputterm[0]; + ASTNode index = SimplifyTerm(inputterm[1]); + out1 = CreateTerm(READ,inputValueWidth,arr,index); + } + } + //it is possible that after all the procesing the READ term + //reduces to READ(Symbol,const) and hence we should check the + //substitutionmap once again. + if(!CheckSubstitutionMap(out1,output)) + output = out1; + break; + } + case ITE: { + ASTNode t0 = SimplifyFormula(inputterm[0],false); + ASTNode t1 = SimplifyTerm(inputterm[1]); + ASTNode t2 = SimplifyTerm(inputterm[2]); + output = CreateSimplifiedTermITE(t0,t1,t2); + break; + } + case SBVMOD: + case SBVDIV: { + ASTVec c = inputterm.GetChildren(); + ASTVec o; + for(ASTVec::iterator it=c.begin(),itend=c.end();it!=itend;it++) { + ASTNode aaa = SimplifyTerm(*it); + o.push_back(aaa); + } + output = CreateTerm(k,inputValueWidth,o); + break; + } + case WRITE: + default: + FatalError("SimplifyTerm: Control should never reach here:", inputterm, k); + return inputterm; + break; + } + + //memoize + UpdateSimplifyMap(inputterm,output,false); + //cerr << "SimplifyTerm: output" << output << endl; + 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) { + //Don't do the check in optimized mode + if(optimize) + return; + + if(NodeSize(a,true) < 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; + } + + 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(); + SortByExprNum(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(); + SortByExprNum(cNodes); + vars_to_consts[cccc].push_back(max); + } + else if(BVCONST == aaa.GetKind()) { + constkids.push_back(aaa); + } + else if(BVUMINUS == aaa.GetKind()) { + //helps to convert BVUMINUS into a BVMULT. here the max + //constant represents -1. this transformation allows us to + //conclude that x + BVUMINUS(x) is 0. + vars_to_consts[aaa[0]].push_back(max); + } + else + vars_to_consts[aaa].push_back(one); + } //end of for loop + + //go over the map from variables to vector of values. combine the + //vector of values, multiply to the variable, and put the + //resultant monomial in the output BVPLUS. + for(ASTNodeToVecMap::iterator it=vars_to_consts.begin(),itend=vars_to_consts.end(); + it!=itend;it++){ + ASTVec ccc = it->second; + + ASTNode constant; + if(1 < ccc.size()) { + constant = CreateTerm(BVPLUS,ccc[0].GetValueWidth(),ccc); + constant = BVConstEvaluator(constant); + } + else + constant = ccc[0]; + + //constant * var + ASTNode monom; + if(zero == constant) + monom = zero; + else if (one == constant) + monom = it->first; + else + monom = + SimplifyTerm(CreateTerm(BVMULT,constant.GetValueWidth(),constant,it->first)); + if(zero != monom) { + outputvec.push_back(monom); + } + } //end of for loop + + if(constkids.size() > 1) { + ASTNode output = CreateTerm(BVPLUS,constkids[0].GetValueWidth(),constkids); + output = BVConstEvaluator(output); + if(output != zero) + outputvec.push_back(output); + } + else if (constkids.size() == 1) { + if(constkids[0] != zero) + outputvec.push_back(constkids[0]); + } + + if (outputvec.size() > 1) { + output = CreateTerm(BVPLUS,len,outputvec); + } + else if(outputvec.size() == 1) { + output = outputvec[0]; + } + else { + output = zero; + } + + //memoize + //UpdateSimplifyMap(a,output,false); + return output; + } //end of CombineLikeTerms() + + //accepts lhs and rhs, and returns lhs - rhs = 0. The function + //assumes that lhs and rhs have already been simplified. although + //this assumption is not needed for correctness, it is essential for + //performance. The function also assumes that lhs is a BVPLUS + ASTNode BeevMgr::LhsMinusRhs(const ASTNode& eq) { + //if input is not an equality, simply return it + if(EQ != eq.GetKind()) + return eq; + + ASTNode lhs = eq[0]; + ASTNode rhs = eq[1]; + Kind k_lhs = lhs.GetKind(); + Kind k_rhs = rhs.GetKind(); + //either the lhs has to be a BVPLUS or the rhs has to be a + //BVPLUS + if(!(BVPLUS == k_lhs || + BVPLUS == k_rhs || + (BVMULT == k_lhs && + BVMULT == k_rhs) + )) { + return eq; + } + + ASTNode output; + if(CheckSimplifyMap(eq,output,false)) { + //check memo table + //cerr << "output of SimplifyTerm Cache: " << output << endl; + return output; + } + + //if the lhs is not a BVPLUS, but the rhs is a BVPLUS, then swap + //the lhs and rhs + bool swap_flag = false; + if(BVPLUS != k_lhs && BVPLUS == k_rhs) { + ASTNode swap = lhs; + lhs = rhs; + rhs = swap; + swap_flag = true; + } + + unsigned int len = lhs.GetValueWidth(); + ASTNode zero = CreateZeroConst(len); + //right is -1*(rhs): Simplify(-1*rhs) + rhs = SimplifyTerm(CreateTerm(BVUMINUS,len,rhs)); + + ASTVec lvec = lhs.GetChildren(); + ASTVec rvec = rhs.GetChildren(); + ASTNode lhsplusrhs; + if(BVPLUS != lhs.GetKind() && BVPLUS != rhs.GetKind()) { + lhsplusrhs = CreateTerm(BVPLUS,len,lhs,rhs); + } + else if(BVPLUS == lhs.GetKind() && BVPLUS == rhs.GetKind()) { + //combine the childnodes of the left and the right + lvec.insert(lvec.end(),rvec.begin(),rvec.end()); + lhsplusrhs = CreateTerm(BVPLUS,len,lvec); + } + else if(BVPLUS == lhs.GetKind() && BVPLUS != rhs.GetKind()){ + lvec.push_back(rhs); + lhsplusrhs = CreateTerm(BVPLUS,len,lvec); + } + else { + //Control should never reach here + FatalError("LhsMinusRhs: Control should never reach here\n"); + } + + //combine like terms + output = CombineLikeTerms(lhsplusrhs); + output = SimplifyTerm(output); + // + //Now make output into: lhs-rhs = 0 + output = CreateSimplifiedEQ(output,zero); + //sort if BVPLUS + if(BVPLUS == output.GetKind()) { + ASTVec outv = output.GetChildren(); + SortByExprNum(outv); + output = CreateTerm(BVPLUS,len,outv); + } + + //memoize + //UpdateSimplifyMap(eq,output,false); + return output; + } //end of LhsMinusRHS() + + //THis function accepts a BVMULT(t1,t2) and distributes the mult + //over plus if either or both t1 and t2 are BVPLUSes. + // + // x*(y1 + y2 + ...+ yn) <==> x*y1 + x*y2 + ... + x*yn + // + // (y1 + y2 + ...+ yn)*x <==> x*y1 + x*y2 + ... + x*yn + // + // The function assumes that the BVPLUSes have been flattened + ASTNode BeevMgr::DistributeMultOverPlus(const ASTNode& a, bool startdistribution) { + if(!startdistribution) + return a; + Kind k = a.GetKind(); + if(BVMULT != k) + return a; + + ASTNode left = a[0]; + ASTNode right = a[1]; + Kind left_kind = left.GetKind(); + Kind right_kind = right.GetKind(); + + ASTNode output; + if(CheckSimplifyMap(a,output,false)) { + //check memo table + //cerr << "output of SimplifyTerm Cache: " << output << endl; + return output; + } + + //special case optimization: c1*(c2*t1) <==> (c1*c2)*t1 + if(BVCONST == left_kind && + BVMULT == right_kind && + BVCONST == right[0].GetKind()) { + ASTNode c = BVConstEvaluator(CreateTerm(BVMULT,a.GetValueWidth(),left,right[0])); + c = CreateTerm(BVMULT,a.GetValueWidth(),c,right[1]); + return c; + left = c[0]; + right = c[1]; + left_kind = left.GetKind(); + right_kind = right.GetKind(); + } + + //special case optimization: c1*(t1*c2) <==> (c1*c2)*t1 + if(BVCONST == left_kind && + BVMULT == right_kind && + BVCONST == right[1].GetKind()) { + ASTNode c = BVConstEvaluator(CreateTerm(BVMULT,a.GetValueWidth(),left,right[1])); + c = CreateTerm(BVMULT,a.GetValueWidth(),c,right[0]); + return c; + left = c[0]; + right = c[1]; + left_kind = left.GetKind(); + right_kind = right.GetKind(); + } + + //atleast one of left or right have to be BVPLUS + if(!(BVPLUS == left_kind || BVPLUS == right_kind)) { + return a; + } + + //if left is BVPLUS and right is not, then swap left and right. we + //can do this since BVMULT is communtative + ASTNode swap; + if(BVPLUS == left_kind && BVPLUS != right_kind) { + swap = left; + left = right; + right = swap; + } + left_kind = left.GetKind(); + right_kind = right.GetKind(); + + //by this point we are gauranteed that right is a BVPLUS, but left + //may not be + ASTVec rightnodes = right.GetChildren(); + ASTVec outputvec; + unsigned len = a.GetValueWidth(); + ASTNode zero = CreateZeroConst(len); + ASTNode one = CreateOneConst(len); + if(BVPLUS != left_kind) { + //if the multiplier is not a BVPLUS then we have a special case + // x*(y1 + y2 + ...+ yn) <==> x*y1 + x*y2 + ... + x*yn + if(zero == left) { + outputvec.push_back(zero); + } + else if(one == left) { + outputvec.push_back(left); + } + else { + for(ASTVec::iterator j=rightnodes.begin(),jend=rightnodes.end(); + j!=jend;j++) { + ASTNode out = SimplifyTerm(CreateTerm(BVMULT,len,left,*j)); + outputvec.push_back(out); + } + } + } + else { + ASTVec leftnodes = left.GetChildren(); + // (x1 + x2 + ... + xm)*(y1 + y2 + ...+ yn) <==> x1*y1 + x1*y2 + + // ... + x2*y1 + ... + xm*yn + for(ASTVec::iterator i=leftnodes.begin(),iend=leftnodes.end(); + i!=iend;i++) { + ASTNode multiplier = *i; + for(ASTVec::iterator j=rightnodes.begin(),jend=rightnodes.end(); + j!=jend;j++) { + ASTNode out = SimplifyTerm(CreateTerm(BVMULT,len,multiplier,*j)); + outputvec.push_back(out); + } + } + } + + //compute output here + if(outputvec.size() > 1) { + output = CombineLikeTerms(CreateTerm(BVPLUS,len,outputvec)); + output = SimplifyTerm(output); + } + else + output = SimplifyTerm(outputvec[0]); + + //memoize + //UpdateSimplifyMap(a,output,false); + return output; + } //end of distributemultoverplus() + + //converts the BVSX(len, a0) operator into ITE( check top bit, + //extend a0 by 1, extend a0 by 0) + ASTNode BeevMgr::ConvertBVSXToITE(const ASTNode& a) { + if(BVSX != a.GetKind()) + return a; + + ASTNode output; + if(CheckSimplifyMap(a,output,false)) { + //check memo table + //cerr << "output of ConvertBVSXToITE Cache: " << output << endl; + return output; + } + + ASTNode a0 = a[0]; + unsigned a_len = a.GetValueWidth(); + unsigned a0_len = a0.GetValueWidth(); + + if(a0_len > a_len){ + FatalError("Trying to sign_extend a larger BV into a smaller BV"); + return ASTUndefined; //to stop the compiler from producing bogus warnings + } + + //sign extend + unsigned extensionlen = a_len-a0_len; + if(0 == extensionlen) { + UpdateSimplifyMap(a,output,false); + return a; + } + + std::string ones; + for(unsigned c=0; c < extensionlen;c++) + ones += '1'; + std::string zeros; + for(unsigned c=0; c < extensionlen;c++) + zeros += '0'; + + //string of oness of length extensionlen + BEEV::ASTNode BVOnes = CreateBVConst(ones.c_str(),2); + //string of zeros of length extensionlen + BEEV::ASTNode BVZeros = CreateBVConst(zeros.c_str(),2); + + //string of ones BVCONCAT a0 + BEEV::ASTNode concatOnes = CreateTerm(BEEV::BVCONCAT,a_len,BVOnes,a0); + //string of zeros BVCONCAT a0 + BEEV::ASTNode concatZeros = CreateTerm(BEEV::BVCONCAT,a_len,BVZeros,a0); + + //extract top bit of a0 + BEEV::ASTNode hi = CreateBVConst(32,a0_len-1); + BEEV::ASTNode low = CreateBVConst(32,a0_len-1); + BEEV::ASTNode topBit = CreateTerm(BEEV::BVEXTRACT,1,a0,hi,low); + + //compare topBit of a0 with 0bin1 + BEEV::ASTNode condition = CreateSimplifiedEQ(CreateBVConst(1,1),topBit); + + //ITE(topbit = 0bin1, 0bin1111...a0, 0bin000...a0) + output = CreateSimplifiedTermITE(condition,concatOnes,concatZeros); + UpdateSimplifyMap(a,output,false); + return output; + } //end of ConvertBVSXToITE() + + + ASTNode BeevMgr::RemoveWrites_TopLevel(const ASTNode& term) { + if(READ != term.GetKind() && WRITE != term[0].GetKind()) { + FatalError("RemovesWrites: Input must be a READ over a WRITE",term); + } + + if(!Begin_RemoveWrites && + !SimplifyWrites_InPlace_Flag && + !start_abstracting) { + return term; + } + else if(!Begin_RemoveWrites && + SimplifyWrites_InPlace_Flag && + !start_abstracting) { + //return term; + return SimplifyWrites_InPlace(term); + } + else { + return RemoveWrites(term); + } + } //end of RemoveWrites_TopLevel() + + ASTNode BeevMgr::SimplifyWrites_InPlace(const ASTNode& term) { + ASTNodeMultiSet WriteIndicesSeenSoFar; + bool SeenNonConstWriteIndex = false; + + if(READ != term.GetKind() && + WRITE != term[0].GetKind()) { + FatalError("RemovesWrites: Input must be a READ over a WRITE",term); + } + + ASTNode output; + if(CheckSimplifyMap(term,output,false)) { + return output; + } + + ASTVec writeIndices, writeValues; + unsigned int width = term.GetValueWidth(); + ASTNode write = term[0]; + unsigned indexwidth = write.GetIndexWidth(); + ASTNode readIndex = SimplifyTerm(term[1]); + + do { + ASTNode writeIndex = SimplifyTerm(write[1]); + ASTNode writeVal = SimplifyTerm(write[2]); + + //compare the readIndex and the current writeIndex and see if they + //simplify to TRUE or FALSE or UNDETERMINABLE at this stage + ASTNode compare_readwrite_indices = + SimplifyFormula(CreateSimplifiedEQ(writeIndex,readIndex),false); + + //if readIndex and writeIndex are equal + if(ASTTrue == compare_readwrite_indices && !SeenNonConstWriteIndex) { + UpdateSimplifyMap(term,writeVal,false); + return writeVal; + } + + if(!(ASTTrue == compare_readwrite_indices || + ASTFalse == compare_readwrite_indices)) { + SeenNonConstWriteIndex = true; + } + + //if (readIndex=writeIndex <=> FALSE) + if(ASTFalse == compare_readwrite_indices + || + (WriteIndicesSeenSoFar.find(writeIndex) != WriteIndicesSeenSoFar.end()) + ) { + //drop the current level write + //do nothing + } + else { + writeIndices.push_back(writeIndex); + writeValues.push_back(writeVal); + } + + //record the write indices seen so far + //if(BVCONST == writeIndex.GetKind()) { + WriteIndicesSeenSoFar.insert(writeIndex); + //} + + //Setup the write for the new iteration, one level inner write + write = write[0]; + }while (SYMBOL != write.GetKind()); + + ASTVec::reverse_iterator it_index = writeIndices.rbegin(); + ASTVec::reverse_iterator itend_index = writeIndices.rend(); + ASTVec::reverse_iterator it_values = writeValues.rbegin(); + ASTVec::reverse_iterator itend_values = writeValues.rend(); + + //"write" must be a symbol at the control point before the + //begining of the "for loop" + + for(;it_index!=itend_index;it_index++,it_values++) { + write = CreateTerm(WRITE,width,write,*it_index,*it_values); + write.SetIndexWidth(indexwidth); + } + + output = CreateTerm(READ,width,write,readIndex); + UpdateSimplifyMap(term,output,false); + return output; + } //end of SimplifyWrites_In_Place() + + //accepts a read over a write and returns a term without the write + //READ(WRITE(A i val) j) <==> ITE(i=j,val,READ(A,j)). We use a memo + //table for this function called RemoveWritesMemoMap + ASTNode BeevMgr::RemoveWrites(const ASTNode& input) { + //unsigned int width = input.GetValueWidth(); + if(READ != input.GetKind() || WRITE != input[0].GetKind()) { + FatalError("RemovesWrites: Input must be a READ over a WRITE",input); + } + + ASTNodeMap::iterator it; + ASTNode output = input; + if(CheckSimplifyMap(input,output,false)) { + return output; + } + + if(!start_abstracting && Begin_RemoveWrites) { + output= ReadOverWrite_To_ITE(input); + } + + if(start_abstracting) { + ASTNode newVar; + if(!CheckSimplifyMap(input,newVar,false)) { + newVar = NewVar(input.GetValueWidth()); + ReadOverWrite_NewName_Map[input] = newVar; + NewName_ReadOverWrite_Map[newVar] = input; + + UpdateSimplifyMap(input,newVar,false); + ASTNodeStats("New Var Name which replace Read_Over_Write: ", newVar); + } + output = newVar; + } //end of start_abstracting if condition + + //memoize + UpdateSimplifyMap(input,output,false); + return output; + } //end of RemoveWrites() + + ASTNode BeevMgr::ReadOverWrite_To_ITE(const ASTNode& term) { + unsigned int width = term.GetValueWidth(); + ASTNode input = term; + if(READ != term.GetKind() || WRITE != term[0].GetKind()) { + FatalError("RemovesWrites: Input must be a READ over a WRITE",term); + } + + ASTNodeMap::iterator it; + ASTNode output; + // if(CheckSimplifyMap(term,output,false)) { + // return output; + // } + + ASTNode partialITE = term; + ASTNode writeA = ASTTrue; + ASTNode oldRead = term; + //iteratively expand read-over-write + do { + ASTNode write = input[0]; + ASTNode readIndex = SimplifyTerm(input[1]); + //DO NOT CALL SimplifyTerm() on write[0]. You will go into an + //infinite loop + writeA = write[0]; + ASTNode writeIndex = SimplifyTerm(write[1]); + ASTNode writeVal = SimplifyTerm(write[2]); + + ASTNode cond = SimplifyFormula(CreateSimplifiedEQ(writeIndex,readIndex),false); + ASTNode newRead = CreateTerm(READ,width,writeA,readIndex); + ASTNode newRead_memoized = newRead; + if(CheckSimplifyMap(newRead, newRead_memoized,false)) { + newRead = newRead_memoized; + } + + if(ASTTrue == cond && (term == partialITE)) { + //found the write-value in the first iteration itself. return + //it + output = writeVal; + UpdateSimplifyMap(term,output,false); + return output; + } + + if(READ == partialITE.GetKind() && WRITE == partialITE[0].GetKind()) { + //first iteration or (previous cond==ASTFALSE and partialITE is a "READ over WRITE") + partialITE = CreateSimplifiedTermITE(cond, writeVal, newRead); + } + else if (ITE == partialITE.GetKind()){ + //ITE(i1 = j, v1, R(A,j)) + ASTNode ElseITE = CreateSimplifiedTermITE(cond, writeVal, newRead); + //R(W(A,i1,v1),j) <==> ITE(i1 = j, v1, R(A,j)) + UpdateSimplifyMap(oldRead,ElseITE,false); + //ITE(i2 = j, v2, R(W(A,i1,v1),j)) <==> ITE(i2 = j, v2, ITE(i1 = j, v1, R(A,j))) + partialITE = SimplifyTerm(partialITE); + } + else { + FatalError("RemoveWrites: Control should not reach here\n"); + } + + if(ASTTrue == cond) { + //no more iterations required + output = partialITE; + UpdateSimplifyMap(term,output,false); + return output; + } + + input = newRead; + oldRead = newRead; + } while(READ == input.GetKind() && WRITE == input[0].GetKind()); + + output = partialITE; + + //memoize + //UpdateSimplifyMap(term,output,false); + return output; + } //ReadOverWrite_To_ITE() + + //compute the multiplicative inverse of the input + ASTNode BeevMgr::MultiplicativeInverse(const ASTNode& d) { + ASTNode c = d; + if(BVCONST != c.GetKind()) { + FatalError("Input must be a constant", c); + } + + if(!BVConstIsOdd(c)) { + FatalError("MultiplicativeInverse: Input must be odd: ",c); + } + + //cerr << "input to multinverse function is: " << d << endl; + ASTNode inverse; + if(CheckMultInverseMap(d,inverse)) { + //cerr << "found the inverse of: " << d << "and it is: " << inverse << endl; + return inverse; + } + + inverse = c; + unsigned inputwidth = c.GetValueWidth(); + +#ifdef NATIVE_C_ARITH + ASTNode one = CreateOneConst(inputwidth); + while(c != one) { + //c = c*c + c = BVConstEvaluator(CreateTerm(BVMULT,inputwidth,c,c)); + //inverse = invsere*c + inverse = BVConstEvaluator(CreateTerm(BVMULT,inputwidth,inverse,c)); + } +#else + //Compute the multiplicative inverse of c using the extended + //euclidian algorithm + // + //create a '0' which is 1 bit long + ASTNode onebit_zero = CreateZeroConst(1); + //zero pad t0, i.e. 0 @ t0 + c = BVConstEvaluator(CreateTerm(BVCONCAT,inputwidth+1,onebit_zero,c)); + + //construct 2^(inputwidth), i.e. a bitvector of length + //'inputwidth+1', which is max(inputwidth)+1 + // + //all 1's + ASTNode max = CreateMaxConst(inputwidth); + //zero pad max + max = BVConstEvaluator(CreateTerm(BVCONCAT,inputwidth+1,onebit_zero,max)); + //Create a '1' which has leading zeros of length 'inputwidth' + ASTNode inputwidthplusone_one = CreateOneConst(inputwidth+1); + //add 1 to max + max = CreateTerm(BVPLUS,inputwidth+1,max,inputwidthplusone_one); + max = BVConstEvaluator(max); + + ASTNode zero = CreateZeroConst(inputwidth+1); + ASTNode max_bvgt_0 = CreateNode(BVGT,max,zero); + ASTNode quotient, remainder; + ASTNode x, x1, x2; + + //x1 initialized to zero + x1 = zero; + //x2 initialized to one + x2 = CreateOneConst(inputwidth+1); + while (ASTTrue == BVConstEvaluator(max_bvgt_0)) { + //quotient = (c divided by max) + quotient = BVConstEvaluator(CreateTerm(BVDIV,inputwidth+1, c, max)); + + //remainder of (c divided by max) + remainder = BVConstEvaluator(CreateTerm(BVMOD,inputwidth+1, c, max)); + + //x = x2 - q*x1 + x = CreateTerm(BVSUB,inputwidth+1,x2,CreateTerm(BVMULT,inputwidth+1,quotient,x1)); + x = BVConstEvaluator(x); + + //fix the inputs to the extended euclidian algo + c = max; + max = remainder; + max_bvgt_0 = CreateNode(BVGT,max,zero); + + x2 = x1; + x1 = x; + } + + ASTNode hi = CreateBVConst(32,inputwidth-1); + ASTNode low = CreateZeroConst(32); + inverse = CreateTerm(BVEXTRACT,inputwidth,x2,hi,low); + inverse = BVConstEvaluator(inverse); +#endif + + UpdateMultInverseMap(d,inverse); + //cerr << "output of multinverse function is: " << inverse << endl; + return inverse; + } //end of MultiplicativeInverse() + + //returns true if the input is odd + bool BeevMgr::BVConstIsOdd(const ASTNode& c) { + if(BVCONST != c.GetKind()) { + FatalError("Input must be a constant", c); + } + + ASTNode zero = CreateZeroConst(1); + ASTNode hi = CreateZeroConst(32); + ASTNode low = hi; + ASTNode lowestbit = CreateTerm(BVEXTRACT,1,c,hi,low); + lowestbit = BVConstEvaluator(lowestbit); + + if(lowestbit == zero) { + return false; + } + else { + return true; + } + } //end of BVConstIsOdd() + + //The big substitution function + ASTNode BeevMgr::CreateSubstitutionMap(const ASTNode& a){ + if(!optimize) + return a; + + ASTNode output = a; + //if the variable has been solved for, then simply return it + if(CheckSolverMap(a,output)) + return output; + + //traverse a and populate the SubstitutionMap + Kind k = a.GetKind(); + if(SYMBOL == k && BOOLEAN_TYPE == a.GetType()) { + bool updated = UpdateSubstitutionMap(a,ASTTrue); + output = updated ? ASTTrue : a; + return output; + } + if(NOT == k + && SYMBOL == a[0].GetKind()) { + bool updated = UpdateSubstitutionMap(a[0],ASTFalse); + output = updated ? ASTTrue : a; + return output; + } + + if(IFF == k) { + ASTVec c = a.GetChildren(); + SortByExprNum(c); + if(SYMBOL != c[0].GetKind() || + VarSeenInTerm(c[0],SimplifyFormula_NoRemoveWrites(c[1],false))) { + return a; + } + bool updated = UpdateSubstitutionMap(c[0],c[1]); + 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(); + SortByExprNum(c); + FillUp_ArrReadIndex_Vec(c[0],c[1]); + + if(SYMBOL == c[0].GetKind() && + VarSeenInTerm(c[0],SimplifyTerm(c[1]))) { + return a; + } + + if(1 == TermOrder(c[0],c[1]) && + READ == c[0].GetKind() && + VarSeenInTerm(c[0][0],SimplifyTerm(c[1]))) { + return a; + } + bool updated = UpdateSubstitutionMap(c[0],c[1]); + output = updated ? ASTTrue : a; + return output; + } + + if(AND == k){ + ASTVec o; + ASTVec c = a.GetChildren(); + for(ASTVec::iterator it = c.begin(),itend=c.end();it!=itend;it++) { + UpdateAlwaysTrueFormMap(*it); + ASTNode aaa = CreateSubstitutionMap(*it); + + if(ASTTrue != aaa) { + if(ASTFalse == aaa) + return ASTFalse; + else + o.push_back(aaa); + } + } + if(o.size() == 0) + return ASTTrue; + + if(o.size() == 1) + return o[0]; + + return CreateNode(AND,o); + } + 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; + } +};//end of namespace |