Optimize 2 ** X to 1 << X if base is signed

This commit is contained in:
Max Wipfli 2025-07-20 14:34:57 +02:00
parent f535a73ea7
commit 4f59b4acfe
3 changed files with 11 additions and 3 deletions

View File

@ -158,6 +158,7 @@ Martin Schmidt
Martin Stadler Martin Stadler
Mateusz Gancarz Mateusz Gancarz
Matthew Ballance Matthew Ballance
Max Wipfli
Michael Bikovitsky Michael Bikovitsky
Michael Killough Michael Killough
Michal Czyz Michal Czyz

View File

@ -1267,8 +1267,12 @@ class ConstVisitor final : public VNVisitor {
&& nodep->lhsp()->isPure()); && nodep->lhsp()->isPure());
} }
bool operandIsTwo(const AstNode* nodep) { bool operandIsTwo(const AstNode* nodep) {
return (VN_IS(nodep, Const) && !VN_AS(nodep, Const)->num().isFourState() const AstConst* const constp = VN_CAST(nodep, Const);
&& nodep->width() <= VL_QUADSIZE && VN_AS(nodep, Const)->toUQuad() == 2); if (!constp) return false; // not constant
if (constp->num().isFourState()) return false; // four-state
if (nodep->width() > VL_QUADSIZE) return false; // too wide
if (nodep->isSigned() && constp->num().isNegative()) return false; // signed and negative
return constp->toUQuad() == 2;
} }
bool operandIsTwostate(const AstNode* nodep) { bool operandIsTwostate(const AstNode* nodep) {
return (VN_IS(nodep, Const) && !VN_AS(nodep, Const)->num().isFourState()); return (VN_IS(nodep, Const) && !VN_AS(nodep, Const)->num().isFourState());
@ -3550,6 +3554,7 @@ class ConstVisitor final : public VNVisitor {
TREEOP ("AstDiv {$lhsp, operandIsPowTwo($rhsp)}", "replaceDivShift(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 ("AstModDiv{$lhsp, operandIsPowTwo($rhsp)}", "replaceModAnd(nodep)"); // a % 2^n -> a&(2^n-1)
TREEOP ("AstPow {operandIsTwo($lhsp), !$rhsp.isZero}", "replacePowShift(nodep)"); // 2**a == 1<<a TREEOP ("AstPow {operandIsTwo($lhsp), !$rhsp.isZero}", "replacePowShift(nodep)"); // 2**a == 1<<a
TREEOP ("AstPowSU {operandIsTwo($lhsp), !$rhsp.isZero}", "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)) TREEOP ("AstSub {$lhsp.castAdd, operandSubAdd(nodep)}", "AstAdd{AstSub{$lhsp->castAdd()->lhsp(),$rhsp}, $lhsp->castAdd()->rhsp()}"); // ((a+x)-y) -> (a+(x-y))
TREEOPC("AstAnd {$lhsp.isOne, matchRedundantClean(nodep)}", "DONE") // 1 & (a == b) -> (IData)(a == b) TREEOPC("AstAnd {$lhsp.isOne, matchRedundantClean(nodep)}", "DONE") // 1 & (a == b) -> (IData)(a == b)
// Trinary ops // Trinary ops

View File

@ -37,7 +37,8 @@ module t (/*AUTOARG*/
wire signed [66:0] bsw = b[66:0]; wire signed [66:0] bsw = b[66:0];
// verilator lint_off WIDTH // verilator lint_off WIDTH
wire [66:0] shifted = 2 ** b[20:0]; wire [66:0] shifted = 32'd2 ** b[20:0];
wire [66:0] shifted_signed = 32'sd2 ** b[20:0];
wire [15:0] uiii = aui ** bui; wire [15:0] uiii = aui ** bui;
wire [15:0] uiiq = aui ** buq; wire [15:0] uiiq = aui ** buq;
@ -358,5 +359,6 @@ module t (/*AUTOARG*/
32'd09: `checkh(shifted, 67'h0000000000000000); 32'd09: `checkh(shifted, 67'h0000000000000000);
default: ; default: ;
endcase endcase
`checkh(shifted_signed, shifted);
end end
endmodule endmodule