void CNFMgr::convertFormulaToCNFNegOR(const ASTNode& varphi, ClauseList* defs) { //**************************************** // (neg) OR ~> UNION NOT //**************************************** ASTVec::const_iterator it = varphi.GetChildren().begin(); convertFormulaToCNF(*it, defs); ClauseList* psi = ClauseList::COPY(*(info[*it]->clausesneg)); reduceMemoryFootprintNeg(*it); for (it++; it != varphi.GetChildren().end(); it++) { convertFormulaToCNF(*it, defs); CNFInfo* x = info[*it]; if (sharesNeg(*x) != 1) { ClauseList::INPLACE_UNION(psi, *(x->clausesneg)); reduceMemoryFootprintNeg(*it); } else { // If this is the only use of "clausesneg", no reason to make a copy. psi->insert(x->clausesneg); // Copied from reduceMemoryFootprintNeg delete x->clausesneg; x->clausesneg = NULL; if (x->clausespos == NULL) { delete x; info.erase(*it); } } } info[varphi]->clausesneg = psi; } //End of convertFormulaToCNFNegOR()
void CNFMgr::convertFormulaToCNFPosAND(const ASTNode& varphi, ClauseList* defs) { //**************************************** // (pos) AND ~> UNION //**************************************** ASTVec::const_iterator it = varphi.GetChildren().begin(); convertFormulaToCNF(*it, defs); ClauseList* psi = ClauseList::COPY(*(info[*it]->clausespos)); for (it++; it != varphi.GetChildren().end(); it++) { convertFormulaToCNF(*it, defs); CNFInfo* x = info[*it]; if (sharesPos(*x) == 1) { psi->insert(x->clausespos); delete (x->clausespos); x->clausespos = NULL; if (x->clausesneg == NULL) { delete x; info.erase(*it); } } else { ClauseList::INPLACE_UNION(psi, *(x->clausespos)); reduceMemoryFootprintPos(*it); } } if (renameAllSiblings) { assert(((unsigned)psi->size()) == varphi.GetChildren().size()); } info[varphi]->clausespos = psi; } //End of convertFormulaToCNFPosAND()
int main() { AbstractSyntaxTree AST; ASTNode Root; Root.name = "Root"; Root.type = "Node"; Root.startLineCount = 1; Root.endLineCount = 0; AST.SetRoot(&Root); ASTNode N1; N1.name = "Node 1"; N1.type = "Node"; N1.startLineCount = 1; N1.endLineCount = 0; Root.GetChildren().push_back(&N1); ASTNode N2; N2.name = "Node 2"; N2.type = "Node"; N2.startLineCount = 1; N2.endLineCount = 0; N1.GetChildren().push_back(&N2); ASTNode N3; N3.name = "Node 3"; N3.type = "Node"; N3.startLineCount = 1; N3.endLineCount = 0; Root.GetChildren().push_back(&N3); AST.TreeWalk(AST.GetRoot()); }
void CNFMgr::convertFormulaToCNFPosPred(const ASTNode& varphi, ClauseList* defs) { ASTVec psis; ASTVec::const_iterator it = varphi.GetChildren().begin(); for (; it != varphi.GetChildren().end(); it++) { convertTermForCNF(*it, defs); psis.push_back(*(info[*it]->termforcnf)); } info[varphi]->clausespos = SINGLETON(bm->CreateNode(varphi.GetKind(), psis)); } //End of convertFormulaToCNFPosPred()
void CNFMgr::convertFormulaToCNFNegAND(const ASTNode& varphi, ClauseList* defs) { bool renamesibs = false; ClauseList* clauses; ClauseList* psi; ClauseList* oldpsi; //**************************************** // (neg) AND ~> PRODUCT NOT //**************************************** ASTVec::const_iterator it = varphi.GetChildren().begin(); convertFormulaToCNF(*it, defs); clauses = info[*it]->clausesneg; if (clauses->size() > 1) { renamesibs = true; } psi = ClauseList::COPY(*clauses); reduceMemoryFootprintNeg(*it); for (it++; it != varphi.GetChildren().end(); it++) { if (renamesibs) { setDoSibRenamingNeg(*(info[*it])); } convertFormulaToCNF(*it, defs); clauses = info[*it]->clausesneg; if (clauses->size() > 1) { renamesibs = true; } if (clauses->size() ==1) psi->INPLACE_PRODUCT(*clauses); else { oldpsi = psi; psi = ClauseList::PRODUCT(*psi, *clauses); DELETE(oldpsi); } reduceMemoryFootprintNeg(*it); } info[varphi]->clausesneg = psi; } //End of convertFormulaToCNFNegAND()
void LetizeNode(const ASTNode& n, ASTNodeSet& PLPrintNodeSet, bool smtlib1) { const Kind kind = n.GetKind(); if (kind == SYMBOL || kind == BVCONST || kind == FALSE || kind == TRUE) return; const ASTVec& c = n.GetChildren(); for (ASTVec::const_iterator it = c.begin(), itend = c.end(); it != itend; it++) { const ASTNode& ccc = *it; const Kind k = ccc.GetKind(); if (k == SYMBOL || k == BVCONST || k == FALSE || k == TRUE) continue; if (PLPrintNodeSet.find(ccc) == PLPrintNodeSet.end()) { // If branch: if *it is not in NodeSet then, // // 1. add it to NodeSet // // 2. Letize its childNodes PLPrintNodeSet.insert(ccc); LetizeNode(ccc, PLPrintNodeSet, smtlib1); } else { // 0. Else branch: Node has been seen before // // 1. Check if the node has a corresponding letvar in the // 1. NodeLetVarMap. // // 2. if no, then create a new var and add it to the // 2. NodeLetVarMap if ((!smtlib1 || ccc.GetType() == BITVECTOR_TYPE) && NodeLetVarMap.find(ccc) == NodeLetVarMap.end()) { // Create a new symbol. Get some name. if it conflicts with a // declared name, too bad. int sz = NodeLetVarMap.size(); std::ostringstream oss; oss << "?let_k_" << sz; ASTNode CurrentSymbol = n.GetSTPMgr()->CreateSymbol( oss.str().c_str(), n.GetIndexWidth(), n.GetValueWidth()); /* If for some reason the variable being created here is * already declared by the user then the printed output will * not be a legal input to the system. too bad. I refuse to * check for this. [Vijay is the author of this comment.] */ NodeLetVarMap[ccc] = CurrentSymbol; std::pair<ASTNode, ASTNode> node_letvar_pair(CurrentSymbol, ccc); NodeLetVarVec.push_back(node_letvar_pair); } } } } // end of LetizeNode()
// Method to find a particular node in tree. Returns its parent ASTNode* AbstractSyntaxTree::FindNode(ASTNode* FindIt) { if (this->Root == NULL) return NULL; // Maintaining a stack to traverse the Tree in DFS manner (non-recursive) std::stack<ASTNode*> DFSStack; // Maintaining a set of nodes which have been visited during traversal std::set<ASTNode*> Visited; DFSStack.push(this->Root); Visited.insert(this->Root); std::vector<ASTNode*> Children; while (!DFSStack.empty()) { ASTNode* Top = DFSStack.top(); DFSStack.pop(); if ((*FindIt).IfEqual(*Top)) return Top; Children = Top->GetChildren(); for (ASTNode* child : Children) { if (Visited.find(child) == Visited.end()) { DFSStack.push(child); Visited.insert(child); } } } return NULL; }
void outputBitVecSMTLIB2(const ASTNode n, ostream& os) { const Kind k = n.GetKind(); const ASTVec &c = n.GetChildren(); ASTNode op; if (BITVECTOR == k) { op = c[0]; } else if (BVCONST == k) { op = n; } else FatalError("nsadfsdaf"); // CONSTANTBV::BitVector_to_Dec returns a signed representation by default. // Prepend with zero to convert to unsigned. os << "(_ bv"; CBV unsign = CONSTANTBV::BitVector_Concat( n.GetSTPMgr()->CreateZeroConst(1).GetBVConst(), op.GetBVConst()); unsigned char * str = CONSTANTBV::BitVector_to_Dec(unsign); CONSTANTBV::BitVector_Destroy(unsign); os << str << " " << op.GetValueWidth() << ")"; CONSTANTBV::BitVector_Dispose(str); }
// Check that the transformations have occurred. void ArrayTransformer::assertTransformPostConditions(const ASTNode& term, ASTNodeSet& visited) { // I haven't measure whether this is the quickest way to do it? std::pair<ASTNodeSet::iterator, bool> p = visited.insert(term); if (!p.second) return; const Kind k = term.GetKind(); // Check the array reads / writes have been removed assert(READ != k); assert(WRITE != k); // There should be no nodes left of type array. assert(0 == term.GetIndexWidth()); const ASTVec& c = term.GetChildren(); ASTVec::const_iterator it = c.begin(); const ASTVec::const_iterator itend = c.end(); for (; it != itend; it++) { assertTransformPostConditions(*it, visited); } }
ASTNode STPMgr::CreateSimpNot(const ASTNode& form) { Kind k = form.GetKind(); switch (k) { case FALSE: { return ASTTrue; } case TRUE: { return ASTFalse; } case NOT: { return form[0]; } // NOT NOT cancellation case XOR: { // Push negation down in this case. // FIXME: Separate pre-pass to push negation down? // CreateSimp should be local, and this isn't. // It isn't memoized. Arg. ASTVec children = form.GetChildren(); children[0] = CreateSimpNot(children[0]); return CreateSimpXor(children); } default: { return CreateNode(NOT, form); //return CreateNode(XOR, ASTTrue, form); } } }
void CNFMgr::convertFormulaToCNFNegXOR(const ASTNode& varphi, ClauseList* defs) { //#ifdef FALSE #if defined CRYPTOMINISAT__2 CNFInfo * xx = info[varphi]; if(NULL != xx && sharesPos(*xx) > 0 && sharesNeg(*xx) > 0) { return; } ASTVec::const_iterator it = varphi.GetChildren().begin(); ClausePtr xor_clause = new vector<const ASTNode*>(); for (; it != varphi.GetChildren().end(); it++) { convertFormulaToCNF(*it, defs); // make pos and neg clause set //Creating a new variable name for each of the children of the //XOR node doRenamingPos(*it, defs); //doRenamingPos(*it, defs); doRenamingNeg(*it, defs); xor_clause->insert(xor_clause->end(), ((*(info[*it]->clausespos)).asList()->front())->begin(), ((*(info[*it]->clausespos)).asList()->front())->end()); } doRenamingPosXor(varphi); //ClauseList* psi = convertFormulaToCNFPosXORAux(varphi, 0, defs); //info[varphi]->clausespos = psi; ASTNode varXorNode = GetNodeFrom_SINGLETON(info[varphi]->clausespos); ASTNode NotVarXorNode = bm->CreateNode(NOT, varXorNode); xor_clause->push_back(ASTNodeToASTNodePtr(NotVarXorNode)); clausesxor->push_back(xor_clause); ASTVec::const_iterator it2 = varphi.GetChildren().begin(); for (; it2 != varphi.GetChildren().end(); it2++) { reduceMemoryFootprintPos(*it2); reduceMemoryFootprintNeg(*it2); } #else ASTVec::const_iterator it = varphi.GetChildren().begin(); for (; it != varphi.GetChildren().end(); it++) { convertFormulaToCNF(*it, defs); // make pos and neg clause sets } ClauseList* psi = convertFormulaToCNFNegXORAux(varphi, 0, defs); info[varphi]->clausesneg = psi; ASTVec::const_iterator it2 = varphi.GetChildren().begin(); for (; it2 != varphi.GetChildren().end(); it2++) { reduceMemoryFootprintPos(*it2); reduceMemoryFootprintNeg(*it2); } #endif } //End of convertFormulaToCNFNegXOR()
void CNFMgr::scanTerm(const ASTNode& varphi) { CNFInfo* x; //######################################## // step 1, get the info associated with this node //######################################## if (info.find(varphi) == info.end()) { x = new CNFInfo(); info[varphi] = x; } else { x = info[varphi]; } //######################################## // step 2, need two hits because of term ITEs. //######################################## if (sharesPos(*x) == 2) { return; } //######################################## // step 3, set appropriate data fields, always rename // term ITEs //######################################## incrementSharesPos(*x); setIsTerm(*x); //######################################## // step 4, recurse over children //######################################## if (varphi.isAtom()) { return; } else if (varphi.isITE()) { scanFormula(varphi[0], true, false); scanFormula(varphi[0], false, false); scanTerm(varphi[1]); scanTerm(varphi[2]); } else { for (unsigned int i = 0; i < varphi.GetChildren().size(); i++) { scanTerm(varphi[i]); } } }//End of scanterm()
void CNFMgr::convertTermForCNF(const ASTNode& varphi, ClauseList* defs) { CNFInfo* x = info[varphi]; //######################################## // step 1, done if we've already visited //######################################## if (x->termforcnf != NULL) { return; } //######################################## // step 2, ITE's always get renamed //######################################## if (varphi.isITE()) { x->termforcnf = doRenameITE(varphi, defs); reduceMemoryFootprintPos(varphi[0]); reduceMemoryFootprintNeg(varphi[0]); } else if (varphi.isAtom()) { x->termforcnf = ASTNodeToASTNodePtr(varphi); } else { ASTVec psis; ASTVec::const_iterator it = varphi.GetChildren().begin(); for (; it != varphi.GetChildren().end(); it++) { convertTermForCNF(*it, defs); psis.push_back(*(info[*it]->termforcnf)); } ASTNode psi = bm->CreateNode(varphi.GetKind(), psis); psi.SetValueWidth(varphi.GetValueWidth()); psi.SetIndexWidth(varphi.GetIndexWidth()); x->termforcnf = ASTNodeToASTNodePtr(psi); } } //End of convertTermForCNF()
void CNFMgr::convertFormulaToCNFNegNAND(const ASTNode& varphi, ClauseList* defs) { //**************************************** // (neg) NAND ~> UNION //**************************************** ASTVec::const_iterator it = varphi.GetChildren().begin(); convertFormulaToCNF(*it, defs); ClauseList* psi = ClauseList::COPY(*(info[*it]->clausespos)); reduceMemoryFootprintPos(*it); for (it++; it != varphi.GetChildren().end(); it++) { convertFormulaToCNF(*it, defs); ClauseList::INPLACE_UNION(psi, *(info[*it]->clausespos)); reduceMemoryFootprintPos(*it); } info[varphi]->clausespos = psi; } //End of convertFormulaToCNFNegNAND()
// If there is a lot of sharing in the graph, this will take a long // time. it doesn't mark subgraphs as already having been // typechecked. bool BVTypeCheckRecursive(const ASTNode& n) { const ASTVec& c = n.GetChildren(); BVTypeCheck(n); for (ASTVec::const_iterator it = c.begin(), itend = c.end(); it != itend; it++) BVTypeCheckRecursive(*it); return true; }
void CNFMgr::convertFormulaToCNFPosOR(const ASTNode& varphi, ClauseList* defs) { bool renamesibs = false; ClauseList* clauses; ClauseList* psi; ClauseList* oldpsi; //**************************************** // (pos) OR ~> PRODUCT //**************************************** ASTVec::const_iterator it = varphi.GetChildren().begin(); convertFormulaToCNF(*it, defs); clauses = info[*it]->clausespos; if (clauses->size() > 1) { renamesibs = true; } psi = ClauseList::COPY(*clauses); reduceMemoryFootprintPos(*it); for (it++; it != varphi.GetChildren().end(); it++) { if (renamesibs) { setDoSibRenamingPos(*(info[*it])); } convertFormulaToCNF(*it, defs); clauses = info[*it]->clausespos; if (clauses->size() > 1) { renamesibs = true; } oldpsi = psi; psi = ClauseList::PRODUCT(*psi, *clauses); reduceMemoryFootprintPos(*it); DELETE(oldpsi); } info[varphi]->clausespos = psi; } //End of convertFormulaToCNFPosOR()
bool ConstantBitPropagation::checkAtFixedPoint(const ASTNode& n, ASTNodeSet & visited) { if (status == CONFLICT) return true; // can't do anything. if (visited.find(n) != visited.end()) return true; visited.insert(n); // get the current for the children. vector<FixedBits> childrenFixedBits; childrenFixedBits.reserve(n.GetChildren().size()); // get a copy of the current fixing from the cache. for (unsigned i = 0; i < n.GetChildren().size(); i++) { childrenFixedBits.push_back(*getCurrentFixedBits(n[i])); } FixedBits current = *getCurrentFixedBits(n); FixedBits newBits = *getUpdatedFixedBits(n); assert(FixedBits::equals(newBits, current)); for (int i = 0; i < n.Degree(); i++) { if (!FixedBits::equals(*getUpdatedFixedBits(n[i]), childrenFixedBits[i])) { cerr << "Not fixed point"; assert(false); } checkAtFixedPoint(n[i], visited); } return true; }
void buildListOfSymbols(const ASTNode& n, ASTNodeSet& visited, ASTNodeSet& symbols) { if (visited.find(n) != visited.end()) return; // already visited. visited.insert(n); if (n.GetKind() == SYMBOL) { symbols.insert(n); } for (unsigned i = 0; i < n.GetChildren().size(); i++) buildListOfSymbols(n[i], visited, symbols); }
void Dot_Print1(ostream &os, const ASTNode n, hash_set<int> *alreadyOutput) { // check if this node has already been printed. If so return. if (alreadyOutput->find(n.GetNodeNum()) != alreadyOutput->end()) return; alreadyOutput->insert(n.GetNodeNum()); os << "n" << n.GetNodeNum() << "[label =\""; switch (n.GetKind()) { case SYMBOL: n.nodeprint(os); break; case BITVECTOR: case BVCONST: outputBitVec(n, os); break; default: os << _kind_names[n.GetKind()]; } os << "\"];" << endl; // print the edges to each child. ASTVec ch = n.GetChildren(); ASTVec::iterator itend = ch.end(); int i = 0; for (ASTVec::iterator it = ch.begin(); it < itend; it++) { os << "n" << n.GetNodeNum() << " -> " << "n" << it->GetNodeNum() << "[label=" << i++ << "];" << endl; } // print each of the children. for (ASTVec::iterator it = ch.begin(); it < itend; it++) { Dot_Print1(os, *it, alreadyOutput); } }
//UserGuided abstraction refinement SOLVER_RETURN_TYPE STP:: UserGuided_AbsRefine(SATSolver& NewSolver, const ASTNode& original_input) { ASTVec v = bm->GetAsserts_WithKey(0); if(v.empty()) { FatalError("UserGuided_AbsRefine: Something is seriously wrong."\ "The input set is empty"); } ASTNode sureAddInput = (v.size() == 1) ? v[0] : bm->CreateNode(AND, v); SOLVER_RETURN_TYPE res = SOLVER_UNDECIDED; res = TopLevelSTPAux(NewSolver, sureAddInput, original_input); if(SOLVER_UNDECIDED != res) { return res; } //Do refinement here if(AND != original_input.GetKind()) { FatalError("UserGuided_AbsRefine: The input must be an AND"); } ASTVec RefineFormulasVec; ASTVec RemainingFormulasVec; ASTNode asttrue = bm->CreateNode(TRUE); ASTNode astfalse = bm->CreateNode(FALSE); for(int count=0; count < bm->UserFlags.num_absrefine; count++) { RemainingFormulasVec.clear(); RemainingFormulasVec.push_back(asttrue); RefineFormulasVec.clear(); RefineFormulasVec.push_back(asttrue); ASTVec InputKids = original_input.GetChildren(); for(ASTVec::iterator it = InputKids.begin(), itend = InputKids.end(); it!=itend;it++) { Ctr_Example->ClearComputeFormulaMap(); if(astfalse == Ctr_Example->ComputeFormulaUsingModel(*it)) { RefineFormulasVec.push_back(*it); } else { RemainingFormulasVec.push_back(*it); } } ASTNode RefineFormulas = (RefineFormulasVec.size() == 1) ? RefineFormulasVec[0] : bm->CreateNode(AND, RefineFormulasVec); res = TopLevelSTPAux(NewSolver, RefineFormulas, original_input); if(SOLVER_UNDECIDED != res) { return res; } } ASTNode RemainingFormulas = (RemainingFormulasVec.size() == 1) ? RemainingFormulasVec[0] : bm->CreateNode(AND, RemainingFormulasVec); res = TopLevelSTPAux(NewSolver, RemainingFormulas, original_input); if(SOLVER_UNDECIDED != res) { return res; } FatalError("TopLevelSTPAux: reached the end without proper conclusion:" "either a divide by zero in the input or a bug in STP"); return SOLVER_ERROR; } //End of UserGuided_AbsRefine()
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; }
// Translates signed BVDIV,BVMOD and BVREM into unsigned variety ASTNode ArrayTransformer::TranslateSignedDivModRem(const ASTNode& in, NodeFactory* nf, STPMgr* bm) { assert(in.GetChildren().size() == 2); const ASTNode& dividend = in[0]; const ASTNode& divisor = in[1]; const unsigned len = in.GetValueWidth(); ASTNode hi1 = bm->CreateBVConst(32, len - 1); ASTNode one = bm->CreateOneConst(1); ASTNode zero = bm->CreateZeroConst(1); // create the condition for the dividend ASTNode cond_dividend = nf->CreateNode(EQ, one, nf->CreateTerm(BVEXTRACT, 1, dividend, hi1, hi1)); // create the condition for the divisor ASTNode cond_divisor = nf->CreateNode(EQ, one, nf->CreateTerm(BVEXTRACT, 1, divisor, hi1, hi1)); if (SBVREM == in.GetKind()) { // BVMOD is an expensive operation. So have the fewest bvmods // possible. Just one. // Take absolute value. ASTNode pos_dividend = nf->CreateTerm(ITE, len, cond_dividend, nf->CreateTerm(BVUMINUS, len, dividend), dividend); ASTNode pos_divisor = nf->CreateTerm(ITE, len, cond_divisor, nf->CreateTerm(BVUMINUS, len, divisor), divisor); // create the modulus term ASTNode modnode = nf->CreateTerm(BVMOD, len, pos_dividend, pos_divisor); // If the dividend is <0 take the unary minus. ASTNode n = nf->CreateTerm(ITE, len, cond_dividend, nf->CreateTerm(BVUMINUS, len, modnode), modnode); return n; } // This is the modulus of dividing rounding to -infinity. else if (SBVMOD == in.GetKind()) { /* (bvsmod s t) abbreviates (let ((?msb_s ((_ extract |m-1| |m-1|) s)) (?msb_t ((_ extract |m-1| |m-1|) t))) (let ((abs_s (ite (= ?msb_s #b0) s (bvneg s))) (abs_t (ite (= ?msb_t #b0) t (bvneg t)))) (let ((u (bvurem abs_s abs_t))) (ite (= u (_ bv0 m)) u (ite (and (= ?msb_s #b0) (= ?msb_t #b0)) u (ite (and (= ?msb_s #b1) (= ?msb_t #b0)) (bvadd (bvneg u) t) (ite (and (= ?msb_s #b0) (= ?msb_t #b1)) (bvadd u t) (bvneg u)))))))) */ // Take absolute value. ASTNode pos_dividend = nf->CreateTerm(ITE, len, cond_dividend, nf->CreateTerm(BVUMINUS, len, dividend), dividend); ASTNode pos_divisor = nf->CreateTerm(ITE, len, cond_divisor, nf->CreateTerm(BVUMINUS, len, divisor), divisor); ASTNode urem_node = nf->CreateTerm(BVMOD, len, pos_dividend, pos_divisor); // If the dividend is <0, then we negate the whole thing. ASTNode rev_node = nf->CreateTerm(ITE, len, cond_dividend, nf->CreateTerm(BVUMINUS, len, urem_node), urem_node); // if It's XOR <0, and it doesn't perfectly divide, then add t (not its // absolute value). ASTNode xor_node = nf->CreateNode(XOR, cond_dividend, cond_divisor); ASTNode neZ = nf->CreateNode( NOT, nf->CreateNode(EQ, rev_node, bm->CreateZeroConst(divisor.GetValueWidth()))); ASTNode cond = nf->CreateNode(AND, xor_node, neZ); ASTNode n = nf->CreateTerm(ITE, len, cond, nf->CreateTerm(BVPLUS, len, rev_node, divisor), rev_node); return n; } else if (SBVDIV == in.GetKind()) { // now handle the BVDIV case // if topBit(dividend) is 1 and topBit(divisor) is 0 // // then output is -BVDIV(-dividend,divisor) // // elseif topBit(dividend) is 0 and topBit(divisor) is 1 // // then output is -BVDIV(dividend,-divisor) // // elseif topBit(dividend) is 1 and topBit(divisor) is 1 // // then output is BVDIV(-dividend,-divisor) // // else simply output BVDIV(dividend,divisor) // Take absolute value. ASTNode pos_dividend = nf->CreateTerm(ITE, len, cond_dividend, nf->CreateTerm(BVUMINUS, len, dividend), dividend); ASTNode pos_divisor = nf->CreateTerm(ITE, len, cond_divisor, nf->CreateTerm(BVUMINUS, len, divisor), divisor); ASTNode divnode = nf->CreateTerm(BVDIV, len, pos_dividend, pos_divisor); // A little confusing. Only negate the result if they are XOR <0. ASTNode xor_node = nf->CreateNode(XOR, cond_dividend, cond_divisor); ASTNode n = nf->CreateTerm(ITE, len, xor_node, nf->CreateTerm(BVUMINUS, len, divnode), divnode); return n; } FatalError("TranslateSignedDivModRem:" "input must be signed DIV/MOD/REM", in); return bm->ASTUndefined; }
/* FUNCTION: Typechecker for terms and formulas * * TypeChecker: Assumes that the immediate Children of the input * ASTNode have been typechecked. This function is suitable in * scenarios like where you are building the ASTNode Tree, and you * typecheck as you go along. It is not suitable as a general * typechecker. * * If this returns, this ALWAYS returns true. If there is an error it * will call FatalError() and abort. */ bool BVTypeCheck(const ASTNode& n) { Kind k = n.GetKind(); //The children of bitvector terms are in turn bitvectors. const ASTVec& v = n.GetChildren(); if (is_Term_kind(k)) { switch (k) { case BVCONST: if (BITVECTOR_TYPE != n.GetType()) FatalError("BVTypeCheck: The term t does not typecheck, where t = \n", n); break; case SYMBOL: return true; case ITE: if (n.Degree() != 3) FatalError("BVTypeCheck: should have exactly 3 args\n", n); if (BOOLEAN_TYPE != n[0].GetType() || (n[1].GetType() != n[2].GetType())) FatalError("BVTypeCheck: The term t does not typecheck, where t = \n", n); if (n[1].GetValueWidth() != n[2].GetValueWidth()) FatalError("BVTypeCheck: length of THENbranch != length of ELSEbranch in the term t = \n", n); if (n[1].GetIndexWidth() != n[2].GetIndexWidth()) FatalError("BVTypeCheck: length of THENbranch != length of ELSEbranch in the term t = \n", n); break; case READ: if (n.GetChildren().size() !=2) FatalError("2 params to read."); if (n[0].GetIndexWidth() != n[1].GetValueWidth()) { cerr << "Length of indexwidth of array: " << n[0] << " is : " << n[0].GetIndexWidth() << endl; cerr << "Length of the actual index is: " << n[1] << " is : " << n[1].GetValueWidth() << endl; FatalError("BVTypeCheck: length of indexwidth of array != length of actual index in the term t = \n", n); } if (ARRAY_TYPE != n[0].GetType()) FatalError("First parameter to read should be an array", n[0]); if (BITVECTOR_TYPE != n[1].GetType()) FatalError("Second parameter to read should be a bitvector", n[1]); break; case WRITE: if (n.GetChildren().size() !=3) FatalError("3 params to write."); if (n[0].GetIndexWidth() != n[1].GetValueWidth()) FatalError("BVTypeCheck: length of indexwidth of array != length of actual index in the term t = \n", n); if (n[0].GetValueWidth() != n[2].GetValueWidth()) FatalError("BVTypeCheck: valuewidth of array != length of actual value in the term t = \n", n); if (ARRAY_TYPE != n[0].GetType()) FatalError("First parameter to read should be an array", n[0]); if (BITVECTOR_TYPE != n[1].GetType()) FatalError("Second parameter to read should be a bitvector", n[1]); if (BITVECTOR_TYPE != n[2].GetType()) FatalError("Third parameter to read should be a bitvector", n[2]); break; case BVDIV: case BVMOD: case BVSUB: case SBVDIV: case SBVREM: case SBVMOD: case BVLEFTSHIFT: case BVRIGHTSHIFT: case BVSRSHIFT: case BVVARSHIFT: if (n.Degree() != 2) FatalError("BVTypeCheck: should have exactly 2 args\n", n); // run on. case BVOR: case BVAND: case BVXOR: case BVNOR: case BVNAND: case BVXNOR: case BVPLUS: case BVMULT: { if (!(v.size() >= 2)) FatalError("BVTypeCheck:bitwise Booleans and BV arith operators must have at least two arguments\n", n); unsigned int width = n.GetValueWidth(); for (ASTVec::const_iterator it = v.begin(), itend = v.end(); it != itend; it++) { if (width != it->GetValueWidth()) { cerr << "BVTypeCheck:Operands of bitwise-Booleans and BV arith operators must be of equal length\n"; cerr << n << endl; cerr << "width of term:" << width << endl; cerr << "width of offending operand:" << it->GetValueWidth() << endl; FatalError("BVTypeCheck:Offending operand:\n", *it); } if (BITVECTOR_TYPE != it->GetType()) FatalError("BVTypeCheck: ChildNodes of bitvector-terms must be bitvectors\n", n); } break; } case BVSX: case BVZX: //in BVSX(n[0],len), the length of the BVSX term must be //greater than the length of n[0] if (n[0].GetValueWidth() > n.GetValueWidth()) { FatalError( "BVTypeCheck: BV[SZ]X(t,bv[sz]x_len) : length of 't' must be <= bv[sz]x_len\n", n); } if ((v.size() != 2)) FatalError( "BVTypeCheck:BV[SZ]X must have two arguments. The second is the new width\n", n); break; case BVCONCAT: checkChildrenAreBV(v, n); if (n.Degree() != 2) FatalError("BVTypeCheck: should have exactly 2 args\n", n); if (n.GetValueWidth() != n[0].GetValueWidth() + n[1].GetValueWidth()) FatalError("BVTypeCheck:BVCONCAT: lengths do not add up\n", n); break; case BVUMINUS: case BVNEG: checkChildrenAreBV(v, n); if (n.Degree() != 1) FatalError("BVTypeCheck: should have exactly 1 args\n", n); break; case BVEXTRACT: checkChildrenAreBV(v, n); if (n.Degree() != 3) FatalError("BVTypeCheck: should have exactly 3 args\n", n); if (!(BVCONST == n[1].GetKind() && BVCONST == n[2].GetKind())) FatalError("BVTypeCheck: indices should be BVCONST\n", n); if (n.GetValueWidth() != n[1].GetUnsignedConst() - n[2].GetUnsignedConst() + 1) FatalError("BVTypeCheck: length mismatch\n", n); if (n[1].GetUnsignedConst() >= n[0].GetValueWidth()) FatalError( "BVTypeCheck: Top index of select is greater or equal to the bitwidth.\n", n); break; default: cerr << _kind_names[k]; FatalError("No type checking for type"); break; } } else { if (!(is_Form_kind(k) && BOOLEAN_TYPE == n.GetType())) FatalError("BVTypeCheck: not a formula:", n); switch (k) { case TRUE: case FALSE: case SYMBOL: return true; case BOOLEXTRACT: checkChildrenAreBV(v, n); if (n.Degree() != 2) FatalError("BVTypeCheck: should have exactly 2 args\n", n); if (!(BVCONST == n[1].GetKind())) FatalError("BVTypeCheck: index should be BVCONST\n", n); if (n[1].GetUnsignedConst() >= n[0].GetValueWidth()) FatalError("BVTypeCheck: index is greater or equal to the bitwidth.\n", n); break; case PARAMBOOL: if(2 != n.Degree()) FatalError("BVTypeCheck: PARAMBOOL formula can have exactly two childNodes", n); break; case EQ: if (n.Degree() != 2) FatalError("BVTypeCheck: should have exactly 2 args\n", n); if (!(n[0].GetValueWidth() == n[1].GetValueWidth() && n[0].GetIndexWidth() == n[1].GetIndexWidth())) { cerr << "valuewidth of lhs of EQ: " << n[0].GetValueWidth() << endl; cerr << "valuewidth of rhs of EQ: " << n[1].GetValueWidth() << endl; cerr << "indexwidth of lhs of EQ: " << n[0].GetIndexWidth() << endl; cerr << "indexwidth of rhs of EQ: " << n[1].GetIndexWidth() << endl; FatalError("BVTypeCheck: terms in atomic formulas must be of equal length", n); } break; case BVLT: case BVLE: case BVGT: case BVGE: case BVSLT: case BVSLE: case BVSGT: case BVSGE: if (n.Degree() != 2) FatalError("BVTypeCheck: should have exactly 2 args\n", n); if (BITVECTOR_TYPE != n[0].GetType() && BITVECTOR_TYPE != n[1].GetType()) FatalError("BVTypeCheck: terms in atomic formulas must be bitvectors", n); if (n[0].GetValueWidth() != n[1].GetValueWidth()) FatalError("BVTypeCheck: terms in atomic formulas must be of equal length", n); if (n[0].GetIndexWidth() != n[1].GetIndexWidth()) FatalError("BVTypeCheck: terms in atomic formulas must be of equal length", n); break; case NOT: if (1 != n.Degree()) FatalError("BVTypeCheck: NOT formula can have exactly one childNode", n); break; case AND: case OR: case XOR: case NAND: case NOR: if (2 > n.Degree()) FatalError("BVTypeCheck: AND/OR/XOR/NAND/NOR: must have atleast 2 ChildNodes", n); break; case IFF: case IMPLIES: if (2 != n.Degree()) FatalError("BVTypeCheck:IFF/IMPLIES must have exactly 2 ChildNodes", n); break; case ITE: if (3 != n.Degree()) FatalError("BVTypeCheck:ITE must have exactly 3 ChildNodes", n); break; default: FatalError("BVTypeCheck: Unrecognized kind: "); break; } } return true; } //End of TypeCheck function
bool BVTypeCheck_nonterm_kind(const ASTNode& n, const Kind& k) { // The children of bitvector terms are in turn bitvectors. const ASTVec& v = n.GetChildren(); if (!(is_Form_kind(k) && BOOLEAN_TYPE == n.GetType())) FatalError("BVTypeCheck: not a formula:", n); switch (k) { case TRUE: case FALSE: case SYMBOL: return true; case BOOLEXTRACT: checkChildrenAreBV(v, n); if (n.Degree() != 2) FatalError("BVTypeCheck: should have exactly 2 args\n", n); if (!(BVCONST == n[1].GetKind())) FatalError("BVTypeCheck: index should be BVCONST\n", n); if (n[1].GetUnsignedConst() >= n[0].GetValueWidth()) { FatalError( "BVTypeCheck: index is greater or equal to the bitwidth.\n", n); } break; case PARAMBOOL: if (2 != n.Degree()) { FatalError( "BVTypeCheck: PARAMBOOL formula can have exactly two childNodes", n); } break; case EQ: if (n.Degree() != 2) FatalError("BVTypeCheck: should have exactly 2 args\n", n); if (!(n[0].GetValueWidth() == n[1].GetValueWidth() && n[0].GetIndexWidth() == n[1].GetIndexWidth())) { cerr << "valuewidth of lhs of EQ: " << n[0].GetValueWidth() << endl; cerr << "valuewidth of rhs of EQ: " << n[1].GetValueWidth() << endl; cerr << "indexwidth of lhs of EQ: " << n[0].GetIndexWidth() << endl; cerr << "indexwidth of rhs of EQ: " << n[1].GetIndexWidth() << endl; FatalError( "BVTypeCheck: terms in atomic formulas must be of equal length", n); } break; case BVLT: case BVLE: case BVGT: case BVGE: case BVSLT: case BVSLE: case BVSGT: case BVSGE: if (n.Degree() != 2) FatalError("BVTypeCheck: should have exactly 2 args\n", n); if (BITVECTOR_TYPE != n[0].GetType() && BITVECTOR_TYPE != n[1].GetType()) { FatalError("BVTypeCheck: terms in atomic formulas must be bitvectors" ,n); } if (n[0].GetValueWidth() != n[1].GetValueWidth()) FatalError( "BVTypeCheck: terms in atomic formulas must be of equal length", n); if (n[0].GetIndexWidth() != n[1].GetIndexWidth()) { FatalError( "BVTypeCheck: terms in atomic formulas must be of equal length", n); } break; case NOT: if (1 != n.Degree()) { FatalError("BVTypeCheck: NOT formula can have exactly one childNode", n); } break; case AND: case OR: case XOR: case NAND: case NOR: if (2 > n.Degree()) { FatalError("BVTypeCheck: AND/OR/XOR/NAND/NOR: must have atleast 2 " "ChildNodes", n); } break; case IFF: case IMPLIES: if (2 != n.Degree()) { FatalError("BVTypeCheck:IFF/IMPLIES must have exactly 2 ChildNodes", n); } break; case ITE: if (3 != n.Degree()) FatalError("BVTypeCheck:ITE must have exactly 3 ChildNodes", n); break; default: FatalError("BVTypeCheck: Unrecognized kind: "); break; } return true; }
ASTNode ArrayTransformer::TransformTerm(const ASTNode& term) { assert(TransformMap != NULL); const Kind k = term.GetKind(); if (!is_Term_kind(k)) FatalError("TransformTerm: Illegal kind: You have input a nonterm:", term, k); ASTNodeMap::const_iterator iter; if ((iter = TransformMap->find(term)) != TransformMap->end()) return iter->second; ASTNode result; switch (k) { case SYMBOL: case BVCONST: { result = term; break; } case WRITE: FatalError("TransformTerm: this kind is not supported", term); break; case READ: result = TransformArrayRead(term); break; case ITE: { ASTNode cond = term[0]; ASTNode thn = term[1]; ASTNode els = term[2]; cond = TransformFormula(cond); if (ASTTrue == cond) result = TransformTerm(thn); else if (ASTFalse == cond) result = TransformTerm(els); else { thn = TransformTerm(thn); els = TransformTerm(els); if (bm->UserFlags.optimize_flag) result = simp->CreateSimplifiedTermITE(cond, thn, els); else result = nf->CreateTerm(ITE, thn.GetValueWidth(), cond, thn, els); } assert(result.GetIndexWidth() == term.GetIndexWidth()); break; } default: { const ASTVec& c = term.GetChildren(); ASTVec::const_iterator it = c.begin(); ASTVec::const_iterator itend = c.end(); const unsigned width = term.GetValueWidth(); const unsigned indexwidth = term.GetIndexWidth(); ASTVec o; o.reserve(c.size()); for (; it != itend; it++) { o.push_back(TransformTerm(*it)); } if (c != o) { result = nf->CreateArrayTerm(k, indexwidth, width, o); } else result = term; } break; } if (term.Degree() > 0) (*TransformMap)[term] = result; if (term.GetValueWidth() != result.GetValueWidth()) FatalError("TransformTerm: " "result and input terms are of different length", result); if (term.GetIndexWidth() != result.GetIndexWidth()) { std::cerr << "TransformTerm: input term is : " << term << std::endl; FatalError("TransformTerm: " "result & input terms have different index length", result); } return result; }
bool BVTypeCheck_term_kind(const ASTNode& n, const Kind& k) { // The children of bitvector terms are in turn bitvectors. const ASTVec& v = n.GetChildren(); switch (k) { case BVCONST: if (BITVECTOR_TYPE != n.GetType()) FatalError("BVTypeCheck: The term t does not typecheck, where t = \n", n); break; case SYMBOL: return true; case ITE: if (n.Degree() != 3) FatalError("BVTypeCheck: should have exactly 3 args\n", n); if (BOOLEAN_TYPE != n[0].GetType() || (n[1].GetType() != n[2].GetType())) FatalError("BVTypeCheck: The term t does not typecheck, where t = \n", n); if (n[1].GetValueWidth() != n[2].GetValueWidth()) FatalError("BVTypeCheck: length of THENbranch != length of " "ELSEbranch in the term t = \n", n); if (n[1].GetIndexWidth() != n[2].GetIndexWidth()) FatalError("BVTypeCheck: length of THENbranch != length of " "ELSEbranch in the term t = \n", n); break; case READ: if (n.GetChildren().size() != 2) FatalError("2 params to read."); if (n[0].GetIndexWidth() != n[1].GetValueWidth()) { cerr << "Length of indexwidth of array: " << n[0] << " is : " << n[0].GetIndexWidth() << endl; cerr << "Length of the actual index is: " << n[1] << " is : " << n[1].GetValueWidth() << endl; FatalError("BVTypeCheck: length of indexwidth of array != length of " "actual index in the term t = \n", n); } if (ARRAY_TYPE != n[0].GetType()) FatalError("First parameter to read should be an array", n[0]); if (BITVECTOR_TYPE != n[1].GetType()) FatalError("Second parameter to read should be a bitvector", n[1]); break; case WRITE: if (n.GetChildren().size() != 3) FatalError("3 params to write."); if (n[0].GetIndexWidth() != n[1].GetValueWidth()) FatalError("BVTypeCheck: length of indexwidth of array != length of " "actual index in the term t = \n", n); if (n[0].GetValueWidth() != n[2].GetValueWidth()) FatalError("BVTypeCheck: valuewidth of array != length of actual " "value in the term t = \n", n); if (ARRAY_TYPE != n[0].GetType()) FatalError("First parameter to read should be an array", n[0]); if (BITVECTOR_TYPE != n[1].GetType()) FatalError("Second parameter to read should be a bitvector", n[1]); if (BITVECTOR_TYPE != n[2].GetType()) FatalError("Third parameter to read should be a bitvector", n[2]); break; case BVDIV: case BVMOD: case BVSUB: case SBVDIV: case SBVREM: case SBVMOD: case BVLEFTSHIFT: case BVRIGHTSHIFT: case BVSRSHIFT: case BVVARSHIFT: if (n.Degree() != 2) FatalError("BVTypeCheck: should have exactly 2 args\n", n); // run on. case BVOR: case BVAND: case BVXOR: case BVNOR: case BVNAND: case BVXNOR: case BVPLUS: case BVMULT: { if (!(v.size() >= 2)) FatalError("BVTypeCheck:bitwise Booleans and BV arith operators must " "have at least two arguments\n",n); unsigned int width = n.GetValueWidth(); for (ASTVec::const_iterator it = v.begin(), itend = v.end(); it != itend; it++) { if (width != it->GetValueWidth()) { cerr << "BVTypeCheck:Operands of bitwise-Booleans and BV arith " "operators must be of equal length\n"; cerr << n << endl; cerr << "width of term:" << width << endl; cerr << "width of offending operand:" << it->GetValueWidth() << endl; FatalError("BVTypeCheck:Offending operand:\n", *it); } if (BITVECTOR_TYPE != it->GetType()) FatalError("BVTypeCheck: ChildNodes of bitvector-terms must be " "bitvectors\n", n); } break; } case BVSX: case BVZX: // in BVSX(n[0],len), the length of the BVSX term must be // greater than the length of n[0] if (n[0].GetValueWidth() > n.GetValueWidth()) { FatalError("BVTypeCheck: BV[SZ]X(t,bv[sz]x_len) : length of 't' must " "be <= bv[sz]x_len\n", n); } if ((v.size() != 2)) FatalError("BVTypeCheck:BV[SZ]X must have two arguments. The second " "is the new width\n", n); break; case BVCONCAT: checkChildrenAreBV(v, n); if (n.Degree() != 2) FatalError("BVTypeCheck: should have exactly 2 args\n", n); if (n.GetValueWidth() != n[0].GetValueWidth() + n[1].GetValueWidth()) FatalError("BVTypeCheck:BVCONCAT: lengths do not add up\n", n); break; case BVUMINUS: case BVNEG: checkChildrenAreBV(v, n); if (n.Degree() != 1) FatalError("BVTypeCheck: should have exactly 1 args\n", n); if (n.GetValueWidth() != n[0].GetValueWidth()) FatalError("BVTypeCheck: should have same value width\n", n); break; case BVEXTRACT: checkChildrenAreBV(v, n); if (n.Degree() != 3) FatalError("BVTypeCheck: should have exactly 3 args\n", n); if (!(BVCONST == n[1].GetKind() && BVCONST == n[2].GetKind())) FatalError("BVTypeCheck: indices should be BVCONST\n", n); if (n.GetValueWidth() != n[1].GetUnsignedConst() - n[2].GetUnsignedConst() + 1) FatalError("BVTypeCheck: length mismatch\n", n); if (n[1].GetUnsignedConst() >= n[0].GetValueWidth()) FatalError("BVTypeCheck: Top index of select is greater or equal to " "the bitwidth.\n", n); break; default: cerr << _kind_names[k]; FatalError("No type checking for type"); break; } return true; }
// helper function for printing C code (copied from PL_Print1()) void C_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { unsigned int upper, lower, num_bytes; Kind LHSkind, RHSkind; // os << spaces(indentation); // os << endl << spaces(indentation); if (!n.IsDefined()) { os << "<undefined>"; return; } // if this node is present in the letvar Map, then print the letvar STPMgr* bm = n.GetSTPMgr(); // this is to print letvars for shared subterms inside the printing // of "(LET v0 = term1, v1=term1@term2,... if ((bm->NodeLetVarMap1.find(n) != bm->NodeLetVarMap1.end()) && !letize) { C_Print1(os, (bm->NodeLetVarMap1[n]), indentation, letize); return; } // this is to print letvars for shared subterms inside the actual // term to be printed if ((bm->NodeLetVarMap.find(n) != bm->NodeLetVarMap.end()) && letize) { C_Print1(os, (bm->NodeLetVarMap[n]), indentation, letize); return; } // otherwise print it normally Kind kind = n.GetKind(); const ASTVec& c = n.GetChildren(); switch (kind) { case BOOLEXTRACT: FatalError("C_Print1: printing not implemented for this kind: ", n); C_Print1(os, c[0], indentation, letize); os << "{"; C_Print1(os, c[1], indentation, letize); os << "}"; break; case BITVECTOR: FatalError("C_Print1: printing not implemented for this kind: ", n); os << "BITVECTOR("; unsigned char* str; str = CONSTANTBV::BitVector_to_Hex(c[0].GetBVConst()); os << str << ")"; CONSTANTBV::BitVector_Dispose(str); break; case BOOLEAN: FatalError("C_Print1: printing not implemented for this kind: ", n); os << "BOOLEAN"; break; case FALSE: os << "0"; break; case TRUE: os << "1"; break; case BVCONST: case SYMBOL: // print in C friendly format: n.nodeprint(os, true); break; case READ: C_Print1(os, c[0], indentation, letize); os << "["; C_Print1(os, c[1], indentation, letize); os << "]"; break; case WRITE: os << "("; C_Print1(os, c[0], indentation, letize); os << " WITH ["; C_Print1(os, c[1], indentation, letize); os << "] := "; C_Print1(os, c[2], indentation, letize); os << ")"; os << endl; break; case BVUMINUS: os << kind << "( "; C_Print1(os, c[0], indentation, letize); os << ")"; break; case NOT: os << "!("; C_Print1(os, c[0], indentation, letize); os << ") " << endl; break; case BVNEG: os << " ~("; C_Print1(os, c[0], indentation, letize); os << ")"; break; case BVCONCAT: // stopgap for un-implemented features FatalError("C_Print1: printing not implemented for this kind: ", n); os << "("; C_Print1(os, c[0], indentation, letize); os << " @ "; C_Print1(os, c[1], indentation, letize); os << ")" << endl; break; case BVOR: os << "("; C_Print1(os, c[0], indentation, letize); os << " | "; C_Print1(os, c[1], indentation, letize); os << ")"; break; case BVAND: os << "("; C_Print1(os, c[0], indentation, letize); os << " & "; C_Print1(os, c[1], indentation, letize); os << ")"; break; case BVEXTRACT: // we only accept indices that are byte-aligned // (e.g., [15:8], [23:16]) // and round down to byte indices rather than bit indices upper = c[1].GetUnsignedConst(); lower = c[2].GetUnsignedConst(); assert(upper > lower); assert(lower % 8 == 0); assert((upper + 1) % 8 == 0); num_bytes = (upper - lower + 1) / 8; assert(num_bytes > 0); // for multi-byte extraction, use the ADDRESS if (num_bytes > 1) { os << "&"; C_Print1(os, c[0], indentation, letize); os << "[" << lower / 8 << "]"; } // for single-byte extraction, use the VALUE else { C_Print1(os, c[0], indentation, letize); os << "[" << lower / 8 << "]"; } break; case BVLEFTSHIFT: // stopgap for un-implemented features FatalError("C_Print1: printing not implemented for this kind: ", n); os << "("; C_Print1(os, c[0], indentation, letize); os << " << "; os << c[1].GetUnsignedConst(); os << ")"; break; case BVRIGHTSHIFT: // stopgap for un-implemented features FatalError("C_Print1: printing not implemented for this kind: ", n); os << "("; C_Print1(os, c[0], indentation, letize); os << " >> "; os << c[1].GetUnsignedConst(); os << ")"; break; case BVMULT: case BVSUB: case BVPLUS: case SBVDIV: case SBVREM: case BVDIV: case BVMOD: os << kind << "("; os << n.GetValueWidth(); for (ASTVec::const_iterator it = c.begin(), itend = c.end(); it != itend; it++) { os << ", " << endl; C_Print1(os, *it, indentation, letize); } os << ")" << endl; break; case ITE: os << "if ("; C_Print1(os, c[0], indentation, letize); os << ")" << endl; os << "{"; C_Print1(os, c[1], indentation, letize); os << endl << "} else {"; C_Print1(os, c[2], indentation, letize); os << endl << "}"; break; case BVLT: // convert to UNSIGNED before doing comparison! os << "((unsigned char)"; C_Print1(os, c[0], indentation, letize); os << " < "; os << "(unsigned char)"; C_Print1(os, c[1], indentation, letize); os << ")"; break; case BVLE: // convert to UNSIGNED before doing comparison! os << "((unsigned char)"; C_Print1(os, c[0], indentation, letize); os << " <= "; os << "(unsigned char)"; C_Print1(os, c[1], indentation, letize); os << ")"; break; case BVGT: // convert to UNSIGNED before doing comparison! os << "((unsigned char)"; C_Print1(os, c[0], indentation, letize); os << " > "; os << "(unsigned char)"; C_Print1(os, c[1], indentation, letize); os << ")"; break; case BVGE: // convert to UNSIGNED before doing comparison! os << "((unsigned char)"; C_Print1(os, c[0], indentation, letize); os << " >= "; os << "(unsigned char)"; C_Print1(os, c[1], indentation, letize); os << ")"; break; case BVXOR: case BVNAND: case BVNOR: case BVXNOR: // stopgap for un-implemented features FatalError("C_Print1: printing not implemented for this kind: ", n); break; case BVSLT: // convert to SIGNED before doing comparison! os << "((signed char)"; C_Print1(os, c[0], indentation, letize); os << " < "; os << "(signed char)"; C_Print1(os, c[1], indentation, letize); os << ")"; break; case BVSLE: // convert to SIGNED before doing comparison! os << "((signed char)"; C_Print1(os, c[0], indentation, letize); os << " <= "; os << "(signed char)"; C_Print1(os, c[1], indentation, letize); os << ")"; break; case BVSGT: // convert to SIGNED before doing comparison! os << "((signed char)"; C_Print1(os, c[0], indentation, letize); os << " > "; os << "(signed char)"; C_Print1(os, c[1], indentation, letize); os << ")"; break; case BVSGE: // convert to SIGNED before doing comparison! os << "((signed char)"; C_Print1(os, c[0], indentation, letize); os << " >= "; os << "(signed char)"; C_Print1(os, c[1], indentation, letize); os << ")"; break; case EQ: // tricky tricky ... if it's a single-byte comparison, // simply do ==, but if it's multi-byte, must do memcmp LHSkind = c[0].GetKind(); RHSkind = c[1].GetKind(); num_bytes = 0; // try to figure out whether it's a single-byte or multi-byte // comparison if (LHSkind == BVEXTRACT) { upper = c[0].GetChildren()[1].GetUnsignedConst(); lower = c[0].GetChildren()[2].GetUnsignedConst(); num_bytes = (upper - lower + 1) / 8; } else if (RHSkind == BVEXTRACT) { upper = c[1].GetChildren()[1].GetUnsignedConst(); lower = c[1].GetChildren()[2].GetUnsignedConst(); num_bytes = (upper - lower + 1) / 8; } if (num_bytes > 1) { os << "(memcmp("; C_Print1(os, c[0], indentation, letize); os << ", "; C_Print1(os, c[1], indentation, letize); os << ", "; os << num_bytes; os << ") == 0)"; } else if (num_bytes == 1) { os << "("; C_Print1(os, c[0], indentation, letize); os << " == "; C_Print1(os, c[1], indentation, letize); os << ")"; } else { FatalError("C_Print1: ugh problem in implementing =="); } break; case AND: case OR: case NAND: case NOR: case XOR: { os << "("; C_Print1(os, c[0], indentation, letize); ASTVec::const_iterator it = c.begin(); ASTVec::const_iterator itend = c.end(); it++; for (; it != itend; it++) { switch (kind) { case AND: os << " && "; break; case OR: os << " || "; break; case NAND: FatalError("unsupported boolean type in C_Print1"); break; case NOR: FatalError("unsupported boolean type in C_Print1"); break; case XOR: FatalError("unsupported boolean type in C_Print1"); break; default: FatalError("unsupported boolean type in C_Print1"); } C_Print1(os, *it, indentation, letize); } os << ")"; break; } case IFF: // stopgap for un-implemented features FatalError("C_Print1: printing not implemented for this kind: ", n); os << "("; os << "("; C_Print1(os, c[0], indentation, letize); os << ")"; os << " <=> "; os << "("; C_Print1(os, c[1], indentation, letize); os << ")"; os << ")"; os << endl; break; case IMPLIES: // stopgap for un-implemented features FatalError("C_Print1: printing not implemented for this kind: ", n); os << "("; os << "("; C_Print1(os, c[0], indentation, letize); os << ")"; os << " => "; os << "("; C_Print1(os, c[1], indentation, letize); os << ")"; os << ")"; os << endl; break; case BVSX: // stopgap for un-implemented features FatalError("C_Print1: printing not implemented for this kind: ", n); os << kind << "("; C_Print1(os, c[0], indentation, letize); os << ","; os << n.GetValueWidth(); os << ")" << endl; break; default: // remember to use LispPrinter here. Otherwise this function will // go into an infinite loop. Recall that "<<" is overloaded to // the lisp printer. FatalError uses lispprinter FatalError("C_Print1: printing not implemented for this kind: ", n); break; } } // end of C_Print1()
// This doesn't rewrite changes through properly so needs to have a substitution // applied to its output. ASTNode PropagateEqualities::propagate(const ASTNode& a, ArrayTransformer* at) { ASTNode output; // if the variable has been solved for, then simply return it if (simp->InsideSubstitutionMap(a, output)) return output; if (!alreadyVisited.insert(a.GetNodeNum()).second) { return a; } output = a; // traverse a and populate the SubstitutionMap const Kind k = a.GetKind(); if (SYMBOL == k && BOOLEAN_TYPE == a.GetType()) { bool updated = simp->UpdateSubstitutionMap(a, ASTTrue); output = updated ? ASTTrue : a; } else if (NOT == k) { bool updated = searchXOR(a[0], ASTFalse); output = updated ? ASTTrue : a; } else if (IFF == k || EQ == k) { const ASTVec& c = a.GetChildren(); if (c[0] == c[1]) return ASTTrue; bool updated = simp->UpdateSubstitutionMap(c[0], c[1]); if (updated) { // fill the arrayname readindices vector if e0 is a // READ(Arr,index) and index is a BVCONST int to; if ((to = TermOrder(c[0], c[1])) == 1 && c[0].GetKind() == READ) at->FillUp_ArrReadIndex_Vec(c[0], c[1]); else if (to == -1 && c[1].GetKind() == READ) at->FillUp_ArrReadIndex_Vec(c[1], c[0]); } if (!updated) updated = searchTerm(c[0], c[1]); if (!updated) updated = searchTerm(c[1], c[0]); output = updated ? ASTTrue : a; } else if (XOR == k) { bool updated = searchXOR(a, ASTTrue); output = updated ? ASTTrue : a; if (updated) return output; // The below block should be subsumed by the searchXOR function which // generalises it. // So the below block should never do anything.. #ifndef NDEBUG if (a.Degree() != 2) return output; int to = TermOrder(a[0], a[1]); if (0 == to) { if (a[0].GetKind() == NOT && a[0][0].GetKind() == EQ && a[0][0][0].GetValueWidth() == 1 && a[0][0][1].GetKind() == SYMBOL) { // (XOR (NOT(= (1 v))) ... ) const ASTNode& symbol = a[0][0][1]; const ASTNode newN = nf->CreateTerm( ITE, 1, a[1], a[0][0][0], nf->CreateTerm(BVNEG, 1, a[0][0][0])); if (simp->UpdateSolverMap(symbol, newN)) { assert(false); output = ASTTrue; } } else if (a[1].GetKind() == NOT && a[1][0].GetKind() == EQ && a[1][0][0].GetValueWidth() == 1 && a[1][0][1].GetKind() == SYMBOL) { const ASTNode& symbol = a[1][0][1]; const ASTNode newN = nf->CreateTerm( ITE, 1, a[0], a[1][0][0], nf->CreateTerm(BVNEG, 1, a[1][0][0])); if (simp->UpdateSolverMap(symbol, newN)) { assert(false); output = ASTTrue; } } else if (a[0].GetKind() == EQ && a[0][0].GetValueWidth() == 1 && a[0][1].GetKind() == SYMBOL) { // XOR ((= 1 v) ... ) const ASTNode& symbol = a[0][1]; const ASTNode newN = nf->CreateTerm( ITE, 1, a[1], nf->CreateTerm(BVNEG, 1, a[0][0]), a[0][0]); if (simp->UpdateSolverMap(symbol, newN)) { assert(false); output = ASTTrue; } } else if (a[1].GetKind() == EQ && a[1][0].GetValueWidth() == 1 && a[1][1].GetKind() == SYMBOL) { const ASTNode& symbol = a[1][1]; const ASTNode newN = nf->CreateTerm( ITE, 1, a[0], nf->CreateTerm(BVNEG, 1, a[1][0]), a[1][0]); if (simp->UpdateSolverMap(symbol, newN)) { assert(false); output = ASTTrue; } } else return output; } else { ASTNode symbol, rhs; if (to == 1) { symbol = a[0]; rhs = a[1]; } else { symbol = a[1]; rhs = a[0]; } assert(symbol.GetKind() == SYMBOL); if (simp->UpdateSolverMap(symbol, nf->CreateNode(NOT, rhs))) { assert(false); output = ASTTrue; } } #endif } else if (AND == k) { const ASTVec& c = a.GetChildren(); ASTVec o; o.reserve(c.size()); for (ASTVec::const_iterator it = c.begin(), itend = c.end(); it != itend; it++) { if (always_true) simp->UpdateAlwaysTrueFormSet(*it); ASTNode aaa = propagate(*it, at); if (ASTTrue != aaa) { if (ASTFalse == aaa) return ASTFalse; else o.push_back(aaa); } } if (o.size() == 0) output = ASTTrue; else if (o.size() == 1) output = o[0]; else if (o != c) output = nf->CreateNode(AND, o); else output = a; } return output; }
void SMTLIB2_Print1(ostream& os, const ASTNode n, int indentation, bool letize) { //os << spaces(indentation); //os << endl << spaces(indentation); if (!n.IsDefined()) { FatalError("<undefined>"); return; } //if this node is present in the letvar Map, then print the letvar //this is to print letvars for shared subterms inside the printing //of "(LET v0 = term1, v1=term1@term2,... if ((NodeLetVarMap1.find(n) != NodeLetVarMap1.end()) && !letize) { SMTLIB2_Print1(os, (NodeLetVarMap1[n]), indentation, letize); return; } //this is to print letvars for shared subterms inside the actual //term to be printed if ((NodeLetVarMap.find(n) != NodeLetVarMap.end()) && letize) { SMTLIB2_Print1(os, (NodeLetVarMap[n]), indentation, letize); return; } //otherwise print it normally const Kind kind = n.GetKind(); const ASTVec &c = n.GetChildren(); switch (kind) { case BITVECTOR: case BVCONST: outputBitVecSMTLIB2(n, os); break; case SYMBOL: os << "|"; n.nodeprint(os); os << "|"; break; case FALSE: os << "false"; break; case NAND: // No NAND, NOR in smtlib format. case NOR: assert(c.size() ==2); os << "(" << "not "; if (NAND == kind ) os << "(" << "and "; else os << "(" << "or "; SMTLIB2_Print1(os, c[0], 0, letize); os << " " ; SMTLIB2_Print1(os, c[1], 0, letize); os << "))"; break; case TRUE: os << "true"; break; case BVSX: case BVZX: { unsigned int amount = c[1].GetUnsignedConst(); if (BVZX == kind) os << "((_ zero_extend "; else os << "((_ sign_extend "; os << (amount - c[0].GetValueWidth()) << ") "; SMTLIB2_Print1(os, c[0], indentation, letize); os << ")"; } break; case BVEXTRACT: { unsigned int upper = c[1].GetUnsignedConst(); unsigned int lower = c[2].GetUnsignedConst(); assert(upper >= lower); os << "((_ extract " << upper << " " << lower << ") "; SMTLIB2_Print1(os, c[0], indentation, letize); os << ")"; } break; default: { if ((kind == AND || kind == OR|| kind == XOR) && n.Degree() == 1) { FatalError("Wrong number of arguments to operation (must be >1).", n); } // SMT-LIB only allows these functions to have two parameters. if ((kind == AND || kind == OR|| kind == XOR || BVPLUS == kind || kind == BVOR || kind == BVAND) && n.Degree() > 2) { string close = ""; for (long int i =0; i < (long int)c.size()-1; i++) { os << "(" << functionToSMTLIBName(kind,false); os << " "; SMTLIB2_Print1(os, c[i], 0, letize); os << " "; close += ")"; } SMTLIB2_Print1(os, c[c.size()-1], 0, letize); os << close; } else { os << "(" << functionToSMTLIBName(kind,false); ASTVec::const_iterator iend = c.end(); for (ASTVec::const_iterator i = c.begin(); i != iend; i++) { os << " "; SMTLIB2_Print1(os, *i, 0, letize); } os << ")"; } } } }
void GDL_Print1(ostream& os, const ASTNode& n, hash_set<int>* alreadyOutput, string (*annotate)(const ASTNode&)) { // check if this node has already been printed. If so return. if (alreadyOutput->find(n.GetNodeNum()) != alreadyOutput->end()) return; alreadyOutput->insert(n.GetNodeNum()); os << "node: { title:\"n" << n.GetNodeNum() << "\" label: \""; switch (n.GetKind()) { case SYMBOL: n.nodeprint(os); break; case BITVECTOR: case BVCONST: outputBitVec(n, os); break; default: os << _kind_names[n.GetKind()]; } os << annotate(n); os << "\"}" << endl; // print the edges to each child. const ASTVec ch = n.GetChildren(); const ASTVec::const_iterator itend = ch.end(); // If a node has the child 'TRUE' twice, we only want to output one TRUE node. ASTNodeSet constantOutput; int i = 0; for (ASTVec::const_iterator it = ch.begin(); it < itend; it++) { std::stringstream label; if (!isCommutative(n.GetKind())) label << " label:\"" << i << "\""; if (it->isConstant()) { std::stringstream ss; ss << n.GetNodeNum() << "_" << it->GetNodeNum(); if (constantOutput.end() == constantOutput.find(*it)) { os << "node: { title:\"n"; os << ss.str() << "\" label: \""; if (it->GetType() == BEEV::BOOLEAN_TYPE) os << _kind_names[it->GetKind()]; else outputBitVec(*it, os); os << "\"}" << endl; constantOutput.insert(*it); } os << "edge: { source:\"n" << n.GetNodeNum() << "\" target: \"" << "n" << ss.str() << "\"" << label.str() << "}" << endl; } else os << "edge: { source:\"n" << n.GetNodeNum() << "\" target: \"" << "n" << it->GetNodeNum() << "\"" << label.str() << "}" << endl; i++; } // print each of the children. for (ASTVec::const_iterator it = ch.begin(); it < itend; it++) { if (!it->isConstant()) GDL_Print1(os, *it, alreadyOutput, annotate); } }