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 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); } } } } } } }