Esempio n. 1
0
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;
}
Esempio n. 2
0
    // 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;
    }
Esempio n. 3
0
    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);
	}
    }
Esempio n. 4
0
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);
    }
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
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);
}
Esempio n. 7
0
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;
    }
}
Esempio n. 8
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);
	}
    }
}
Esempio n. 9
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();
             }
         }
     }
 }
Esempio n. 10
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;
	    }
	}
    }
Esempio n. 11
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);
    }
Esempio n. 12
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);
    }
Esempio n. 13
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);
			}
		    }
		}
	    }
	}
    }
}
Esempio n. 14
0
    virtual AstNUser* visit(GateVarVertex *vvertexp, AstNUser*) {
	for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep; ) {
	    V3GraphEdge* oldedgep = edgep;
	    edgep = edgep->inNextp();  // for recursive since the edge could be deleted
	    if (GateLogicVertex* lvertexp = dynamic_cast<GateLogicVertex*>(oldedgep->fromp())) {
		if (AstNodeAssign* assignp = lvertexp->nodep()->castNodeAssign()) {
		    //if (lvertexp->outSize1() && assignp->lhsp()->castSel()) {
		    if (assignp->lhsp()->castSel() && lvertexp->outSize1()) {
			UINFO(9, "assing to the nodep["<<assignp->lhsp()->castSel()->lsbConst()<<"]"<<endl);
			// first assign with Sel-lhs
			if (!m_activep) m_activep = lvertexp->activep();
			if (!m_logicvp) m_logicvp = lvertexp;
			if (!m_assignp) m_assignp = assignp;

			// not under the same active
			if (m_activep != lvertexp->activep()) {
			    m_activep = lvertexp->activep();
			    m_logicvp = lvertexp;
			    m_assignp = assignp;
			    continue;
			}

			AstSel* preselp = m_assignp->lhsp()->castSel();
			AstSel* curselp = assignp->lhsp()->castSel();
			if (!preselp || !curselp) continue;

			if (AstSel* newselp = merge(preselp, curselp)) {
			    UINFO(5, "assemble to new sel: "<<newselp<<endl);
			    // replace preSel with newSel
			    preselp->replaceWith(newselp); preselp->deleteTree(); VL_DANGLING(preselp);
			    // create new rhs for pre assignment
			    AstNode* newrhsp = new AstConcat(m_assignp->rhsp()->fileline(), m_assignp->rhsp()->cloneTree(false), assignp->rhsp()->cloneTree(false));
			    AstNode* oldrhsp = m_assignp->rhsp();
			    oldrhsp->replaceWith(newrhsp); oldrhsp->deleteTree(); VL_DANGLING(oldrhsp);
			    m_assignp->dtypeChgWidthSigned(m_assignp->width()+assignp->width(), m_assignp->width()+assignp->width(), AstNumeric::fromBool(true));
			    // don't need to delete, will be handled
			    //assignp->unlinkFrBack(); assignp->deleteTree(); VL_DANGLING(assignp);

			    // update the graph
			    {
				// delete all inedges to lvertexp
				if (!lvertexp->inEmpty()) { 
				    for (V3GraphEdge* ledgep = lvertexp->inBeginp(); ledgep; ) {
					V3GraphEdge* oedgep = ledgep;
					ledgep = ledgep->inNextp();
					GateEitherVertex* fromvp = dynamic_cast<GateEitherVertex*>(oedgep->fromp());
					new V3GraphEdge(m_graphp, fromvp, m_logicvp, 1);
					oedgep->unlinkDelete(); VL_DANGLING(oedgep);
				    }
				}
				// delete all outedges to lvertexp, only one
				oldedgep->unlinkDelete(); VL_DANGLING(oldedgep);
			    }
			    ++m_numMergedAssigns;
			} else {
			    m_assignp = assignp;
			    m_logicvp = lvertexp;
			}
		    }
		}
	    }
	}
	return NULL;
    }