diff --git a/src/V3Ast.h b/src/V3Ast.h index 594749a0f..50fc3dfaf 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2025,12 +2025,15 @@ public: #include "V3Ast__gen_impl.h" // From ./astgen // Specializations of privateMayBeUnder -template <> inline bool AstNode::mayBeUnder(const AstNode* nodep) { +template <> inline bool AstNode::privateMayBeUnder(const AstNode* nodep) { return !VN_IS(nodep, NodeStmt) && !VN_IS(nodep, NodeMath); } -template <> inline bool AstNode::mayBeUnder(const AstNode* nodep) { +template <> inline bool AstNode::privateMayBeUnder(const AstNode* nodep) { return !VN_IS(nodep, NodeMath); } +template <> inline bool AstNode::privateMayBeUnder(const AstNode* nodep) { + return !VN_IS(nodep, NodeStmt) && !VN_IS(nodep, NodeMath); +} inline std::ostream& operator<<(std::ostream& os, const AstNode* rhs) { if (!rhs) { diff --git a/src/V3Changed.cpp b/src/V3Changed.cpp index 5bb6bd1f8..bddcf76a7 100644 --- a/src/V3Changed.cpp +++ b/src/V3Changed.cpp @@ -117,8 +117,8 @@ public: class ChangedInsertVisitor final : public VNVisitor { private: // STATE - ChangedState* m_statep = nullptr; // Shared state across visitors - AstVarScope* m_vscp = nullptr; // Original (non-change) variable we're change-detecting + ChangedState& m_state; // Shared state across visitors + AstVarScope* const m_vscp; // Original (non-change) variable we're change-detecting AstVarScope* m_newvscp = nullptr; // New (change detect) variable we're change-detecting AstNode* m_varEqnp = nullptr; // Original var's equation to get var value AstNode* m_newLvEqnp = nullptr; // New var's equation to read value @@ -126,34 +126,32 @@ private: uint32_t m_detects = 0; // # detects created // CONSTANTS - enum MiscConsts { - DETECTARRAY_MAX_INDEXES = 256 // How many indexes before error - // Ok to increase this, but may result in much slower model - }; + // How many indexes before error. Ok to increase this, but may result in much slower model + static constexpr uint32_t DETECTARRAY_MAX_INDEXES = 256; void newChangeDet() { if (++m_detects > DETECTARRAY_MAX_INDEXES) { m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect more than " - << cvtToStr(DETECTARRAY_MAX_INDEXES) + << DETECTARRAY_MAX_INDEXES << " array indexes (probably with UNOPTFLAT warning suppressed): " << m_vscp->prettyName() << '\n' << m_vscp->warnMore() << "... Could recompile with DETECTARRAY_MAX_INDEXES increased"); return; } - m_statep->maybeCreateChgFuncp(); + m_state.maybeCreateChgFuncp(); AstChangeDet* const changep = new AstChangeDet{ m_vscp->fileline(), m_varEqnp->cloneTree(true), m_newRvEqnp->cloneTree(true)}; - m_statep->m_chgFuncp->addStmtsp(changep); + m_state.m_chgFuncp->addStmtsp(changep); AstAssign* const initp = new AstAssign{m_vscp->fileline(), m_newLvEqnp->cloneTree(true), m_varEqnp->cloneTree(true)}; - m_statep->m_chgFuncp->addFinalsp(initp); + m_state.m_chgFuncp->addFinalsp(initp); // Later code will expand words which adds to GCC compile time, // so add penalty based on word width also - m_statep->m_numStmts += initp->nodeCount() + m_varEqnp->widthWords(); + m_state.m_numStmts += initp->nodeCount() + m_varEqnp->widthWords(); } virtual void visit(AstBasicDType*) override { // @@ -202,13 +200,13 @@ private: public: // CONSTRUCTORS - ChangedInsertVisitor(AstVarScope* vscp, ChangedState* statep) { + ChangedInsertVisitor(AstVarScope* vscp, ChangedState& state) + : m_state{state} + , m_vscp{vscp} { // DPI export trigger should never need change detect. See similar assertions in V3Order // (OrderVisitor::nodeMarkCircular), and V3GenClk (GenClkRenameVisitor::genInpClk). UASSERT_OBJ(vscp != v3Global.rootp()->dpiExportTriggerp(), vscp, "DPI export trigger should not need change detect"); - m_statep = statep; - m_vscp = vscp; { AstVar* const varp = m_vscp->varp(); const string newvarname{"__Vchglast__" + m_vscp->scopep()->nameDotless() + "__" @@ -219,9 +217,9 @@ public: // CHANGEDET(VARREF(_last), VARREF(var)) AstVar* const newvarp = new AstVar{varp->fileline(), VVarType::MODULETEMP, newvarname, varp}; - m_statep->m_topModp->addStmtp(newvarp); - m_newvscp = new AstVarScope{m_vscp->fileline(), m_statep->m_scopetopp, newvarp}; - m_statep->m_scopetopp->addVarp(m_newvscp); + m_state.m_topModp->addStmtp(newvarp); + m_newvscp = new AstVarScope{m_vscp->fileline(), m_state.m_scopetopp, newvarp}; + m_state.m_scopetopp->addVarp(m_newvscp); m_varEqnp = new AstVarRef{m_vscp->fileline(), m_vscp, VAccess::READ}; m_newLvEqnp = new AstVarRef{m_vscp->fileline(), m_newvscp, VAccess::WRITE}; @@ -236,72 +234,22 @@ public: VL_UNCOPYABLE(ChangedInsertVisitor); }; -//###################################################################### -// Changed state, as a visitor of each AstNode - -class ChangedVisitor final : public VNVisitor { -private: - // NODE STATE - // Entire netlist: - // AstVarScope::user1() -> bool. True indicates processed - const VNUser1InUse m_inuser1; - - // STATE - ChangedState* const m_statep; // Shared state across visitors - - // METHODS - VL_DEBUG_FUNC; // Declare debug() - - void genChangeDet(AstVarScope* vscp) { - vscp->v3warn(IMPERFECTSCH, "Imperfect scheduling of variable: " << vscp->prettyNameQ()); - { ChangedInsertVisitor{vscp, m_statep}; } - } - - // VISITORS - virtual void visit(AstNodeModule* nodep) override { - UINFO(4, " MOD " << nodep << endl); - if (nodep->isTop()) m_statep->m_topModp = nodep; - iterateChildren(nodep); - } - - virtual void visit(AstTopScope* nodep) override { - UINFO(4, " TS " << nodep << endl); - // Clearing - AstNode::user1ClearTree(); - // Prep for if make change detection function - AstScope* const scopep = nodep->scopep(); - UASSERT_OBJ(scopep, nodep, "No scope found on top level, perhaps you have no statements?"); - m_statep->m_scopetopp = scopep; - - iterateChildren(nodep); - } - virtual void visit(AstVarScope* nodep) override { - if (nodep->isCircular()) { - UINFO(8, " CIRC " << nodep << endl); - if (!nodep->user1SetOnce()) genChangeDet(nodep); - } - } - //-------------------- - virtual void visit(AstNodeMath*) override {} // Accelerate - virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } - -public: - // CONSTRUCTORS - ChangedVisitor(AstNetlist* nodep, ChangedState* statep) - : m_statep{statep} { - iterate(nodep); - } - virtual ~ChangedVisitor() override = default; -}; - //###################################################################### // Changed class functions void V3Changed::changedAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); - { - ChangedState state; - ChangedVisitor{nodep, &state}; - } // Destruct before checking + + ChangedState state; + state.m_scopetopp = nodep->topScopep()->scopep(); + state.m_topModp = nodep->topModulep(); + nodep->foreach([&state](AstVarScope* vscp) { + if (vscp->isCircular()) { + vscp->v3warn(IMPERFECTSCH, + "Imperfect scheduling of variable: " << vscp->prettyNameQ()); + ChangedInsertVisitor{vscp, state}; + } + }); + V3Global::dumpCheckGlobalTree("changed", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); } diff --git a/src/V3GenClk.cpp b/src/V3GenClk.cpp index a6c252723..a358ca2aa 100644 --- a/src/V3GenClk.cpp +++ b/src/V3GenClk.cpp @@ -53,9 +53,7 @@ private: // METHODS AstVarScope* genInpClk(AstVarScope* vscp) { - if (vscp->user2p()) { - return VN_AS(vscp->user2p(), VarScope); - } else { + if (!vscp->user2p()) { // In order to create a __VinpClk* for a signal, it needs to be marked circular. // The DPI export trigger is never marked circular by V3Order (see comments in // OrderVisitor::nodeMarkCircular). The only other place where one might mark @@ -86,22 +84,15 @@ private: m_scopetopp->addFinalClkp(asninitp); // vscp->user2p(newvscp); - return newvscp; } + return VN_AS(vscp->user2p(), VarScope); } // VISITORS - virtual void visit(AstTopScope* nodep) override { - AstNode::user2ClearTree(); // user2p() used on entire tree - iterateChildren(nodep); - } - //---- virtual void visit(AstVarRef* nodep) override { // Consumption/generation of a variable, - AstVarScope* const vscp = nodep->varScopep(); - UASSERT_OBJ(vscp, nodep, "Scope not assigned"); - if (m_activep && !nodep->user3()) { - nodep->user3(true); + if (m_activep && !nodep->user3SetOnce()) { + AstVarScope* const vscp = nodep->varScopep(); if (vscp->isCircular()) { UINFO(8, " VarActReplace " << nodep << endl); // Replace with the new variable @@ -115,10 +106,8 @@ private: } virtual void visit(AstActive* nodep) override { m_activep = nodep; - UASSERT_OBJ(nodep->sensesp(), nodep, "Unlinked"); iterate(nodep->sensesp()); m_activep = nullptr; - iterateChildren(nodep); } //----- @@ -141,7 +130,6 @@ private: // NODE STATE // Cleared on top scope // AstVarScope::user() -> bool. Set when the var has been used as clock - const VNUser1InUse m_inuser1; // STATE bool m_tracingCall = false; // Iterating into a call to a cfunc @@ -151,13 +139,13 @@ private: // VISITORS virtual void visit(AstTopScope* nodep) override { - AstNode::user1ClearTree(); // user1p() used on entire tree - iterateChildren(nodep); { - // Make the new clock signals and replace any activate references - // See rename, it does some AstNode::userClearTree()'s - GenClkRenameVisitor{nodep, m_topModp}; + const VNUser1InUse user1InUse; + iterateChildren(nodep); } + // Make the new clock signals and replace any activate references + // See rename, it does some AstNode::userClearTree()'s + GenClkRenameVisitor{nodep, m_topModp}; } virtual void visit(AstNodeModule* nodep) override { // Only track the top scopes, not lower level functions