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; }
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; }
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; } } }
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; }
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; } } } } }
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; }
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 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); }
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 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()); } } } } }
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; }
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; }
// From *this, populate *mstp with the minimum spanning tree. // *mstp must be initially empty. void makeMinSpanningTree(TspGraphTmpl* mstp) { UASSERT(mstp->empty(), "Output graph must start empty"); // Use Prim's algorithm to efficiently construct the MST. vl_unordered_set<Vertex*> visited_set; EdgeCmp cmp; typedef std::set<V3GraphEdge*, EdgeCmp&> PendingEdgeSet; // This is the set of pending edges from visited to unvisited // nodes. PendingEdgeSet pendingEdges(cmp); vluint32_t vertCount = 0; for (V3GraphVertex* vxp = verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { mstp->addVertex(castVertexp(vxp)->key()); vertCount++; } // Choose an arbitrary start vertex and visit it; // all incident edges from this vertex go into a pending edge set. Vertex* start_vertexp = castVertexp(verticesBeginp()); visited_set.insert(start_vertexp); for (V3GraphEdge* edgep = start_vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { pendingEdges.insert(edgep); } // Repeatedly find the least costly edge in the pending set. // If it connects to an unvisited node, visit that node and update // the pending edge set. If it connects to an already visited node, // discard it and repeat again. unsigned edges_made = 0; while (!pendingEdges.empty()) { typename PendingEdgeSet::iterator firstIt = pendingEdges.begin(); V3GraphEdge* bestEdgep = *firstIt; pendingEdges.erase(firstIt); // bestEdgep->fromp() should be already seen Vertex* from_vertexp = castVertexp(bestEdgep->fromp()); UASSERT(visited_set.find(from_vertexp) != visited_set.end(), "Can't find vertex"); // If the neighbor is not yet visited, visit it and add its edges // to the pending set. Vertex* neighborp = castVertexp(bestEdgep->top()); if (visited_set.find(neighborp) == visited_set.end()) { int bestCost = bestEdgep->weight(); UINFO(6, "bestCost = "<<bestCost <<" from "<<from_vertexp->key() <<" to "<<neighborp->key()<<endl); // Create the edge in our output MST graph mstp->addEdge(from_vertexp->key(), neighborp->key(), bestCost); edges_made++; // Mark this vertex as visited visited_set.insert(neighborp); // Update the pending edges with new edges for (V3GraphEdge* edgep = neighborp->outBeginp(); edgep; edgep = edgep->outNextp()) { pendingEdges.insert(edgep); } } else { UINFO(6, "Discarding edge to already-visited neighbor " <<neighborp->key()<<endl); } } UASSERT(edges_made + 1 == vertCount, "Algorithm failed"); UASSERT(visited_set.size() == vertCount, "Algorithm failed"); }
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"); }
void findEulerTourRecurse(vl_unordered_set<unsigned>* markedEdgesp, Vertex* startp, std::vector<T_Key>* sortedOutp) { Vertex* cur_vertexp = startp; // Go on a random tour. Fun! std::vector<Vertex*> tour; do { UINFO(6, "Adding "<<cur_vertexp->key()<<" to tour.\n"); tour.push_back(cur_vertexp); // Look for an arbitrary edge we've not yet marked for (V3GraphEdge* edgep = cur_vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { vluint32_t edgeId = edgep->user(); if (markedEdgesp->end() == markedEdgesp->find(edgeId)) { // This edge is not yet marked, so follow it. markedEdgesp->insert(edgeId); Vertex* neighborp = castVertexp(edgep->top()); UINFO(6, "following edge "<<edgeId <<" from "<<cur_vertexp->key() <<" to "<<neighborp->key()<<endl); cur_vertexp = neighborp; goto found; } } v3fatalSrc("No unmarked edges found in tour"); found: ; } while (cur_vertexp != startp); UINFO(6, "stopped, got back to start of tour @ "<<cur_vertexp->key()<<endl); // Look for nodes on the tour that still have // un-marked edges. If we find one, recurse. for (typename std::vector<Vertex*>::iterator it = tour.begin(); it != tour.end(); ++it) { Vertex* vxp = *it; bool recursed; do { recursed = false; // Look for an arbitrary edge at vxp we've not yet marked for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) { vluint32_t edgeId = edgep->user(); if (markedEdgesp->end() == markedEdgesp->find(edgeId)) { UINFO(6, "Recursing.\n"); findEulerTourRecurse(markedEdgesp, vxp, sortedOutp); recursed = true; goto recursed; } } recursed: ; } while (recursed); sortedOutp->push_back(vxp->key()); } UINFO(6, "Tour was: "); for (typename std::vector<Vertex*>::iterator it = tour.begin(); it != tour.end(); ++it) { Vertex* vxp = *it; UINFONL(6, " "<<vxp->key()); } UINFONL(6, "\n"); }
void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) { // This generates a file used by graphviz, http://www.graphviz.org // "hardcoded" parameters: const auto_ptr<ofstream> logp (V3File::new_ofstream(filename)); if (logp->fail()) v3fatalSrc("Can't write "<<filename); // Header *logp<<"digraph v3graph {\n"; *logp<<"\tgraph\t[label=\""<<filename<<"\",\n"; *logp<<"\t\t labelloc=t, labeljust=l,\n"; *logp<<"\t\t //size="<<"\"7.5,10\","<<"\n"; *logp<<"\t\t rankdir="<<dotRankDir()<<"];\n"; // List of all possible subgraphs typedef multimap<string,V3GraphVertex*> SubgraphMmap; SubgraphMmap subgraphs; for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { string vertexSubgraph = (colorAsSubgraph && vertexp->color()) ? cvtToStr(vertexp->color()) : ""; subgraphs.insert(make_pair(vertexSubgraph, vertexp)); } // We use a map here, as we don't want to corrupt anything (userp) in the graph, // and we don't care if this is slow. map<V3GraphVertex*,int> numMap; // Print vertices int n=0; string subgr; for (SubgraphMmap::iterator it = subgraphs.begin(); it!=subgraphs.end(); ++it) { string vertexSubgraph = it->first; V3GraphVertex* vertexp = it->second; numMap[vertexp] = n; if (subgr != vertexSubgraph) { if (subgr!="") *logp<<"\t};\n"; subgr = vertexSubgraph; if (subgr!="") *logp<<"\tsubgraph cluster_"<<subgr<<" {\n"; } if (subgr!="") *logp<<"\t"; *logp<<"\tn"<<vertexp->dotName()<<(n++) <<"\t[fontsize=8 " <<"label=\""<<(vertexp->name()!="" ? vertexp->name() : "\\N"); if (vertexp->rank()) *logp<<" r"<<vertexp->rank(); if (vertexp->fanout()) *logp<<" f"<<vertexp->fanout(); if (vertexp->color()) *logp<<"\\n c"<<vertexp->color(); *logp<<"\""; *logp<<", color="<<vertexp->dotColor(); if (vertexp->dotStyle()!="") *logp<<", style="<<vertexp->dotStyle(); if (vertexp->dotShape()!="") *logp<<", shape="<<vertexp->dotShape(); *logp<<"];\n"; } if (subgr!="") *logp<<"\t};\n"; // Print edges for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) { for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) { if (edgep->weight()) { int fromVnum = numMap[edgep->fromp()]; int toVnum = numMap[edgep->top()]; *logp<<"\tn"<<edgep->fromp()->dotName()<<fromVnum <<" -> n"<<edgep->top()->dotName()<<toVnum <<" [" //<<"fontsize=8 label=\""<<(edgep->name()!="" ? edgep->name() : "\\E")<<"\"" <<"fontsize=8 label=\""<<(edgep->dotLabel()!="" ? edgep->dotLabel() : "")<<"\"" <<" weight="<<edgep->weight() <<" color="<<edgep->dotColor(); if (edgep->dotStyle()!="") *logp<<" style="<<edgep->dotStyle(); //if (edgep->cutable()) { *logp<<",constraint=false"; } // to rank without following edges *logp<<"];\n"; } } } // Vertex::m_user end, now unused // Trailer *logp << "}\n"; logp->close(); cout << "dot -Tpdf -o ~/a.pdf "<<filename<<endl; }
void GateVisitor::optimizeSignals(bool allowMultiIn) { for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) { if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) { if (vvertexp->inEmpty()) { vvertexp->clearReducibleAndDedupable("inEmpty"); // Can't deal with no sources if (!vvertexp->isTop() // Ok if top inputs are driverless && !vvertexp->varScp()->varp()->valuep() && !vvertexp->varScp()->varp()->isSigPublic()) { UINFO(4, "No drivers "<<vvertexp->varScp()<<endl); if (0) { // If we warned here after constant propagation, what the user considered // reasonable logic may have disappeared. Issuing a warning would // thus be confusing. V3Undriven now handles this. vvertexp->varScp()->varp()->v3warn(UNDRIVEN,"Signal has no drivers " <<vvertexp->scopep()->prettyName()<<"." <<vvertexp->varScp()->varp()->prettyName()); } } } else if (!vvertexp->inSize1()) { vvertexp->clearReducibleAndDedupable("size!1"); // Can't deal with more than one src } // Reduce it? if (!vvertexp->reducible()) { UINFO(8, "SigNotRed "<<vvertexp->name()<<endl); } else { UINFO(8, "Sig "<<vvertexp->name()<<endl); GateLogicVertex* logicVertexp = dynamic_cast<GateLogicVertex*> (vvertexp->inBeginp()->fromp()); UINFO(8, " From "<<logicVertexp->name()<<endl); AstNode* logicp = logicVertexp->nodep(); if (logicVertexp->reducible()) { // Can we eliminate? GateOkVisitor okVisitor(logicp, vvertexp->isClock(), false); bool multiInputs = okVisitor.rhsVarRefs().size() > 1; // Was it ok? bool doit = okVisitor.isSimple(); if (doit && multiInputs) { if (!allowMultiIn) doit = false; // Doit if one input, or not used, or used only once, ignoring traces int n=0; for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { GateLogicVertex* consumeVertexp = dynamic_cast<GateLogicVertex*>(edgep->top()); if (!consumeVertexp->slow()) { // Not tracing or other slow path junk if (edgep->top()->outBeginp()) { // Destination is itself used n += edgep->weight(); } } if (n>1) { doit = false; break; } } } // Process it if (!doit) { if (allowMultiIn && (debug()>=9)) { UINFO(9, "Not ok simp"<<okVisitor.isSimple()<<" mi"<<multiInputs <<" ob"<<vvertexp->outBeginp()<<" on"<<(vvertexp->outBeginp()?vvertexp->outBeginp()->outNextp():0) <<" "<<vvertexp->name() <<endl); for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { GateLogicVertex* consumeVertexp = dynamic_cast<GateLogicVertex*>(edgep->top()); UINFO(9, " edge "<<edgep<<" to: "<<consumeVertexp->nodep()<<endl); } for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { GateLogicVertex* consumeVertexp = dynamic_cast<GateLogicVertex*>(edgep->fromp()); UINFO(9, " edge "<<edgep<<" from: "<<consumeVertexp->nodep()<<endl); } } } else { AstNode* substp = okVisitor.substTree(); if (debug()>=5) logicp->dumpTree(cout,"\telimVar: "); if (debug()>=5) substp->dumpTree(cout,"\t subst: "); ++m_statSigs; bool removedAllUsages = true; for (V3GraphEdge* edgep = vvertexp->outBeginp(); edgep; ) { GateLogicVertex* consumeVertexp = dynamic_cast<GateLogicVertex*>(edgep->top()); AstNode* consumerp = consumeVertexp->nodep(); if (!elimLogicOkOutputs(consumeVertexp, okVisitor/*ref*/)) { // Cannot optimize this replacement removedAllUsages = false; edgep = edgep->outNextp(); } else { optimizeElimVar(vvertexp->varScp(), substp, consumerp); // If the new replacement referred to a signal, // Correct the graph to point to this new generating variable const GateVarRefList& rhsVarRefs = okVisitor.rhsVarRefs(); for (GateVarRefList::const_iterator it = rhsVarRefs.begin(); it != rhsVarRefs.end(); ++it) { AstVarScope* newvarscp = (*it)->varScopep(); UINFO(9," Point-to-new vertex "<<newvarscp<<endl); GateVarVertex* varvertexp = makeVarVertex(newvarscp); new V3GraphEdge(&m_graph, varvertexp, consumeVertexp, 1); // Propagate clock attribute onto generating node varvertexp->propagateAttrClocksFrom(vvertexp); } // Remove the edge edgep->unlinkDelete(); VL_DANGLING(edgep); ++m_statRefs; edgep = vvertexp->outBeginp(); } } if (removedAllUsages) { // Remove input links while (V3GraphEdge* edgep = vvertexp->inBeginp()) { edgep->unlinkDelete(); VL_DANGLING(edgep); } // Clone tree so we remember it for tracing, and keep the pointer // to the "ALWAYS" part of the tree as part of this statement // That way if a later signal optimization that retained a pointer to the always // can optimize it further logicp->unlinkFrBack(); vvertexp->varScp()->valuep(logicp); logicp = NULL; // Mark the vertex so we don't mark it as being unconsumed in the next step vvertexp->user(true); logicVertexp->user(true); } } } } } } }