/* 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); } }
/******************************************************** * 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; }
string Bench_Print1(ostream &os, const ASTNode& n, map<ASTNode, string> *alreadyOutput) { assert(((n.GetKind() == SYMBOL) || (n.GetKind() == BVCONST) || n.GetValueWidth() <= 1)); assert(!n.IsNull()); map<ASTNode, string>::iterator it; if ((it = alreadyOutput->find(n)) != alreadyOutput->end()) return it->second; if (n.GetKind() == BVCONST) { (*alreadyOutput)[n] = bvconstToString(n); return (*alreadyOutput)[n]; } if (n.GetKind() == SYMBOL) { (*alreadyOutput)[n] = symbolToString(n); return (*alreadyOutput)[n]; } if (n.GetKind() == TRUE) { return "vdd"; } if (n.GetKind() == FALSE) { return "gnd"; } if (n.GetKind() == BVGETBIT) { assert(n[1].GetKind() == BVCONST); std::stringstream nn; nn << Bench_Print1(os, n[0], alreadyOutput) << "_" << Bench_Print1(os, n[1], alreadyOutput); (*alreadyOutput)[n] = nn.str(); return (*alreadyOutput)[n]; } std::stringstream nodeNameSS; nodeNameSS << "n" << n.GetNodeNum(); string thisNode = nodeNameSS.str(); (*alreadyOutput)[n] = thisNode; assert(n.Degree() > 0); std::stringstream output; // The bench format doesn't accept propositional ITEs. if (n.GetKind() == ITE) { assert(n.Degree() == 3); string p = Bench_Print1(os, n[0], alreadyOutput); string p1 = Bench_Print1(os, n[1], alreadyOutput); string p2 = Bench_Print1(os, n[2], alreadyOutput); os << thisNode << "_1 = AND(" << p << "," << p1 << ")" << endl; os << thisNode << "_2" << " = NOT(" << p << ")," << endl; os << thisNode << "_3" << " = AND(" << thisNode << "_2" << "," << p2 << ")" << endl; os << thisNode << "=" << "OR(," << thisNode << "_1" << "," << thisNode << "_3)" << endl; } else { if (n.Degree() > 2) { assert(n.GetKind() == AND || n.GetKind() == XOR || n.GetKind() == OR); // must be associative. std::deque<string> names; for (unsigned i = 0; i < n.Degree(); i++) names.push_back(Bench_Print1(os, n[i], alreadyOutput)); int id = 0; while (names.size() > 2) { string a = names.front(); names.pop_front(); string b = names.front(); names.pop_front(); std::stringstream thisName; thisName << thisNode << "___" << id++; output << thisName.str() << "=" << name(n.GetKind()) << "(" << a << "," << b << ")" << endl; names.push_back(thisName.str()); } assert(names.size() == 2); // last two now. string a = names.front(); names.pop_front(); string b = names.front(); names.pop_front(); output << thisNode << "=" << name(n.GetKind()) << "(" << a << "," << b << ")" << endl; os << output.str(); } else { output << thisNode << "=" << name(n.GetKind()) << "("; for (unsigned i = 0; i < n.Degree(); i++) { if (i >= 1) output << " , "; output << Bench_Print1(os, n[i], alreadyOutput); } os << output.str() << ")" << endl; } } return thisNode; }
// 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; }