bool compareDfaOrigins(const DfaStates& nfasWithInput, DfaVertex* dfa2p) { // Return true if the NFA nodes both DFAs came from are the same list // Assume there are no duplicates in either input list or NFAs under dfa2 nextStep(); // Mark all input vertexes int num1s = 0; for (DfaStates::const_iterator nfaIt=nfasWithInput.begin(); nfaIt!=nfasWithInput.end(); ++nfaIt) { DfaVertex* nfaStatep = *nfaIt; nfaStatep->user(m_step); num1s++; } if (!num1s) v3fatalSrc("DFA node construction that contains no NFA states"); // Check comparison; must all be marked // (Check all in dfa2p were in dfa1p) int num2s = 0; for (V3GraphEdge* dfaEdgep = dfa2p->outBeginp(); dfaEdgep; dfaEdgep=dfaEdgep->outNextp()) { if (nfaState(dfaEdgep->top())) { if (dfaEdgep->top()->user() != m_step) return false; num2s++; } } // If we saw all of the nodes, then they have the same number of hits // (Else something in dfa1p that wasn't in dfa2p) if (num1s != num2s) return false; // Match return true; }
uint32_t V3GraphVertex::outHash() const { uint32_t hash=0; for (V3GraphEdge* edgep = this->outBeginp(); edgep; edgep=edgep->outNextp()) { hash += cvtToHash(edgep->top()); } return hash; }
void optimize_orphans() { // Remove states that don't come from start // Presumably the previous optimization orphaned them. // Vertex::m_user begin: 1 indicates on the work list, 2 processed // (Otherwise we might have nodes on the list twice, and reference after deleting them.) m_graphp->userClearVertices(); DfaVertex* startp = graphp()->findStart(); stack<V3GraphVertex*> workps; workps.push(startp); // Mark all nodes connected to start while (!workps.empty()) { V3GraphVertex* vertexp = workps.top(); workps.pop(); vertexp->user(2); // Processed // Add nodes from here to the work list for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { V3GraphVertex* tovertexp = edgep->top(); if (!tovertexp->user()) { workps.push(tovertexp); tovertexp->user(1); } } } // Delete all nodes not connected for (V3GraphVertex* nextp,*vertexp = m_graphp->verticesBeginp(); vertexp; vertexp=nextp) { nextp = vertexp->verticesNextp(); if (!vertexp->user()) { vertexp->unlinkDelete(m_graphp); vertexp=NULL; } } }
// Returns only the result from the LAST vertex iterated over AstNUser* iterateInEdges(GateGraphBaseVisitor& v, AstNUser* vup=NULL) { AstNUser* retp = NULL; for (V3GraphEdge* edgep = inBeginp(); edgep; edgep = edgep->inNextp()) { retp = dynamic_cast<GateEitherVertex*>(edgep->fromp())->accept(v, vup); } return retp; }
bool isDead(DfaVertex* vertexp) { // A state is dead if not accepting, and goes nowhere if (vertexp->accepting() || vertexp->start()) return false; for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { if (edgep->top() != vertexp) return false; } return true; }
// Populate *outp with a minimal perfect matching of *this. // *outp must be initially empty. void perfectMatching(const std::vector<T_Key>& oddKeys, TspGraphTmpl* outp) { UASSERT(outp->empty(), "Output graph must start empty"); std::list<Vertex*> odds = keysToVertexList(oddKeys); vl_unordered_set<Vertex*> unmatchedOdds; typedef typename std::list<Vertex*>::iterator VertexListIt; for (VertexListIt it = odds.begin(); it != odds.end(); ++it) { outp->addVertex((*it)->key()); unmatchedOdds.insert(*it); } UASSERT(odds.size() % 2 == 0, "number of odd-order nodes should be even"); // TODO: The true Chrisofides algorithm calls for minimum-weight // perfect matching. Instead, we have a simple greedy algorithm // which might get close to the minimum, maybe, with luck? // // TODO: Revisit this. It's possible to compute the true minimum in // N*N*log(N) time using variants of the Blossom algorithm. // Implementing Blossom looks hard, maybe we can use an existing // open source implementation -- for example the "LEMON" library // which has a TSP solver. // ----- // Reuse the comparator from Prim's routine. The logic is the same // here. Note that the two V3GraphEdge's representing a single // bidir edge will collide in the pendingEdges set here, but this // is OK, we'll ignore the direction on the edge anyway. EdgeCmp cmp; typedef std::set<V3GraphEdge*, EdgeCmp&> PendingEdgeSet; PendingEdgeSet pendingEdges(cmp); for (VertexListIt it = odds.begin(); it != odds.end(); ++it) { for (V3GraphEdge* edgep = (*it)->outBeginp(); edgep; edgep = edgep->outNextp()) { pendingEdges.insert(edgep); } } // Iterate over all edges, in order from low to high cost. // For any edge whose ends are both odd-order vertices which // haven't been matched yet, match them. for (typename PendingEdgeSet::iterator it = pendingEdges.begin(); it != pendingEdges.end(); ++it) { Vertex* fromp = castVertexp((*it)->fromp()); Vertex* top = castVertexp((*it)->top()); if ((unmatchedOdds.find(fromp) != unmatchedOdds.end()) && (unmatchedOdds.find(top) != unmatchedOdds.end())) { outp->addEdge(fromp->key(), top->key(), (*it)->weight()); unmatchedOdds.erase(fromp); unmatchedOdds.erase(top); } } UASSERT(unmatchedOdds.empty(), "Algorithm should have processed all vertices"); }
void nafgMarkRecurse(V3GraphVertex* vertexp, uint32_t generation) { // Backwards mark user() on the path we recurse //UINFO(9," nafgMark: v "<<(void*)(vertexp)<<" "<<vertexp->name()<<endl); for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { //UINFO(9," nafgMark: "<<(void*)(edgep)<<" "<<edgep->name()<<endl); edgep->user(generation); nafgMarkRecurse(edgep->fromp(), generation); } }
void V3Graph::userClearEdges() { // Clear user() in all of tree for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { edgep->user(0); edgep->userp(NULL); // Its a union, but might be different size than user() } } }
void GateVisitor::consumedMarkRecurse(GateEitherVertex* vertexp) { if (vertexp->user()) return; // Already marked vertexp->user(true); if (!vertexp->consumed()) vertexp->setConsumed("propagated"); // Walk sources and mark them too for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { GateEitherVertex* eFromVertexp = (GateEitherVertex*)edgep->fromp(); consumedMarkRecurse(eFromVertexp); } }
uint32_t V3GraphVertex::inHash() const { // We want the same hash ignoring the order of edges. // So we need an associative operator, like XOR. // However with XOR multiple edges to the same source will cancel out, // so we use ADD. (Generally call this only after removing duplicates though) uint32_t hash=0; for (V3GraphEdge* edgep = this->inBeginp(); edgep; edgep=edgep->inNextp()) { hash += cvtToHash(edgep->fromp()); } return hash; }
void dumpGraph(std::ostream& os, const string& nameComment) const { // UINFO(0) as controlled by caller os<<"At "<<nameComment<<", dumping graph. Keys:\n"; for (V3GraphVertex* vxp = verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { Vertex* tspvp = castVertexp(vxp); os<<" "<<tspvp->key()<<endl; for (V3GraphEdge* edgep = tspvp->outBeginp(); edgep; edgep = edgep->outNextp()) { Vertex* neighborp = castVertexp(edgep->top()); os<<" has edge "<<edgep->user()<<" to "<<neighborp->key()<<endl; } } }
void V3GraphVertex::rerouteEdges(V3Graph* graphp) { // Make new edges for each from/to pair for (V3GraphEdge* iedgep = inBeginp(); iedgep; iedgep=iedgep->inNextp()) { for (V3GraphEdge* oedgep = outBeginp(); oedgep; oedgep=oedgep->outNextp()) { new V3GraphEdge (graphp, iedgep->fromp(), oedgep->top(), min(iedgep->weight(),oedgep->weight()), iedgep->cutable() && oedgep->cutable()); } } // Remove old edges unlinkEdges(graphp); }
std::vector<T_Key> getOddDegreeKeys() const { std::vector<T_Key> result; for (V3GraphVertex* vxp = verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { Vertex* tspvp = castVertexp(vxp); vluint32_t degree = 0; for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) { degree++; } if (degree & 1) { result.push_back(tspvp->key()); } } return result; }
void V3Graph::dump(ostream& os) { // This generates a file used by graphviz, http://www.graphviz.org os<<" Graph:\n"; // Print vertices for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { os<<"\tNode: "<<vertexp->name(); if (vertexp->color()) os<<" color="<<vertexp->color(); os<<endl; // Print edges for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) { dumpEdge (os, vertexp, edgep); } for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { dumpEdge (os, vertexp, edgep); } } }
AstNode* nafgCreateRecurse(V3GraphVertex* vertexp, uint32_t generation) { // Forewards follow user() marked previously and build tree AstNode* nodep = NULL; // OR across all edges found at this level //UINFO(9," nafgEnter: v "<<(void*)(vertexp)<<" "<<vertexp->name()<<endl); for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { if (edgep->user() == generation) { GaterEdge* cedgep = static_cast<GaterEdge*>(edgep); AstNode* eqnp = NULL; //UINFO(9," nafgFollow: "<<(void*)(edgep)<<" "<<edgep->name()<<endl); if (dynamic_cast<GaterHeadVertex*>(edgep->fromp())) { // Just OR in all lower terms eqnp = nafgCreateRecurse(edgep->top(), generation); } else if (GaterIfVertex* cVxp = dynamic_cast<GaterIfVertex*>(edgep->fromp())) { // Edges from IFs represent a real IF branch in the equation tree //UINFO(9," ifver "<<(void*)(edgep)<<" cc"<<edgep->dotColor()<<endl); eqnp = cVxp->nodep()->condp()->cloneTree(true); if (eqnp && cedgep->ifelseFalse()) { eqnp = new AstNot(eqnp->fileline(),eqnp); } // We need to AND this term onto whatever was found below it AstNode* belowp = nafgCreateRecurse(edgep->top(), generation); if (belowp) eqnp = new AstAnd(eqnp->fileline(),eqnp,belowp); } // Top level we could choose to make multiple gaters, or ORs under the gater // Right now we'll put OR lower down and let other optimizations deal if (nodep) nodep = new AstOr(eqnp->fileline(),nodep,eqnp); else nodep = eqnp; //if (debug()>=9) nodep->dumpTree(cout," followExpr: "); } } //UINFO(9," nafgExit: "<<(void*)(vertexp)<<" "<<vertexp->name()<<endl); return nodep; }
void pruneDepsOnInputs() { for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { if (!vertexp->outBeginp() && dynamic_cast<SplitVarStdVertex*>(vertexp)) { if (debug() >= 9) { SplitVarStdVertex* stdp = (SplitVarStdVertex*)(vertexp); UINFO(0, "Will prune deps on var "<<stdp->nodep()<<endl); stdp->nodep()->dumpTree(cout, "- "); } for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) { SplitEdge* oedgep = dynamic_cast<SplitEdge*>(edgep); oedgep->setIgnoreThisStep(); } } } }
uint32_t hashDfaOrigins(DfaVertex* dfaStatep) { // Find the NFA states this dfa came from, // Record a checksum, so we can search for it later by the list of nfa nodes. // The order of the nodes is not deterministic; the hash thus must not depend on order of edges uint32_t hash = 0; // Foreach NFA state (this DFA state was formed from) if (debug()) nextStep(); for (V3GraphEdge* dfaEdgep = dfaStatep->outBeginp(); dfaEdgep; dfaEdgep=dfaEdgep->outNextp()) { if (nfaState(dfaEdgep->top())) { DfaVertex* nfaStatep = static_cast<DfaVertex*>(dfaEdgep->top()); hash ^= hashVertex(nfaStatep); if (debug()) { if (nfaStatep->user()==m_step) v3fatalSrc("DFA state points to duplicate NFA state."); nfaStatep->user(m_step); } } } return hash; }
virtual AstNUser* visit(GateVarVertex *vvertexp, AstNUser*) { // Check that we haven't been here before if (vvertexp->varScp()->user2()) return NULL; vvertexp->varScp()->user2(true); AstNodeVarRef* dupVarRefp = (AstNodeVarRef*) vvertexp->iterateInEdges(*this, (AstNUser*) vvertexp); if (dupVarRefp && vvertexp->inSize1()) { V3GraphEdge* edgep = vvertexp->inBeginp(); GateLogicVertex* lvertexp = (GateLogicVertex*)edgep->fromp(); if (!vvertexp->dedupable()) vvertexp->varScp()->v3fatalSrc("GateLogicVertex* visit should have returned NULL if consumer var vertex is not dedupable."); GateOkVisitor okVisitor(lvertexp->nodep(), false, true); if (okVisitor.isSimple()) { AstVarScope* dupVarScopep = dupVarRefp->varScopep(); GateVarVertex* dupVvertexp = (GateVarVertex*) (dupVarScopep->user1p()); UINFO(4,"replacing " << vvertexp << " with " << dupVvertexp << endl); ++m_numDeduped; // Replace all of this varvertex's consumers with dupVarRefp for (V3GraphEdge* outedgep = vvertexp->outBeginp();outedgep;) { GateLogicVertex* consumeVertexp = dynamic_cast<GateLogicVertex*>(outedgep->top()); AstNode* consumerp = consumeVertexp->nodep(); GateElimVisitor elimVisitor(consumerp,vvertexp->varScp(),dupVarRefp); outedgep = outedgep->relinkFromp(dupVvertexp); } // Propogate attributes dupVvertexp->propagateAttrClocksFrom(vvertexp); // Remove inputs links while (V3GraphEdge* inedgep = vvertexp->inBeginp()) { inedgep->unlinkDelete(); VL_DANGLING(inedgep); } // replaceAssigns() does the deleteTree on lvertexNodep in a later step AstNode* lvertexNodep = lvertexp->nodep(); lvertexNodep->unlinkFrBack(); vvertexp->varScp()->valuep(lvertexNodep); lvertexNodep = NULL; vvertexp->user(true); lvertexp->user(true); } } return NULL; }
void V3Graph::clear() { // Empty it of all points, as if making a new object // Delete the old edges for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; /*BELOW*/) { V3GraphEdge* nextp = edgep->outNextp(); delete edgep; edgep = nextp; } vertexp->outUnlink(); } // Delete the old vertices for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; /*BELOW*/) { V3GraphVertex* nextp = vertexp->verticesNextp(); delete vertexp; vertexp = nextp; } verticesUnlink(); }
int GaterVertex::sortCmp(const V3GraphVertex* rhsp) const { const GaterVertex* crhsp = static_cast<const GaterVertex*>(rhsp); // We really only care about ordering Var's together, but... // First put same type together if (typeNum() < crhsp->typeNum()) return -1; if (typeNum() > crhsp->typeNum()) return 1; // If variable, group by same input fanin // (know they're the same type based on above compare) if (dynamic_cast<const GaterVarVertex*>(this)) { // We've already sorted by edges, so just see if same tree // If this gets too slow, we could compute a hash up front V3GraphEdge* lEdgep = this->inBeginp(); V3GraphEdge* rEdgep = rhsp->inBeginp(); while (lEdgep && rEdgep) { const GaterEdge* clEdgep = static_cast<const GaterEdge*>(lEdgep); const GaterEdge* crEdgep = static_cast<const GaterEdge*>(rEdgep); if (lEdgep->fromp()->rank() < rEdgep->fromp()->rank()) return -1; if (lEdgep->fromp()->rank() > rEdgep->fromp()->rank()) return 1; if (clEdgep->ifelse() < crEdgep->ifelse()) return -1; if (clEdgep->ifelse() > crEdgep->ifelse()) return 1; lEdgep = lEdgep->inNextp(); rEdgep = rEdgep->inNextp(); } if (!lEdgep && !rEdgep) return 0; return lEdgep ? -1 : 1; } // Finally by rank of this vertex if (rank() < rhsp->rank()) return -1; if (rank() > rhsp->rank()) return 1; return 0; }
void optimize_no_outbound() { // Non-accepting states with no outbound transitions may be // deleted. Then, any arcs feeding those states, and perhaps those // states... // Vertex::m_user begin: 1 indicates on the work list // (Otherwise we might have nodes on the list twice, and reference after deleting them.) m_graphp->userClearVertices(); // Find all dead vertexes stack<DfaVertex*> workps; for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { if (DfaVertex* vvertexp = dynamic_cast<DfaVertex*>(vertexp)) { workps.push(vvertexp); vertexp->user(1); } else { // If ever remove this, need dyn cast below v3fatalSrc("Non DfaVertex in dfa graph"); } } // While deadness... Delete and find new dead nodes. while (!workps.empty()) { DfaVertex* vertexp = workps.top(); workps.pop(); vertexp->user(0); if (isDead(vertexp)) { // Add nodes that go here to the work list for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) { DfaVertex* fromvertexp = static_cast<DfaVertex*>(edgep->fromp()); if (fromvertexp != vertexp && !fromvertexp->user()) { workps.push(static_cast<DfaVertex*>(fromvertexp)); fromvertexp->user(1); } } // Transitions to this state removed by the unlink function vertexp->unlinkDelete(m_graphp); vertexp=NULL; } } }
bool GateVisitor::elimLogicOkOutputs(GateLogicVertex* consumeVertexp, const GateOkVisitor& okVisitor) { // Return true if can optimize // Return false if the consuming logic has an output signal that the replacement logic has as an input typedef set<AstVarScope*> VarScopeSet; // Use map to find duplicates between two lists VarScopeSet varscopes; // Replacement logic usually has shorter input list, so faster to build list based on it const GateVarRefList& rhsVarRefs = okVisitor.rhsVarRefs(); for (GateVarRefList::const_iterator it = rhsVarRefs.begin(); it != rhsVarRefs.end(); ++it) { AstVarScope* vscp = (*it)->varScopep(); if (varscopes.find(vscp) == varscopes.end()) varscopes.insert(vscp); } for (V3GraphEdge* edgep = consumeVertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { GateVarVertex* consVVertexp = dynamic_cast<GateVarVertex*>(edgep->top()); AstVarScope* vscp = consVVertexp->varScp(); if (varscopes.find(vscp) != varscopes.end()) { UINFO(9," Block-unopt, insertion generates input vscp "<<vscp<<endl); return false; } } return true; }
void V3GraphVertex::unlinkEdges(V3Graph* graphp) { for (V3GraphEdge* edgep = outBeginp(); edgep; /*BELOW*/) { V3GraphEdge* nextp = edgep->outNextp(); edgep->unlinkDelete(); edgep = nextp; } for (V3GraphEdge* edgep = inBeginp(); edgep; /*BELOW*/) { V3GraphEdge* nextp = edgep->inNextp(); edgep->unlinkDelete(); edgep = nextp; } }
void findNfasWithInput(DfaVertex* dfaStatep, DfaInput input, DfaStates& nfasWithInput) { // Return all NFA states, with the given input transition from // the nfa states a given dfa state was constructed from. nextStep(); nfasWithInput.clear(); // NFAs with given input // Foreach NFA state (this DFA state was formed from) for (V3GraphEdge* dfaEdgep = dfaStatep->outBeginp(); dfaEdgep; dfaEdgep=dfaEdgep->outNextp()) { if (nfaState(dfaEdgep->top())) { DfaVertex* nfaStatep = static_cast<DfaVertex*>(dfaEdgep->top()); // Foreach input transition (on this nfaStatep) for (V3GraphEdge* nfaEdgep = nfaStatep->outBeginp(); nfaEdgep; nfaEdgep=nfaEdgep->outNextp()) { DfaEdge* cNfaEdgep = static_cast<DfaEdge*>(nfaEdgep); if (cNfaEdgep->input() == input) { DfaVertex* nextStatep = static_cast<DfaVertex*>(cNfaEdgep->top()); if (unseenNfaThisStep(nextStatep)) { // Not processed? nfasWithInput.push_back(nextStatep); nextStatep->user(m_step); UINFO(9," Reachable "<<nextStatep<<endl); } } } } } // Expand the nfasWithInput list to include epsilon states reachable by those on nfasWithInput for (DfaStates::iterator nfaIt=nfasWithInput.begin(); nfaIt!=nfasWithInput.end(); ++nfaIt) { DfaVertex* nfaStatep = *nfaIt; // Foreach epsilon-reachable (on this nfaStatep) for (V3GraphEdge* nfaEdgep = nfaStatep->outBeginp(); nfaEdgep; nfaEdgep=nfaEdgep->outNextp()) { DfaEdge* cNfaEdgep = static_cast<DfaEdge*>(nfaEdgep); if (cNfaEdgep->epsilon()) { DfaVertex* nextStatep = static_cast<DfaVertex*>(cNfaEdgep->top()); if (unseenNfaThisStep(nextStatep)) { // Not processed? nfasWithInput.push_back(nextStatep); nextStatep->user(m_step); UINFO(9," Epsilon Reachable "<<nextStatep<<endl); } } } } }
void simplifyIfElseRecurse(V3GraphVertex* vertexp) { // From bottom-up, propagate duplicate IF/ELSE branches to grandparent for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { simplifyIfElseRecurse(edgep->top()); } //UINFO(9,"IERecurse "<<vertexp<<endl); if (dynamic_cast<GaterIfVertex*>(vertexp)) { // Clear indications for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { edgep->top()->user(VU_NONE); } // Mark nodes on to/from side for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { V3GraphVertex* toVxp = edgep->top(); GaterEdge* cedgep = static_cast<GaterEdge*>(edgep); // We may mark this twice in one pass - if so it's duplicated; no worries if (cedgep->ifelseTrue()) toVxp->user(toVxp->user() | VU_IF); if (cedgep->ifelseFalse()) toVxp->user(toVxp->user() | VU_ELSE); //UINFO(9," mark "<<edgep<<" "<<toVxp<<endl); } // Any with both IF & ELSE mark get removal mark, and new parent edge for (V3GraphEdge* nextp,* edgep = vertexp->outBeginp(); edgep; edgep = nextp) { nextp = edgep->outNextp(); // We may edit the list V3GraphVertex* toVxp = edgep->top(); //UINFO(9," to "<<toVxp->user()<<" "<<toVxp<<endl); if ((toVxp->user() & VU_IF) && (toVxp->user() & VU_ELSE)) { edgep->unlinkDelete(); edgep = NULL; if (!(toVxp->user() & VU_MADE)) { // Make an edge only once toVxp->user(toVxp->user() | VU_MADE); GaterEdge* inedgep = static_cast<GaterEdge*>(vertexp->inBeginp()); V3GraphVertex* grandparent = inedgep->fromp(); new GaterEdge(&m_graph, grandparent, toVxp, inedgep->ifelse()); } } } } }
void combineGraph(const TspGraphTmpl& g) { vl_unordered_set<vluint32_t> edges_done; for (V3GraphVertex* vxp = g.verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { Vertex* fromp = castVertexp(vxp); for (V3GraphEdge* edgep = fromp->outBeginp(); edgep; edgep = edgep->outNextp()) { Vertex* top = castVertexp(edgep->top()); if (edges_done.find(edgep->user()) == edges_done.end()) { addEdge(fromp->key(), top->key(), edgep->weight()); edges_done.insert(edgep->user()); } } } }
void simplifyGrandRecurse(V3GraphVertex* vertexp, uint32_t depth) { // From top-down delete any vars that grandparents source // IE A -> B -> C -> VAR // \----------^ //UINFO(9,"GRecurse "<<depth<<" "<<vertexp<<endl); // Mark all variables to be swept for (V3GraphEdge *nextp, *edgep = vertexp->outBeginp(); edgep; edgep=nextp) { nextp = edgep->outNextp(); // We may edit the list if (GaterVarVertex* toVxp = dynamic_cast<GaterVarVertex*>(edgep->top())) { if (toVxp->user() && toVxp->user() < depth) { // A recursion "above" us marked it, // Remove this edge, it's redundant with the upper edge edgep->unlinkDelete(); edgep=NULL; } else { GaterEdge* cedgep = static_cast<GaterEdge*>(edgep); if (cedgep->ifelseBoth()) { toVxp->user(depth); } } } } // Recurse for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { simplifyGrandRecurse(edgep->top(), depth+1); } // Clean our marks for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { V3GraphVertex* toVxp = edgep->top(); if (toVxp->user() && toVxp->user() < depth) { // A recursion "above" us marked it; don't mess with it } else { toVxp->user(0); // We marked it originally, so unmark now } } // Delete any If nodes with no children // Last, as want bottom-up cleanup for (V3GraphEdge *nextp, *edgep = vertexp->outBeginp(); edgep; edgep=nextp) { nextp = edgep->outNextp(); // We may edit the list if (GaterIfVertex* toVxp = dynamic_cast<GaterIfVertex*>(edgep->top())) { if (!toVxp->outBeginp()) { if (!nextp || nextp->top() != edgep->top()) { // Else next would disappear; we'll do it next loop toVxp->unlinkDelete(&m_graph); toVxp=NULL; edgep=NULL; } } } } }
void colorAlwaysGraph() { // Color the graph to indicate subsets, each of which // we can split into its own always block. m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue); // Some vars are primary inputs to the always block; prune // edges on those vars. Reasoning: if two statements both depend // on primary input A, it's ok to split these statements. Whereas // if they both depend on locally-generated variable B, the statements // must be kept together. SplitEdge::incrementStep(); pruneDepsOnInputs(); // For any 'if' node whose deps have all been pruned // (meaning, its conditional expression only looks at primary // inputs) prune all edges that depend on the 'if'. for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { SplitLogicVertex* logicp = dynamic_cast<SplitLogicVertex*>(vertexp); if (!logicp) continue; AstNodeIf* ifNodep = VN_CAST(logicp->nodep(), NodeIf); if (!ifNodep) continue; bool pruneMe = true; for (V3GraphEdge* edgep = logicp->outBeginp(); edgep; edgep = edgep->outNextp()) { SplitEdge* oedgep = dynamic_cast<SplitEdge*>(edgep); if (!oedgep->ignoreThisStep()) { // This if conditional depends on something we can't // prune -- a variable generated in the current block. pruneMe = false; // When we can't prune dependencies on the conditional, // give a hint about why... if (debug() >= 9) { V3GraphVertex* vxp = oedgep->top(); SplitNodeVertex* nvxp = dynamic_cast<SplitNodeVertex*>(vxp); UINFO(0, "Cannot prune if-node due to edge "<<oedgep<< " pointing to node "<<nvxp->nodep()<<endl); nvxp->nodep()->dumpTree(cout, "- "); } break; } } if (!pruneMe) continue; // This if can be split; prune dependencies on it. for (V3GraphEdge* edgep = logicp->inBeginp(); edgep; edgep = edgep->inNextp()) { SplitEdge* oedgep = dynamic_cast<SplitEdge*>(edgep); oedgep->setIgnoreThisStep(); } } if (debug()>=9) { m_graph.dumpDotFilePrefixed("splitg_nodup", false); } // Weak coloring to determine what needs to remain grouped // in a single always. This follows all edges excluding: // - those we pruned above // - PostEdges, which are done later m_graph.weaklyConnected(&SplitEdge::followScoreboard); }
void cleanupBlockGraph(AstNode* nodep) { // Transform the graph into what we need UINFO(5, "ReorderBlock "<<nodep<<endl); m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue); if (debug()>=9) { m_graph.dumpDotFilePrefixed("reorderg_nodup", false); //m_graph.dump(); cout<<endl; } // Mark all the logic for this step // Vertex::m_user begin: true indicates logic for this step m_graph.userClearVertices(); for (AstNode* nextp=nodep; nextp; nextp=nextp->nextp()) { SplitLogicVertex* vvertexp = (SplitLogicVertex*)nextp->user3p(); vvertexp->user(true); } // If a var vertex has only inputs, it's a input-only node, // and can be ignored for coloring **this block only** SplitEdge::incrementStep(); pruneDepsOnInputs(); // For reordering this single block only, mark all logic // vertexes not involved with this step as unimportant for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { if (SplitLogicVertex* vvertexp = dynamic_cast<SplitLogicVertex*>(vertexp)) { if (!vvertexp->user()) { for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) { SplitEdge* oedgep = dynamic_cast<SplitEdge*>(edgep); oedgep->setIgnoreThisStep(); } for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { SplitEdge* oedgep = dynamic_cast<SplitEdge*>(edgep); oedgep->setIgnoreThisStep(); } } } } // Weak coloring to determine what needs to remain in order // This follows all step-relevant edges excluding PostEdges, which are done later m_graph.weaklyConnected(&SplitEdge::followScoreboard); // Add hard orderings between all nodes of same color, in the order they appeared vl_unordered_map<uint32_t, SplitLogicVertex*> lastOfColor; for (AstNode* nextp=nodep; nextp; nextp=nextp->nextp()) { SplitLogicVertex* vvertexp = (SplitLogicVertex*)nextp->user3p(); uint32_t color = vvertexp->color(); if (!color) nextp->v3fatalSrc("No node color assigned"); if (lastOfColor[color]) { new SplitStrictEdge(&m_graph, lastOfColor[color], vvertexp); } lastOfColor[color] = vvertexp; } // And a real ordering to get the statements into something reasonable // We don't care if there's cutable violations here... // Non-cutable violations should be impossible; as those edges are program-order if (debug()>=9) m_graph.dumpDotFilePrefixed((string)"splitg_preo", false); m_graph.acyclic(&SplitEdge::followCyclic); m_graph.rank(&SplitEdge::followCyclic); // Or order(), but that's more expensive if (debug()>=9) m_graph.dumpDotFilePrefixed((string)"splitg_opt", false); }
void main() { UINFO(5,"Dfa to Nfa conversion...\n"); // Vertex::color() begin: 1 indicates vertex on DFA graph, 0=NFA graph m_graphp->clearColors(); // Vertex::m_user begin: # indicates processed this m_step number m_graphp->userClearVertices(); if (debug()>=6) m_graphp->dumpDotFilePrefixed("dfa_nfa"); // Find NFA start DfaVertex* nfaStartp = graphp()->findStart(); // Create new DFA State (start state) from the NFA states DfaVertex* dfaStartp = newDfaVertex(nfaStartp); DfaStates dfaUnprocps; // Unprocessed DFA nodes dfaUnprocps.push_back(dfaStartp); UINFO(5,"Starting state conversion...\n"); // Form DFA starting state from epsilon closure of NFA start nextStep(); DfaStates workps; workps.push_back(nfaStartp); while (!workps.empty()) { // While work DfaVertex* nfaStatep = workps.back(); workps.pop_back(); //UINFO(9," Processing "<<nfaStatep<<endl); nfaStatep->user(m_step); // Mark as processed // Add a edge so we can find NFAs from a given DFA. // The NFA will never see this edge, because we only look at TO edges. new DfaEdge(graphp(), dfaStartp, nfaStatep, DfaEdge::NA()); // Find epsilon closure of this nfa node, and destinations to work list for (V3GraphEdge* nfaEdgep = nfaStatep->outBeginp(); nfaEdgep; nfaEdgep=nfaEdgep->outNextp()) { DfaEdge* cNfaEdgep = static_cast<DfaEdge*>(nfaEdgep); DfaVertex* nfaStatep = static_cast<DfaVertex*>(nfaEdgep->top()); //UINFO(9," Consider "<<nfaEdgep->top()<<" EP "<<cNfaEdgep->epsilon()<<endl); if (cNfaEdgep->epsilon() && unseenNfaThisStep(nfaStatep)) { // Not processed? workps.push_back(nfaStatep); } } } if (debug()>=6) m_graphp->dumpDotFilePrefixed("dfa_start"); insertDfaOrigins(dfaStartp); int i=0; UINFO(5,"Main state conversion...\n"); while (!dfaUnprocps.empty()) { DfaVertex* dfaStatep = dfaUnprocps.back(); dfaUnprocps.pop_back(); UINFO(9," On dfaState "<<dfaStatep<<endl); // From this dfaState, what corresponding nfaStates have what inputs? set<DfaInput> inputs; // Foreach NFA state (this DFA state was formed from) for (V3GraphEdge* dfaEdgep = dfaStatep->outBeginp(); dfaEdgep; dfaEdgep=dfaEdgep->outNextp()) { if (nfaState(dfaEdgep->top())) { DfaVertex* nfaStatep = static_cast<DfaVertex*>(dfaEdgep->top()); // Foreach input on this nfaStatep for (V3GraphEdge* nfaEdgep = nfaStatep->outBeginp(); nfaEdgep; nfaEdgep=nfaEdgep->outNextp()) { DfaEdge* cNfaEdgep = static_cast<DfaEdge*>(nfaEdgep); if (!cNfaEdgep->epsilon()) { if (inputs.find(cNfaEdgep->input()) == inputs.end()) { inputs.insert(cNfaEdgep->input()); UINFO(9," Input to "<<dfaStatep<<" is "<<(void*)(cNfaEdgep->input())<<" via "<<nfaStatep<<endl); } } } } } // Foreach input state (NFA inputs of this DFA state) for (set<DfaInput>::const_iterator inIt=inputs.begin(); inIt!=inputs.end(); ++inIt) { DfaInput input = *inIt; UINFO(9," ==="<<++i<<"=======================\n"); UINFO(9," On input "<<(void*)(input)<<endl); // Find all states reachable for given input DfaStates nfasWithInput; findNfasWithInput(dfaStatep, input, nfasWithInput/*ref*/); // nfasWithInput now maps to the DFA we want a transition to. // Does a DFA already exist with this, and only this subset of NFA's? DfaVertex* toDfaStatep = findDfaOrigins(nfasWithInput); if (!toDfaStatep) { // Doesn't exist, make new dfa state corresponding to this one, toDfaStatep = newDfaVertex(); dfaUnprocps.push_back(toDfaStatep); // Add to process list // Track what nfa's point to it. for (DfaStates::const_iterator nfaIt=nfasWithInput.begin(); nfaIt!=nfasWithInput.end(); ++nfaIt) { UINFO(9," NewContainsNfa "<<*nfaIt<<endl); new DfaEdge (graphp(), toDfaStatep, *nfaIt, DfaEdge::NA()); if ((*nfaIt)->accepting()) toDfaStatep->accepting(true); } insertDfaOrigins(toDfaStatep); } // Add input transition new DfaEdge (graphp(), dfaStatep, toDfaStatep, input); if (debug()>=6) m_graphp->dumpDotFilePrefixed("step"); } } // Remove old NFA states UINFO(5,"Removing NFA states...\n"); if (debug()>=6) m_graphp->dumpDotFilePrefixed("dfa_withnfa"); for (V3GraphVertex* nextp,*vertexp = m_graphp->verticesBeginp(); vertexp; vertexp=nextp) { nextp = vertexp->verticesNextp(); if (nfaState(vertexp)) { vertexp->unlinkDelete(m_graphp); vertexp=NULL; } } UINFO(5,"Done.\n"); if (debug()>=6) m_graphp->dumpDotFilePrefixed("dfa_done"); }