Пример #1
0
    // VISITs
    virtual void visit(AstNetlist* nodep, AstNUser*) {
	AstNode::user1ClearTree();
	readModNames();
	nodep->iterateChildren(*this);
	// Find levels in graph
	m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue);
	m_graph.dumpDotFilePrefixed("linkcells");
	m_graph.rank();
	for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
	    if (LinkCellsVertex* vvertexp = dynamic_cast<LinkCellsVertex*>(itp)) {
		// +1 so we leave level 1  for the new wrapper we'll make in a moment
		AstNodeModule* modp = vvertexp->modp();
		modp->level(vvertexp->rank()+1);
		if (vvertexp == m_topVertexp && modp->level() != 2) {
		    AstNodeModule* abovep = NULL;
		    if (V3GraphEdge* edgep = vvertexp->inBeginp()) {
			if (LinkCellsVertex* eFromVertexp = dynamic_cast<LinkCellsVertex*>(edgep->fromp())) {
			    abovep = eFromVertexp->modp();
			}
		    }
		    v3error("Specified --top-module '"<<v3Global.opt.topModule()
			    <<"' isn't at the top level, it's under another cell '"
			    <<(abovep ? abovep->prettyName() : "UNKNOWN")<<"'");
		}
	    }
	}
	if (v3Global.opt.topModule()!=""
	    && !m_topVertexp) {
	    v3error("Specified --top-module '"<<v3Global.opt.topModule()<<"' was not found in design.");
	}
    }
Пример #2
0
void GateVisitor::warnSignals() {
    AstNode::user2ClearTree();
    for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
	if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
	    AstVarScope* vscp = vvertexp->varScp();
	    AstNode* sp = vvertexp->rstSyncNodep();
	    AstNode* ap = vvertexp->rstAsyncNodep();
	    if (ap && sp && !vscp->varp()->user2()) {
		// This is somewhat wrong, as marking one flop as ok for sync
		// may mean a different flop now fails.  However it's a pain to
		// then report a warning in a new place - we should report them all at once.
		// Instead we'll disable if any disabled
		if (!vscp->fileline()->warnIsOff(V3ErrorCode::SYNCASYNCNET)
		    && !ap->fileline()->warnIsOff(V3ErrorCode::SYNCASYNCNET)
		    && !sp->fileline()->warnIsOff(V3ErrorCode::SYNCASYNCNET)
		    ) {
		    vscp->varp()->user2(true);  // Warn only once per signal
		    vscp->v3warn(SYNCASYNCNET,"Signal flopped as both synchronous and async: "<<vscp->prettyName()<<endl
				 <<ap->warnMore()<<"... Location of async usage"<<endl
				 <<sp->warnMore()<<"... Location of sync usage"<<endl);
		}
	    }
	}
    }
}
Пример #3
0
    void newAlwaysTrees(AstAlways* nodep) {
	// Across all variables we're moving
	uint32_t lastColor = 0;
	AstNode* lastExprp = NULL;
	for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
	    if (GaterVarVertex* vVxp = dynamic_cast<GaterVarVertex*>(vertexp)) {
		if (!lastExprp || lastColor != vVxp->color()) {
		    lastColor = vVxp->color();
		    // Create the block we've just finished
		    if (lastExprp) newAlwaysTree(nodep, lastExprp); // Duplicate below
		    // New expression for this color
		    lastExprp = newExprFromGraph(vVxp);
		}
		// Mark variable to move
		if (vVxp->nodep()->user2p()) vVxp->nodep()->v3fatalSrc("One variable got marked under two gaters");
		vVxp->nodep()->user2p(lastExprp);
		m_statBits += vVxp->nodep()->width();  // Moving a wide bus counts more!
		// There shouldn't be two possibilities we want to
		// move to, IE {A,B} <= Z because we marked such
		// things as unoptimizable
	    }
	}
	// Create the final block we've just finished
	if (lastExprp) newAlwaysTree(nodep, lastExprp);   // Duplicate above
    }
