2012-04-13 01:08:20 +00:00
|
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
2006-08-26 11:35:28 +00:00
|
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: Dead code elimination
|
|
|
|
|
//
|
2008-04-25 12:14:27 +00:00
|
|
|
|
// Code available from: http://www.veripool.org/verilator
|
2006-08-26 11:35:28 +00:00
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2013-01-01 14:42:59 +00:00
|
|
|
|
// Copyright 2003-2013 by Wilson Snyder. This program is free software; you can
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// redistribute it and/or modify it under the terms of either the GNU
|
2009-05-04 21:07:57 +00:00
|
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
// Version 2.0.
|
2006-08-26 11:35:28 +00:00
|
|
|
|
//
|
|
|
|
|
// Verilator is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// DEAD TRANSFORMATIONS:
|
|
|
|
|
// Remove any unreferenced modules
|
|
|
|
|
// Remove any unreferenced variables
|
2008-06-10 01:25:10 +00:00
|
|
|
|
//
|
2012-05-03 00:53:19 +00:00
|
|
|
|
// TODO: A graph would make the process of circular and interlinked
|
|
|
|
|
// dependencies easier to resolve.
|
2009-11-08 02:05:02 +00:00
|
|
|
|
// NOTE: If redo this, consider using maybePointedTo()/broken() ish scheme
|
|
|
|
|
// instead of needing as many visitors.
|
2006-08-26 11:35:28 +00:00
|
|
|
|
//*************************************************************************
|
|
|
|
|
|
2006-12-18 19:20:45 +00:00
|
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
2008-06-30 17:11:25 +00:00
|
|
|
|
#include <cstdio>
|
|
|
|
|
#include <cstdarg>
|
2006-08-26 11:35:28 +00:00
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <vector>
|
2006-09-26 17:05:08 +00:00
|
|
|
|
#include <map>
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
|
#include "V3Global.h"
|
|
|
|
|
#include "V3Dead.h"
|
|
|
|
|
#include "V3Ast.h"
|
|
|
|
|
|
2006-09-01 14:05:20 +00:00
|
|
|
|
//######################################################################
|
|
|
|
|
|
|
|
|
|
class DeadModVisitor : public AstNVisitor {
|
|
|
|
|
// In a module that is dead, cleanup the in-use counts of the modules
|
|
|
|
|
private:
|
|
|
|
|
// NODE STATE
|
|
|
|
|
// ** Shared with DeadVisitor **
|
|
|
|
|
// VISITORS
|
|
|
|
|
virtual void visit(AstCell* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
2008-11-25 14:03:49 +00:00
|
|
|
|
nodep->modp()->user1(nodep->modp()->user1() - 1);
|
2006-09-01 14:05:20 +00:00
|
|
|
|
}
|
|
|
|
|
//-----
|
|
|
|
|
virtual void visit(AstNodeMath* nodep, AstNUser*) {} // Accelerate
|
|
|
|
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
}
|
|
|
|
|
public:
|
|
|
|
|
// CONSTRUCTORS
|
2009-11-07 11:20:20 +00:00
|
|
|
|
DeadModVisitor(AstNodeModule* nodep) {
|
2006-09-01 14:05:20 +00:00
|
|
|
|
nodep->accept(*this);
|
|
|
|
|
}
|
|
|
|
|
virtual ~DeadModVisitor() {}
|
|
|
|
|
};
|
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
//######################################################################
|
|
|
|
|
// Dead state, as a visitor of each AstNode
|
|
|
|
|
|
|
|
|
|
class DeadVisitor : public AstNVisitor {
|
|
|
|
|
private:
|
|
|
|
|
// NODE STATE
|
|
|
|
|
// Entire Netlist:
|
2012-03-01 04:05:11 +00:00
|
|
|
|
// AstNodeModule::user1() -> int. Count of number of cells referencing this module.
|
|
|
|
|
// AstVar::user1() -> int. Count of number of references
|
|
|
|
|
// AstVarScope::user1() -> int. Count of number of references
|
2012-04-29 14:14:13 +00:00
|
|
|
|
// AstNodeDType::user1() -> int. Count of number of references
|
2008-11-25 14:03:49 +00:00
|
|
|
|
AstUser1InUse m_inuser1;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
2006-09-26 17:05:08 +00:00
|
|
|
|
// TYPES
|
|
|
|
|
typedef multimap<AstVarScope*,AstNodeAssign*> AssignMap;
|
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// STATE
|
2012-03-01 04:05:11 +00:00
|
|
|
|
vector<AstNode*> m_varEtcsp; // List of all encountered to avoid another loop through tree
|
2006-09-01 14:05:20 +00:00
|
|
|
|
vector<AstVarScope*> m_vscsp; // List of all encountered to avoid another loop through tree
|
2006-09-26 17:05:08 +00:00
|
|
|
|
AssignMap m_assignMap; // List of all simple assignments for each variable
|
2006-08-26 11:35:28 +00:00
|
|
|
|
bool m_elimUserVars; // Allow removal of user's vars
|
2012-04-29 14:14:13 +00:00
|
|
|
|
bool m_elimDTypes; // Allow removal of DTypes
|
2006-09-26 17:05:08 +00:00
|
|
|
|
bool m_sideEffect; // Side effects discovered in assign RHS
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
|
// METHODS
|
2009-01-21 21:56:50 +00:00
|
|
|
|
static int debug() {
|
|
|
|
|
static int level = -1;
|
|
|
|
|
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
|
|
|
|
|
return level;
|
|
|
|
|
}
|
2012-04-29 14:14:13 +00:00
|
|
|
|
|
2012-03-03 17:10:29 +00:00
|
|
|
|
void checkAll(AstNode* nodep) {
|
2012-04-29 14:14:13 +00:00
|
|
|
|
if (nodep != nodep->dtypep()) { // NodeDTypes reference themselves
|
|
|
|
|
if (AstNode* subnodep = nodep->dtypep()) subnodep->user1Inc();
|
|
|
|
|
}
|
|
|
|
|
if (AstNode* subnodep = nodep->getChildDTypep()) subnodep->user1Inc();
|
|
|
|
|
}
|
|
|
|
|
void checkDType(AstNodeDType* nodep) {
|
|
|
|
|
if (!nodep->generic() // Don't remove generic types
|
|
|
|
|
&& m_elimDTypes) { // dtypes stick around until post-widthing
|
|
|
|
|
m_varEtcsp.push_back(nodep);
|
|
|
|
|
}
|
|
|
|
|
if (AstNode* subnodep = nodep->virtRefDTypep()) subnodep->user1Inc();
|
2012-03-03 17:10:29 +00:00
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
|
|
|
|
|
// VISITORS
|
|
|
|
|
virtual void visit(AstCell* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
2012-03-03 17:10:29 +00:00
|
|
|
|
checkAll(nodep);
|
2010-04-16 00:56:54 +00:00
|
|
|
|
nodep->modp()->user1Inc();
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstNodeVarRef* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
2012-03-03 17:10:29 +00:00
|
|
|
|
checkAll(nodep);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
if (nodep->varScopep()) {
|
2010-04-16 00:56:54 +00:00
|
|
|
|
nodep->varScopep()->user1Inc();
|
|
|
|
|
nodep->varScopep()->varp()->user1Inc();
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
if (nodep->varp()) {
|
2010-04-16 00:56:54 +00:00
|
|
|
|
nodep->varp()->user1Inc();
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
2009-11-08 02:05:02 +00:00
|
|
|
|
if (nodep->packagep()) {
|
2010-04-16 00:56:54 +00:00
|
|
|
|
nodep->packagep()->user1Inc();
|
2009-11-08 02:05:02 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
2012-03-03 17:10:29 +00:00
|
|
|
|
checkAll(nodep);
|
2009-11-08 02:05:02 +00:00
|
|
|
|
if (nodep->packagep()) {
|
2010-04-16 00:56:54 +00:00
|
|
|
|
nodep->packagep()->user1Inc();
|
2009-11-08 02:05:02 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstRefDType* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
2012-04-29 14:14:13 +00:00
|
|
|
|
checkDType(nodep);
|
2012-03-03 17:10:29 +00:00
|
|
|
|
checkAll(nodep);
|
2009-11-08 02:05:02 +00:00
|
|
|
|
if (nodep->packagep()) {
|
2010-04-16 00:56:54 +00:00
|
|
|
|
nodep->packagep()->user1Inc();
|
2009-11-08 02:05:02 +00:00
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
2012-04-29 14:14:13 +00:00
|
|
|
|
virtual void visit(AstNodeDType* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
|
|
|
|
checkDType(nodep);
|
|
|
|
|
checkAll(nodep);
|
|
|
|
|
}
|
2011-04-13 23:34:14 +00:00
|
|
|
|
virtual void visit(AstEnumItemRef* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
2012-03-03 17:10:29 +00:00
|
|
|
|
checkAll(nodep);
|
2011-04-13 23:34:14 +00:00
|
|
|
|
if (nodep->packagep()) {
|
|
|
|
|
nodep->packagep()->user1Inc();
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
virtual void visit(AstVarScope* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
2012-03-03 17:10:29 +00:00
|
|
|
|
checkAll(nodep);
|
2012-03-01 04:05:11 +00:00
|
|
|
|
if (mightElim(nodep->varp())) {
|
|
|
|
|
m_vscsp.push_back(nodep);
|
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
virtual void visit(AstVar* nodep, AstNUser*) {
|
|
|
|
|
nodep->iterateChildren(*this);
|
2012-03-03 17:10:29 +00:00
|
|
|
|
checkAll(nodep);
|
2012-03-01 04:05:11 +00:00
|
|
|
|
if (mightElim(nodep)) {
|
|
|
|
|
m_varEtcsp.push_back(nodep);
|
|
|
|
|
}
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2006-09-26 17:05:08 +00:00
|
|
|
|
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);
|
2012-04-29 14:14:13 +00:00
|
|
|
|
checkAll(nodep);
|
2006-09-26 17:05:08 +00:00
|
|
|
|
// 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));
|
2012-05-03 00:53:19 +00:00
|
|
|
|
checkAll(varrefp); // Must track reference to dtype()
|
2006-09-26 17:05:08 +00:00
|
|
|
|
} else { // Track like any other statement
|
|
|
|
|
nodep->lhsp()->iterateAndNext(*this);
|
|
|
|
|
}
|
2012-03-03 17:10:29 +00:00
|
|
|
|
checkAll(nodep);
|
2006-09-26 17:05:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2006-08-26 11:35:28 +00:00
|
|
|
|
//-----
|
|
|
|
|
virtual void visit(AstNode* nodep, AstNUser*) {
|
2010-04-19 23:38:22 +00:00
|
|
|
|
if (nodep->isOutputter()) m_sideEffect=true;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
nodep->iterateChildren(*this);
|
2012-03-03 17:10:29 +00:00
|
|
|
|
checkAll(nodep);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// METHODS
|
|
|
|
|
void deadCheckMod() {
|
|
|
|
|
// Kill any unused modules
|
2006-09-01 14:05:20 +00:00
|
|
|
|
// V3LinkCells has a graph that is capable of this too, but we need to do it
|
|
|
|
|
// after we've done all the generate blocks
|
2006-08-26 11:35:28 +00:00
|
|
|
|
for (bool retry=true; retry; ) {
|
|
|
|
|
retry=false;
|
2009-11-07 11:20:20 +00:00
|
|
|
|
AstNodeModule* nextmodp;
|
|
|
|
|
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp=nextmodp) {
|
|
|
|
|
nextmodp = modp->nextp()->castNodeModule();
|
2008-11-25 14:03:49 +00:00
|
|
|
|
if (modp->level()>2 && modp->user1()==0) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// > 2 because L1 is the wrapper, L2 is the top user module
|
|
|
|
|
UINFO(4," Dead module "<<modp<<endl);
|
2006-09-01 14:05:20 +00:00
|
|
|
|
// And its children may now be killable too; correct counts
|
|
|
|
|
// Recurse, as cells may not be directly under the module but in a generate
|
|
|
|
|
DeadModVisitor visitor(modp);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
modp->unlinkFrBack()->deleteTree(); modp=NULL;
|
2006-09-01 14:05:20 +00:00
|
|
|
|
retry = true;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-03-01 04:05:11 +00:00
|
|
|
|
bool mightElim(AstVar* nodep) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
return (!nodep->isSigPublic() // Can't elim publics!
|
2006-09-26 17:05:08 +00:00
|
|
|
|
&& !nodep->isIO()
|
2006-08-26 11:35:28 +00:00
|
|
|
|
&& (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) {
|
2006-09-26 17:05:08 +00:00
|
|
|
|
AstVarScope* vscp = *it;
|
2012-03-01 04:05:11 +00:00
|
|
|
|
if (vscp->user1() == 0) {
|
2006-09-26 17:05:08 +00:00
|
|
|
|
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;
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2012-03-01 04:05:11 +00:00
|
|
|
|
for (vector<AstNode*>::iterator it = m_varEtcsp.begin(); it!=m_varEtcsp.end(); ++it) {
|
|
|
|
|
if ((*it)->user1() == 0) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
UINFO(4," Dead "<<(*it)<<endl);
|
|
|
|
|
(*it)->unlinkFrBack()->deleteTree(); (*it)=NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
// CONSTRUCTORS
|
2012-04-29 14:14:13 +00:00
|
|
|
|
DeadVisitor(AstNetlist* nodep, bool elimUserVars, bool elimDTypes) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
m_elimUserVars = elimUserVars;
|
2012-04-29 14:14:13 +00:00
|
|
|
|
m_elimDTypes = elimDTypes;
|
2006-09-26 17:05:08 +00:00
|
|
|
|
m_sideEffect = false;
|
2012-04-29 14:14:13 +00:00
|
|
|
|
// Prepare to remove some datatypes
|
|
|
|
|
nodep->typeTablep()->clearCache();
|
2006-08-26 11:35:28 +00:00
|
|
|
|
// Operate on whole netlist
|
|
|
|
|
nodep->accept(*this);
|
|
|
|
|
deadCheckVar();
|
|
|
|
|
// Modules after vars, because might be vars we delete inside a mod we delete
|
|
|
|
|
deadCheckMod();
|
2012-04-29 14:14:13 +00:00
|
|
|
|
// We may have removed some datatypes, cleanup
|
|
|
|
|
nodep->typeTablep()->repairCache();
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|
|
|
|
|
virtual ~DeadVisitor() {}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Dead class functions
|
|
|
|
|
|
2012-04-29 12:24:32 +00:00
|
|
|
|
void V3Dead::deadifyModules(AstNetlist* nodep) {
|
2006-08-26 11:35:28 +00:00
|
|
|
|
UINFO(2,__FUNCTION__<<": "<<endl);
|
2012-04-29 14:14:13 +00:00
|
|
|
|
DeadVisitor visitor (nodep, false, false);
|
2012-04-29 12:24:32 +00:00
|
|
|
|
}
|
|
|
|
|
void V3Dead::deadifyDTypes(AstNetlist* nodep) {
|
|
|
|
|
UINFO(2,__FUNCTION__<<": "<<endl);
|
2012-04-29 14:14:13 +00:00
|
|
|
|
DeadVisitor visitor (nodep, false, true);
|
2012-04-29 12:24:32 +00:00
|
|
|
|
}
|
|
|
|
|
void V3Dead::deadifyAll(AstNetlist* nodep) {
|
|
|
|
|
UINFO(2,__FUNCTION__<<": "<<endl);
|
2012-04-29 14:14:13 +00:00
|
|
|
|
DeadVisitor visitor (nodep, true, true);
|
2006-08-26 11:35:28 +00:00
|
|
|
|
}
|