Optimize n*powers of 2. (For parameterized DDR model)

git-svn-id: file://localhost/svn/verilator/trunk/verilator@775 77ca24e4-aefa-0310-84f0-b9a241c72d87
This commit is contained in:
Wilson Snyder 2006-09-01 16:53:14 +00:00
parent 6f48185a1f
commit 749fdaae31
5 changed files with 56 additions and 11 deletions

View File

@ -87,6 +87,10 @@ private:
return (nodep->castConst()
&& !nodep->castConst()->num().isFourState());
}
bool operandIsPowTwo(AstNode* nodep) {
if (!operandIsTwostate(nodep)) return false;
return (1==nodep->castConst()->num().countOnes());
}
bool operandShiftOp(AstNodeBiop* nodep) {
if (!nodep->rhsp()->castConst()) return false;
AstNodeBiop* lhsp = nodep->lhsp()->castNodeBiop();
@ -317,6 +321,24 @@ private:
newp->lhsp()->widthSignedFrom(nodep);
nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL;
}
void replaceMulShift (AstMul* nodep) { // Mul, but not MulS as not simple shift
UINFO(5,"MUL(2^n,b)->SHIFTL(b,n) "<<nodep<<endl);
int amount = nodep->lhsp()->castConst()->num().mostSetBitP1()-1; // 2^n->n+1
AstNode* opp = nodep->rhsp()->unlinkFrBack();
AstShiftL* newp = new AstShiftL(nodep->fileline(),
opp, new AstConst(nodep->fileline(), amount));
newp->widthSignedFrom(nodep);
nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL;
}
void replaceDivShift (AstDiv* nodep) { // Mul, but not MulS as not simple shift
UINFO(5,"DIV(b,2^n)->SHIFTR(b,n) "<<nodep<<endl);
int amount = nodep->rhsp()->castConst()->num().mostSetBitP1()-1; // 2^n->n+1
AstNode* opp = nodep->lhsp()->unlinkFrBack();
AstShiftR* newp = new AstShiftR(nodep->fileline(),
opp, new AstConst(nodep->fileline(), amount));
newp->widthSignedFrom(nodep);
nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL;
}
void replaceShiftOp (AstNodeBiop* nodep) {
UINFO(5,"SHIFT(AND(a,b),CONST)->AND(SHIFT(a,CONST),SHIFT(b,CONST)) "<<nodep<<endl);
AstNRelinker handle;
@ -970,8 +992,14 @@ 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("AstPow {operandIsTwo($lhsp), $rhsp}","replacePowShift(nodep)"); // 2**a == 1<<a
TREEOP("AstPowS {operandIsTwo($lhsp), $rhsp}","replacePowShift(nodep)"); // 2**a == 1<<a
TREEOP("AstMul {$lhsp.isOne, $rhsp}", "replaceWRhs(nodep)");
TREEOP("AstMulS {$lhsp.isOne, $rhsp}", "replaceWRhs(nodep)");
TREEOP("AstDiv {$lhsp, $rhsp.isOne}", "replaceWLhs(nodep)");
TREEOP("AstDivS {$lhsp, $rhsp.isOne}", "replaceWLhs(nodep)");
TREEOP("AstMul {operandIsPowTwo($lhsp), $rhsp}", "replaceMulShift(nodep)"); // a*2^n -> a<<n
TREEOP("AstDiv {$lhsp, operandIsPowTwo($rhsp)}", "replaceDivShift(nodep)"); // a/2^n -> a>>n
TREEOP("AstPow {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<<a
TREEOP("AstPowS {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<<a
// Trinary ops
// Note V3Case::Sel requires Cond to always be conditionally executed in C to prevent core dump!
TREEOP("AstNodeCond{$condp.isZero, $expr1p, $expr2p}", "replaceWChild(nodep,$expr2p)");

View File

@ -430,6 +430,12 @@ uint32_t V3Number::countOnes() const {
return n;
}
uint32_t V3Number::mostSetBitP1() const {
for (int bit=this->width()-1; bit>=0; bit--) {
if (bitIs1(bit)) return bit+1;
}
return 0;
}
//======================================================================
V3Number& V3Number::opBitsNonX (const V3Number& lhs) { // 0/1->1, X/Z->0

View File

@ -130,6 +130,7 @@ public:
uint32_t asHash() const;
uint32_t dataWord(int word) const;
uint32_t countOnes() const;
uint32_t mostSetBitP1() const; // Highest bit set plus one, IE for 16 return 5, for 0 return 0.
// STATICS
static int log2b(uint32_t num);

View File

@ -75,6 +75,7 @@ module t (/*AUTOARG*/
endfunction
integer cyc; initial cyc=0;
wire [31:0] ucyc = cyc;
always @ (posedge clk) begin
cyc <= cyc + 1;
$write("%x %x %x %x %x %x %x\n", cyc, sr,srs,sl,sls, b_s,b_us);
@ -88,9 +89,24 @@ module t (/*AUTOARG*/
end
2: begin
a <= 16'sh8b1b; b <= 5'sh1e; // shift AMOUNT is really unsigned
if (ucyc / 1 != 32'd2) $stop;
if (ucyc / 2 != 32'd1) $stop;
if (ucyc * 1 != 32'd2) $stop;
if (ucyc * 2 != 32'd4) $stop;
if (ucyc * 3 != 32'd6) $stop;
if (cyc * 32'sd1 != 32'sd2) $stop;
if (cyc * 32'sd2 != 32'sd4) $stop;
if (cyc * 32'sd3 != 32'sd6) $stop;
end
3: begin
a <= 16'sh0048; b <= 5'sh1f;
if (ucyc * 1 != 32'd3) $stop;
if (ucyc * 2 != 32'd6) $stop;
if (ucyc * 3 != 32'd9) $stop;
if (ucyc * 4 != 32'd12) $stop;
if (cyc * 32'sd1 != 32'sd3) $stop;
if (cyc * 32'sd2 != 32'sd6) $stop;
if (cyc * 32'sd3 != 32'sd9) $stop;
end
4: begin
a <= 16'sh4154; b <= 5'sh02;

View File

@ -1,14 +1,8 @@
// $Id:$
// $Id$
// DESCRIPTION: Verilator: Verilog Test module
//
// Use this file as a template for submitting bugs, etc.
// This module takes a single clock input, and should either
// $write("*-* All Finished *-*\n");
// $finish
// on success, or $stop.
//
// **If you do not wish for your code to be released to the public
// please note it here**
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2005 by Wilson Snyder.
module t (/*AUTOARG*/);