Пример #4
0
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()
	}
    }
}
Пример #5
0
void GateVisitor::mergeAssigns() {
    GateMergeAssignsGraphVisitor merger(&m_graph);
    for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
	if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
	    merger.mergeAssignsTree(vvertexp);
	}
    }
    m_statAssignMerged += merger.numMergedAssigns();
}
Пример #6
0
void GateVisitor::consumedMark() {
    // Propagate consumed signals backwards to all producers into a consumed node
    m_graph.userClearVertices();
    for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
	GateEitherVertex* evertexp = (GateEitherVertex*)vertexp;
	if (!evertexp->user() && evertexp->consumed()) {
	    consumedMarkRecurse(evertexp);
	}
    }
}
Пример #7
0
void V3Graph::userClearVertices() {
    // Clear user() in all of tree
    // We may use the userCnt trick in V3Ast later... (but gblCnt would be
    // in V3Graph instead of static - which has the complication of finding
    // the graph pointer given a vertex.)  For now we don't call this often, and
    // the extra code on each read of user() would probably slow things
    // down more than help.
    for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
	vertexp->user(0);
	vertexp->userp(NULL);	 // Its a union, but might be different size than user()
    }
}
Пример #8
0
 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;
         }
     }
 }
Пример #9
0
 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());
             }
         }
     }
 }
Пример #10
0
    void optimize_accepting_out() {
	// Delete outbound edges from accepting states
	// (As once we've accepted, we no longer care about anything else.)
	for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
	    if (DfaVertex* vvertexp = dynamic_cast<DfaVertex*>(vertexp)) {
		if (vvertexp->accepting()) {
		    for (V3GraphEdge* nextp,*edgep = vertexp->outBeginp(); edgep; edgep=nextp) {
			nextp = edgep->outNextp();
			edgep->unlinkDelete(); edgep=NULL;
		    }
		}
	    }
	}
    }
Пример #11
0
 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;
 }
Пример #12
0
    // VISITORS
    virtual void visit(AstAlways* nodep, AstNUser*) {
	if (debug()>=9) cout<<endl<<endl<<endl;
	UINFO(5, "Gater: ALWAYS: "<<nodep<<endl);
	if (nodep->user4Inc()) return;

	clear();

	if (debug()>=9) nodep->dumpTree(cout,"  Alwin:  ");

	// Look for constructs we can't optimize
	// Form graph with Vertices at each IF, and each Variable
	m_aboveTrue = VU_IF | VU_ELSE;
	iterateChildrenAlw(nodep, true);

	// Other reasons to not optimize
	if (!m_numIfs) nonOptimizable(nodep, "No if statements");

	// Something to optimize, oh my!
	if (m_nonopt!="") {
	    UINFO(5, "  Gater non-opt: "<<m_nonopt<<endl);
	} else {
	    // Process it
	    simplifyGraph();

	    // See how much moves
	    uint32_t lastColor = 0;
	    for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
		if (GaterVarVertex* vVxp = dynamic_cast<GaterVarVertex*>(vertexp)) {
		    if (lastColor < vVxp->color()) {
			lastColor = vVxp->color();
		    }
		}
	    }
	    if (lastColor == 0) { // Nothing we moved!
		nonOptimizable(nodep, "Nothing moved");
	    }
	    else if (lastColor > DOMAINS_MAX) {
		// Our move algorithm is fairly slow and if we're splitting
		// up too much it'll get really nasty.  It's probably a bad
		// move for performance to split too much, anyhow, as the
		// number of gaters will result in calling many small c functions.
		nonOptimizable(nodep, "Too much moved");
	    }
	    if (m_nonopt=="") {
		newAlwaysTrees(nodep);
		if (debug()>=9) nodep->dumpTree(cout,"  Gaterout: ");
	    }
	}
	UINFO(5, "  Gater done"<<endl);
    }
