diff --git a/Changes b/Changes index 177919ff7..9a6288984 100644 --- a/Changes +++ b/Changes @@ -7,7 +7,9 @@ indicates the contributor was also the author of the fix; Thanks! *** Optimize two-level shift and and/or trees, +23% on one test. -**** Support posedge of bit-selected signals, bug45. [Rodney Sinclair] +*** Support posedge of bit-selected signals, bug45. [Rodney Sinclair] + +**** Minor performance improvements of Verilator compiler runtime. **** Fix arrayed variables under function not compiling, bug44. [Ralf Karge] diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 917f794d5..ecb6b7e06 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -84,8 +84,6 @@ void AstNode::init() { m_user3Cnt = 0; m_user4p = NULL; m_user4Cnt = 0; - m_user5p = NULL; - m_user5Cnt = 0; } string AstNode::encodeName(const string& namein) { diff --git a/src/V3Ast.h b/src/V3Ast.h index 279088c5e..ae7476bc0 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -580,8 +580,6 @@ class AstNode { int m_user3Cnt; // Mark of when userp was set AstNUser* m_user4p; // Pointer to any information the user iteration routine wants int m_user4Cnt; // Mark of when userp was set - AstNUser* m_user5p; // Pointer to any information the user iteration routine wants - int m_user5Cnt; // Mark of when userp was set // METHODS void op1p(AstNode* nodep) { m_op1p = nodep; if (nodep) nodep->m_backp = this; } @@ -723,14 +721,6 @@ public: void user4(int val) { user4p(AstNUser::fromInt(val)); } static void user4ClearTree() { AstUser4InUse::clear(); } - AstNUser* user5p() const { - //UASSERT_STATIC(AstUser5InUse::s_userBusy, "user5p set w/o busy"); - return ((m_user5Cnt==AstUser5InUse::s_userCntGbl)?m_user5p:NULL); } - void user5p(void* userp) { m_user5p=(AstNUser*)(userp); m_user5Cnt=AstUser5InUse::s_userCntGbl; } - int user5() const { return user5p()->castInt(); } - void user5(int val) { user5p(AstNUser::fromInt(val)); } - static void user5ClearTree() { AstUser5InUse::clear(); } - vluint64_t editCount() const { return m_editCount; } void editCountInc() { m_editCount = ++s_editCntGbl; } static vluint64_t editCountLast() { return s_editCntLast; } diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index bb0d35da7..46d158452 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -75,19 +75,18 @@ private: // AstVarScope::userp() -> AstVarScope*. Points to temp var created. // AstVarScope::user2p() -> AstActive*. Points to activity block of signal // AstVarScope::user4p() -> AstAlwaysPost*. Post block for this variable + // AstVar::user() -> VarUsage. Tracks delayed vs non-delayed usage // AstVar::user2() -> bool. Set true if already made warning - // AstVar::user3() -> VarUsage. Tracks delayed vs non-delayed usage // AstVar::user4() -> int. Vector number, for assignment creation // AstVarRef::user2() -> bool. Set true if already processed // AstAlwaysPost::user4() -> AstIf*. Last IF (__Vdlyvset__) created under this AlwaysPost // Cleared each scope: - // AstAssignDly::user5() -> AstVarScope*. __Vdlyvset__ created for this assign - // AstAlwaysPost::user5() -> AstVarScope*. __Vdlyvset__ last referenced in IF + // AstAssignDly::user3() -> AstVarScope*. __Vdlyvset__ created for this assign + // AstAlwaysPost::user3() -> AstVarScope*. __Vdlyvset__ last referenced in IF AstUserInUse m_inuse1; AstUser2InUse m_inuse2; AstUser3InUse m_inuse3; AstUser4InUse m_inuse4; - AstUser5InUse m_inuse5; enum VarUsage { VU_NONE=0, VU_DLY=1, VU_NONDLY=2 }; @@ -107,8 +106,8 @@ private: // METHODS void markVarUsage(AstVar* nodep, uint32_t flags) { //UINFO(4," MVU "<user3( nodep->user3() | flags ); - if ((nodep->user3() & VU_DLY) && (nodep->user3() & VU_NONDLY)) { + nodep->user( nodep->user() | flags ); + if ((nodep->user() & VU_DLY) && (nodep->user() & VU_NONDLY)) { nodep->v3warn(BLKANDNBLK,"Unsupported: Blocked and non-blocking assignments to same variable: "<prettyName()); } } @@ -227,13 +226,13 @@ private: bool sharedVset = false; AstVarScope* setvscp; - if (nodep->user5p()) { + if (nodep->user3p()) { // Simplistic optimization. If the previous statement in same scope was also a =>, - // then we told this nodep->user5 we can use its Vdlyvset rather than making a new one. + // then we told this nodep->user3 we can use its Vdlyvset rather than making a new one. // This is good for code like: // for (i=0; i<5; i++) vector[i] <= something; sharedVset = true; - setvscp = nodep->user5p()->castNode()->castVarScope(); + setvscp = nodep->user3p()->castNode()->castVarScope(); m_statSharedSet++; } else { // Create new one string setvarname = (string("__Vdlyvset__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum)); @@ -251,7 +250,7 @@ private: nodep->addNextHere(setassignp); } if (m_nextDlyp) { // Tell next assigndly it can share the variable - m_nextDlyp->user5p(setvscp); + m_nextDlyp->user3p(setvscp); } // // Create ALWAYSPOST for delayed variable @@ -278,7 +277,7 @@ private: varrefp->varScopep()->user4p(finalp); } AstIf* postLogicp; - if (finalp->user5p()->castNode() == setvscp) { + if (finalp->user3p()->castNode() == setvscp) { // Optimize as above; if sharing Vdlyvset *ON SAME VARIABLE*, // we can share the IF statement too postLogicp = finalp->user4p()->castNode()->castIf(); @@ -290,7 +289,7 @@ private: NULL); UINFO(9," Created "<addBodysp(postLogicp); - finalp->user5p(setvscp); // Remember IF's vset variable + finalp->user3p(setvscp); // Remember IF's vset variable finalp->user4p(postLogicp); // and the associated IF, as we may be able to reuse it } postLogicp->addIfsp(new AstAssign(nodep->fileline(), selectsp, valreadp)); @@ -306,7 +305,7 @@ private: } virtual void visit(AstScope* nodep, AstNUser*) { UINFO(4," MOD "<iterateChildren(*this); } virtual void visit(AstCFunc* nodep, AstNUser*) { diff --git a/src/V3Order.cpp b/src/V3Order.cpp index bceccec47..9cdfd40cd 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -241,8 +241,8 @@ private: // Entire Netlist: // AstVarScope::userp -> OrderUser* for usage var // {statement}Node::userp-> AstModule* statement is under - // USER5 Cleared on each Logic stmt - // AstVarScope::user5() -> VarUsage(gen/con/both). Where already encountered signal + // USER4 Cleared on each Logic stmt + // AstVarScope::user4() -> VarUsage(gen/con/both). Where already encountered signal // Ordering (user3/4/5 cleared between forming and ordering) // AstScope::userp() -> AstModule*. Module this scope is under // AstModule::user3() -> Number of routines created @@ -250,7 +250,6 @@ private: AstUser2InUse m_inuse2; AstUser3InUse m_inuse3; AstUser4InUse m_inuse4; - AstUser5InUse m_inuse5; //int debug() { return 9; } @@ -297,8 +296,8 @@ private: void iterateNewStmt(AstNode* nodep) { if (m_scopep) { UINFO(4," STMT "<sensesp()) nodep->v3fatalSrc("NULL"); // If inside combo logic, ignore the domain, we'll assign one based on interconnect AstSenTree* startDomainp = m_activep->sensesp(); @@ -461,7 +460,7 @@ private: // Done topscope, erase extra user information // userp passed to next process() operation AstNode::user3ClearTree(); - AstNode::user5ClearTree(); + AstNode::user4ClearTree(); } virtual void visit(AstModule* nodep, AstNUser*) { m_modp = nodep; @@ -516,10 +515,10 @@ private: bool gen = false; bool con = false; if (nodep->lvalue()) { - gen = !(varscp->user5() & VU_GEN); + gen = !(varscp->user4() & VU_GEN); } else { - con = !(varscp->user5() & VU_CON); - if ((varscp->user5() & VU_GEN) && !m_inClocked) { + con = !(varscp->user4() & VU_CON); + if ((varscp->user4() & VU_GEN) && !m_inClocked) { // Dangerous assumption: // If a variable is used in the same activation which defines it first, // consider it something like: @@ -536,8 +535,8 @@ private: con = false; } } - if (gen) varscp->user5(varscp->user5() | VU_GEN); - if (con) varscp->user5(varscp->user5() | VU_CON); + if (gen) varscp->user4(varscp->user4() | VU_GEN); + if (con) varscp->user4(varscp->user4() | VU_CON); // Add edges if (!m_inClocked || m_inPost diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 5d02e938f..abfee7236 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -62,13 +62,18 @@ public: class TaskFTaskVertex : public TaskBaseVertex { // Every task gets a vertex, and we link tasks together based on funcrefs. AstNodeFTask* m_nodep; + AstCFunc* m_cFuncp; public: TaskFTaskVertex(V3Graph* graphp, AstNodeFTask* nodep) - : TaskBaseVertex(graphp), m_nodep(nodep) {} + : TaskBaseVertex(graphp), m_nodep(nodep) { + m_cFuncp=NULL; + } virtual ~TaskFTaskVertex() {} AstNodeFTask* nodep() const { return m_nodep; } virtual string name() const { return nodep()->name(); } virtual string dotColor() const { return pure() ? "black" : "red"; } + AstCFunc* cFuncp() const { return m_cFuncp; } + void cFuncp(AstCFunc* nodep) { m_cFuncp=nodep; } }; class TaskCodeVertex : public TaskBaseVertex { @@ -99,6 +104,9 @@ private: // AstNodeFTask::user4p // GraphFTaskVertex* this FTask is under // AstVar::user4p // GraphFTaskVertex* this variable is declared in + AstUser3InUse m_inuse3; + AstUser4InUse m_inuse4; + // TYPES typedef std::map,AstVarScope*> VarToScopeMap; // MEMBERS @@ -122,6 +130,13 @@ public: bool ftaskNoInline(AstNodeFTask* nodep) { return (getFTaskVertex(nodep)->noInline()); } + AstCFunc* ftaskCFuncp(AstNodeFTask* nodep) { + return (getFTaskVertex(nodep)->cFuncp()); + } + void ftaskCFuncp(AstNodeFTask* nodep, AstCFunc* cfuncp) { + getFTaskVertex(nodep)->cFuncp(cfuncp); + } + void checkPurity(AstNodeFTask* nodep) { checkPurity(nodep, getFTaskVertex(nodep)); } @@ -136,11 +151,11 @@ public: } } private: - TaskBaseVertex* getFTaskVertex(AstNodeFTask* nodep) { + TaskFTaskVertex* getFTaskVertex(AstNodeFTask* nodep) { if (!nodep->user4p()) { nodep->user4p(new TaskFTaskVertex(&m_callGraph, nodep)); } - return static_cast(nodep->user4p()->castGraphVertex()); + return static_cast(nodep->user4p()->castGraphVertex()); } // VISITORS @@ -277,10 +292,13 @@ class TaskVisitor : public AstNVisitor { private: // NODE STATE // Each module: - // AstNodeFTask::user // True if its been expanded + // AstNodeFTask::user // True if its been expanded // Each funccall - // AstVar::user2p // AstVarScope* to replace varref with - // AstNodeFTask::user5p // AstCFunc* created for non-inlined tasks + // to TaskRelinkVisitor: + // AstVar::user2p // AstVarScope* to replace varref with + + AstUserInUse m_inuse; + AstUser2InUse m_inuse2; // TYPES enum InsertMode { @@ -415,7 +433,7 @@ private: AstNode* createNonInlinedFTask(AstNodeFTaskRef* refp, string namePrefix, AstVarScope* outvscp) { // outvscp is the variable for functions only, if NULL, it's a task if (!refp->taskp()) refp->v3fatalSrc("Unlinked?"); - AstCFunc* cfuncp = refp->taskp()->user5p()->castNode()->castCFunc(); + AstCFunc* cfuncp = m_statep->ftaskCFuncp(refp->taskp()); if (!cfuncp) refp->v3fatalSrc("No non-inline task associated with this task call?"); // @@ -686,7 +704,7 @@ private: m_statep->checkPurity(nodep); AstNodeFTask* clonedFuncp = nodep->cloneTree(false); AstCFunc* cfuncp = makeUserFunc(clonedFuncp, false); - nodep->user5p(cfuncp); + m_statep->ftaskCFuncp(nodep, cfuncp); nodep->addNextHere(cfuncp); iterateIntoFTask(clonedFuncp); // Do the clone too } @@ -708,7 +726,8 @@ private: pushDeletep(vscp->unlinkFrBack()); vscp=NULL; } } - // Just push, as other references to func may remain until visitor exits + // Just push for deletion, as other references to func may + // remain until visitor exits nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL; } @@ -753,7 +772,6 @@ public: m_scopep = NULL; m_insStmtp = NULL; AstNode::userClearTree(); - AstNode::user5ClearTree(); nodep->accept(*this); } virtual ~TaskVisitor() {} @@ -764,11 +782,6 @@ public: void V3Task::taskAll(AstNetlist* nodep) { UINFO(2,__FUNCTION__<<": "<