Optimize modulus by power-of-two constants.

This commit is contained in:
Wilson Snyder 2019-11-10 12:12:57 -05:00
parent fcb733e8d0
commit ce178ec987
3 changed files with 32 additions and 0 deletions

View File

@ -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]

View File

@ -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) "<<nodep<<endl);
int amount = VN_CAST(nodep->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)) "<<nodep<<endl);
AstNRelinker handle;
@ -2257,6 +2268,7 @@ private:
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 ("AstModDiv{$lhsp, operandIsPowTwo($rhsp)}", "replaceModAnd(nodep)"); // a % 2^n -> a&(2^n-1)
TREEOP ("AstPow {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<<a
TREEOP ("AstSub {$lhsp.castAdd, operandSubAdd(nodep)}", "AstAdd{AstSub{$lhsp->castAdd()->lhsp(),$rhsp}, $lhsp->castAdd()->rhsp()}"); // ((a+x)-y) -> (a+(x-y))
// Trinary ops

View File

@ -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