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
Mateusz Gancarz
Matthew Ballance
Max Wipfli
Michael Bikovitsky
Michael Killough
Michal Czyz

View File

@ -1267,8 +1267,12 @@ class ConstVisitor final : public VNVisitor {
&& nodep->lhsp()->isPure());
}
bool operandIsTwo(const AstNode* nodep) {
return (VN_IS(nodep, Const) && !VN_AS(nodep, Const)->num().isFourState()
&& nodep->width() <= VL_QUADSIZE && VN_AS(nodep, Const)->toUQuad() == 2);
const AstConst* const constp = VN_CAST(nodep, Const);
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) {
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 ("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 ("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))
TREEOPC("AstAnd {$lhsp.isOne, matchRedundantClean(nodep)}", "DONE") // 1 & (a == b) -> (IData)(a == b)
// Trinary ops

View File

@ -37,7 +37,8 @@ module t (/*AUTOARG*/
wire signed [66:0] bsw = b[66:0];
// 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] uiiq = aui ** buq;
@ -358,5 +359,6 @@ module t (/*AUTOARG*/
32'd09: `checkh(shifted, 67'h0000000000000000);
default: ;
endcase
`checkh(shifted_signed, shifted);
end
endmodule