From 94f0809d333903465ffe226878b12c45d6952314 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 27 Sep 2006 18:00:53 +0000 Subject: [PATCH] Add more boolean identity fixes git-svn-id: file://localhost/svn/verilator/trunk/verilator@798 77ca24e4-aefa-0310-84f0-b9a241c72d87 --- Changes | 4 +++- bin/verilator | 5 +++++ src/V3AstNodes.h | 4 +++- src/V3Const.cpp | 45 +++++++++++++++++++++++++++++++++--------- src/astgen | 23 +++++++++++---------- test_verilated/vgen.pl | 29 +++++++++++++++++++++++++-- 6 files changed, 87 insertions(+), 23 deletions(-) diff --git a/Changes b/Changes index 2495e471f..9339965ae 100644 --- a/Changes +++ b/Changes @@ -9,11 +9,13 @@ indicates the contributor was also the author of the fix; Thanks! *** Allow overriding Perl, Flex and Bison versions. [by Robert Farrell] -*** Optimize variables set to constants within basic blocks. +*** Optimize variables set to constants within basic blocks for ~3%. **** Default make no longer makes the docs; if you edit the documentation sources, run "make info" to get them. +**** Optimize additional boolean identities (a|a = a, etc.) + * Verilator 3.610 09/20/2006 *** Verilator now works under DJGPP (Pentium GCC). [John Stroebel] diff --git a/bin/verilator b/bin/verilator index 704c98ea1..94681f84b 100755 --- a/bin/verilator +++ b/bin/verilator @@ -1516,6 +1516,11 @@ Call Verilated::assertOn(false) before you first call the model, then turn it back on after reset. It defaults to true. When false, all assertions controlled by --assert are disabled. +=item Why do I get "undefined reference to `sc_time_stamp()'"? + +In C++ (non SystemC) code you need to define this function so that the +simulator knows the current time. See the "CONNECTING TO C++" examples. + =item Is the PLI supported? No. diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 792a55a6d..5df207817 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -1597,7 +1597,8 @@ public: bool hasClocked() const { return m_sensesp->hasClocked(); } }; -class AstAttrOf : public AstNode { +struct AstAttrOf : public AstNode { +private: // Return a value of a attribute, for example a LSB or array LSB of a signal AstAttrType m_attrType; // What sort of extraction int m_dimension; // Dimension number (0 is leftmost), for ARRAY_LSB extractions @@ -1739,6 +1740,7 @@ struct AstRedXor : public AstNodeUniop { virtual int instrCount() const { return 1+V3Number::log2b(width()); } }; struct AstRedXnor : public AstNodeUniop { + // AstRedXnors are replaced with AstRedXors in V3Const. AstRedXnor(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { width(1,1); } virtual ~AstRedXnor() {} diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 18b0493b4..23076f4cf 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -170,15 +170,10 @@ private: static bool operandsSame(AstNode* node1p, AstNode* node2p) { // For now we just detect constants & simple vars, though it could be more generic if (node1p->castConst() && node2p->castConst()) { - // Match ignoring any X values - V3Number num (node1p->fileline(), 1); - num.opCaseEq(node1p->castConst()->num(), node2p->castConst()->num()); - return num.isNeqZero(); + return node1p->sameTree(node2p); } - else if (node1p->castVarRef() && node2p->castVarRef() - && node1p->sameTree(node2p)) { - // Same variable - return true; + else if (node1p->castVarRef() && node2p->castVarRef()) { + return node1p->sameTree(node2p); } else { return false; } @@ -239,6 +234,12 @@ private: void replaceZero(AstNode* nodep) { replaceNum(nodep, 0); nodep=NULL; } + void replaceAllOnes (AstNode* nodep) { + V3Number num (nodep->fileline(), nodep->width(), 0); + V3Number ones (nodep->fileline(), nodep->width()); + ones.opNot(num); + replaceNum(nodep, ones); nodep=NULL; + } void replaceConst(AstNodeUniop* nodep) { V3Number num (nodep->fileline(), nodep->width()); nodep->numberOperate(num, nodep->lhsp()->castConst()->num()); @@ -945,6 +946,7 @@ private: // }" # bracket not paren // ,"function to call" // or ,"AstREPLACEMENT_TYPE{ $accessor }" + // or ,"! # Print line number when matches, so can see operations // Lint Checks // v--- *1* These ops are always first, as we warn before replacing @@ -969,6 +971,7 @@ private: TREEOP("AstShiftR{$lhsp.isZero, $rhsp}", "replaceZero(nodep)"); TREEOP("AstShiftRS{$lhsp.isZero, $rhsp}", "replaceZero(nodep)"); TREEOP("AstXor {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)"); + TREEOP("AstXnor {$lhsp.isZero, $rhsp}", "AstNot{$rhsp}"); TREEOP("AstSub {$lhsp.isZero, $rhsp}", "AstUnaryMin{$rhsp}"); TREEOP("AstAdd {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)"); TREEOP("AstAnd {$lhsp, $rhsp.isZero}", "replaceZero(nodep)"); @@ -982,6 +985,7 @@ private: TREEOP("AstShiftRS{$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)"); TREEOP("AstSub {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)"); TREEOP("AstXor {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)"); + TREEOP("AstXnor {$lhsp, $rhsp.isZero}", "AstNot{$lhsp}"); // Non-zero on one side or the other TREEOP("AstAnd {$lhsp.isAllOnes, $rhsp}", "replaceWRhs(nodep)"); TREEOP("AstLogAnd{$lhsp.isNeqZero, $rhsp}", "replaceWRhs(nodep)"); @@ -992,6 +996,7 @@ private: TREEOP("AstOr {$lhsp, $rhsp.isAllOnes}", "replaceWRhs(nodep)"); //->allOnes TREEOP("AstLogOr {$lhsp, $rhsp.isNeqZero}", "replaceNum(nodep,1)"); TREEOP("AstXor {$lhsp.isAllOnes, $rhsp}", "AstNot{$rhsp}"); + TREEOP("AstXnor {$lhsp.isAllOnes, $rhsp}", "replaceWRhs(nodep)"); TREEOP("AstMul {$lhsp.isOne, $rhsp}", "replaceWRhs(nodep)"); TREEOP("AstMulS {$lhsp.isOne, $rhsp}", "replaceWRhs(nodep)"); TREEOP("AstDiv {$lhsp, $rhsp.isOne}", "replaceWLhs(nodep)"); @@ -1058,6 +1063,28 @@ private: TREEOP ("AstShiftL{operandShiftShift(nodep)}", "replaceShiftShift(nodep)"); TREEOP ("AstShiftR{operandShiftShift(nodep)}", "replaceShiftShift(nodep)"); TREEOP ("AstWordSel{operandWordOOB(nodep)}", "replaceZero(nodep)"); + // Identical operands on both sides + // AstLogAnd/AstLogOr already converted to AstAnd/AstOr for these rules + // AstAdd->ShiftL(#,1) but uncommon + TREEOP("AstAnd {operandsSame($lhsp,,$rhsp)}", "replaceWLhs(nodep)"); + TREEOP("AstDiv {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); + TREEOP("AstDivS {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); + TREEOP("AstOr {operandsSame($lhsp,,$rhsp)}", "replaceWLhs(nodep)"); + TREEOP("AstSub {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)"); + TREEOP("AstXnor {operandsSame($lhsp,,$rhsp)}", "replaceAllOnes(nodep)"); + TREEOP("AstXor {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)"); + TREEOP("AstEq {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); // We let X==X -> 1, although in a true 4-state sim it's X. + TREEOP("AstEqCase {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); + TREEOP("AstGt {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)"); + TREEOP("AstGtS {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)"); + TREEOP("AstGte {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); + TREEOP("AstGteS {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); + TREEOP("AstLt {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)"); + TREEOP("AstLtS {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)"); + TREEOP("AstLte {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); + TREEOP("AstLteS {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); + TREEOP("AstNeq {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)"); + TREEOP("AstNeqCase{operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)"); ///=== Verilog operators // Comparison against 1'b0/1'b1; must be careful about widths. // These use Not, so must be Verilog only @@ -1075,7 +1102,6 @@ private: TREEOPV("AstLte {$lhsp->width()==$rhsp->width(), $rhsp.isAllOnes}", "replaceNum(nodep,1)"); // Simplify reduction operators // This also gets &{...,0,....} => const 0 (Common for unused_ok signals) - TREEOPV("AstRedXnor{$lhsp}", "AstNot{AstRedXor{$lhsp}}"); // Just eliminate XNOR's TREEOPV("AstRedAnd{$lhsp, $lhsp.width1}", "replaceWLhs(nodep)"); TREEOPV("AstRedOr {$lhsp, $lhsp.width1}", "replaceWLhs(nodep)"); TREEOPV("AstRedXor{$lhsp, $lhsp.width1}", "replaceWLhs(nodep)"); @@ -1108,6 +1134,7 @@ private: TREEOPV("AstSel{$fromp.castConcat, $lsbp.castConst, $widthp.castConst, }", "replaceSelConcat(nodep)"); TREEOPV("AstSel{$fromp.castReplicate, $lsbp.castConst, $widthp.isOne, }", "replaceSelReplicate(nodep)"); // Conversions + TREEOPV("AstRedXnor{$lhsp}", "AstNot{AstRedXor{$lhsp}}"); // Just eliminate XNOR's TREEOPV("AstLogIf {$lhsp, $rhsp}", "AstLogOr{AstLogNot{$lhsp},$rhsp}"); TREEOPV("AstLogIff{$lhsp, $rhsp}", "AstLogNot{AstXor{$lhsp,$rhsp}}"); diff --git a/src/astgen b/src/astgen index b935358fa..3b7a325ab 100755 --- a/src/astgen +++ b/src/astgen @@ -324,6 +324,7 @@ sub tree_line { match_func => "match_${type}_${n}", match_if => $mif, exec_func => $exec_func, + uinfo_level => ($to =~ /^!/ ? 0:7), }; ($typefunc->{uinfo} = $func) =~ s/[ \t\"\{\}]+/ /g; push @{$self->{treeop}{$type}}, $typefunc; @@ -373,8 +374,11 @@ sub _exec_new_recurse { sub treeop_exec_func { my $self = shift; my $func = shift; + my $out = ""; + $func =~ s/^!//; if ($func =~ /^\s*[a-zA-Z0-9]+\s*\(/) { # Function call - $func =~ s/\$([a-zA-Z0-9]+)/nodep->$1()/g; + (my $outl = $func) =~ s/\$([a-zA-Z0-9]+)/nodep->$1()/g; + $out .= $outl; } elsif ($func =~ /^\s*Ast([a-zA-Z0-9]+) \s*\{\s* (.*) \s* \}$/x) { @@ -419,23 +423,22 @@ sub treeop_exec_func { $_Exec_Nsyms = 0; _exec_syms_recurse($aref); - $func = ""; foreach my $sym (sort {$_Exec_Syms{$a} cmp $_Exec_Syms{$b}} (keys %_Exec_Syms)) { my $argnp = $_Exec_Syms{$sym}; my $arg = add_nodep($sym); - $func .= "AstNode* ${argnp} = ${arg}->unlinkFrBack();\n"; + $out .= "AstNode* ${argnp} = ${arg}->unlinkFrBack();\n"; } - $func .= "AstNode* newp = " . _exec_new_recurse($aref).";\n"; - $func .= "nodep->replaceWith(newp);"; - $func .= "nodep->deleteTree(); nodep=NULL;"; - #print "FF $func\n" if $Debug; + $out .= "AstNode* newp = " . _exec_new_recurse($aref).";\n"; + $out .= "nodep->replaceWith(newp);"; + $out .= "nodep->deleteTree(); nodep=NULL;"; + #print "FF $out\n" if $Debug; } elsif ($func eq "NEVER") { - $func = "nodep->v3fatalSrc(\"Executing transform that was NEVERed\");"; + $out .= "nodep->v3fatalSrc(\"Executing transform that was NEVERed\");"; } else { $self->error("Unknown execution function format: $func\n"); } - return $func; + return $out; } sub tree_match { @@ -448,7 +451,7 @@ sub tree_match { $self->print(" bool $typefunc->{match_func}(Ast${base}* nodep) {\n", "\t// $typefunc->{comment}\n",); $self->print( "\tif ($typefunc->{match_if}) {\n"); - $self->print( "\t UINFO(7,(void*)(nodep)<<\" $typefunc->{uinfo}\\n\");\n"); + $self->print( "\t UINFO($typefunc->{uinfo_level},(void*)(nodep)<<\" $typefunc->{uinfo}\\n\");\n"); $self->print( "\t $typefunc->{exec_func};\n"); $self->print( "\t return true;\n"); $self->print( "\t}\n"); diff --git a/test_verilated/vgen.pl b/test_verilated/vgen.pl index 6f6e16e03..f2b485c18 100755 --- a/test_verilated/vgen.pl +++ b/test_verilated/vgen.pl @@ -54,6 +54,7 @@ our $Raise_Weight_Max = 50; 'VCONST'=> {weight=>1&&20, width=>0, sc=>1, terminal=>1, v=>'%v', }, 'VIDNEW'=> {weight=>1&&10, width=>0, sc=>1, terminal=>0, v=>'%i', }, 'VIDOLD'=> {weight=>1&&20, width=>0, sc=>1, terminal=>0, v=>'%i', }, + 'VIDSAME'=> {weight=>1&&200, width=>0, sc=>1, terminal=>0, v=>'%i', }, 'VRANGE'=> {weight=>1&&30, width=>0, signed=>0,sc=>0, terminal=>0, v=>'%i[%2:%3]', }, 'VBITSEL'=> {weight=>1&&10, width=>1, signed=>0,sc=>0, terminal=>0, v=>'%i[%2]', }, 'VBITSELP'=> {weight=>1&&10, width=>0, signed=>0,sc=>0, terminal=>0, v=>'%i[%2+:%3]', }, @@ -119,7 +120,8 @@ my %ops2 = 'VCONST'=> {pl=>'', rnd=>'rnd_const(%tr);'}, 'VIDNEW'=> {pl=>'%tv=$Vars{%i}{val};', rnd=>'%i=next_id(%tw); $Vars{%i}=gen_leaf(width=>%tw,trunc=>1,signed=>%tg); id_commit(%tr,"%i");1;',}, - 'VIDOLD'=> {pl=>'%tv=$Vars{%i}{val};', rnd=>'%i=old_id(%tr);', ok_id_width=>1,}, + 'VIDOLD'=> {pl=>'%tv=$Vars{%i}{val};', rnd=>'%i=id_old(%tr);', ok_id_width=>1,}, + 'VIDSAME'=> {pl=>'%tv=$Vars{%i}{val};', rnd=>'%i=id_same(%tr);', ok_id_width=>1,}, 'VRANGE'=> {pl=>'VRANGE(%tr,$Vars{%i}{val},%2v,%3v);', rnd=>'%i=next_id(%tw); my $lsb=rnd(128-%tw); my $msb=$lsb+%tw-1; %2r=val_leaf($msb); %3r=val_leaf($lsb); $Vars{%i}=gen_leaf(width=>($msb+1));'}, 'VBITSEL'=> {pl=>'VRANGE(%tr,$Vars{%i}{val},%2v,%2v);', rnd=>'%i=next_id(%tw); my $wid=min(128,rnd_width()|3); %2r=gen_leaf(width=>(log2($wid)-1),signed=>0); $Vars{%i}=gen_leaf(width=>$wid);'}, 'VBITSELP'=> {pl=>'VBITSELP(%tr,$Vars{%i}{val},%2v,%3v);', rnd=>'%i=next_id(%tw); my $wid=min(128,(%tw+rnd_width()|3)); %3r=val_leaf(%tw); my $maxval = $wid-%tw; %2r=(($maxval<4)?val_leaf($maxval):gen_leaf(width=>(log2($maxval)-1),signed=>0)); $Vars{%i}=gen_leaf(width=>$wid);'}, @@ -421,7 +423,7 @@ sub id_commit { }; } -sub old_id { +sub id_old { my $treeref = shift; my $width = $treeref->{width}; my $signed = $treeref->{signed}; @@ -433,6 +435,29 @@ sub old_id { return $id; } +sub id_same { + my $treeref = shift; + my $width = $treeref->{width}; + my $signed = $treeref->{signed}; + + my @possible; + foreach my $id (keys %VarsBlock) { + next if !$VarsBlock{$id}{used}; + my $varref = $Vars{$id}; + next if $varref->{signed} != $signed; + next if $varref->{width} != $width; + push @possible, $id; + } + my $n = $#possible + 1; + if ($n<1) { # Nothing, grab another! + return id_old($treeref,$width,$signed); + } + my $idn = rnd($n); + my $id = $possible[$idn]; + $VarsBlock{$id}{used} = 1; + return $id; +} + sub write_output_v { my $filename = shift;