Пример #13
0
DfaVertex* DfaGraph::findStart() {
    DfaVertex* startp = NULL;
    for (V3GraphVertex* vertexp = this->verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
	if (DfaVertex* vvertexp = dynamic_cast<DfaVertex*>(vertexp)) {
	    if (vvertexp->start()) {
		if (startp) v3fatalSrc("Multiple start points in NFA graph");
		startp = vvertexp;
	    }
	} else {
	    v3fatalSrc("Non DfaVertex in DfaGraph\n");
	}
    }
    if (!startp) v3fatalSrc("No start point in NFA graph");
    return startp;
}
Пример #14
0
    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;
		    }
		}
	    }
	}
    }
Пример #15
0
 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();
             }
         }
     }
 }
Пример #16
0
    void add_complement_edges() {
	// Find accepting vertex
	DfaVertex* acceptp = NULL;
	for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
	    if (DfaVertex* vvertexp = dynamic_cast<DfaVertex*>(vertexp)) {
		if (vvertexp->accepting()) {
		    acceptp = vvertexp;
		    break;
		}
	    }
	}
	if (!acceptp) v3fatalSrc("No accepting vertex in DFA\n");

	// Remap edges
	for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
	    if (DfaVertex* vvertexp = dynamic_cast<DfaVertex*>(vertexp)) {
		//UINFO(9, "   on vertex "<<vvertexp->name()<<endl);
		if (!vvertexp->accepting() && vvertexp != m_tempNewerReject) {
		    for (V3GraphEdge* nextp, *edgep = vertexp->outBeginp(); edgep; edgep=nextp) {
			nextp = edgep->outNextp();
			if (!edgep->user()) { // Not processed
			    // Old edges to accept now go to new reject
			    DfaEdge* vedgep = static_cast<DfaEdge*>(edgep);
			    DfaVertex* tovertexp = static_cast<DfaVertex*>(edgep->top());
			    if (tovertexp->accepting()) {
				new DfaEdge(graphp(), vvertexp, m_tempNewerReject, vedgep);
				edgep->unlinkDelete(); edgep=NULL;
			    }

			    // NOT of all values goes to accept
			    // We make a edge for each value to OR, IE
			    // edge(complemented,a) edge(complemented,b) means !(a | b)
			    if (!tovertexp->accepting()) {  // Note we must include edges moved above to reject
				DfaEdge* newp = new DfaEdge (graphp(), vvertexp, acceptp, vedgep);
				newp->complement(!newp->complement());
				newp->user(1);
			    }
			}
		    }
		}
	    }
	}
    }
Пример #17
0
void GateVisitor::consumedMove() {
    // Remove unused logic (logic that doesn't hit a combo block or a display statement)
    // We need the "usually" block logic to do a better job at this
    for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
	if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(vertexp)) {
	    if (!vvertexp->consumed() && !vvertexp->user()) {
		UINFO(8, "Unconsumed "<<vvertexp->varScp()<<endl);
	    }
	}
	if (GateLogicVertex* lvertexp = dynamic_cast<GateLogicVertex*>(vertexp)) {
	    AstNode* nodep = lvertexp->nodep();
	    AstActive* oldactp = lvertexp->activep();  // NULL under cfunc
	    if (!lvertexp->consumed() && oldactp) {
		// Eventually: Move the statement to a new active block with "tracing-on" sensitivity
		UINFO(8,"    Remove unconsumed "<<nodep<<endl);
		nodep->unlinkFrBack();
		pushDeletep(nodep); VL_DANGLING(nodep);
	    }
	}
    }
}
Пример #18
0
void GateVisitor::dedupe() {
    AstNode::user2ClearTree();
    GateDedupeGraphVisitor deduper;
    // Traverse starting from each of the clocks
    for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
	if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
	    if (vvertexp->isClock()) {
		deduper.dedupeTree(vvertexp);
	    }
	}
    }
    // Traverse starting from each of the outputs
    for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
	if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
	    if (vvertexp->isTop() && vvertexp->varScp()->varp()->isOutput()) {
		deduper.dedupeTree(vvertexp);
	    }
	}
    }
    m_statDedupLogic += deduper.numDeduped();
}
Пример #19
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;
	    }
	}
    }
