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.
**** 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]

View File

@ -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) {

View File

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

View File

@ -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 "<<flags<<" "<<nodep<<endl);
nodep->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: "<<nodep->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 "<<postLogicp<<endl);
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
}
postLogicp->addIfsp(new AstAssign(nodep->fileline(), selectsp, valreadp));
@ -306,7 +305,7 @@ private:
}
virtual void visit(AstScope* nodep, AstNUser*) {
UINFO(4," MOD "<<nodep<<endl);
AstNode::user5ClearTree();
AstNode::user3ClearTree();
nodep->iterateChildren(*this);
}
virtual void visit(AstCFunc* nodep, AstNUser*) {

View File

@ -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 "<<nodep<<endl);
//VV***** We reset user5p()
AstNode::user5ClearTree();
//VV***** We reset user4p()
AstNode::user4ClearTree();
if (!m_activep || !m_activep->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

View File

@ -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<pair<AstScope*,AstVar*>,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<TaskBaseVertex*>(nodep->user4p()->castGraphVertex());
return static_cast<TaskFTaskVertex*>(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__<<": "<<endl);
AstUserInUse m_inuse;
AstUser2InUse m_inuse2;
AstUser3InUse m_inuse3;
AstUser4InUse m_inuse4;
AstUser5InUse m_inuse5;
TaskStateVisitor visitors (nodep);
TaskVisitor visitor (nodep, &visitors);
}