Optimize wide word shifts by multiple of word size (#6970)

V3Expand wide SHIFTL and SHIFTR if the shift amount is know and is a
multiple of VL_EDATA_SIZE. This case results in each word requiring a
simple copy from the original, or store of a constant zero, which
subsequent V3Subst can then eliminate.
This commit is contained in:
Geza Lore 2026-02-01 05:07:57 +00:00 committed by GitHub
parent cea4c88e12
commit bef709a235
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 60 additions and 2 deletions

View File

@ -373,6 +373,47 @@ class ExpandVisitor final : public VNVisitor {
}
return true;
}
bool expandWideShift(AstNodeAssign* nodep, AstNodeBiop* rhsp, bool isLeftShift) {
if (!doExpandWide(nodep)) return false;
// Simplify the shift amount, in case it becomes a constant
V3Const::constifyEditCpp(rhsp->rhsp());
// If it's a constant shift by whole words, expand it so V3Subst can substitute it
if (const AstConst* const rhsConstp = VN_CAST(rhsp->rhsp(), Const)) {
const uint32_t shiftBits = rhsConstp->toUInt();
if (VL_BITBIT_E(shiftBits) == 0) {
const int widthWords = nodep->widthWords();
const int shiftWords = std::min<int>(VL_BITWORD_E(shiftBits), widthWords);
FileLine* const flp = rhsp->fileline();
if (isLeftShift) {
UINFO(8, " Wordize ASSIGN(SHIFTL,words) " << nodep);
// Low words of the result are zero
for (int w = 0; w < shiftWords; ++w) {
addWordAssign(nodep, w, new AstConst{flp, AstConst::SizedEData{}, 0});
}
// High words of the result are copied from higher words of the source
for (int w = shiftWords; w < widthWords; ++w) {
addWordAssign(nodep, w, newAstWordSelClone(rhsp->lhsp(), w - shiftWords));
}
} else {
UINFO(8, " Wordize ASSIGN(SHIFTR,words) " << nodep);
// Low words of the result are copied from higher words of the source
for (int w = 0; w < widthWords - shiftWords; ++w) {
addWordAssign(nodep, w, newAstWordSelClone(rhsp->lhsp(), w + shiftWords));
}
// High words of the result are zero
for (int w = widthWords - shiftWords; w < widthWords; ++w) {
addWordAssign(nodep, w, new AstConst{flp, AstConst::SizedEData{}, 0});
}
}
return true;
}
}
return false;
}
//-------- Triops
bool expandWide(AstNodeAssign* nodep, AstCond* rhsp) {
UINFO(8, " Wordize ASSIGN(COND) " << nodep);
@ -1026,7 +1067,7 @@ class ExpandVisitor final : public VNVisitor {
m_stmtp = nodep;
iterateChildren(nodep);
bool did = false;
if (nodep->isWide() && ((VN_IS(nodep->lhsp(), VarRef) || VN_IS(nodep->lhsp(), ArraySel)))
if (nodep->isWide() //
&& ((VN_IS(nodep->lhsp(), VarRef) || VN_IS(nodep->lhsp(), ArraySel)))
&& !AstVar::scVarRecurse(nodep->lhsp()) // Need special function for SC
&& !AstVar::scVarRecurse(nodep->rhsp())) {
@ -1052,6 +1093,10 @@ class ExpandVisitor final : public VNVisitor {
did = expandWide(nodep, rhsp);
} else if (AstXor* const rhsp = VN_CAST(nodep->rhsp(), Xor)) {
did = expandWide(nodep, rhsp);
} else if (AstShiftL* const rhsp = VN_CAST(nodep->rhsp(), ShiftL)) {
did = expandWideShift(nodep, rhsp, /* isLeftShift: */ true);
} else if (AstShiftR* const rhsp = VN_CAST(nodep->rhsp(), ShiftR)) {
did = expandWideShift(nodep, rhsp, /* isLeftShift: */ false);
} else if (AstCond* const rhsp = VN_CAST(nodep->rhsp(), Cond)) {
did = expandWide(nodep, rhsp);
}

View File

@ -6,7 +6,7 @@
module t (/*AUTOARG*/
// Outputs
ign, ign2, ign3, ign4, ign4s,
ign, ign2, ign3, c_wright_32, c_wleft_32, ign4, ign4s,
// Inputs
clk
);
@ -59,6 +59,12 @@ module t (/*AUTOARG*/
reg [63:0] qamt;
reg [95:0] wamt;
output reg [95:0] c_wright_32;
output reg [95:0] c_wleft_32;
reg [63:0] crc = 64'h5aef0c8d_d70a4497;
wire [95:0] rand_96 = {crc[63:32] | crc[31:0], crc};
assign ign = {31'h0, clk} >>> 4'bx; // bug760
assign ign2 = {iamt[1:0] >> {22{iamt[5:2]}}, iamt[1:0] << (0 <<< iamt[5:2])}; // bug1174
assign ign3 = {iamt[1:0] >> {22{iamt[5:2]}},
@ -104,12 +110,16 @@ module t (/*AUTOARG*/
w_wright = 96'hf784bf8f_12734089_190abe48 >> wamt;
w_wrights = 96'shf784bf8f_12734089_190abe48 >>> signed'(wamt);
w_wleft = 96'hf784bf8f_12734089_190abe48 << wamt;
c_wright_32 = rand_96 >> 32;
c_wleft_32 = rand_96 << 32;
end
integer cyc; initial cyc=1;
always @ (posedge clk) begin
if (cyc!=0) begin
cyc <= cyc + 1;
crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]};
`ifdef TEST_VERBOSE
$write("%d %x %x %x %x %x %x\n", cyc, ileft, iright, qleft, qright, wleft, wright);
`endif
@ -233,6 +243,9 @@ module t (/*AUTOARG*/
if (wleft != w_wleft) $stop;
if (wright != w_wright) $stop;
if (wrights != w_wrights) $stop;
if (c_wright_32 << 32 != {rand_96[95:32], 32'd0}) $stop;
if (c_wleft_32 >> 32 != {32'd0, rand_96[63:0]}) $stop;
end
end
end