diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp index 4e513ec0e..ed6a0eb98 100644 --- a/src/V3Expand.cpp +++ b/src/V3Expand.cpp @@ -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(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); } diff --git a/test_regress/t/t_math_shift.v b/test_regress/t/t_math_shift.v index d37162520..c78333832 100644 --- a/test_regress/t/t_math_shift.v +++ b/test_regress/t/t_math_shift.v @@ -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