From ca4e3c173753067893e833eea8736504fcf09fef Mon Sep 17 00:00:00 2001 From: Wilson Snyder <wsnyder@wsnyder.org> Date: Tue, 26 Sep 2006 17:05:08 +0000 Subject: [PATCH] Eliminate assigned only variables git-svn-id: file://localhost/svn/verilator/trunk/verilator@797 77ca24e4-aefa-0310-84f0-b9a241c72d87 --- src/V3Dead.cpp | 40 +++++++++++++++++++++++++++++++++++++--- src/V3Life.cpp | 26 +++++++++++++++++++++++--- src/Verilator.cpp | 7 +++++++ 3 files changed, 67 insertions(+), 6 deletions(-) diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index 573b16113..fb8cde3be 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -29,6 +29,7 @@ #include <stdarg.h> #include <unistd.h> #include <vector> +#include <map> #include "V3Global.h" #include "V3Dead.h" @@ -70,10 +71,15 @@ private: // AstVar::user() -> int. Count of number of references // AstVarScope::user() -> int. Count of number of references + // TYPES + typedef multimap<AstVarScope*,AstNodeAssign*> AssignMap; + // STATE vector<AstVar*> m_varsp; // List of all encountered to avoid another loop through tree vector<AstVarScope*> m_vscsp; // List of all encountered to avoid another loop through tree + AssignMap m_assignMap; // List of all simple assignments for each variable bool m_elimUserVars; // Allow removal of user's vars + bool m_sideEffect; // Side effects discovered in assign RHS //int debug() { return 9; } // METHODS @@ -102,6 +108,25 @@ private: m_varsp.push_back(nodep); } + virtual void visit(AstNodeAssign* nodep, AstNUser*) { + // See if simple assignments to variables may be eliminated because that variable is never used. + // Similar code in V3Life + m_sideEffect = false; + nodep->rhsp()->iterateAndNext(*this); + // Has to be direct assignment without any EXTRACTing. + AstVarRef* varrefp = nodep->lhsp()->castVarRef(); + if (varrefp && !m_sideEffect + && varrefp->varScopep()) { // For simplicity, we only remove post-scoping + m_assignMap.insert(make_pair(varrefp->varScopep(), nodep)); + } else { // Track like any other statement + nodep->lhsp()->iterateAndNext(*this); + } + } + virtual void visit(AstUCFunc* nodep, AstNUser*) { + m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment + nodep->iterateChildren(*this); + } + //----- virtual void visit(AstNode* nodep, AstNUser*) { nodep->iterateChildren(*this); @@ -131,14 +156,22 @@ private: } bool canElim(AstVar* nodep) { return (!nodep->isSigPublic() // Can't elim publics! + && !nodep->isIO() && (nodep->isTemp() || nodep->isParam() || m_elimUserVars)); } void deadCheckVar() { // Delete any unused varscopes for (vector<AstVarScope*>::iterator it = m_vscsp.begin(); it!=m_vscsp.end(); ++it) { - if ((*it)->user() == 0 && canElim((*it)->varp())) { - UINFO(4," Dead "<<(*it)<<endl); - (*it)->unlinkFrBack()->deleteTree(); (*it)=NULL; + AstVarScope* vscp = *it; + if (vscp->user() == 0 && canElim(vscp->varp())) { + UINFO(4," Dead "<<vscp<<endl); + pair <AssignMap::iterator,AssignMap::iterator> eqrange = m_assignMap.equal_range(vscp); + for (AssignMap::iterator it = eqrange.first; it != eqrange.second; ++it) { + AstNodeAssign* assp = it->second; + UINFO(4," Dead assign "<<assp<<endl); + assp->unlinkFrBack()->deleteTree(); assp=NULL; + } + vscp->unlinkFrBack()->deleteTree(); vscp=NULL; } } for (vector<AstVar*>::iterator it = m_varsp.begin(); it!=m_varsp.end(); ++it) { @@ -153,6 +186,7 @@ public: // CONSTRUCTORS DeadVisitor(AstNetlist* nodep, bool elimUserVars) { m_elimUserVars = elimUserVars; + m_sideEffect = false; // Operate on whole netlist AstNode::userClearTree(); // userp() used on entire tree nodep->accept(*this); diff --git a/src/V3Life.cpp b/src/V3Life.cpp index d94df75fa..c35a87b1f 100644 --- a/src/V3Life.cpp +++ b/src/V3Life.cpp @@ -264,7 +264,8 @@ public: class LifeVisitor : public AstNVisitor { private: // STATE - LifeState* m_statep; // Current state + LifeState* m_statep; // Current state + bool m_sideEffect; // Side effects discovered in assign RHS //static int debug() { return 9; } // LIFE MAP @@ -289,7 +290,9 @@ private: } virtual void visit(AstNodeAssign* nodep, AstNUser*) { // Collect any used variables first, as lhs may also be on rhs + // Similar code in V3Dead vluint64_t lastEdit = AstNode::editCountGbl(); // When it was last edited + m_sideEffect = false; nodep->rhsp()->iterateAndNext(*this); if (lastEdit != AstNode::editCountGbl()) { // We changed something, try to constant propagate, but don't delete the @@ -297,7 +300,7 @@ private: V3Const::constifyTree(nodep->rhsp()); } // Has to be direct assignment without any EXTRACTing. - if (nodep->lhsp()->castVarRef()) { + if (nodep->lhsp()->castVarRef() && !m_sideEffect) { AstVarScope* vscp = nodep->lhsp()->castVarRef()->varScopep(); if (!vscp) vscp->v3fatalSrc("Scope lost on variable"); m_lifep->simpleAssign(vscp, nodep); @@ -373,6 +376,10 @@ private: // Enter the function and trace it nodep->funcp()->accept(*this); } + virtual void visit(AstUCFunc* nodep, AstNUser*) { + m_sideEffect = true; // If appears on assign RHS, don't ever delete the assignment + nodep->iterateChildren(*this); + } virtual void visit(AstVar*, AstNUser*) {} // Don't want varrefs under it virtual void visit(AstNode* nodep, AstNUser*) { @@ -381,9 +388,10 @@ private: public: // CONSTRUCTORS - LifeVisitor(AstCFunc* nodep, LifeState* statep) { + LifeVisitor(AstNode* nodep, LifeState* statep) { UINFO(4," LifeVisitor on "<<nodep<<endl); m_statep = statep; + m_sideEffect = false; { m_lifep = new LifeBlock (NULL, m_statep); nodep->accept(*this); @@ -409,6 +417,18 @@ private: LifeVisitor visitor (nodep, m_statep); } } + virtual void visit(AstAlways* nodep, AstNUser*) { + // Usage model 2: Cleanup basic blocks + LifeVisitor visitor (nodep, m_statep); + } + virtual void visit(AstInitial* nodep, AstNUser*) { + // Usage model 2: Cleanup basic blocks + LifeVisitor visitor (nodep, m_statep); + } + virtual void visit(AstFinal* nodep, AstNUser*) { + // Usage model 2: Cleanup basic blocks + LifeVisitor visitor (nodep, m_statep); + } virtual void visit(AstVar*, AstNUser*) {} // Accelerate virtual void visit(AstNodeStmt*, AstNUser*) {} // Accelerate virtual void visit(AstNodeMath*, AstNUser*) {} // Accelerate diff --git a/src/Verilator.cpp b/src/Verilator.cpp index e132efd92..85b95e5bc 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -248,7 +248,13 @@ void process () { V3Case::caseAll(v3Global.rootp()); v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("case.tree")); + // Push constants across variables and remove redundant assignments V3Const::constifyAll(v3Global.rootp()); + if (v3Global.opt.oLife()) { + V3Life::lifeAll(v3Global.rootp()); + v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("life.tree")); + } + //v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree")); // Make large low-fanin logic blocks into lookup tables @@ -329,6 +335,7 @@ void process () { // Cleanup any dly vars or other temps that are simple assignments // Life must be done before Subst, as it assumes each CFunc under _eval is called only once. if (v3Global.opt.oLife()) { + V3Const::constifyAll(v3Global.rootp()); V3Life::lifeAll(v3Global.rootp()); } if (v3Global.opt.oLifePost()) {