Internals: Eliminate user5 for smaller AstNode/better runtime
This commit is contained in:
parent
314c9de845
commit
30ad20be52
4
Changes
4
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]
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
10
src/V3Ast.h
10
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; }
|
||||
|
|
|
|||
|
|
@ -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*) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue