Internals: Eliminate user5 for smaller AstNode/better runtime

This commit is contained in:
Wilson Snyder 2008-11-25 07:57:02 -05:00
parent 314c9de845
commit 30ad20be52
6 changed files with 53 additions and 52 deletions

View File

@ -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. *** 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] **** Fix arrayed variables under function not compiling, bug44. [Ralf Karge]

View File

@ -84,8 +84,6 @@ void AstNode::init() {
m_user3Cnt = 0; m_user3Cnt = 0;
m_user4p = NULL; m_user4p = NULL;
m_user4Cnt = 0; m_user4Cnt = 0;
m_user5p = NULL;
m_user5Cnt = 0;
} }
string AstNode::encodeName(const string& namein) { string AstNode::encodeName(const string& namein) {

View File

@ -580,8 +580,6 @@ class AstNode {
int m_user3Cnt; // Mark of when userp was set int m_user3Cnt; // Mark of when userp was set
AstNUser* m_user4p; // Pointer to any information the user iteration routine wants AstNUser* m_user4p; // Pointer to any information the user iteration routine wants
int m_user4Cnt; // Mark of when userp was set 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 // METHODS
void op1p(AstNode* nodep) { m_op1p = nodep; if (nodep) nodep->m_backp = this; } 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)); } void user4(int val) { user4p(AstNUser::fromInt(val)); }
static void user4ClearTree() { AstUser4InUse::clear(); } 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; } vluint64_t editCount() const { return m_editCount; }
void editCountInc() { m_editCount = ++s_editCntGbl; } void editCountInc() { m_editCount = ++s_editCntGbl; }
static vluint64_t editCountLast() { return s_editCntLast; } static vluint64_t editCountLast() { return s_editCntLast; }

View File

