From 5c93520b27a6e77eeeff8b7c3927d21e791e6cc3 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 28 Sep 2006 14:37:28 +0000 Subject: [PATCH] Associative same variable elimination git-svn-id: file://localhost/svn/verilator/trunk/verilator@799 77ca24e4-aefa-0310-84f0-b9a241c72d87 --- Changes | 2 +- src/V3Case.cpp | 29 +++++------ src/V3Const.cpp | 23 +++++++-- src/V3Number.cpp | 2 - src/V3Signed.cpp | 10 ---- src/verilog.y | 2 - test_regress/t/t_case_wild.pl | 18 +++++++ test_regress/t/t_case_wild.v | 93 +++++++++++++++++++++++++++++++++++ test_verilated/vgen.pl | 2 +- 9 files changed, 147 insertions(+), 34 deletions(-) create mode 100755 test_regress/t/t_case_wild.pl create mode 100644 test_regress/t/t_case_wild.v diff --git a/Changes b/Changes index 9339965ae..119c45f24 100644 --- a/Changes +++ b/Changes @@ -11,7 +11,7 @@ indicates the contributor was also the author of the fix; Thanks! *** Optimize variables set to constants within basic blocks for ~3%. -**** Default make no longer makes the docs; if you edit the documentation +**** 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.) diff --git a/src/V3Case.cpp b/src/V3Case.cpp index b588819cf..5663eae07 100644 --- a/src/V3Case.cpp +++ b/src/V3Case.cpp @@ -29,12 +29,12 @@ // (other items)) // body // Or, converts to a if/else tree. -// Constants: -// RHS, Replace 5'bx_1_x with a module global we init to a random value -// CONST(5'bx_1_x) -> VARREF(_{numberedtemp}) -// -> VAR(_{numberedtemp}) -// -> INITIAL(VARREF(_{numberedtemp}), OR(5'bx_1_x,AND(random,5'b0_1_x)) -// OPTIMIZE: Must not collapse this initial back into the equation. +// FUTURES: +// Large 16+ bit tables with constants and no masking (address muxes) +// Enter all into multimap, sort by value and use a tree of < and == compares. +// "Diagonal" find of {rightmost,leftmost} bit {set,clear} +// Ignoring mask, check each value is unique (using multimap as above?) +// Each branch is then mask-and-compare operation (IE <000000001_000000000 at midpoint.) // //************************************************************************* @@ -49,7 +49,8 @@ #include "V3Ast.h" #include "V3Stats.h" -#define CASE_OVERLAP_WIDTH 12 // Maximum width we can check for overlaps in +#define CASE_OVERLAP_WIDTH 12 // Maximum width we can check for overlaps in +#define CASE_BARF 999999 // Magic width when non-constant //###################################################################### @@ -126,22 +127,22 @@ private: //int debug() { return 9; } // METHODS - bool checkCaseTree(AstCase* nodep) { + bool isCaseTreeFast(AstCase* nodep) { int width = 0; m_caseItems = 0; m_caseNoOverlapsAllCovered = true; for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) { for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) { if (icondp->width() > width) width = icondp->width(); - if (!icondp->castConst()) width = 999; // Can't parse; not a constant + if (!icondp->castConst()) width = CASE_BARF; // Can't parse; not a constant m_caseItems++; } } + m_caseWidth = width; if (width==0 || width > CASE_OVERLAP_WIDTH) { m_caseNoOverlapsAllCovered = false; return false; // Too wide for analysis } - m_caseWidth = width; UINFO(8,"Simple case statement: "<condsp()) { // Case statement's default... Fill the table + if (itemp->isDefault()) { // Case statement's default... Fill the table for (uint32_t i=0; i<(1UL<iterateChildren(*this); if (debug()>=9) nodep->dumpTree(cout," case_old: "); - if (checkCaseTree(nodep) && v3Global.opt.oCase()) { + if (isCaseTreeFast(nodep) && v3Global.opt.oCase()) { // It's a simple priority encoder or complete statement // we can make a tree of statements to avoid extra comparisons m_statCaseFast++; @@ -381,7 +382,7 @@ public: } virtual ~CaseVisitor() { V3Stats::addStat("Optimizations, Cases parallelized", m_statCaseFast); - V3Stats::addStat("Optimizations, Cases priority-encoded", m_statCaseSlow); + V3Stats::addStat("Optimizations, Cases complex", m_statCaseSlow); } }; diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 23076f4cf..7c8af8ba5 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -70,6 +70,16 @@ private: if (!rnodep->lhsp()->castConst()) return false; return true; } + bool operandAsvSame (AstNode* nodep) { + // BIASV(SAMEa, BIASV(SAMEb,...)) -> BIASV( BIASV(SAMEa,SAMEb), ...) + AstNodeBiComAsv* bnodep = nodep->castNodeBiComAsv(); + if (!bnodep) return false; + AstNodeBiComAsv* rnodep = bnodep->rhsp()->castNodeBiComAsv(); + if (!rnodep) return false; + if (rnodep->type() != bnodep->type()) return false; + if (rnodep->width() != bnodep->width()) return false; + return operandsSame(bnodep->lhsp(), rnodep->lhsp()); + } bool operandHugeShiftL(AstNodeBiop* nodep) { return (nodep->rhsp()->castConst() && nodep->rhsp()->castConst()->asInt() >= (uint32_t)(nodep->width())); @@ -284,8 +294,9 @@ private: // Keep RHS, remove LHS replaceWChild(nodep, nodep->rhsp()); } - void replaceAsvConst (AstNodeBiop* nodep) { + void replaceAsv (AstNodeBiop* nodep) { // BIASV(CONSTa, BIASV(CONSTb, c)) -> BIASV( BIASV_CONSTED(a,b), c) + // BIASV(SAMEa, BIASV(SAMEb, c)) -> BIASV( BIASV(SAMEa,SAMEb), c) //nodep->dumpTree(cout, " repAsvConst_old: "); AstNode* ap = nodep->lhsp(); AstNodeBiop* rp = nodep->rhsp()->castNodeBiop(); @@ -299,7 +310,7 @@ private: nodep->rhsp(cp); rp->lhsp(ap); rp->rhsp(bp); - replaceConst(rp); + if (rp->lhsp()->castConst() && rp->rhsp()->castConst()) replaceConst(rp); //nodep->dumpTree(cout, " repAsvConst_new: "); } void replaceExtend (AstNode* nodep, AstNode* arg0p) { @@ -1017,8 +1028,9 @@ private: TREEOP("AstNodeCond{$condp.width1, $expr1p.width1, $expr1p.isZero, $expr2p}", "AstAnd{AstNot{$condp}, $expr2p}"); // a?0:b == ~a&b TREEOP("AstNodeCond{!$condp.width1, operandBoolShift(nodep->condp())}", "replaceBoolShift(nodep->condp())"); // Prefer constants on left, since that often needs a shift, it lets constant red remove the shift - TREEOP("AstNodeBiCom{$lhsp, $rhsp.castConst}", "swapSides(nodep)"); - TREEOP("AstNodeBiComAsv{operandAsvConst(nodep)}", "replaceAsvConst(nodep)"); + TREEOP("AstNodeBiCom{!$lhsp.castConst, $rhsp.castConst}", "swapSides(nodep)"); + TREEOP("AstNodeBiComAsv{operandAsvConst(nodep)}", "replaceAsv(nodep)"); + TREEOP("AstNodeBiComAsv{operandAsvSame(nodep)}", "replaceAsv(nodep)"); // v--- *1* as These ops are always first, as we warn before replacing TREEOP1("AstLt {$lhsp, $rhsp.isZero}", "replaceNumSigned(nodep,0)"); TREEOP1("AstGte {$lhsp, $rhsp.isZero}", "replaceNumSigned(nodep,1)"); @@ -1067,6 +1079,7 @@ private: // AstLogAnd/AstLogOr already converted to AstAnd/AstOr for these rules // AstAdd->ShiftL(#,1) but uncommon TREEOP("AstAnd {operandsSame($lhsp,,$rhsp)}", "replaceWLhs(nodep)"); + TREEOP("AstChangeXor{operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)"); TREEOP("AstDiv {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); TREEOP("AstDivS {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); TREEOP("AstOr {operandsSame($lhsp,,$rhsp)}", "replaceWLhs(nodep)"); @@ -1085,6 +1098,8 @@ private: TREEOP("AstLteS {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); TREEOP("AstNeq {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)"); TREEOP("AstNeqCase{operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)"); + TREEOP("AstLogAnd {operandsSame($lhsp,,$rhsp), $lhsp.width1}", "replaceWLhs(nodep)"); + TREEOP("AstLogOr {operandsSame($lhsp,,$rhsp), $lhsp.width1}", "replaceWLhs(nodep)"); ///=== Verilog operators // Comparison against 1'b0/1'b1; must be careful about widths. // These use Not, so must be Verilog only diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 65ab841bb..c54573ccc 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -115,9 +115,7 @@ V3Number::V3Number (FileLine* fileline, const char* sourcep) { // Otherwise... else if (!m_sized) { width(32, false); // Says the spec. -#ifndef VL_UNSIGNED if (unbased) isSigned(true); // Also says the spec. -#endif } // Ignore leading blanks diff --git a/src/V3Signed.cpp b/src/V3Signed.cpp index 83cab04b8..9f3c0c3ba 100644 --- a/src/V3Signed.cpp +++ b/src/V3Signed.cpp @@ -284,9 +284,7 @@ private: // VISITORS - defaults virtual void visit(AstNodeMath* nodep, AstNUser*) { -#ifndef VL_UNSIGNED nodep->v3fatalSrc("Visit function missing? Signedness unknown for this node: "<iterateChildren(*this); } virtual void visit(AstNode* nodep, AstNUser*) { @@ -347,12 +345,6 @@ public: class SignedRemoveVisitor : public AstNVisitor { private: - // METHODS - void supportCheck(AstNode* nodep) { -#ifdef VL_UNSIGNED - if (nodep->isSigned()) nodep->v3error("Unsupported: signed numbers"); -#endif - } // VISITORS virtual void visit(AstSigned* nodep, AstNUser*) { replaceWithSignedVersion(nodep, nodep->lhsp()->unlinkFrBack()); nodep=NULL; @@ -362,13 +354,11 @@ private: } virtual void visit(AstNode* nodep, AstNUser*) { nodep->iterateChildren(*this); - supportCheck(nodep); } void replaceWithSignedVersion(AstNode* nodep, AstNode* newp) { UINFO(6," Replace "<replaceWith(newp); newp->widthSignedFrom(nodep); - supportCheck(nodep); pushDeletep(nodep); nodep=NULL; } public: diff --git a/src/verilog.y b/src/verilog.y index b6f2e1f2b..e2f6e8de3 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -1086,9 +1086,7 @@ AstVar* V3Parse::createVariable(FileLine* fileline, string name, AstRange* array rangep->cloneTree(false), arrayp); nodep->isSigned(V3Parse::s_varSigned); -#ifndef VL_UNSIGNED if (type == AstVarType::INTEGER) nodep->isSigned(true); -#endif if (V3Parse::s_varDecl != AstVarType::UNKNOWN) nodep->combineType(V3Parse::s_varDecl); if (V3Parse::s_varIO != AstVarType::UNKNOWN) nodep->combineType(V3Parse::s_varIO); diff --git a/test_regress/t/t_case_wild.pl b/test_regress/t/t_case_wild.pl new file mode 100755 index 000000000..7bfdbe852 --- /dev/null +++ b/test_regress/t/t_case_wild.pl @@ -0,0 +1,18 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; } +# $Id$ +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# General Public License or the Perl Artistic License. + +compile ( + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_case_wild.v b/test_regress/t/t_case_wild.v new file mode 100644 index 000000000..e55da38d1 --- /dev/null +++ b/test_regress/t/t_case_wild.v @@ -0,0 +1,93 @@ +// $Id$ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2006 by Wilson Snyder. + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + integer cyc; initial cyc=0; + reg [63:0] crc; + reg [63:0] sum; + + reg out1; + reg [4:0] out2; + sub sub (.in(crc[23:0]), .out1(out1), .out2(out2)); + + always @ (posedge clk) begin + $write("[%0t] cyc==%0d crc=%x sum=%x out=%x,%x\n",$time, cyc, crc, sum, out1,out2); + cyc <= cyc + 1; + crc <= {crc[62:0], crc[63]^crc[2]^crc[0]}; + sum <= {sum[62:0], sum[63]^sum[2]^sum[0]} ^ {58'h0,out1,out2}; + if (cyc==0) begin + // Setup + crc <= 64'h00000000_00000097; + sum <= 64'h0; + end + else if (cyc==90) begin + if (sum != 64'hf0afc2bfa78277c5) $stop; + end + else if (cyc==91) begin + end + else if (cyc==92) begin + end + else if (cyc==93) begin + end + else if (cyc==94) begin + end + else if (cyc==99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + +module sub (/*AUTOARG*/ + // Outputs + out1, out2, + // Inputs + in + ); + + input [23:0] in; + output reg out1; + output reg [4:0] out2; + + always @* begin + casez (in) + 24'b0000_0000_0000_0000_0000_0000 : {out1,out2} = {1'b0,5'h00}; + 24'b????_????_????_????_????_???1 : {out1,out2} = {1'b1,5'h00}; + 24'b????_????_????_????_????_??10 : {out1,out2} = {1'b1,5'h01}; + 24'b????_????_????_????_????_?100 : {out1,out2} = {1'b1,5'h02}; + 24'b????_????_????_????_????_1000 : {out1,out2} = {1'b1,5'h03}; + 24'b????_????_????_????_???1_0000 : {out1,out2} = {1'b1,5'h04}; + 24'b????_????_????_????_??10_0000 : {out1,out2} = {1'b1,5'h05}; + 24'b????_????_????_????_?100_0000 : {out1,out2} = {1'b1,5'h06}; + 24'b????_????_????_????_1000_0000 : {out1,out2} = {1'b1,5'h07}; + // Same pattern, but reversed to test we work OK. + 24'b1000_0000_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h17}; + 24'b?100_0000_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h16}; + 24'b??10_0000_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h15}; + 24'b???1_0000_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h14}; + 24'b????_1000_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h13}; + 24'b????_?100_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h12}; + 24'b????_??10_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h11}; + 24'b????_???1_0000_0000_0000_0000 : {out1,out2} = {1'b1,5'h10}; + 24'b????_????_1000_0000_0000_0000 : {out1,out2} = {1'b1,5'h0f}; + 24'b????_????_?100_0000_0000_0000 : {out1,out2} = {1'b1,5'h0e}; + 24'b????_????_??10_0000_0000_0000 : {out1,out2} = {1'b1,5'h0d}; + 24'b????_????_???1_0000_0000_0000 : {out1,out2} = {1'b1,5'h0c}; + 24'b????_????_????_1000_0000_0000 : {out1,out2} = {1'b1,5'h0b}; + 24'b????_????_????_?100_0000_0000 : {out1,out2} = {1'b1,5'h0a}; + 24'b????_????_????_??10_0000_0000 : {out1,out2} = {1'b1,5'h09}; + 24'b????_????_????_???1_0000_0000 : {out1,out2} = {1'b1,5'h08}; + endcase + end + +endmodule diff --git a/test_verilated/vgen.pl b/test_verilated/vgen.pl index f2b485c18..6c2061135 100755 --- a/test_verilated/vgen.pl +++ b/test_verilated/vgen.pl @@ -54,7 +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', }, + 'VIDSAME'=> {weight=>1&&20, 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]', },