diff --git a/Changes b/Changes index b13aa6b33..814573a35 100644 --- a/Changes +++ b/Changes @@ -28,6 +28,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Support quoted arguments in -f files, bug1535. [Yves Mathieu] +**** Optimize modulus by power-of-two constants. + **** Fix detecting missing reg types, bug1570. [Jacko Dirks] **** Fix multithreaded yield behavior when no work. [Patrick Stewart] diff --git a/src/V3Const.cpp b/src/V3Const.cpp index bce61826a..ad2759694 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -880,6 +880,17 @@ private: newp->dtypeFrom(nodep); nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep); } + void replaceModAnd(AstModDiv* nodep) { // Mod, but not ModS as not simple shift + UINFO(5,"MOD(b,2^n)->AND(b,2^n-1) "<rhsp(), Const)->num().mostSetBitP1()-1; // 2^n->n+1 + V3Number mask(nodep, nodep->width()); + mask.setMask(amount); + AstNode* opp = nodep->lhsp()->unlinkFrBack(); + AstAnd* newp = new AstAnd(nodep->fileline(), + opp, new AstConst(nodep->fileline(), mask)); + newp->dtypeFrom(nodep); + nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep); + } void replaceShiftOp(AstNodeBiop* nodep) { UINFO(5,"SHIFT(AND(a,b),CONST)->AND(SHIFT(a,CONST),SHIFT(b,CONST)) "< a< a>>n + TREEOP ("AstModDiv{$lhsp, operandIsPowTwo($rhsp)}", "replaceModAnd(nodep)"); // a % 2^n -> a&(2^n-1) TREEOP ("AstPow {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<castAdd()->lhsp(),$rhsp}, $lhsp->castAdd()->rhsp()}"); // ((a+x)-y) -> (a+(x-y)) // Trinary ops diff --git a/test_regress/t/t_math_div.v b/test_regress/t/t_math_div.v index 46d05411a..2fe380be8 100644 --- a/test_regress/t/t_math_div.v +++ b/test_regress/t/t_math_div.v @@ -14,12 +14,20 @@ module t (/*AUTOARG*/ reg [60:0] divisor; reg [60:0] qq; reg [60:0] rq; + reg [60:0] qq4; + reg [60:0] rq4; + reg [60:0] qq5; + reg [60:0] rq5; reg signed [60:0] qqs; reg signed [60:0] rqs; always @* begin qq = a[60:0] / divisor; rq = a[60:0] % divisor; + qq4 = a[60:0] / 4; // Check power-of-two constification + rq4 = a[60:0] % 4; + qq5 = a[60:0] / 5; // Non power-of-two + rq5 = a[60:0] % 5; qqs = $signed(a[60:0]) / $signed(divisor); rqs = $signed(a[60:0]) % $signed(divisor); end @@ -34,6 +42,10 @@ module t (/*AUTOARG*/ divisor <= 61'h12371; a[60] <= 1'b0; divisor[60] <= 1'b0; // Unsigned end + if (cyc > 1) begin + if (qq4 != {2'b0, a[60:2]}) $stop; + if (rq4 != {59'h0, a[1:0]}) $stop; + end if (cyc==2) begin a <= 256'h0e17c88f3d5fe51a982646c8e2bd68c3e236ddfddddbdad20a48e039c9f395b8; divisor <= 61'h1238123771; @@ -42,6 +54,8 @@ module t (/*AUTOARG*/ if (rq!==61'h00000000000090ec) $stop; if (qqs!==61'h00000403ad81c0da) $stop; if (rqs!==61'h00000000000090ec) $stop; + if (qq4 != 61'h01247cf6851f9fc9) $stop; + if (rq4 != 61'h0000000000000002) $stop; end if (cyc==3) begin a <= 256'h0e17c88f00d5fe51a982646c8002bd68c3e236ddfd00ddbdad20a48e00f395b8; @@ -51,6 +65,8 @@ module t (/*AUTOARG*/ if (rq!==61'h0000000334becc6a) $stop; if (qqs!==61'h000000000090832e) $stop; if (rqs!==61'h0000000334becc6a) $stop; + if (qq4 != 61'h0292380e727ce56e) $stop; + if (rq4 != 61'h0000000000000000) $stop; end if (cyc==4) begin a[60] <= 1'b0; divisor[60] <= 1'b1; // Signed @@ -58,6 +74,8 @@ module t (/*AUTOARG*/ if (rq!==61'h0000000000000c40) $stop; if (qqs!==61'h1fffcf5187c76510) $stop; if (rqs!==61'h1ffffffffffffd08) $stop; + if (qq4 != 61'h07482923803ce56e) $stop; + if (rq4 != 61'h0000000000000000) $stop; end if (cyc==5) begin a[60] <= 1'b1; divisor[60] <= 1'b1; // Signed