// If the bits are totally fixed, then return a new matching ASTNode. ASTNode bitsToNode(const ASTNode& node, const FixedBits& bits) { ASTNode result; STPMgr & beev = *node.GetSTPMgr(); assert (bits.isTotallyFixed()); assert (!node.isConstant()); // Peformance. Shouldn't waste time calling it on constants. if (node.GetType() == BOOLEAN_TYPE) { if (bits.getValue(0)) { result = beev.CreateNode(TRUE); } else { result = beev.CreateNode(FALSE); } } else if (node.GetType() == BITVECTOR_TYPE) { result = beev.CreateBVConst(bits.GetBVConst(), node.GetValueWidth()); } else FatalError("sadf234s"); assert(result.isConstant()); return result; }
// Build the polarities, then iterate through fixing them. bool FindPureLiterals::topLevel(ASTNode& n, Simplifier* simplifier, STPMgr* stpMgr) { stpMgr->GetRunTimes()->start(RunTimes::PureLiterals); build(n, truePolarity); bool changed = false; map<ASTNode, polarity_type>::const_iterator it = nodeToPolarity.begin(); while (it != nodeToPolarity.end()) { const ASTNode& n = it->first; const polarity_type polarity = it->second; if (n.GetType() == BOOLEAN_TYPE && n.GetKind() == SYMBOL && polarity != bothPolarity) { if (polarity == truePolarity) simplifier->UpdateSubstitutionMap(n, stpMgr->ASTTrue); else { assert(polarity == falsePolarity); simplifier->UpdateSubstitutionMap(n, stpMgr->ASTFalse); } changed = true; } it++; } stpMgr->GetRunTimes()->stop(RunTimes::PureLiterals); return changed; }
bool containsArrayOps(const ASTNode& n, ASTNodeSet& visited) { if (visited.find(n) != visited.end()) return false; if (n.GetType() == ARRAY_TYPE) return true; for (int i =0; i < n.Degree();i++) if (containsArrayOps(n[i],visited)) return true; visited.insert(n); return false; }
// Propagates. No writing in of values. Doesn't assume the top is true. ConstantBitPropagation::ConstantBitPropagation(BEEV::Simplifier* _sm, NodeFactory* _nf,const ASTNode & top) { assert (BOOLEAN_TYPE == top.GetType()); assert (top.GetSTPMgr()->UserFlags.bitConstantProp_flag); status = NO_CHANGE; simplifier = _sm; nf = _nf; fixedMap = new NodeToFixedBitsMap(1000); // better to use the function that returns the number of nodes.. whatever that is. workList = new WorkList(top); dependents = new Dependencies(top); // List of the parents of a node. msm = new MultiplicationStatsMap(); // not fixing the topnode. propagate(); if (debug_cBitProp_messages) { cerr << "status:" << status <<endl; cerr << "ended propagation" << endl; printNodeWithFixings(); } // is there are good reason to clear out some of them?? #if 0 // remove constants, and things with nothing fixed. NodeToFixedBitsMap::NodeToFixedBitsMapType::iterator it = fixedMap->map->begin(); NodeToFixedBitsMap::NodeToFixedBitsMapType::iterator it_end = fixedMap->map->end(); while (it != it_end) { // No constants, nothing completely unfixed. if ( (it->second)->countFixed() == 0 ) { delete it->second; // making this a reference causes reading from freed memory. const ASTNode n = it->first; it++; fixedMap->map->erase(n); } else it++; } #endif topFixed = false; }
/* 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; }
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; }
// 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; }
/* This function transforms Array Reads, Read over Writes, Read over * ITEs into flattened form. * * Transform1: Suppose there are two array reads in the input * Read(A,i) and Read(A,j) over the same array. Then Read(A,i) is * replaced with a symbolic constant, say v1, and Read(A,j) is * replaced with the following ITE: * * ITE(i=j,v1,v2) * */ ASTNode ArrayTransformer::TransformArrayRead(const ASTNode& term) { assert(TransformMap != NULL); const unsigned int width = term.GetValueWidth(); if (READ != term.GetKind()) return term; ASTNodeMap::const_iterator iter; if ((iter = TransformMap->find(term)) != TransformMap->end()) return iter->second; //'term' is of the form READ(arrName, readIndex) const ASTNode& arrName = term[0]; const ASTNode& readIndex = TransformTerm(term[1]); ASTNode result; switch (arrName.GetKind()) { case SYMBOL: { /* input is of the form: READ(A, readIndex) * * output is of the from: A1, if this is the first READ over A * * ITE(previous_readIndex=readIndex,A1,A2) * * ..... */ { ArrType::const_iterator it; if ((it = arrayToIndexToRead.find(arrName)) != arrayToIndexToRead.end()) { std::map<ASTNode, ArrayRead>::const_iterator it2; if ((it2 = it->second.find(readIndex)) != it->second.end()) { result = it2->second.ite; break; } } } // Make up a new abstract variable. Build symbolic name // corresponding to array read. The symbolic name has 2 // components: stringname, and a count ASTNode CurrentSymbol = bm->CreateFreshVariable(term.GetIndexWidth(), term.GetValueWidth(), "array_" + std::string(arrName.GetName())); result = CurrentSymbol; if (!bm->UserFlags.ackermannisation) { // result is a variable here; it is an ite in the // else-branch } else if (bm->UserFlags.isSet("old_ack", "0")) { /* oops. * This version of ack. doesn't do what I thought it did. The STP 0.1 * version of Ack. produces simpler * expressions. I've put that in the next block. Trevor's thesis * measures AckITE using this implementation, * rather than the next one like it should have!!!! */ // Full Array transform if we're not doing read refinement. // list of array-read indices corresponding to arrName, seen while // traversing the AST tree. we need this list to construct the ITEs const arrTypeMap& new_read_Indices = arrayToIndexToRead[arrName]; arrTypeMap::const_iterator it2 = new_read_Indices.begin(); arrTypeMap::const_iterator it2end = new_read_Indices.end(); for (; it2 != it2end; it2++) { ASTNode cond = simp->CreateSimplifiedEQ(readIndex, it2->first); if (ASTFalse == cond) continue; if (ASTTrue == cond) { result = it2->second.ite; break; } result = simp->CreateSimplifiedTermITE(cond, it2->second.ite, result); } } else { // Full Array transform if we're not doing read refinement. // list of array-read indices corresponding to arrName, seen while // traversing the AST tree. we need this list to construct the ITEs vector<std::pair<ASTNode, ASTNode>> p = ack_pair[arrName]; vector<std::pair<ASTNode, ASTNode>>::const_reverse_iterator it2 = p.rbegin(); vector<std::pair<ASTNode, ASTNode>>::const_reverse_iterator it2end = p.rend(); for (; it2 != it2end; it2++) { ASTNode cond = simp->CreateSimplifiedEQ(readIndex, it2->first); if (ASTFalse == cond) continue; if (ASTTrue == cond) { result = it2->second; break; } result = simp->CreateSimplifiedTermITE(cond, it2->second, result); } ack_pair[arrName].push_back(make_pair(readIndex, CurrentSymbol)); } assert(arrName.GetType() == ARRAY_TYPE); arrayToIndexToRead[arrName].insert( make_pair(readIndex, ArrayRead(result, CurrentSymbol))); break; } case WRITE: { /* The input to this case is: READ((WRITE A i val) j) * * The output of this case is: ITE( (= i j) val (READ A j)) */ /* 1. arrName or term[0] is infact a WRITE(A,i,val) expression * * 2. term[1] is the read-index j * * 3. arrName[0] is the new arrName i.e. A. A can be either a SYMBOL or a nested WRITE. no other possibility * * 4. arrName[1] is the WRITE index i.e. i * * 5. arrName[2] is the WRITE value i.e. val (val can inturn * be an array read) */ ASTNode writeIndex = TransformTerm(arrName[1]); ASTNode writeVal = TransformTerm(arrName[2]); if (ARRAY_TYPE != arrName[0].GetType()) FatalError("TransformArray: " "An array write is being attempted on a non-array:", term); // if ((SYMBOL == arrName[0].GetKind() //|| WRITE == arrName[0].GetKind())) { ASTNode cond = simp->CreateSimplifiedEQ(writeIndex, readIndex); assert(BVTypeCheck(cond)); // If the condition is true, it saves iteratively transforming through // all the (possibly nested) arrays. if (ASTTrue == cond) { result = writeVal; } else { ASTNode readTerm = nf->CreateTerm(READ, width, arrName[0], readIndex); assert(BVTypeCheck(readTerm)); // The simplifying node factory may have produced // something that's not a READ. ASTNode readPushedIn = TransformTerm(readTerm); assert(BVTypeCheck(readPushedIn)); result = simp->CreateSimplifiedTermITE(cond, writeVal, readPushedIn); } } // Trevor: I've removed this code because I don't see the advantage in working // inside out. i.e. transforming read(write(ite(p,A,B),i,j),k), into // read(ite(p,write(A,i,j),write(B,i,j),k). That is bringing up the ite. // Without this code it will become: ite(i=k, j, read(ite(p,A,B),k)) #if 0 else if (ITE == arrName[0].GetKind()) { // pull out the ite from the write // pushes the write // through. ASTNode writeTrue = nf->CreateNode(WRITE, (arrName[0][1]), writeIndex, writeVal); writeTrue.SetIndexWidth(writeIndex.GetValueWidth()); writeTrue.SetValueWidth(writeVal.GetValueWidth()); assert(ARRAY_TYPE == writeTrue.GetType()); ASTNode writeFalse = nf->CreateNode(WRITE, (arrName[0][2]), writeIndex, writeVal); writeFalse.SetIndexWidth(writeIndex.GetValueWidth()); writeFalse.SetValueWidth(writeVal.GetValueWidth()); assert(ARRAY_TYPE == writeFalse.GetType()); result = (writeTrue == writeFalse) ? writeTrue : simp->CreateSimplifiedTermITE(TransformFormula(arrName[0][0]), writeTrue, writeFalse); result.SetIndexWidth(writeIndex.GetValueWidth()); result.SetValueWidth(writeVal.GetValueWidth()); assert(ARRAY_TYPE == result.GetType()); result = nf->CreateTerm(READ, writeVal.GetValueWidth(), result, readIndex); BVTypeCheck(result); result = TransformArrayRead(result); } else FatalError("TransformArray: Write over bad type."); #endif break; } case ITE: { /* READ((ITE cond thn els) j) * * is transformed into * * (ITE cond (READ thn j) (READ els j)) */ // pull out the ite from the read // pushes the read through. //(ITE cond thn els) ASTNode cond = arrName[0]; cond = TransformFormula(cond); const ASTNode& thn = arrName[1]; const ASTNode& els = arrName[2]; //(READ thn j) ASTNode thnRead = nf->CreateTerm(READ, width, thn, readIndex); assert(BVTypeCheck(thnRead)); //(READ els j) ASTNode elsRead = nf->CreateTerm(READ, width, els, readIndex); assert(BVTypeCheck(elsRead)); /* We try to call TransformTerm only if necessary, because it * introduces a new symbol for each read. The amount of work we * need to do later is based on the square of the number of symbols. */ if (ASTTrue == cond) { result = TransformTerm(thnRead); } else if (ASTFalse == cond) { result = TransformTerm(elsRead); } else { thnRead = TransformTerm(thnRead); elsRead = TransformTerm(elsRead); //(ITE cond (READ thn j) (READ els j)) result = simp->CreateSimplifiedTermITE(cond, thnRead, elsRead); } break; } default: FatalError("TransformArray: " "The READ is NOT over SYMBOL/WRITE/ITE", term); break; }
/******************************************************** * 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; }
// 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; }