Пример #20
0
    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;
	    }
	}
    }
Пример #21
0
void GateVisitor::replaceAssigns() {
    for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
	if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
	    // Take the Comments/assigns that were moved to the VarScope and change them to a
	    // simple value assignment
	    AstVarScope* vscp = vvertexp->varScp();
	    if (vscp->valuep() && !vscp->valuep()->castNodeMath()) {
		//if (debug()>9) vscp->dumpTree(cout, "-vscPre:  ");
		while (AstNode* delp=vscp->valuep()->castComment()) {
		    delp->unlinkFrBack()->deleteTree(); VL_DANGLING(delp);
		}
		if (AstInitial* delp=vscp->valuep()->castInitial()) {
		    AstNode* bodyp=delp->bodysp();
		    bodyp->unlinkFrBackWithNext();
		    delp->replaceWith(bodyp);
		    delp->deleteTree(); VL_DANGLING(delp);
		}
		if (AstAlways* delp=vscp->valuep()->castAlways()) {
		    AstNode* bodyp=delp->bodysp();
		    bodyp->unlinkFrBackWithNext();
		    delp->replaceWith(bodyp);
		    delp->deleteTree(); VL_DANGLING(delp);
		}
		if (AstNodeAssign* delp=vscp->valuep()->castNodeAssign()) {
		    AstNode* rhsp=delp->rhsp();
		    rhsp->unlinkFrBack();
		    delp->replaceWith(rhsp);
		    delp->deleteTree(); VL_DANGLING(delp);
		}
		//if (debug()>9) {vscp->dumpTree(cout, "-vscDone: "); cout<<endl;}
		if (!vscp->valuep()->castNodeMath()
		    || vscp->valuep()->nextp()) {
		    vscp->dumpTree(cerr, "vscStrange: ");
		    vscp->v3fatalSrc("Value of varscope not mathematical\n");
		}
	    }
	}
    }
}
Пример #22
0
    void graphColorSameFeeder() {
	// Assign same color to all destination vertices that have same
	// subgraph feeding into them
	// (I.E. all "from" nodes are common within each color)
	// We could hash, but instead it's faster to sort edges, so we know
	// the same edge list is always adjacent.  The result is a
	// O(vertices*edges) loop, but we'd need that to hash too.
	if (debug()>9) { cout<<"PreColor:\n"; m_graph.dump(); }

	m_graph.sortEdges();

	// Now sort vertices, so same inbound edge set ends up adjacent
	m_graph.sortVertices();

	// Now walk and assign colors; same color is adjacent
	m_graph.clearColors();
	m_graph.userClearEdges(); // Used by newExprFromGraph
	uint32_t color = 1;
	GaterVarVertex* lastVxp	= NULL;
	for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
	    if (GaterVarVertex* vVxp = dynamic_cast<GaterVarVertex*>(vertexp)) {
		if (!vVxp->inBeginp()) {
		    // At this point, any variable not linked is an error
		    // (It should have at least landed under the Head node)
		    vVxp->nodep()->v3fatalSrc("Variable became stranded in clk gate detection\n");
		}
		if (!lastVxp || vVxp->sortCmp(lastVxp)) {
		    // Different sources for this new node
		    color++;
		}
		vVxp->color(color);
		lastVxp = vVxp;
	    }
	}

	if (debug()>9) { cout<<"PostColor:\n"; m_graph.dump(); }
    }
Пример #23
0
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);
	}
    }
}
Пример #24
0
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();
}
Пример #25
0
    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);
    }
Пример #26
0
    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);
    }
Пример #27
0
    // 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");
    }
Пример #28
0
void V3Graph::clearColors() {
    // Reset colors
    for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
	vertexp->m_color = 0;
    }
}
Пример #29
0
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;
}
Пример #30
0
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);
			}
		    }
		}
	    }
	}
    }
}