void OutputInputs(ostream &os, const ASTNode& n, hash_set<int> *alreadyOutput) { if (alreadyOutput->find(n.GetNodeNum()) != alreadyOutput->end()) return; alreadyOutput->insert(n.GetNodeNum()); if (n.GetKind() == BVGETBIT) { assert(n[1].GetKind() == BVCONST); std::stringstream nn; n[0].nodeprint(nn); nn << "_" << bvconstToString(n[1]); os << "INPUT(" << nn.str() << ")" << endl; return; } // A boolean symbol. if (n.GetKind() == SYMBOL) { os << "INPUT(" << symbolToString(n) << ")" << endl; return; } for (unsigned i = 0; i < n.Degree(); i++) { OutputInputs(os, n[i], alreadyOutput); } }
bool VariablesInExpression::VarSeenInTerm(const ASTNode& var, const ASTNode& term) { // This only returns true if we are searching for variables that aren't arrays. assert(var.GetKind() == SYMBOL && var.GetIndexWidth() == 0); if (term.isConstant()) return false; getSymbol(term); SymbolPtrSet visited; ASTNodeSet *symbols = new ASTNodeSet(); vector<Symbols*> av; VarSeenInTerm(symbol_graph[term.GetNodeNum()], visited, *symbols, av); bool result = (symbols->count(var) != 0); //cerr << "visited:" << visited.size() << endl; //cerr << "av:" << av.size() << endl; //cerr << "Term is const" << term.isConstant() << endl; if (visited.size() > 250) // No use caching it, unless we've done some work. { sort(av.begin(), av.end()); //cout << "===" << endl; for (size_t i = 0; i < av.size(); i++) { if (i!=0 && av[i] == av[i-1]) continue; const ASTNodeSet& sym = *TermsAlreadySeenMap.find(av[i])->second; //cout << "set: " << i << " " << sym.size() << endl; symbols->insert(sym.begin(), sym.end()); } TermsAlreadySeenMap.insert(make_pair(symbol_graph[term.GetNodeNum()], symbols)); //cout << "finish" << symbols->size() << endl; //cout << "===" << endl; result = (symbols->count(var) != 0); } else { const int size = av.size(); for (int i = 0; i < size; i++) { if (result) break; const ASTNodeSet& sym = *TermsAlreadySeenMap.find(av[i])->second; result |= (sym.find(var) != sym.end()); } delete symbols; } return result; }
void CNFMgr::doRenamingNeg(const ASTNode& varphi, ClauseList* defs) { CNFInfo* x = info[varphi]; //######################################## // step 2, calc new variable //######################################## ostringstream oss; oss << "cnf" << "{" << varphi.GetNodeNum() << "}"; ASTNode psi = bm->CreateSymbol(oss.str().c_str(),0,0); //######################################## // step 3, add defs //######################################## ASTNode* copy = ASTNodeToASTNodePtr(psi); ClauseList* cl = info[varphi]->clausesneg; cl->appendToAllClauses(copy); defs->insert(cl); delete cl; //######################################## // step 4, update info[varphi] //######################################## x->clausesneg = SINGLETON(bm->CreateNode(NOT, psi)); setWasRenamedNeg(*x); } //End of doRenamingNeg()
void CNFMgr::doRenamingPosXor(const ASTNode& varphi) { CNFInfo* x = info[varphi]; //######################################## // step 1, calc new variable //######################################## ostringstream oss; oss << "cnf" << "{" << varphi.GetNodeNum() << "}"; ASTNode psi = bm->CreateSymbol(oss.str().c_str(),0,0); //######################################## // step 2, add defs //######################################## // ClauseList* cl1; // cl1 = SINGLETON(bm->CreateNode(NOT, psi)); // ClauseList* cl2 = PRODUCT(*(info[varphi]->clausespos), *cl1); // defs->insert(defs->end(), cl2->begin(), cl2->end()); // DELETE(info[varphi]->clausespos); // DELETE(cl1); // delete cl2; //######################################## // step 3, update info[varphi] //######################################## x->clausespos = SINGLETON(psi); x->clausesneg = SINGLETON(bm->CreateNode(NOT, psi)); setWasRenamedPos(*x); }//End of doRenamingPos
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); } }
bool containsArrayOps(const ASTNode& n, hash_set<int> & visited) { if (n.GetIndexWidth() > 0) return true; if (n.Degree() ==0) return false; if (visited.find(n.GetNodeNum()) != visited.end()) return false; visited.insert(n.GetNodeNum()); for (int i =0; i < n.Degree();i++) if (containsArrayOps(n[i],visited)) return true; return false; }
// counts the number of reads. Shortcut when we get to the limit. void numberOfReadsLessThan(const ASTNode& n, hash_set<int>& visited, int& soFar, const int limit) { if (n.isAtom()) return; if (visited.find(n.GetNodeNum()) != visited.end()) return; if (n.GetKind() == READ) soFar++; if (soFar > limit) return; visited.insert(n.GetNodeNum()); for (size_t i = 0; i < n.Degree(); i++) numberOfReadsLessThan(n[i], visited, soFar, limit); }
// This is for sorting by arithmetic expressions (for // combining like terms, etc.) bool arithless(const ASTNode n1, const ASTNode n2) { Kind k1 = n1.GetKind(); Kind k2 = n2.GetKind(); if (n1 == n2) { // necessary for "strict weak ordering" return false; } else if (BVCONST == k1 && BVCONST != k2) { // put consts first return true; } else if (BVCONST != k1 && BVCONST == k2) { // put consts first return false; } else if (SYMBOL == k1 && SYMBOL != k2) { // put symbols next return true; } else if (SYMBOL != k1 && SYMBOL == k2) { // put symbols next return false; } else { // otherwise, sort by exprnum (descendents will appear // before ancestors). return (n1.GetNodeNum() < n2.GetNodeNum()); } } //end of arithless
// If n0 is replaced by n1 in the substitution map. Will it cause a loop? // i.e. will the dependency graph be an acyclic graph still. // For example, if we have x = F(y,z,w), it would make the substitutionMap loop // if there's already z = F(x). bool SubstitutionMap::loops(const ASTNode& n0, const ASTNode& n1) { if (n0.GetKind() != SYMBOL) return false; // sometimes this function is called with constants on the // lhs. if (n1.isConstant()) return false; // constants contain no variables. Can't loop. // We are adding an edge FROM n0, so unless there is already an edge TO n0, // there is no change it can loop. Unless adding this would add a TO and FROM // edge. if (rhs.find(n0) == rhs.end()) { return vars.VarSeenInTerm(n0, n1); } if (n1.GetKind() == SYMBOL && dependsOn.find(n1) == dependsOn.end()) return false; // The rhs is a symbol and doesn't appear. if (debug_substn) cout << loopCount++ << endl; bool destruct = true; ASTNodeSet* dependN = vars.SetofVarsSeenInTerm(n1, destruct); if (debug_substn) { cout << n0 << " " << n1.GetNodeNum(); //<< " Expression size:" << bm->NodeSize(n1,true); cout << "Variables in expression: " << dependN->size() << endl; } set<ASTNode> depend(dependN->begin(), dependN->end()); if (destruct) delete dependN; set<ASTNode> visited; loops_helper(depend, visited); bool loops = visited.find(n0) != visited.end(); if (debug_substn) cout << "Visited:" << visited.size() << "Loops:" << loops << endl; return (loops); }
void VariablesInExpression::insert(const ASTNode& n, Symbols *s) { assert (s!= NULL); symbol_graph.insert(std::make_pair(n.GetNodeNum(), s)); }
// Sort ASTNodes by expression numbers bool exprless(const ASTNode n1, const ASTNode n2) { return (n1.GetNodeNum() < n2.GetNodeNum()); }
string Bench_Print1(ostream &os, const ASTNode& n, map<ASTNode, string> *alreadyOutput) { assert(((n.GetKind() == SYMBOL) || (n.GetKind() == BVCONST) || n.GetValueWidth() <= 1)); assert(!n.IsNull()); map<ASTNode, string>::iterator it; if ((it = alreadyOutput->find(n)) != alreadyOutput->end()) return it->second; if (n.GetKind() == BVCONST) { (*alreadyOutput)[n] = bvconstToString(n); return (*alreadyOutput)[n]; } if (n.GetKind() == SYMBOL) { (*alreadyOutput)[n] = symbolToString(n); return (*alreadyOutput)[n]; } if (n.GetKind() == TRUE) { return "vdd"; } if (n.GetKind() == FALSE) { return "gnd"; } if (n.GetKind() == BVGETBIT) { assert(n[1].GetKind() == BVCONST); std::stringstream nn; nn << Bench_Print1(os, n[0], alreadyOutput) << "_" << Bench_Print1(os, n[1], alreadyOutput); (*alreadyOutput)[n] = nn.str(); return (*alreadyOutput)[n]; } std::stringstream nodeNameSS; nodeNameSS << "n" << n.GetNodeNum(); string thisNode = nodeNameSS.str(); (*alreadyOutput)[n] = thisNode; assert(n.Degree() > 0); std::stringstream output; // The bench format doesn't accept propositional ITEs. if (n.GetKind() == ITE) { assert(n.Degree() == 3); string p = Bench_Print1(os, n[0], alreadyOutput); string p1 = Bench_Print1(os, n[1], alreadyOutput); string p2 = Bench_Print1(os, n[2], alreadyOutput); os << thisNode << "_1 = AND(" << p << "," << p1 << ")" << endl; os << thisNode << "_2" << " = NOT(" << p << ")," << endl; os << thisNode << "_3" << " = AND(" << thisNode << "_2" << "," << p2 << ")" << endl; os << thisNode << "=" << "OR(," << thisNode << "_1" << "," << thisNode << "_3)" << endl; } else { if (n.Degree() > 2) { assert(n.GetKind() == AND || n.GetKind() == XOR || n.GetKind() == OR); // must be associative. std::deque<string> names; for (unsigned i = 0; i < n.Degree(); i++) names.push_back(Bench_Print1(os, n[i], alreadyOutput)); int id = 0; while (names.size() > 2) { string a = names.front(); names.pop_front(); string b = names.front(); names.pop_front(); std::stringstream thisName; thisName << thisNode << "___" << id++; output << thisName.str() << "=" << name(n.GetKind()) << "(" << a << "," << b << ")" << endl; names.push_back(thisName.str()); } assert(names.size() == 2); // last two now. string a = names.front(); names.pop_front(); string b = names.front(); names.pop_front(); output << thisNode << "=" << name(n.GetKind()) << "(" << a << "," << b << ")" << endl; os << output.str(); } else { output << thisNode << "=" << name(n.GetKind()) << "("; for (unsigned i = 0; i < n.Degree(); i++) { if (i >= 1) output << " , "; output << Bench_Print1(os, n[i], alreadyOutput); } os << output.str() << ")" << endl; } } return thisNode; }
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); } }
// 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; }