Internals: Add V3Const preserving liveness, no functional change

This commit is contained in:
Wilson Snyder 2010-12-28 21:23:16 -05:00
parent 9f161b20ef
commit c8852d183f
3 changed files with 210 additions and 185 deletions

View File

@ -103,8 +103,9 @@ private:
bool m_required; // If true, must become a constant
bool m_wremove; // Inside scope, no assignw removal
bool m_warn; // Output warnings
bool m_doV; // Verilog, not C++ conversion
bool m_doExpensive; // Enable computationally expensive optimizations
bool m_doNConst; // Enable non-constant-child simplifications
bool m_doV; // Verilog, not C++ conversion
AstNodeModule* m_modp; // Current module
AstNode* m_scopep; // Current scope
@ -1070,6 +1071,7 @@ private:
if (operandConst(nodep->varp()->valuep())
&& !nodep->lvalue()
&& ((!m_params // Can reduce constant wires into equations
&& m_doNConst
&& v3Global.opt.oConst()
&& !nodep->varp()->isSigPublic())
|| nodep->varp()->isParam())) {
@ -1122,8 +1124,9 @@ private:
}
virtual void visit(AstSenItem* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (nodep->sensp()->castConst()
|| (nodep->varrefp() && nodep->varrefp()->varp()->isParam())) {
if (m_doNConst
&& (nodep->sensp()->castConst()
|| (nodep->varrefp() && nodep->varrefp()->varp()->isParam()))) {
// Constants in sensitivity lists may be removed (we'll simplify later)
if (nodep->isClocked()) { // A constant can never get a pos/negexge
if (onlySenItemInSenTree(nodep)) {
@ -1136,7 +1139,7 @@ private:
nodep->replaceWith(new AstSenItem(nodep->fileline(), AstSenItem::Combo()));
nodep->deleteTree(); nodep=NULL;
}
} else if (nodep->sensp()->castNot()) {
} else if (m_doNConst && nodep->sensp()->castNot()) {
// V3Gate may propagate NOTs into clocks... Just deal with it
AstNode* sensp = nodep->sensp();
AstNode* lastSensp = sensp;
@ -1306,16 +1309,16 @@ private:
// Zero elimination
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
nodep->iterateChildren(*this);
replaceNodeAssign(nodep);
if (m_doNConst && replaceNodeAssign(nodep)) return;
}
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
// Don't perform any optimizations, keep the alias around
}
virtual void visit(AstAssignW* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (replaceNodeAssign(nodep)) return;
if (m_doNConst && replaceNodeAssign(nodep)) return;
AstNodeVarRef* varrefp = nodep->lhsp()->castVarRef(); // Not VarXRef, as different refs may set different values to each hierarchy
if (m_wremove && !m_params
if (m_wremove && !m_params && m_doNConst
&& m_modp && operandConst(nodep->rhsp())
&& !nodep->rhsp()->castConst()->num().isFourState()
&& varrefp // Don't do messes with BITREFs/ARRAYREFs
@ -1340,6 +1343,7 @@ private:
virtual void visit(AstNodeIf* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (m_doNConst) {
if (AstConst* constp = nodep->condp()->castConst()) {
AstNode* keepp = NULL;
if (constp->isZero()) {
@ -1413,6 +1417,7 @@ private:
replaceBoolShift(nodep->condp());
}
}
}
virtual void visit(AstSFormatF* nodep, AstNUser*) {
// Substitute constants into displays. The main point of this is to
@ -1423,7 +1428,7 @@ private:
for (AstNode* argp = nodep->exprsp(); argp; argp=argp->nextp()) {
if (argp->castConst()) { anyconst=true; break; }
}
if (anyconst) {
if (m_doNConst && anyconst) {
//UINFO(9," Display in "<<nodep->text()<<endl);
string dispout = "";
string fmt = "";
@ -1486,6 +1491,7 @@ private:
virtual void visit(AstWhile* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (m_doNConst) {
if (nodep->condp()->isZero()) {
UINFO(4,"WHILE(0) => nop "<<nodep<<endl);
if (nodep->precondsp()) nodep->replaceWith(nodep->precondsp());
@ -1496,6 +1502,7 @@ private:
replaceBoolShift(nodep->condp());
}
}
}
// These are converted by V3Param. Don't constify as we don't want the from() VARREF to disappear, if any
// If output of a presel didn't get consted, chances are V3Param didn't visit properly
@ -1547,10 +1554,11 @@ private:
// Lint Checks
// v--- *1* These ops are always first, as we warn before replacing
// v--- *V* This op is a verilog op, only in m_doV mode
// v--- *C* This op works on all constant children, allowed in m_doConst mode
TREEOP1("AstSel{warnSelect(nodep)}", "NEVER");
// Generic constants on both side. Do this first to avoid other replacements
TREEOP("AstNodeBiop {$lhsp.castConst, $rhsp.castConst}", "replaceConst(nodep)");
TREEOP("AstNodeUniop{$lhsp.castConst, !nodep->isOpaque()}", "replaceConst(nodep)");
TREEOPC("AstNodeBiop {$lhsp.castConst, $rhsp.castConst}", "replaceConst(nodep)");
TREEOPC("AstNodeUniop{$lhsp.castConst, !nodep->isOpaque()}", "replaceConst(nodep)");
// Zero on one side or the other
TREEOP ("AstAdd {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
TREEOP ("AstAnd {$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
@ -1746,7 +1754,7 @@ private:
TREEOPV("AstSel{operandSelExtend(nodep)}", "replaceWChild(nodep, nodep->fromp()->castExtend()->lhsp())");
TREEOPV("AstSel{operandSelFull(nodep)}", "replaceWChild(nodep, nodep->fromp())");
TREEOPV("AstSel{$fromp.castSel}", "replaceSelSel(nodep)");
TREEOPV("AstSel{$fromp.castConst, $lsbp.castConst, $widthp.castConst, }", "replaceConst(nodep)");
TREEOPC("AstSel{$fromp.castConst, $lsbp.castConst, $widthp.castConst, }", "replaceConst(nodep)");
TREEOPV("AstSel{$fromp.castConcat, $lsbp.castConst, $widthp.castConst, }", "replaceSelConcat(nodep)");
TREEOPV("AstSel{$fromp.castReplicate, $lsbp.castConst, $widthp.isOne, }", "replaceSelReplicate(nodep)");
// Conversions
@ -1754,7 +1762,7 @@ private:
TREEOPV("AstLogIf {$lhsp, $rhsp}", "AstLogOr{AstLogNot{$lhsp},$rhsp}");
TREEOPV("AstLogIff{$lhsp, $rhsp}", "AstLogNot{AstXor{$lhsp,$rhsp}}");
// Strings
TREEOP ("AstCvtPackString{$lhsp.castConst}", "replaceConstString(nodep, nodep->lhsp()->castConst()->num().toString())");
TREEOPC("AstCvtPackString{$lhsp.castConst}", "replaceConstString(nodep, nodep->lhsp()->castConst()->num().toString())");
// Possible futures:
@ -1784,6 +1792,7 @@ public:
// Processing Mode Enum
enum ProcMode {
PROC_PARAMS,
PROC_V_LIVE,
PROC_V_WARN,
PROC_V_NOWARN,
PROC_V_EXPENSIVE,
@ -1794,19 +1803,21 @@ public:
ConstVisitor(ProcMode pmode) {
m_params = false;
m_required = false;
m_doV = false;
m_doExpensive = false;
m_doNConst = false;
m_doV = false;
m_warn = false;
m_wremove = true; // Overridden in visitors
m_modp = NULL;
m_scopep = NULL;
//
switch (pmode) {
case PROC_PARAMS: m_doV = true; m_params = true; m_required = true; break;
case PROC_V_WARN: m_doV = true; m_warn = true; break;
case PROC_V_NOWARN: m_doV = true; break;
case PROC_V_EXPENSIVE: m_doV = true; m_doExpensive = true; break;
case PROC_CPP: m_doV = false; break;
case PROC_PARAMS: m_doV = true; m_doNConst = true; m_params = true; m_required = true; break;
case PROC_V_LIVE: m_doV = true; break;
case PROC_V_WARN: m_doV = true; m_doNConst = true; m_warn = true; break;
case PROC_V_NOWARN: m_doV = true; m_doNConst = true; break;
case PROC_V_EXPENSIVE: m_doV = true; m_doNConst = true; m_doExpensive = true; break;
case PROC_CPP: m_doV = false; m_doNConst = true; break;
default: v3fatalSrc("Bad case"); break;
}
}
@ -1858,6 +1869,15 @@ AstNode* V3Const::constifyEdit(AstNode* nodep) {
return nodep;
}
void V3Const::constifyAllLive(AstNetlist* nodep) {
// Only call from Verilator.cpp, as it uses user#'s
// This only pushes constants up, doesn't make any other edits
// IE doesn't prune dead statements, as we need to do some usability checks after this
UINFO(2,__FUNCTION__<<": "<<endl);
ConstVisitor visitor (ConstVisitor::PROC_V_LIVE);
(void)visitor.mainAcceptEdit(nodep);
}
void V3Const::constifyAll(AstNetlist* nodep) {
// Only call from Verilator.cpp, as it uses user#'s
UINFO(2,__FUNCTION__<<": "<<endl);

View File

@ -34,6 +34,8 @@ public:
// Force this cell node's parameter list to become a constant
// Return new node that may have replaced nodep
static AstNode* constifyParamsEdit(AstNode* nodep);
// Only do constant pushing, without removing dead logic
static void constifyAllLive(AstNetlist* nodep);
// Everything that's possible
static void constifyAll(AstNetlist* nodep);
// Also, warn

View File

@ -268,8 +268,8 @@ sub tree_line {
$func =~ s!\s*//.*$!!;
$func =~ s!\s*;\s*$!!;
if ($func =~ /TREEOP(1?)(V?)\s*\(\s* \"([^\"]*)\" \s*,\s* \"([^\"]*)\" \s*\)/sx) {
my $order = $1; my $cpp = $2; my $from = $3; my $to = $4;
if ($func =~ /TREEOP(1?)([VC]?)\s*\(\s* \"([^\"]*)\" \s*,\s* \"([^\"]*)\" \s*\)/sx) {
my $order = $1; my $doflag = $2; my $from = $3; my $to = $4;
#$self->print("// $from $to\n");
if (!$self->{did_out_tree}) {
$self->{did_out_tree} = 1;
@ -284,8 +284,11 @@ sub tree_line {
my $subnodes = $2;
(::subclasses_of($type)) or $self->error("Unknown AstNode type: $type: in $func");
my $mif = "";
$mif = "m_doV" if $cpp;
my $mif;
if ($doflag eq '') { $mif = "m_doNConst"; }
elsif ($doflag eq 'V') { $mif = "m_doV"; }
elsif ($doflag eq 'C') { $mif = ""; }
else { die; }
$subnodes =~ s/,,/__ESCAPEDCOMMA__/g;
foreach my $subnode (split /\s*,\s*/, $subnodes) {
$subnode =~ s/__ESCAPEDCOMMA__/,/g;