@ -75,19 +75,18 @@ private:
// AstVarScope::userp() -> AstVarScope*. Points to temp var created. // AstVarScope::userp() -> AstVarScope*. Points to temp var created.
// AstVarScope::user2p() -> AstActive*. Points to activity block of signal // AstVarScope::user2p() -> AstActive*. Points to activity block of signal
// AstVarScope::user4p() -> AstAlwaysPost*. Post block for this variable // 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::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 // AstVar::user4() -> int. Vector number, for assignment creation
// AstVarRef::user2() -> bool. Set true if already processed // AstVarRef::user2() -> bool. Set true if already processed
// AstAlwaysPost::user4() -> AstIf*. Last IF (__Vdlyvset__) created under this AlwaysPost // AstAlwaysPost::user4() -> AstIf*. Last IF (__Vdlyvset__) created under this AlwaysPost
// Cleared each scope: // Cleared each scope:
// AstAssignDly::user5() -> AstVarScope*. __Vdlyvset__ created for this assign // AstAssignDly::user3() -> AstVarScope*. __Vdlyvset__ created for this assign
// AstAlwaysPost::user5() -> AstVarScope*. __Vdlyvset__ last referenced in IF // AstAlwaysPost::user3() -> AstVarScope*. __Vdlyvset__ last referenced in IF
AstUserInUse m_inuse1; AstUserInUse m_inuse1;
AstUser2InUse m_inuse2; AstUser2InUse m_inuse2;
AstUser3InUse m_inuse3; AstUser3InUse m_inuse3;
AstUser4InUse m_inuse4; AstUser4InUse m_inuse4;
AstUser5InUse m_inuse5;
enum VarUsage { VU_NONE=0, VU_DLY=1, VU_NONDLY=2 }; enum VarUsage { VU_NONE=0, VU_DLY=1, VU_NONDLY=2 };
@ -107,8 +106,8 @@ private:
// METHODS // METHODS
void markVarUsage(AstVar* nodep, uint32_t flags) { void markVarUsage(AstVar* nodep, uint32_t flags) {
//UINFO(4," MVU "<<flags<<" "<<nodep<<endl); //UINFO(4," MVU "<<flags<<" "<<nodep<<endl);
nodep->user3( nodep->user3() | flags ); nodep->user( nodep->user() | flags );
if ((nodep->user3() & VU_DLY) && (nodep->user3() & VU_NONDLY)) { if ((nodep->user() & VU_DLY) && (nodep->user() & VU_NONDLY)) {
nodep->v3warn(BLKANDNBLK,"Unsupported: Blocked and non-blocking assignments to same variable: "<<nodep->prettyName()); nodep->v3warn(BLKANDNBLK,"Unsupported: Blocked and non-blocking assignments to same variable: "<<nodep->prettyName());
} }
} }
@ -227,13 +226,13 @@ private:
bool sharedVset = false; bool sharedVset = false;
AstVarScope* setvscp; AstVarScope* setvscp;
if (nodep->user5p()) { if (nodep->user3p()) {
// Simplistic optimization. If the previous statement in same scope was also a =>, // 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: // This is good for code like:
// for (i=0; i<5; i++) vector[i] <= something; // for (i=0; i<5; i++) vector[i] <= something;
sharedVset = true; sharedVset = true;
setvscp = nodep->user5p()->castNode()->castVarScope(); setvscp = nodep->user3p()->castNode()->castVarScope();
m_statSharedSet++; m_statSharedSet++;
} else { // Create new one } else { // Create new one
string setvarname = (string("__Vdlyvset__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum)); string setvarname = (string("__Vdlyvset__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
@ -251,7 +250,7 @@ private:
nodep->addNextHere(setassignp); nodep->addNextHere(setassignp);
} }
if (m_nextDlyp) { // Tell next assigndly it can share the variable if (m_nextDlyp) { // Tell next assigndly it can share the variable
m_nextDlyp->user5p(setvscp); m_nextDlyp->user3p(setvscp);
} }
// //
// Create ALWAYSPOST for delayed variable // Create ALWAYSPOST for delayed variable
@ -278,7 +277,7 @@ private:
varrefp->varScopep()->user4p(finalp); varrefp->varScopep()->user4p(finalp);
} }
AstIf* postLogicp; AstIf* postLogicp;
if (finalp->user5p()->castNode() == setvscp) { if (finalp->user3p()->castNode() == setvscp) {
// Optimize as above; if sharing Vdlyvset *ON SAME VARIABLE*, // Optimize as above; if sharing Vdlyvset *ON SAME VARIABLE*,
// we can share the IF statement too // we can share the IF statement too
postLogicp = finalp->user4p()->castNode()->castIf(); postLogicp = finalp->user4p()->castNode()->castIf();
@ -290,7 +289,7 @@ private:
NULL); NULL);
UINFO(9," Created "<<postLogicp<<endl); UINFO(9," Created "<<postLogicp<<endl);
finalp->addBodysp(postLogicp); finalp->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 finalp->user4p(postLogicp); // and the associated IF, as we may be able to reuse it
} }
postLogicp->addIfsp(new AstAssign(nodep->fileline(), selectsp, valreadp)); postLogicp->addIfsp(new AstAssign(nodep->fileline(), selectsp, valreadp));
@ -306,7 +305,7 @@ private:
} }
virtual void visit(AstScope* nodep, AstNUser*) { virtual void visit(AstScope* nodep, AstNUser*) {
UINFO(4," MOD "<<nodep<<endl); UINFO(4," MOD "<<nodep<<endl);
AstNode::user5ClearTree(); AstNode::user3ClearTree();
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
} }
virtual void visit(AstCFunc* nodep, AstNUser*) { virtual void visit(AstCFunc* nodep, AstNUser*) {

View File

@ -241,8 +241,8 @@ private:
// Entire Netlist: // Entire Netlist:
// AstVarScope::userp -> OrderUser* for usage var // AstVarScope::userp -> OrderUser* for usage var
// {statement}Node::userp-> AstModule* statement is under // {statement}Node::userp-> AstModule* statement is under
// USER5 Cleared on each Logic stmt // USER4 Cleared on each Logic stmt
// AstVarScope::user5() -> VarUsage(gen/con/both). Where already encountered signal // AstVarScope::user4() -> VarUsage(gen/con/both). Where already encountered signal
// Ordering (user3/4/5 cleared between forming and ordering) // Ordering (user3/4/5 cleared between forming and ordering)
// AstScope::userp() -> AstModule*. Module this scope is under // AstScope::userp() -> AstModule*. Module this scope is under
// AstModule::user3() -> Number of routines created // AstModule::user3() -> Number of routines created
@ -250,7 +250,6 @@ private:
AstUser2InUse m_inuse2; AstUser2InUse m_inuse2;
AstUser3InUse m_inuse3; AstUser3InUse m_inuse3;
AstUser4InUse m_inuse4; AstUser4InUse m_inuse4;
AstUser5InUse m_inuse5;
//int debug() { return 9; } //int debug() { return 9; }
@ -297,8 +296,8 @@ private:
void iterateNewStmt(AstNode* nodep) { void iterateNewStmt(AstNode* nodep) {
if (m_scopep) { if (m_scopep) {
UINFO(4," STMT "<<nodep<<endl); UINFO(4," STMT "<<nodep<<endl);
//VV***** We reset user5p() //VV***** We reset user4p()
AstNode::user5ClearTree(); AstNode::user4ClearTree();
if (!m_activep || !m_activep->sensesp()) nodep->v3fatalSrc("NULL"); if (!m_activep || !m_activep->sensesp()) nodep->v3fatalSrc("NULL");
// If inside combo logic, ignore the domain, we'll assign one based on interconnect // If inside combo logic, ignore the domain, we'll assign one based on interconnect
AstSenTree* startDomainp = m_activep->sensesp(); AstSenTree* startDomainp = m_activep->sensesp();
@ -461,7 +460,7 @@ private:
// Done topscope, erase extra user information // Done topscope, erase extra user information
// userp passed to next process() operation // userp passed to next process() operation
AstNode::user3ClearTree(); AstNode::user3ClearTree();
AstNode::user5ClearTree(); AstNode::user4ClearTree();
} }
virtual void visit(AstModule* nodep, AstNUser*) { virtual void visit(AstModule* nodep, AstNUser*) {
m_modp = nodep; m_modp = nodep;
@ -516,10 +515,10 @@ private:
bool gen = false; bool gen = false;
bool con = false; bool con = false;
if (nodep->lvalue()) { if (nodep->lvalue()) {
gen = !(varscp->user5() & VU_GEN); gen = !(varscp->user4() & VU_GEN);
} else { } else {
con = !(varscp->user5() & VU_CON); con = !(varscp->user4() & VU_CON);
if ((varscp->user5() & VU_GEN) && !m_inClocked) { if ((varscp->user4() & VU_GEN) && !m_inClocked) {
// Dangerous assumption: // Dangerous assumption:
// If a variable is used in the same activation which defines it first, // If a variable is used in the same activation which defines it first,
// consider it something like: // consider it something like:
@ -536,8 +535,8 @@ private:
con = false; con = false;
} }
} }
if (gen) varscp->user5(varscp->user5() | VU_GEN); if (gen) varscp->user4(varscp->user4() | VU_GEN);
if (con) varscp->user5(varscp->user5() | VU_CON); if (con) varscp->user4(varscp->user4() | VU_CON);
// Add edges // Add edges
if (!m_inClocked if (!m_inClocked
|| m_inPost || m_inPost

View File

@ -62,13 +62,18 @@ public:
class TaskFTaskVertex : public TaskBaseVertex { class TaskFTaskVertex : public TaskBaseVertex {
// Every task gets a vertex, and we link tasks together based on funcrefs. // Every task gets a vertex, and we link tasks together based on funcrefs.
AstNodeFTask* m_nodep; AstNodeFTask* m_nodep;
AstCFunc* m_cFuncp;
public: public:
TaskFTaskVertex(V3Graph* graphp, AstNodeFTask* nodep) TaskFTaskVertex(V3Graph* graphp, AstNodeFTask* nodep)
: TaskBaseVertex(graphp), m_nodep(nodep) {} : TaskBaseVertex(graphp), m_nodep(nodep) {
m_cFuncp=NULL;
}
virtual ~TaskFTaskVertex() {} virtual ~TaskFTaskVertex() {}
AstNodeFTask* nodep() const { return m_nodep; } AstNodeFTask* nodep() const { return m_nodep; }
virtual string name() const { return nodep()->name(); } virtual string name() const { return nodep()->name(); }
virtual string dotColor() const { return pure() ? "black" : "red"; } 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 { class TaskCodeVertex : public TaskBaseVertex {
@ -99,6 +104,9 @@ private:
// AstNodeFTask::user4p // GraphFTaskVertex* this FTask is under // AstNodeFTask::user4p // GraphFTaskVertex* this FTask is under
// AstVar::user4p // GraphFTaskVertex* this variable is declared in // AstVar::user4p // GraphFTaskVertex* this variable is declared in
AstUser3InUse m_inuse3;
AstUser4InUse m_inuse4;
// TYPES // TYPES
typedef std::map<pair<AstScope*,AstVar*>,AstVarScope*> VarToScopeMap; typedef std::map<pair<AstScope*,AstVar*>,AstVarScope*> VarToScopeMap;
// MEMBERS // MEMBERS
@ -122,6 +130,13 @@ public:
bool ftaskNoInline(AstNodeFTask* nodep) { bool ftaskNoInline(AstNodeFTask* nodep) {
return (getFTaskVertex(nodep)->noInline()); 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) { void checkPurity(AstNodeFTask* nodep) {
checkPurity(nodep, getFTaskVertex(nodep)); checkPurity(nodep, getFTaskVertex(nodep));
} }
@ -136,11 +151,11 @@ public:
} }
} }
private: private:
TaskBaseVertex* getFTaskVertex(AstNodeFTask* nodep) { TaskFTaskVertex* getFTaskVertex(AstNodeFTask* nodep) {
if (!nodep->user4p()) { if (!nodep->user4p()) {
nodep->user4p(new TaskFTaskVertex(&m_callGraph, nodep)); nodep->user4p(new TaskFTaskVertex(&m_callGraph, nodep));
} }
return static_cast<TaskBaseVertex*>(nodep->user4p()->castGraphVertex()); return static_cast<TaskFTaskVertex*>(nodep->user4p()->castGraphVertex());
} }
// VISITORS // VISITORS
@ -277,10 +292,13 @@ class TaskVisitor : public AstNVisitor {
private: private:
// NODE STATE // NODE STATE
// Each module: // Each module:
// AstNodeFTask::user // True if its been expanded // AstNodeFTask::user // True if its been expanded
// Each funccall // Each funccall
// AstVar::user2p // AstVarScope* to replace varref with // to TaskRelinkVisitor:
// AstNodeFTask::user5p // AstCFunc* created for non-inlined tasks // AstVar::user2p // AstVarScope* to replace varref with
AstUserInUse m_inuse;
AstUser2InUse m_inuse2;
// TYPES // TYPES
enum InsertMode { enum InsertMode {
@ -415,7 +433,7 @@ private:
AstNode* createNonInlinedFTask(AstNodeFTaskRef* refp, string namePrefix, AstVarScope* outvscp) { AstNode* createNonInlinedFTask(AstNodeFTaskRef* refp, string namePrefix, AstVarScope* outvscp) {
// outvscp is the variable for functions only, if NULL, it's a task // outvscp is the variable for functions only, if NULL, it's a task
if (!refp->taskp()) refp->v3fatalSrc("Unlinked?"); 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?"); if (!cfuncp) refp->v3fatalSrc("No non-inline task associated with this task call?");
// //
@ -686,7 +704,7 @@ private:
m_statep->checkPurity(nodep); m_statep->checkPurity(nodep);
AstNodeFTask* clonedFuncp = nodep->cloneTree(false); AstNodeFTask* clonedFuncp = nodep->cloneTree(false);
AstCFunc* cfuncp = makeUserFunc(clonedFuncp, false); AstCFunc* cfuncp = makeUserFunc(clonedFuncp, false);
nodep->user5p(cfuncp); m_statep->ftaskCFuncp(nodep, cfuncp);
nodep->addNextHere(cfuncp); nodep->addNextHere(cfuncp);
iterateIntoFTask(clonedFuncp); // Do the clone too iterateIntoFTask(clonedFuncp); // Do the clone too
} }
@ -708,7 +726,8 @@ private:
pushDeletep(vscp->unlinkFrBack()); vscp=NULL; 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(); nodep->unlinkFrBack();
pushDeletep(nodep); nodep=NULL; pushDeletep(nodep); nodep=NULL;
} }
@ -753,7 +772,6 @@ public:
m_scopep = NULL; m_scopep = NULL;
m_insStmtp = NULL; m_insStmtp = NULL;
AstNode::userClearTree(); AstNode::userClearTree();
AstNode::user5ClearTree();
nodep->accept(*this); nodep->accept(*this);
} }
virtual ~TaskVisitor() {} virtual ~TaskVisitor() {}
@ -764,11 +782,6 @@ public:
void V3Task::taskAll(AstNetlist* nodep) { void V3Task::taskAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl); UINFO(2,__FUNCTION__<<": "<<endl);
AstUserInUse m_inuse;
AstUser2InUse m_inuse2;
AstUser3InUse m_inuse3;
AstUser4InUse m_inuse4;
AstUser5InUse m_inuse5;
TaskStateVisitor visitors (nodep); TaskStateVisitor visitors (nodep);
TaskVisitor visitor (nodep, &visitors); TaskVisitor visitor (nodep, &visitors);
} }