// True if any descendants are arrays. bool containsArrayOps(const ASTNode& n) { NodeIterator ni(n, n.GetSTPMgr()->ASTUndefined, *n.GetSTPMgr()); ASTNode current; while ((current = ni.next()) != ni.end()) if (current.GetIndexWidth() > 0) return true; return false; }
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()
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); }
// 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; }
Result dispatchToMaximallyPrecise(const Kind k, vector<FixedBits*>& children, FixedBits& output, const ASTNode n) { #if WITHCBITP Signature signature; signature.kind = k; vector<FixedBits> childrenCopy; for (int i = 0; i < (int) children.size(); i++) childrenCopy.push_back(*(children[i])); FixedBits outputCopy(output); if (k == BVMULT) { // We've got some of multiply already implemented. So help it out by getting some done first. Result r = bvMultiplyBothWays(children, output, n.GetSTPMgr()); if (CONFLICT == r) return CONFLICT; } bool bad = maxPrecision(children, output, k, n.GetSTPMgr()); if (bad) return CONFLICT; if (!FixedBits::equals(outputCopy, output)) return CHANGED; for (int i = 0; i < (int) children.size(); i++) { if (!FixedBits::equals(*(children[i]), childrenCopy[i])) return CHANGED; } #endif return NOT_IMPLEMENTED; }
// 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; }
// 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()
Result dispatchToTransferFunctions(const Kind k, vector<FixedBits*>& children, FixedBits& output, const ASTNode n, MultiplicationStatsMap * msm) { Result result = NO_CHANGE; assert(!n.isConstant()); Result(*transfer)(vector<FixedBits*>&, FixedBits&); switch (k) { case READ: case WRITE: // do nothing. Seems difficult to track properly. return NO_CHANGE; break; #define MAPTFN(caseV, FN) case caseV: transfer = FN; break; // Shifting MAPTFN(BVLEFTSHIFT, bvLeftShiftBothWays) MAPTFN(BVRIGHTSHIFT, bvRightShiftBothWays) MAPTFN(BVSRSHIFT, bvArithmeticRightShiftBothWays) // Unsigned Comparison. MAPTFN(BVLT,bvLessThanBothWays) MAPTFN(BVLE,bvLessThanEqualsBothWays) MAPTFN(BVGT, bvGreaterThanBothWays) MAPTFN(BVGE, bvGreaterThanEqualsBothWays) // Signed Comparison. MAPTFN(BVSLT, bvSignedLessThanBothWays) MAPTFN(BVSGT,bvSignedGreaterThanBothWays) MAPTFN(BVSLE, bvSignedLessThanEqualsBothWays) MAPTFN(BVSGE, bvSignedGreaterThanEqualsBothWays) // Logic. MAPTFN(XOR,bvXorBothWays) MAPTFN(BVXOR, bvXorBothWays) MAPTFN(OR, bvOrBothWays) MAPTFN(BVOR, bvOrBothWays) MAPTFN(AND,bvAndBothWays) MAPTFN(BVAND,bvAndBothWays) MAPTFN(IFF, bvEqualsBothWays) MAPTFN(EQ, bvEqualsBothWays) MAPTFN(IMPLIES,bvImpliesBothWays) MAPTFN(NOT,bvNotBothWays) MAPTFN(BVNEG, bvNotBothWays) // OTHER MAPTFN(BVZX, bvZeroExtendBothWays) MAPTFN(BVSX, bvSignExtendBothWays) MAPTFN(BVUMINUS,bvUnaryMinusBothWays) MAPTFN(BVEXTRACT,bvExtractBothWays) MAPTFN(BVPLUS, bvAddBothWays) MAPTFN(BVSUB, bvSubtractBothWays) MAPTFN(ITE,bvITEBothWays) MAPTFN(BVCONCAT, bvConcatBothWays) #ifdef WITHCBITP case BVMULT: // handled specially later. case BVDIV: case BVMOD: case SBVDIV: case SBVREM: case SBVMOD: transfer = NULL; break; #endif default: { notHandled(k); return NO_CHANGE; } } #undef MAPTFN bool mult_like = false; #ifdef WITHCBITP // safe approximation to no overflow multiplication. if (k == BVMULT) { MultiplicationStats ms; result = bvMultiplyBothWays(children, output, n.GetSTPMgr(),&ms); if (CONFLICT != result) msm->map[n] = ms; mult_like=true; } else if (k == BVDIV) { result = bvUnsignedDivisionBothWays(children, output, n.GetSTPMgr()); mult_like=true; } else if (k == BVMOD) { result = bvUnsignedModulusBothWays(children, output, n.GetSTPMgr()); mult_like=true; } else if (k == SBVDIV) { result = bvSignedDivisionBothWays(children, output, n.GetSTPMgr()); mult_like=true; } else if (k == SBVREM) { result = bvSignedRemainderBothWays(children, output, n.GetSTPMgr()); mult_like=true; } else if (k == SBVMOD) { result = bvSignedModulusBothWays(children, output, n.GetSTPMgr()); mult_like=true; } else #endif result = transfer(children, output); if (mult_like && output_mult_like) { cerr << output << "="; cerr << *children[0] << k; cerr << *children[1] << std::endl; } 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; }