bool PropagateEqualities::searchTerm(const ASTNode& lhs, const ASTNode& rhs) { const unsigned width = lhs.GetValueWidth(); if (lhs == rhs) return true; if (lhs.GetKind() == SYMBOL) return simp->UpdateSubstitutionMap(lhs, rhs); // checks whether it's been // solved for, or if the RHS // contains the LHS. if (lhs.GetKind() == BVUMINUS) return searchTerm(lhs[0], nf->CreateTerm(BVUMINUS, width, rhs)); if (lhs.GetKind() == BVNEG) return searchTerm(lhs[0], nf->CreateTerm(BVNEG, width, rhs)); if (lhs.GetKind() == BVXOR || lhs.GetKind() == BVPLUS) for (size_t i = 0; i < lhs.Degree(); i++) { ASTVec others; for (size_t j = 0; j < lhs.Degree(); j++) if (j != i) others.push_back(lhs[j]); ASTNode new_rhs; if (lhs.GetKind() == BVXOR) { others.push_back(rhs); assert(others.size() > 1); new_rhs = nf->CreateTerm(lhs.GetKind(), width, others); } else if (lhs.GetKind() == BVPLUS) { if (others.size() > 1) new_rhs = nf->CreateTerm(BVPLUS, width, others); else new_rhs = others[0]; new_rhs = nf->CreateTerm(BVUMINUS, width, new_rhs); new_rhs = nf->CreateTerm(BVPLUS, width, new_rhs, rhs); } else FatalError("sdafasfsdf2q3234423"); bool result = searchTerm(lhs[i], new_rhs); if (result) return true; } if (lhs.Degree() == 2 && lhs.GetKind() == BVMULT && lhs[0].isConstant() && simp->BVConstIsOdd(lhs[0])) return searchTerm(lhs[1], nf->CreateTerm(BVMULT, width, simp->MultiplicativeInverse(lhs[0]), rhs)); return false; }
ASTNode NodeFactory::CreateArrayTerm(Kind kind, unsigned int index, unsigned int width, const ASTNode& child0, const ASTNode& child1, const ASTNode& child2, const ASTVec &children) { ASTVec child; child.reserve(children.size() + 3); child.push_back(child0); child.push_back(child1); child.push_back(child2); child.insert(child.end(), children.begin(), children.end()); return CreateArrayTerm(kind, index, width, child); }
ASTNode STPMgr::CreateSimpForm(Kind kind, const ASTNode& child0, const ASTNode& child1) { ASTVec children; //child_stack.clear(); // could just reset top pointer. children.push_back(child0); //child_stack.push_back(child0); children.push_back(child1); //child_stack.push_back(child1); return CreateSimpForm(kind, children); //return CreateSimpForm(kind, child_stack); }
ASTNode STPMgr::CreateSimpXor(const ASTNode& form1, const ASTNode& form2) { ASTVec children; children.push_back(form1); children.push_back(form2); return CreateSimpXor(children); }
bool PropagateEqualities::searchXOR(const ASTNode& lhs, const ASTNode& rhs) { Kind k = lhs.GetKind(); if (lhs == rhs) return true; if (k == SYMBOL) return simp->UpdateSubstitutionMap( lhs, rhs); // checks whether it's been solved for or loops. if (k == NOT) return searchXOR(lhs[0], nf->CreateNode(NOT, rhs)); bool result = false; if (k == XOR) for (size_t i = 0; i < lhs.Degree(); i++) { ASTVec others; for (size_t j = 0; j < lhs.Degree(); j++) if (j != i) others.push_back(lhs[j]); others.push_back(rhs); assert(others.size() > 1); ASTNode new_rhs = nf->CreateNode(XOR, others); result = searchXOR(lhs[i], new_rhs); if (result) return result; } if (k == EQ && lhs[0].GetValueWidth() == 1) { bool result = searchTerm(lhs[0], nf->CreateTerm(ITE, 1, rhs, lhs[1], nf->CreateTerm(BVNEG, 1, lhs[1]))); if (!result) result = searchTerm(lhs[1], nf->CreateTerm(ITE, 1, rhs, lhs[0], nf->CreateTerm(BVNEG, 1, lhs[0]))); } return result; }
ASTNode STPMgr::CreateSimpAndOr(bool IsAnd, const ASTNode& form1, const ASTNode& form2) { ASTVec children; children.push_back(form1); children.push_back(form2); return CreateSimpAndOr(IsAnd, children); }
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 FlattenKind(const Kind k, const ASTVec &children, ASTVec & flat_children) { ASTVec::const_iterator ch_end = children.end(); for (ASTVec::const_iterator it = children.begin(); it != ch_end; it++) { Kind ck = it->GetKind(); if (k == ck) { FlattenKind(k,it->GetChildren(), flat_children); } else { flat_children.push_back(*it); } } }
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()
/* Maintains a set of nodes that have already been seen. So that deeply shared * AND,OR operations are not * flattened multiple times. */ void FlattenKindNoDuplicates(const Kind k, const ASTVec& children, ASTVec& flat_children, ASTNodeSet& alreadyFlattened) { const ASTVec::const_iterator ch_end = children.end(); for (ASTVec::const_iterator it = children.begin(); it != ch_end; it++) { const Kind ck = it->GetKind(); if (k == ck) { if (alreadyFlattened.find(*it) == alreadyFlattened.end()) { alreadyFlattened.insert(*it); FlattenKindNoDuplicates(k, it->GetChildren(), flat_children, alreadyFlattened); } } else { flat_children.push_back(*it); } } }
//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()
// FIXME: How do I know whether ITE is a formula or not? ASTNode STPMgr::CreateSimpFormITE(const ASTNode& child0, const ASTNode& child1, const ASTNode& child2) { ASTNode retval; if (_trace_simpbool) { cout << "========" << endl << "CreateSimpFormITE " << child0 << child1 << child2 << endl; } if (ASTTrue == child0) { retval = child1; } else if (ASTFalse == child0) { retval = child2; } else if (child1 == child2) { retval = child1; } // ITE(x, TRUE, y ) == x OR y else if (ASTTrue == child1) { retval = CreateSimpAndOr(0, child0, child2); } // ITE(x, FALSE, y ) == (!x AND y) else if (ASTFalse == child1) { retval = CreateSimpAndOr(1, CreateSimpNot(child0), child2); } // ITE(x, y, TRUE ) == (!x OR y) else if (ASTTrue == child2) { retval = CreateSimpAndOr(0, CreateSimpNot(child0), child1); } // ITE(x, y, FALSE ) == (x AND y) else if (ASTFalse == child2) { retval = CreateSimpAndOr(1, child0, child1); } else { ASTNode left = CreateNode(AND, child0, child1); ASTNode right = CreateNode(AND, CreateNode(NOT,child0), child2); ASTVec c; c.push_back(left); c.push_back(right); retval = CreateSimpXor(c); } if (_trace_simpbool) { cout << "returns " << retval << endl; } return retval; }
ASTNode RemoveUnconstrained::topLevel_other(const ASTNode &n, Simplifier *simplifier) { if (n.GetKind() == SYMBOL) return n; // top level is an unconstrained symbol/. simplifier_convenient = simplifier; ASTNodeSet noCheck; // We don't want to check some expensive nodes over and over again. vector<MutableASTNode*> variable_array; MutableASTNode* topMutable = MutableASTNode::build(n); vector<MutableASTNode*> extracts; topMutable->getDisjointExtractVariables(extracts); if (extracts.size() > 0) { splitExtractOnly(extracts); } topMutable->getAllUnconstrainedVariables(variable_array); for (int i =0; i < variable_array.size() ; i++) { // Don't make this is a reference. If the vector gets resized, it will point to // memory that no longer contains the object. MutableASTNode& muteNode = *variable_array[i]; const ASTNode var = muteNode.n; assert(var.GetKind() == SYMBOL); if (!muteNode.isUnconstrained()) continue; MutableASTNode& muteParent = muteNode.getParent(); if (noCheck.find(muteParent.n) != noCheck.end()) { continue; } vector <MutableASTNode*> mutable_children = muteParent.children; //nb. The children might be dirty. i.e. not have substitutions written through them yet. ASTVec children; children.reserve(mutable_children.size()); for (int j = 0; j <mutable_children.size(); j++ ) children.push_back(mutable_children[j]->n); const size_t numberOfChildren = children.size(); const Kind kind = muteNode.getParent().n.GetKind(); unsigned width = muteNode.getParent().n.GetValueWidth(); unsigned indexWidth = muteNode.getParent().n.GetIndexWidth(); ASTNode other; MutableASTNode* muteOther; if(numberOfChildren == 2) { if (children[0] != var) { other = children[0]; muteOther = mutable_children[0]; } else { other = children[1]; muteOther = mutable_children[1]; } if (kind != AND && kind != OR && kind != BVOR && kind != BVAND) if (other == var) continue; // Most rules don't like duplicate variables. } else { if (kind != AND && kind != OR && kind != BVOR && kind != BVAND) { int found = 0; for (int i = 0; i < numberOfChildren; i++) { if (children[i] == var) found++; } if (found != 1) continue; // Most rules don't like duplicate variables. } } /* cout << i << " " << kind << " " << variable_array.size() << " " << mutable_children.size() << endl; cout << "children[0]" << children[0] << endl; cout << "children[1]" << children[1] << endl; cout << muteParent.n << endl; */ switch (kind) { case BVCONCAT: assert(numberOfChildren == 2); if (mutable_children[0]->isUnconstrained() && (mutable_children[1]->isUnconstrained())) { ASTNode v =replaceParentWithFresh(muteParent, variable_array); ASTNode top_lhs = bm.CreateBVConst(32, width - 1); ASTNode bottom_lhs = bm.CreateBVConst(32, children[1].GetValueWidth()); ASTNode top_rhs = bm.CreateBVConst(32, children[1].GetValueWidth()- 1); ASTNode bottom_rhs = bm.CreateBVConst(32, 0); ASTNode lhs = nf->CreateTerm(BVEXTRACT, children[0].GetValueWidth(), v,top_lhs, bottom_lhs); ASTNode rhs = nf->CreateTerm(BVEXTRACT, children[1].GetValueWidth(), v,top_rhs, bottom_rhs); replace(children[0],lhs); replace(children[1],rhs); } break; case NOT: { ASTNode v =replaceParentWithFresh(muteParent, variable_array); replace(children[0], nf->CreateNode(NOT, v)); } break; case BVUMINUS: case BVNEG: { assert(numberOfChildren ==1); ASTNode v =replaceParentWithFresh(muteParent, variable_array); replace(var, nf->CreateTerm(kind, width,v)); } break; case BVSGT: case BVSGE: case BVGT: case BVGE: { width = var.GetValueWidth(); if (width ==1) continue; // Hard to get right, not used often. ASTNode biggestNumber, smallestNumber; if (kind == BVSGT || kind == BVSGE) { // 011111111 (most positive number.) CBV max = CONSTANTBV::BitVector_Create(width, false); CONSTANTBV::BitVector_Fill(max); CONSTANTBV::BitVector_Bit_Off(max, width - 1); biggestNumber = bm.CreateBVConst(max, width); // 1000000000 (most negative number.) max = CONSTANTBV::BitVector_Create(width, true); CONSTANTBV::BitVector_Bit_On(max, width - 1); smallestNumber = bm.CreateBVConst(max, width); } else if (kind == BVGT || kind == BVGE) { biggestNumber = bm.CreateMaxConst(width); smallestNumber = bm.CreateZeroConst(width); } else FatalError("SDFA!@S"); ASTNode c1,c2; if (kind == BVSGT || kind == BVGT) { c1= biggestNumber; c2 = smallestNumber; } else if (kind == BVSGE || kind == BVGE) { c1= smallestNumber; c2 = biggestNumber; } else FatalError("SDFA!@S"); if (mutable_children[0]->isUnconstrained() && mutable_children[1]->isUnconstrained()) { ASTNode v =replaceParentWithFresh(muteParent, variable_array); ASTNode lhs = nf->CreateTerm(ITE, width, v, bm.CreateOneConst(width), bm.CreateZeroConst(width)); ASTNode rhs = nf->CreateTerm(ITE, width, v, bm.CreateZeroConst(width), bm.CreateOneConst(width)); replace(children[0], lhs); replace(children[1], rhs); } else if (children[0] == var && children[1].isConstant()) { if (children[1] == c1) continue; // always false. Or always false. ASTNode v =replaceParentWithFresh(muteParent, variable_array); ASTNode rhs = nf->CreateTerm(ITE, width, v,biggestNumber, smallestNumber); replace(var, rhs); } else if (children[1] == var && children[0].isConstant()) { if (children[0] == c2) continue; // always false. Or always false. ASTNode v =replaceParentWithFresh(muteParent, variable_array); ASTNode rhs = nf->CreateTerm(ITE, width, v, smallestNumber, biggestNumber); replace(var, rhs); } else // One side is a variable. The other is anything. { bool varOnLHS = (var == children[0]); // All the ASTNode vars need to map to their existing MutableASTNodes. So we collect all the variables vector<MutableASTNode*> vars; set<MutableASTNode*> visited; muteOther->getAllVariablesRecursively(vars, visited); visited.clear(); map<ASTNode, MutableASTNode *> create; for (vector<MutableASTNode*>::iterator it = vars.begin(); it != vars.end();it++) create.insert(make_pair((*it)->n, *it)); vars.clear(); ASTNode v= bm.CreateFreshVariable(0, 0, "STP_INTERNAL_comparison"); ASTNode rhs; ASTNode n; if (varOnLHS) { rhs = nf->CreateTerm(ITE, width, v, biggestNumber, smallestNumber); if (kind == BVSGE || kind == BVGE) n= nf->CreateNode(OR, v, nf->CreateNode(EQ, mutable_children[1]->toASTNode(nf), c1)); else n= nf->CreateNode(AND, v, nf->CreateNode(NOT,nf->CreateNode(EQ, mutable_children[1]->toASTNode(nf), c1))); } else { rhs = nf->CreateTerm(ITE, width, v, smallestNumber, biggestNumber); if (kind == BVSGE || kind == BVGE) n= nf->CreateNode(OR, v, nf->CreateNode(EQ, mutable_children[0]->toASTNode(nf), c2)); else n= nf->CreateNode(AND, v, nf->CreateNode(NOT,nf->CreateNode(EQ, mutable_children[0]->toASTNode(nf), c2))); } replace(var, rhs); MutableASTNode *newN = MutableASTNode::build(n,create); muteParent.replaceWithAnotherNode(newN); //assert(muteParent.checkInvariant()); } } break; case AND: case OR: case BVOR: case BVAND: { if (allChildrenAreUnconstrained(mutable_children)) { ASTNodeSet already; ASTNode v =replaceParentWithFresh(muteParent, variable_array); for (int i =0; i < numberOfChildren;i++) { /* to avoid problems with: 734:(AND 732:unconstrained_4 716:unconstrained_2 732:unconstrained_4) */ if (already.find(children[i]) == already.end()) { replace(children[i], v); already.insert(children[i]); } } } else { // Hack. ff.stp has a 325k node conjunction // So we check if all the children are unconstrained each time // we find a new unconstrained conjunct. This means that if // eventually all the nodes become unconstrained we will miss it // and not rewrite the AND to a fresh unconstrained variable. if (mutable_children.size() > 200) noCheck.insert(muteParent.n); } } break; case XOR: case BVXOR: { ASTNode v =replaceParentWithFresh(muteParent, variable_array); ASTVec others; for (int i = 0; i < numberOfChildren; i++) { if (children[i] !=var) others.push_back(mutable_children[i]->toASTNode(nf)); } assert(others.size() +1 == numberOfChildren); assert(others.size() >=1); if (kind == XOR) { ASTNode xorNode = nf->CreateNode(XOR, others); replace(var, nf->CreateNode(XOR, v, xorNode)); } else { ASTNode xorNode ; if (others.size() > 1 ) xorNode = nf->CreateTerm(BVXOR, width, others); else xorNode = others[0]; replace(var, nf->CreateTerm(BVXOR, width, v, xorNode)); } } break; case ITE: { if (indexWidth > 0) continue; // don't do arrays. if (mutable_children[0]->isUnconstrained() && mutable_children[1]->isUnconstrained() && children[0] != children[1]) { ASTNode v =replaceParentWithFresh(muteParent, variable_array); replace(children[0], bm.ASTTrue); replace(children[1], v); } else if (mutable_children[0]->isUnconstrained() && mutable_children[2]->isUnconstrained() && children[0] != children[2]) { ASTNode v =replaceParentWithFresh(muteParent, variable_array); replace(children[0], bm.ASTFalse); replace(children[2], v); } else if (mutable_children[1]->isUnconstrained() && mutable_children[2]->isUnconstrained()) { ASTNode v =replaceParentWithFresh(muteParent, variable_array); replace(children[1], v); if (children[1] != children[2]) replace(children[2], v); } } break; case BVLEFTSHIFT: case BVRIGHTSHIFT: case BVSRSHIFT: { assert(numberOfChildren == 2); if (mutable_children[0]->isUnconstrained() && mutable_children[1]->isUnconstrained()) { assert(children[0] != children[1]); ASTNode v =replaceParentWithFresh(muteParent, variable_array); replace(children[1], bm.CreateZeroConst(width)); replace(children[0], v); } } break; case BVMOD: { assert(numberOfChildren == 2); if (mutable_children[0]->isUnconstrained() && mutable_children[1]->isUnconstrained() && bm.UserFlags.isSet("unconstrained-bvmod", "0") ) { assert (children[0] != children[1]); ASTNode v =replaceParentWithFresh(muteParent, variable_array); replace(children[1], bm.CreateZeroConst(width)); replace(children[0], v); } } break; case BVDIV: { assert(numberOfChildren == 2); if (mutable_children[0]->isUnconstrained() && mutable_children[1]->isUnconstrained()) { assert (children[0] != children[1]); ASTNode v =replaceParentWithFresh(muteParent, variable_array); replace(children[1], bm.CreateOneConst(width)); replace(children[0], v); } } break; case BVMULT: { assert(numberOfChildren == 2); if (mutable_children[1]->isUnconstrained() && mutable_children[0]->isUnconstrained()) // both are unconstrained { ASTNode v =replaceParentWithFresh(muteParent, variable_array); replace(children[0], bm.CreateOneConst(width)); replace(children[1], v); } if (other.isConstant() && simplifier->BVConstIsOdd(other)) { ASTNode v =replaceParentWithFresh(muteParent, variable_array); ASTNode inverse = simplifier->MultiplicativeInverse(other); ASTNode rhs = nf->CreateTerm(BVMULT, width, inverse, v); replace(var, rhs); } break; case IFF: { ASTNode v =replaceParentWithFresh(muteParent, variable_array); ASTNode rhs = nf->CreateNode(ITE, v, muteOther->toASTNode(nf), nf->CreateNode(NOT, muteOther->toASTNode(nf))); replace(var, rhs); } break; case EQ: { ASTNode v =replaceParentWithFresh(muteParent, variable_array); width = var.GetValueWidth(); ASTNode rhs = nf->CreateTerm(ITE, width, v, muteOther->toASTNode(nf), nf->CreateTerm(BVPLUS, width, muteOther->toASTNode(nf), bm.CreateOneConst(width))); replace(var, rhs); } break; case BVSUB: { assert(numberOfChildren == 2); ASTNode v =replaceParentWithFresh(muteParent, variable_array); ASTNode rhs; if (children[0] == var) rhs= nf->CreateTerm(BVPLUS, width, v, muteOther->toASTNode(nf)); if (children[1] == var) rhs= nf->CreateTerm(BVSUB, width, muteOther->toASTNode(nf), v); replace(var, rhs); } break; case BVPLUS: { ASTVec other; for (int i = 0; i < children.size(); i++) if (children[i] != var) other.push_back(mutable_children[i]->toASTNode(nf)); assert(other.size() == children.size()-1); assert(other.size() >=1); ASTNode v =replaceParentWithFresh(muteParent, variable_array); ASTNode rhs; if (other.size() > 1) rhs = nf->CreateTerm(BVSUB, width, v, nf->CreateTerm(BVPLUS, width, other)); else rhs = nf->CreateTerm(BVSUB, width, v, other[0]); replace(var, rhs); } break; case BVEXTRACT: { ASTNode v =replaceParentWithFresh(muteParent, variable_array); const unsigned resultWidth = width; const unsigned operandWidth = var.GetValueWidth(); assert(children[0] == var); // It can't be anywhere else. // Create Fresh variables to pad the LHS and RHS. const unsigned high = children[1].GetUnsignedConst(); const unsigned low = children[2].GetUnsignedConst(); assert(high >=low); const int rhsSize = low; const int lhsSize = operandWidth - high - 1; ASTNode current = v; int newWidth = v.GetValueWidth(); if (lhsSize > 0) { ASTNode lhsFresh = bm.CreateFreshVariable(0, lhsSize, "lhs_padding"); current = nf->CreateTerm(BVCONCAT, newWidth + lhsSize, lhsFresh, current); newWidth += lhsSize; } if (rhsSize > 0) { ASTNode rhsFresh = bm.CreateFreshVariable(0, rhsSize, "rhs_padding"); current = nf->CreateTerm(BVCONCAT, newWidth + rhsSize, current, rhsFresh); newWidth += rhsSize; } assert(newWidth == operandWidth); replace(var, current); } break; default: { //cerr << "!!!!" << kind << endl; } // cerr << var; // cerr << parent; } } } ASTNode result = topMutable->toASTNode(nf); topMutable->cleanup(); //cout << result; return result; }
// 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; }
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; }
/******************************************************** * TransformFormula() * * Get rid of DIV/MODs, ARRAY read/writes, FOR constructs ********************************************************/ ASTNode ArrayTransformer::TransformFormula(const ASTNode& simpleForm) { assert(TransformMap != NULL); const Kind k = simpleForm.GetKind(); if (!(is_Form_kind(k) && BOOLEAN_TYPE == simpleForm.GetType())) { // FIXME: "You have inputted a NON-formula"? FatalError("TransformFormula:" "You have input a NON-formula", simpleForm); } ASTNodeMap::const_iterator iter; if ((iter = TransformMap->find(simpleForm)) != TransformMap->end()) return iter->second; ASTNode result; switch (k) { case TRUE: case FALSE: { result = simpleForm; break; } case NOT: { ASTVec c; c.push_back(TransformFormula(simpleForm[0])); result = nf->CreateNode(NOT, c); break; } case BOOLEXTRACT: { ASTVec c; c.push_back(TransformTerm(simpleForm[0])); c.push_back(simpleForm[1]); result = nf->CreateNode(BOOLEXTRACT, c); break; } case BVLT: case BVLE: case BVGT: case BVGE: case BVSLT: case BVSLE: case BVSGT: case BVSGE: { ASTVec c; c.push_back(TransformTerm(simpleForm[0])); c.push_back(TransformTerm(simpleForm[1])); result = nf->CreateNode(k, c); break; } case EQ: { ASTNode term1 = TransformTerm(simpleForm[0]); ASTNode term2 = TransformTerm(simpleForm[1]); if (bm->UserFlags.optimize_flag) result = simp->CreateSimplifiedEQ(term1, term2); else result = nf->CreateNode(EQ, term1, term2); break; } case AND: // These could shortcut. Not sure if the extra effort is // justified. case OR: case NAND: case NOR: case IFF: case XOR: case ITE: case IMPLIES: { ASTVec vec; vec.reserve(simpleForm.Degree()); for (ASTVec::const_iterator it = simpleForm.begin(), itend = simpleForm.end(); it != itend; it++) { vec.push_back(TransformFormula(*it)); } result = nf->CreateNode(k, vec); break; } case PARAMBOOL: { // If the parameteric boolean variable is of the form // VAR(const), then convert it into a Boolean variable of the // form "VAR(const)". // // Else if the paramteric boolean variable is of the form // VAR(expression), then simply return it if (BVCONST == simpleForm[1].GetKind()) { result = bm->NewParameterized_BooleanVar(simpleForm[0], simpleForm[1]); } else { result = simpleForm; } break; } default: { if (k == SYMBOL && BOOLEAN_TYPE == simpleForm.GetType()) result = simpleForm; else { FatalError("TransformFormula: Illegal kind: ", ASTUndefined, k); std::cerr << "The input is: " << simpleForm << std::endl; std::cerr << "The valuewidth of input is : " << simpleForm.GetValueWidth() << std::endl; } break; } } assert(!result.IsNull()); if (simpleForm.Degree() > 0) (*TransformMap)[simpleForm] = result; return result; }
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); result = simp->CreateSimplifiedTermITE(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; const Kind k = result.GetKind(); if (BVDIV == k || BVMOD == k || SBVDIV == k || SBVREM == k || SBVMOD == k) { // I had this as a reference, but that was wrong. Because // "result" gets over-written in the next block, result[1], may // get a reference count of zero, so be garbage collected. const ASTNode bottom = result[1]; if (SBVDIV == result.GetKind() || SBVREM == result.GetKind() || SBVMOD == result.GetKind()) { result = TranslateSignedDivModRem(result); } if (bm->UserFlags.division_by_zero_returns_one_flag) { // This is a difficult rule to introduce in other // places because it's recursive. i.e. result is // embedded unchanged inside the result. unsigned inputValueWidth = result.GetValueWidth(); ASTNode zero = bm->CreateZeroConst(inputValueWidth); ASTNode one = bm->CreateOneConst(inputValueWidth); result = nf->CreateTerm(ITE, inputValueWidth, nf->CreateNode(EQ, zero, bottom), one, result); //return result; if (bm->UserFlags.optimize_flag) return simp->SimplifyTerm_TopLevel(result); else return result; } } } 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()) { cerr << "TransformTerm: input term is : " << term << endl; FatalError("TransformTerm: "\ "result & input terms have different index length", result); } return result; } //End of TransformTerm
/* The most complicated handling is for EXTRACTS. If a variable has parents that * are all extracts and each of those extracts is disjoint (i.e. reads different bits) * Then each of the extracts are replaced by a fresh variable. This is the only case * where a variable with multiple distinct parents is replaced by a fresh variable. * + We perform this check upfront, so will miss any extra cases the the unconstrained * variable elimination introduces. * + It's all or nothing. So even if there's an extract of [0:2] [1:2] and [3:5], we wont * replace the [3:5] (even though it could be). */ void RemoveUnconstrained::splitExtractOnly(vector<MutableASTNode*> extracts) { assert(extracts.size() >0); // Going to be rebuilt later anyway, so discard. vector<MutableASTNode*> variables; for (int i =0; i <extracts.size(); i++) { ASTNode& var = extracts[i]->n; assert(var.GetKind() == SYMBOL); const int size = var.GetValueWidth(); std::vector<ASTNode> toVar(size); // Create a mutable copy that we can iterate over. vector <MutableASTNode*> mut; mut.insert(mut.end(), extracts[i]->parents.begin(), extracts[i]->parents.end()); for (vector<MutableASTNode*>::iterator it = mut.begin(); it != mut.end(); it++) { ASTNode parent_node = (*it)->n; assert(((**it)).children[0] == extracts[i]); assert(!parent_node.IsNull()); assert(parent_node.GetKind() == BVEXTRACT); int lb = parent_node[2].GetUnsignedConst(); // Replace each parent with a fresh. toVar[lb] = replaceParentWithFresh(**it,variables); } ASTVec concatVec; int empty =0; for (int j=0; j < size;j++) { if (toVar[j].IsNull()) { empty++; continue; } if (empty > 0) { concatVec.push_back(bm.CreateFreshVariable(0, empty, "extract_unc")); empty = 0; } concatVec.push_back(toVar[j]); //cout << toVar[j]; assert(toVar[j].GetValueWidth() > 0); j+=toVar[j].GetValueWidth()-1; } if (empty> 0) { concatVec.push_back(bm.CreateFreshVariable(0, empty, "extract_unc")); } ASTNode concat = concatVec[0]; for (int i=1; i < concatVec.size();i++) { assert(!concat.IsNull()); concat = bm.CreateTerm(BVCONCAT, concat.GetValueWidth() + concatVec[i].GetValueWidth(),concatVec[i], concat); } replace(var,concat); } }
// NB: This expects that the constructor was called with teh same node. Sorry. ASTNode ConstantBitPropagation::topLevelBothWays(const ASTNode& top) { assert(top.GetSTPMgr()->UserFlags.bitConstantProp_flag); assert (BOOLEAN_TYPE == top.GetType()); propagate(); status = NO_CHANGE; //Determine what must always be true. ASTNodeMap fromTo = getAllFixed(); if (debug_cBitProp_messages) { cerr << "Number removed by bottom UP:" << fromTo.size() << endl; } setNodeToTrue(top); if (debug_cBitProp_messages) { cerr << "starting propagation" << endl; printNodeWithFixings(); cerr << "Initial Tree:" << endl; cerr << top; } propagate(); if (debug_cBitProp_messages) { cerr << "status:" << status <<endl; cerr << "ended propagation" << endl; printNodeWithFixings(); } // propagate may have stopped with a conflict. if (CONFLICT == status) return top.GetSTPMgr()->CreateNode(FALSE); ASTVec toConjoin; // go through the fixedBits. If a node is entirely fixed. // "and" it onto the top. Creates redundancy. Check that the // node doesn't already depend on "top" directly. for (NodeToFixedBitsMap::NodeToFixedBitsMapType::iterator it = fixedMap->map->begin(); it != fixedMap->map->end(); it++) // iterates through all the pairs of node->fixedBits. { const FixedBits& bits = *it->second; if (!bits.isTotallyFixed()) continue; const ASTNode& node = (it->first); // Don't constrain nodes we already know all about. if (node.isConstant()) continue; // other nodes will contain the same information (the extract doesn't change the fixings). if (BVEXTRACT == node.GetKind() || BVCONCAT == node.GetKind()) continue; // toAssign: conjoin it with the top level. // toReplace: replace all references to it (except the one conjoined to the top) with this. ASTNode propositionToAssert; ASTNode constantToReplaceWith; // skip the assigning and replacing. bool doAssign = true; { // If it is already contained in the fromTo map, then it's one of the values // that have fully been determined (previously). Not conjoined. if (fromTo.find(node) != fromTo.end()) continue; ASTNode constNode = bitsToNode(node,bits); if (node.GetType() == BOOLEAN_TYPE) { if (SYMBOL == node.GetKind()) { bool r = simplifier->UpdateSubstitutionMap(node, constNode); assert(r); doAssign = false; } else if (bits.getValue(0)) { propositionToAssert = node; constantToReplaceWith = constNode; } else { propositionToAssert = nf->CreateNode(NOT, node); constantToReplaceWith = constNode; } } else if (node.GetType() == BITVECTOR_TYPE) { assert(((unsigned)bits.getWidth()) == node.GetValueWidth()); if (SYMBOL == node.GetKind()) { bool r = simplifier->UpdateSubstitutionMap(node, constNode); assert(r); doAssign = false; } else { propositionToAssert = nf->CreateNode(EQ, node, constNode); constantToReplaceWith = constNode; } } else FatalError("sadf234s"); } if (doAssign && top != propositionToAssert && !dependents->nodeDependsOn(top, propositionToAssert)) { assert(!constantToReplaceWith.IsNull()); assert(constantToReplaceWith.isConstant()); assert(propositionToAssert.GetType() == BOOLEAN_TYPE); assert(node.GetValueWidth() == constantToReplaceWith.GetValueWidth()); fromTo.insert(make_pair(node, constantToReplaceWith)); toConjoin.push_back(propositionToAssert); } } // Write the constants into the main graph. ASTNodeMap cache; ASTNode result = SubstitutionMap::replace(top, fromTo, cache,nf); if (0 != toConjoin.size()) { // It doesn't happen very often. But the "toConjoin" might contain a variable // that was added to the substitution map (because the value was determined just now // during propagation. ASTNode conjunct = (1 == toConjoin.size())? toConjoin[0]: nf->CreateNode(AND,toConjoin); conjunct = simplifier->applySubstitutionMap(conjunct); result = nf->CreateNode(AND, result, conjunct); // conjoin the new conditions. } if (debug_print_graph_after) { ofstream file; file.open("afterCbitp.gdl"); PrintingHackfixedMap = fixedMap; printer::GDL_Print(file,top,&toString); file.close(); } assert(BVTypeCheck(result)); assert(status != CONFLICT); // conflict should have been seen earlier. return result; }