diff --git a/Changes b/Changes index bf1928f0c..ca1e6bff2 100644 --- a/Changes +++ b/Changes @@ -16,6 +16,8 @@ The contributors that suggested a given feature are shown in []. Thanks! **** Fix iteration over mutating list bug in VPI (#2588). [Kaleb Barrett] +**** Fix cast width propagation (#2597). [flex-liu] + **** Fix return from callValueCbs (#2589) (#2605). [Marlon James] **** Fix WIDTH warnings on comparisons with nullptr (#2602). [Rupert Swarbrick] diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 8d77fc54c..24334009d 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -5953,6 +5953,7 @@ public: virtual bool cleanLhs() const { return true; } virtual bool sizeMattersLhs() const { return false; } AstNode* lhsp() const { return op1p(); } + void lhsp(AstNode* nodep) { setOp1p(nodep); } virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } AstNodeDType* childDTypep() const { return VN_CAST(op2p(), NodeDType); } virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 6555db0f0..d735de1f4 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1661,41 +1661,47 @@ private: // Note we don't sign lhsp() that would make the algorithm O(n^2) if lots of casting. AstBasicDType* basicp = nodep->dtypep()->basicp(); UASSERT_OBJ(basicp, nodep, "Unimplemented: Casting non-simple data type"); - // When implement more complicated types need to convert childDTypep to - // dtypep() not as a child - if (!basicp->isDouble() && !nodep->lhsp()->isDouble()) { - // Note widthCheckSized might modify nodep->lhsp() - AstNodeDType* subDTypep = nodep->findLogicDType(nodep->width(), nodep->width(), - nodep->lhsp()->dtypep()->numeric()); - iterateCheck(nodep, "value", nodep->lhsp(), CONTEXT, FINAL, subDTypep, EXTEND_EXP, - false); - } else { - iterateCheck(nodep, "value", nodep->lhsp(), SELF, FINAL, nodep->lhsp()->dtypep(), - EXTEND_EXP, false); - } - AstNode* newp = nodep->lhsp()->unlinkFrBack(); - if (basicp->isDouble() && !newp->isDouble()) { - if (newp->isSigned()) { - newp = new AstISToRD(nodep->fileline(), newp); + if (m_vup->prelim()) { + userIterateAndNext(nodep->lhsp(), WidthVP(SELF, PRELIM).p()); + // When implement more complicated types need to convert childDTypep to + // dtypep() not as a child + if (!basicp->isDouble() && !nodep->lhsp()->isDouble()) { + // Note castSized might modify nodep->lhsp() + int width = nodep->dtypep()->width(); + castSized(nodep, nodep->lhsp(), width); } else { - newp = new AstIToRD(nodep->fileline(), newp); + iterateCheck(nodep, "value", nodep->lhsp(), SELF, FINAL, nodep->lhsp()->dtypep(), + EXTEND_EXP, false); } - } else if (!basicp->isDouble() && newp->isDouble()) { - if (basicp->isSigned()) { - newp = new AstRToIRoundS(nodep->fileline(), newp); + AstNode* newp = nodep->lhsp()->unlinkFrBack(); + if (basicp->isDouble() && !newp->isDouble()) { + if (newp->isSigned()) { + newp = new AstISToRD(nodep->fileline(), newp); + } else { + newp = new AstIToRD(nodep->fileline(), newp); + } + } else if (!basicp->isDouble() && newp->isDouble()) { + if (basicp->isSigned()) { + newp = new AstRToIRoundS(nodep->fileline(), newp); + } else { + newp = new AstUnsigned(nodep->fileline(), + new AstRToIS(nodep->fileline(), newp)); + } + } else if (basicp->isSigned() && !newp->isSigned()) { + newp = new AstSigned(nodep->fileline(), newp); + } else if (!basicp->isSigned() && newp->isSigned()) { + newp = new AstUnsigned(nodep->fileline(), newp); } else { - newp = new AstUnsigned(nodep->fileline(), new AstRToIS(nodep->fileline(), newp)); + // newp = newp; // Can just remove cast } - } else if (basicp->isSigned() && !newp->isSigned()) { - newp = new AstSigned(nodep->fileline(), newp); - } else if (!basicp->isSigned() && newp->isSigned()) { - newp = new AstUnsigned(nodep->fileline(), newp); - } else { - // newp = newp; // Can just remove cast + nodep->lhsp(newp); + // if (debug()) nodep->dumpTree(cout, " CastOut: "); + } + if (m_vup->final()) { + AstNode* underp = nodep->lhsp()->unlinkFrBack(); + nodep->replaceWith(underp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } - nodep->replaceWith(newp); - VL_DO_DANGLING(pushDeletep(nodep), nodep); - // if (debug()) newp->dumpTree(cout, " CastOut: "); } virtual void visit(AstCastSize* nodep) override { // IEEE: Signedness of result is same as self-determined signedness diff --git a/test_regress/t/t_math_shift_extend.v b/test_regress/t/t_math_shift_extend.v index b0f4707de..8e40234c0 100644 --- a/test_regress/t/t_math_shift_extend.v +++ b/test_regress/t/t_math_shift_extend.v @@ -9,9 +9,14 @@ module t (/*AUTOARG*/); logic in1 = 1; logic [1:0] in2 = 2'b11; logic [31:0] out; + logic [7:0] ones = 8'b11111111; + logic [9:0] ones10 = 10'b1111111111; typedef logic [7:0] data_t; + typedef logic [9:0] ten_t; + ten_t out10; + // verilator lint_off WIDTH initial begin in1 = 1; @@ -31,6 +36,28 @@ module t (/*AUTOARG*/); out = data_t'(in1 << in2); if (out != 8'b1000) $stop; + // Check upper bits get cleared when cast + in2 = 3; + out = data_t'(ones << in2); + if (out != 8'b11111000) $stop; + + in2 = 3; + out = data_t'(ones10 << in2); + if (out != 8'b11111000) $stop; + + // bug2597 + out = data_t'(10'h208 >> 2); + if (out != 8'h82) $stop; + + out = data_t'(10'h208 >> 2); + if (out != 8'h82) $stop; + + out = data_t'('h208 >> 2); + if (out != 8'h82) $stop; + + out10 = ten_t'('h404 >> 2); + if (out10 != 10'h101) $stop; + $write("*-* All Finished *-*\n"); $finish(); end