void V3Hashed::erase(iterator it) { AstNode* nodep = iteratorNodep(it); UINFO(8," erase "<<nodep<<endl); if (!nodep->user4p()) nodep->v3fatalSrc("Called removeNode on non-hashed node"); m_hashMmap.erase(it); nodep->user4p(NULL); // So we don't allow removeNode again }
virtual void visit(AstVarRef* nodep, AstNUser*) { if (nodep->lvalue()) { AstVarScope* vscp = nodep->varScopep(); if (nodep->varp()->isSigPublic()) { // Public signals shouldn't be changed, pli code might be messing with them scoreboardPli(nodep); } // If another lvalue in this node, give up optimizing. // We could just not optimize this variable, but we've already marked the // other variable as optimizable, so we can instead pretend it's a PLI node. if (m_stmtVscp) { UINFO(5, " Multiple lvalues in one statement: "<<nodep<<endl); scoreboardPli(nodep); // This will set m_stmtInPli } m_stmtVscp = vscp; // Find, or make new Vertex GaterVarVertex* vertexp = (GaterVarVertex*)(vscp->user1p()); if (!vertexp) { vertexp = new GaterVarVertex(&m_graph, vscp); vscp->user1p(vertexp); } new GaterEdge(&m_graph, m_aboveVertexp, vertexp, m_aboveTrue); if (m_stmtInPli) { new GaterEdge(&m_graph, m_pliVertexp, vertexp, VU_PLI); } } }
// VISITORS virtual void visit(AstNodeModule* nodep, AstNUser*) { UINFO(4," MOD "<<nodep<<endl); m_modp = nodep; m_constXCvt = true; nodep->iterateChildren(*this); m_modp = NULL; }
void moveVars() { for (vector<AstVar*>::iterator it = m_varps.begin(); it != m_varps.end(); ++it) { AstVar* nodep = *it; if (nodep->valuep()) clearOptimizable(nodep,"HasInitValue"); if (!VarFlags(nodep).m_stdFuncAsn) clearStdOptimizable(nodep,"NoStdAssign"); VarFlags flags (nodep); if ((nodep->isMovableToBlock() // Blocktemp || !flags.m_notStd) // Or used only in block && !flags.m_notOpt // Optimizable && nodep->user1p()) { // Single cfunc // We don't need to test for tracing; it would be in the tracefunc if it was needed UINFO(4," ModVar->BlkVar "<<nodep<<endl); ++m_statLocVars; AstCFunc* newfuncp = nodep->user1p()->castCFunc(); nodep->unlinkFrBack(); newfuncp->addInitsp(nodep); // Done flags.m_done = true; flags.setNodeFlags(nodep); } else { clearOptimizable(nodep, "NotDone"); } } m_varps.clear(); }
virtual void visit(AstVarRef* nodep) { if (!VarFlags(nodep->varp()).m_notOpt) { if (!m_cfuncp) { // Not in function, can't optimize clearOptimizable(nodep->varp(), "BVnofunc"); } else { // If we're scoping down to it, it isn't really in the same block if (!nodep->hierThis()) clearOptimizable(nodep->varp(),"HierRef"); // Allow a variable to appear in only a single function AstNode* oldfunc = nodep->varp()->user1p(); if (!oldfunc) { UINFO(4," BVnewref "<<nodep<<endl); nodep->varp()->user1p(m_cfuncp); // Remember where it was used } else if (m_cfuncp == oldfunc) { // Same usage } else { // Used in multiple functions clearOptimizable(nodep->varp(),"BVmultiF"); } // First varref in function must be assignment found earlier AstVarRef* firstasn = (AstVarRef*)(nodep->varp()->user4p()); if (firstasn && nodep!=firstasn) { clearStdOptimizable(nodep->varp(),"notFirstAsn"); nodep->varp()->user4p(NULL); } } } // No iterate; Don't want varrefs under it }
// VISITORS virtual void visit(AstNodeModule* nodep, AstNUser*) { m_stmtCnt = 0; m_modp = nodep; m_modp->user2(CIL_MAYBE); if (m_modp->castIface()) { // Inlining an interface means we no longer have a cell handle to resolve to. // If inlining moves post-scope this can perhaps be relaxed. cantInline("modIface",true); } if (m_modp->modPublic()) cantInline("modPublic",false); // nodep->iterateChildren(*this); // bool userinline = nodep->user1(); int allowed = nodep->user2(); int refs = nodep->user3(); // Should we automatically inline this module? // inlineMult = 2000 by default. If a mod*#instances is < this # nodes, can inline it bool doit = ((allowed == CIL_NOTSOFT || allowed == CIL_MAYBE) && (userinline || ((allowed == CIL_MAYBE) && (refs==1 || m_stmtCnt < INLINE_MODS_SMALLER || v3Global.opt.inlineMult() < 1 || refs*m_stmtCnt < v3Global.opt.inlineMult())))); // Packages aren't really "under" anything so they confuse this algorithm if (nodep->castPackage()) doit = false; UINFO(4, " Inline="<<doit<<" Possible="<<allowed<<" Usr="******" Refs="<<refs<<" Stmts="<<m_stmtCnt <<" "<<nodep<<endl); nodep->user1(doit); m_modp = NULL; }
// VISITORS virtual void visit(AstAlways* nodep, AstNUser*) { UINFO(4," ALW "<<nodep<<endl); if (debug()>=9) nodep->dumpTree(cout," alwIn:: "); scoreboardClear(); processBlock(nodep->bodysp()); if (debug()>=9) nodep->dumpTree(cout," alwOut: "); }
void V3GenClk::genClkAll(AstNetlist* nodep) { UINFO(2,__FUNCTION__<<": "<<endl); { GenClkReadVisitor visitor (nodep); } // Destruct before checking V3Global::dumpCheckGlobalTree("genclk", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); }
void V3Localize::localizeAll(AstNetlist* nodep) { UINFO(2,__FUNCTION__<<": "<<endl); LocalizeVisitor visitor (nodep); // Fix up hiernames LocalizeDehierVisitor dvisitor (nodep); V3Global::dumpCheckGlobalTree("localize.tree", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6); }
virtual void visit(AstNodeStmt* nodep, AstNUser*) { uint32_t oldstate = m_state; // Find if children want to delete this or not. // Note children may bicker, and want to both keep and delete (branches on a if) uint32_t childstate; { m_state = STATE_UNKNOWN; nodep->iterateChildren(*this); childstate = m_state; } m_state = oldstate; UINFO(9," Did state="<<childstate<<" "<<nodep<<endl); // Indeterminate (statement with no lvalue), so keep only in original if (childstate == STATE_UNKNOWN) { if (m_original) childstate |= STATE_KEEP; else childstate |= STATE_DELETE; } if ((childstate & STATE_DELETE) && !(childstate & STATE_KEEP)) { nodep->unlinkFrBack()->deleteTree(); nodep=NULL; // Pass upwards we did delete m_state |= STATE_DELETE; } else { // Pass upwards we must keep m_state |= STATE_KEEP; } }
void visitEqNeqCase(AstNodeBiop* nodep) { UINFO(4," N/EQCASE->EQ "<<nodep<<endl); V3Const::constifyEdit(nodep->lhsp()); // lhsp may change V3Const::constifyEdit(nodep->rhsp()); // rhsp may change if (nodep->lhsp()->castConst() && nodep->rhsp()->castConst()) { // Both sides are constant, node can be constant V3Const::constifyEdit(nodep); nodep=NULL; return; } else { AstNode* lhsp = nodep->lhsp()->unlinkFrBack(); AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); AstNode* newp; // If we got ==1'bx it can never be true (but 1'bx==1'bx can be!) if (((lhsp->castConst() && lhsp->castConst()->num().isFourState()) || (rhsp->castConst() && rhsp->castConst()->num().isFourState()))) { V3Number num (nodep->fileline(), 1, (nodep->castEqCase()?0:1)); newp = new AstConst (nodep->fileline(), num); lhsp->deleteTree(); lhsp=NULL; rhsp->deleteTree(); rhsp=NULL; } else { if (nodep->castEqCase()) newp = new AstEq (nodep->fileline(), lhsp, rhsp); else newp = new AstNeq (nodep->fileline(), lhsp, rhsp); } nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL; // Iterate tree now that we may have gotten rid of Xs newp->iterateChildren(*this); } }
virtual void visit(AstNodeModule* nodep, AstNUser*) { UINFO(4," MOD "<<nodep<<endl); m_modp = nodep; m_modNFuncs = 0; m_hashed.clear(); // Compute hash of all statement trees in the function m_state = STATE_HASH; nodep->iterateChildren(*this); m_state = STATE_IDLE; if (debug()>=9) { m_hashed.dumpFilePrefixed("combine"); } // Walk the hashes removing empty functions if (emptyFunctionDeletion()) { walkEmptyFuncs(); } // Walk the hashes looking for duplicate functions if (duplicateFunctionCombine()) { walkDupFuncs(); } // Walk the statements looking for large replicated code sections if (statementCombine()) { m_state = STATE_DUP; nodep->iterateChildren(*this); m_state = STATE_IDLE; } m_modp = NULL; }
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) { // Track what scope it was originally under so V3LinkDot can resolve it string newname = m_cellp->name(); if (nodep->inlinedDots() != "") { newname += "." + nodep->inlinedDots(); } nodep->inlinedDots(newname); UINFO(8," "<<nodep<<endl); nodep->iterateChildren(*this); }
DfaVertex* newDfaVertex(DfaVertex* nfaTemplatep=NULL) { DfaVertex* vertexp = new DfaVertex (graphp()); vertexp->color(1); // Mark as dfa if (nfaTemplatep && nfaTemplatep->start()) vertexp->start(true); if (nfaTemplatep && nfaTemplatep->accepting()) vertexp->accepting(true); UINFO(9, " New "<<vertexp<<endl); return vertexp; }
virtual void visit(AstCell* nodep, AstNUser*) { UINFO(4," CELL "<<nodep<<endl); m_cellp = nodep; //VV***** We reset user1p() on each cell!!! AstNode::user1ClearTree(); nodep->iterateChildren(*this); m_cellp = NULL; }
// VISITORS bool cantUnroll(AstNode* nodep, const char* reason) { if (m_generate) { nodep->v3error("Unsupported: Can't unroll generate for; "<<reason); } UINFO(3," Can't Unroll: "<<reason<<" :"<<nodep<<endl); V3Stats::addStatSum(string("Unrolling gave up, ")+reason, 1); return false; }
virtual void visit(AstCoverToggle* nodep, AstNUser*) { // Add to list of blocks under this scope UINFO(4," Move "<<nodep<<endl); AstNode* clonep = nodep->cloneTree(false); nodep->user2p(clonep); m_scopep->addActivep(clonep); clonep->iterateChildren(*this); // We iterate under the *clone* }
virtual void visit(AstVarScope* nodep, AstNUser*) { if (nodep->isCircular()) { UINFO(8," CIRC "<<nodep<<endl); if (!nodep->user1SetOnce()) { genChangeDet(nodep); } } }
void V3Life::lifeAll(AstNetlist* nodep) { UINFO(2,__FUNCTION__<<": "<<endl); { LifeState state; LifeTopVisitor visitor (nodep, &state); } // Destruct before checking V3Global::dumpCheckGlobalTree("life", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); }
virtual void visit(AstAssignVarScope* nodep, AstNUser*) { // Copy under the scope but don't recurse UINFO(4," Move "<<nodep<<endl); AstNode* clonep = nodep->cloneTree(false); nodep->user2p(clonep); m_scopep->addActivep(clonep); clonep->iterateChildren(*this); // We iterate under the *clone* }
virtual void visit(AstInitial* nodep, AstNUser*) { // Relink to IACTIVE, unless already under it UINFO(4," INITIAL "<<nodep<<endl); ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_INITIAL); AstActive* wantactivep = m_namer.getIActive(nodep->fileline()); nodep->unlinkFrBack(); wantactivep->addStmtsp(nodep); }
virtual void visit(AstActive* nodep) { UINFO(8,"ACTIVE "<<nodep<<endl); m_activep = nodep; if (!nodep->sensesp()) nodep->v3fatalSrc("Unlinked"); iterateChildren(nodep->sensesp()); // iterateAndNext? m_activep = NULL; iterateChildren(nodep); }
// EmitSplitVisitor visits through always block *nodep // and generates its split blocks, writing the split blocks // into *newBlocksp. EmitSplitVisitor(AstAlways* nodep, const IfColorVisitor* ifColorp, AlwaysVec* newBlocksp) : m_origAlwaysp(nodep) , m_ifColorp(ifColorp) , m_newBlocksp(newBlocksp) { UINFO(6, " splitting always " << nodep << endl); }
void drivenBit (int bit, int width) { UINFO(9, "set d["<<(bit+width-1)<<":"<<bit<<"] "<<m_varp->name()<<endl); for (int i=0; i<width; i++) { if (bitNumOk(bit+i)) { m_flags[(bit+i)*FLAGS_PER_BIT + FLAG_DRIVEN] = true; } } }
// METHODS virtual void visit(AstVarRef* nodep, AstNUser*) { if (nodep->lvalue()) { if (nodep->varScopep()==m_splitVscp) { UINFO(6," CL VAR "<<nodep<<endl); m_matches = true; } } }
// METHODS void splitAlways(AstAlways* nodep) { UINFO(3,"Split "<<nodep<<endl); UINFO(3," For "<<m_splitVscp<<endl); if (debug()>=9) nodep->dumpTree(cout,"-in : "); // Duplicate it and link in AstAlways* newp = nodep->cloneTree(false); newp->user1(true); // So we don't clone it again nodep->addNextHere(newp); { // Delete stuff we don't want in old SplitAsCleanVisitor visitor (nodep, m_splitVscp, false); if (debug()>=9) nodep->dumpTree(cout,"-out0: "); } { // Delete stuff we don't want in new SplitAsCleanVisitor visitor (newp, m_splitVscp, true); if (debug()>=9) newp->dumpTree(cout,"-out1: "); } }
//-------------------- // Default virtual void visit(AstNode* nodep) { // **** SPECIAL default type that sets PLI_ORDERING if (!m_stmtStackps.empty() && !nodep->isPure()) { UINFO(9," NotSplittable "<<nodep<<endl); scoreboardPli(nodep); } iterateChildren(nodep); }
// VISITORS virtual void visit(AstScope* nodep, AstNUser*) { // Create required actives and add to scope UINFO(4," SCOPE "<<nodep<<endl); // Clear last scope's names, and collect this scope's existing names m_namer.main(nodep); m_scopeFinalp = NULL; nodep->iterateChildren(*this); }
virtual void visit(AstNodeIf* nodep) { UINFO(4," IF "<<nodep<<endl); m_curIfConditional = nodep; iterateAndNextNull(nodep->condp()); m_curIfConditional = NULL; scanBlock(nodep->ifsp()); scanBlock(nodep->elsesp()); }
virtual void visit(AstVarRef* nodep, AstNUser*) { if (!nodep->user2Inc()) { // Not done yet if (m_inDly && nodep->lvalue()) { UINFO(4,"AssignDlyVar: "<<nodep<<endl); markVarUsage(nodep->varScopep(), VU_DLY); if (!m_activep) nodep->v3fatalSrc("<= not under sensitivity block"); if (!m_activep->hasClocked()) nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should have converted in V3Active"); AstVarScope* oldvscp = nodep->varScopep(); if (!oldvscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp\n"); AstVarScope* dlyvscp = oldvscp->user1p()->castNode()->castVarScope(); if (dlyvscp) { // Multiple use of delayed variable AstActive* oldactivep = dlyvscp->user2p()->castNode()->castActive(); checkActivePost(nodep, oldactivep); } if (!dlyvscp) { // First use of this delayed variable string newvarname = (string("__Vdly__")+nodep->varp()->shortName()); dlyvscp = createVarSc(oldvscp, newvarname, 0); AstNodeAssign* prep = new AstAssignPre (nodep->fileline(), new AstVarRef(nodep->fileline(), dlyvscp, true), new AstVarRef(nodep->fileline(), oldvscp, false)); AstNodeAssign* postp = new AstAssignPost (nodep->fileline(), new AstVarRef(nodep->fileline(), oldvscp, true), new AstVarRef(nodep->fileline(), dlyvscp, false)); postp->lhsp()->user2(true); // Don't detect this assignment oldvscp->user1p(dlyvscp); // So we can find it later // Make new ACTIVE with identical sensitivity tree AstActive* newactp = createActivePost(nodep); dlyvscp->user2p(newactp); newactp->addStmtsp(prep); // Add to FRONT of statements newactp->addStmtsp(postp); } AstVarRef* newrefp = new AstVarRef(nodep->fileline(), dlyvscp, true); newrefp->user2(true); // No reason to do it again nodep->replaceWith(newrefp); nodep->deleteTree(); nodep=NULL; } else if (!m_inDly && nodep->lvalue()) { //UINFO(9,"NBA "<<nodep<<endl); if (!m_inInitial) { UINFO(4,"AssignNDlyVar: "<<nodep<<endl); markVarUsage(nodep->varScopep(), VU_NONDLY); } } } }