Fix shift to remove operation side effects (#4563).

This commit is contained in:
Wilson Snyder
2023-10-14 22:34:37 -04:00
parent 3940a214d0
commit 46f8a659b3
9 changed files with 206 additions and 61 deletions
+26 -46
View File
@@ -49,11 +49,8 @@ class PremitVisitor final : public VNVisitor {
private:
// NODE STATE
// AstNodeExpr::user() -> bool. True if iterated already
// AstShiftL::user2() -> bool. True if converted to conditional
// AstShiftR::user2() -> bool. True if converted to conditional
// *::user3() -> Used when visiting AstNodeAssign
const VNUser1InUse m_inuser1;
const VNUser2InUse m_inuser2;
// STATE - across all visitors
VDouble0 m_extractedToConstPool; // Statistic tracking
@@ -236,47 +233,33 @@ private:
}
void visitShift(AstNodeBiop* nodep) {
// Shifts of > 32/64 bits in C++ will wrap-around and generate non-0s
if (!nodep->user2SetOnce()) {
UINFO(4, " ShiftFix " << nodep << endl);
const AstConst* const shiftp = VN_CAST(nodep->rhsp(), Const);
if (shiftp && shiftp->num().mostSetBitP1() > 32) {
shiftp->v3error(
"Unsupported: Shifting of by over 32-bit number isn't supported."
<< " (This isn't a shift of 32 bits, but a shift of 2^32, or 4 billion!)\n");
}
if (nodep->widthMin() <= 64 // Else we'll use large operators which work right
// C operator's width must be < maximum shift which is
// based on Verilog width
&& nodep->width() < (1LL << nodep->rhsp()->widthMin())) {
VNRelinker replaceHandle;
nodep->unlinkFrBack(&replaceHandle);
AstNodeExpr* constzerop;
const int m1value
= nodep->widthMin() - 1; // Constant of width-1; not changing dtype width
if (nodep->signedFlavor()) {
// Then over shifting gives the sign bit, not all zeros
// Note *NOT* clean output -- just like normal shift!
// Create equivalent of VL_SIGNONES_(node_width)
constzerop = new AstNegate{
nodep->fileline(),
new AstShiftR{nodep->fileline(), nodep->lhsp()->cloneTreePure(false),
new AstConst(nodep->fileline(), m1value), nodep->width()}};
} else {
constzerop = new AstConst{nodep->fileline(), AstConst::WidthedValue{},
nodep->width(), 0};
}
constzerop->dtypeFrom(nodep); // unsigned
AstNodeExpr* const constwidthp
= new AstConst(nodep->fileline(), AstConst::WidthedValue{},
nodep->rhsp()->widthMin(), m1value);
constwidthp->dtypeFrom(nodep->rhsp()); // unsigned
AstCond* const newp = new AstCond{nodep->fileline(),
new AstGte{nodep->fileline(), constwidthp,
nodep->rhsp()->cloneTreePure(false)},
nodep, constzerop};
replaceHandle.relink(newp);
UINFO(4, " ShiftFix " << nodep << endl);
const AstConst* const shiftp = VN_CAST(nodep->rhsp(), Const);
if (shiftp && shiftp->num().mostSetBitP1() > 32) {
shiftp->v3error(
"Unsupported: Shifting of by over 32-bit number isn't supported."
<< " (This isn't a shift of 32 bits, but a shift of 2^32, or 4 billion!)\n");
}
if (nodep->widthMin() <= 64 // Else we'll use large operators which work right
// C operator's width must be < maximum shift which is
// based on Verilog width
&& nodep->width() < (1LL << nodep->rhsp()->widthMin())) {
AstNode* newp;
if (VN_IS(nodep, ShiftL)) {
newp = new AstShiftLOvr{nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
nodep->rhsp()->unlinkFrBack()};
} else if (VN_IS(nodep, ShiftR)) {
newp = new AstShiftROvr{nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
nodep->rhsp()->unlinkFrBack()};
} else {
UASSERT_OBJ(VN_IS(nodep, ShiftRS), nodep, "Bad case");
newp = new AstShiftRSOvr{nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
nodep->rhsp()->unlinkFrBack()};
}
newp->dtypeFrom(nodep);
nodep->replaceWith(newp);
VL_DO_DANGLING(pushDeletep(nodep), nodep);
return;
}
iterateChildren(nodep);
checkNode(nodep);
@@ -403,9 +386,6 @@ public:
}
};
//----------------------------------------------------------------------
// Top loop
//######################################################################
// Premit class functions