Fix cast width propagation (#2597).

This commit is contained in:
Wilson Snyder 2020-11-08 19:07:33 -05:00
parent 6e7b07c794
commit d78941885b
4 changed files with 66 additions and 30 deletions

View File

@ -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]

View File

@ -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(); }

View File

@ -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

View File

@ -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