Optimize staticly known oversize shifts
The non *Ovr flavours of AstShift* have better downstream constant folding, so keep using those if proven safe. Fold overshifts explicitly instead of introducing *Ovr shifts.
This commit is contained in:
parent
749b93e405
commit
0cd1fdf47e
|
|
@ -139,34 +139,51 @@ class PremitVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
void visitShift(AstNodeBiop* nodep) {
|
void visitShift(AstNodeBiop* nodep) {
|
||||||
// Shifts of > 32/64 bits in C++ will wrap-around and generate non-0s
|
|
||||||
UINFO(4, " ShiftFix " << nodep);
|
UINFO(4, " ShiftFix " << nodep);
|
||||||
const AstConst* const shiftp = VN_CAST(nodep->rhsp(), Const);
|
UASSERT_OBJ(VN_IS(nodep, ShiftL) || VN_IS(nodep, ShiftR) || VN_IS(nodep, ShiftRS), nodep,
|
||||||
if (shiftp && shiftp->num().mostSetBitP1() > 32) {
|
"Bad case");
|
||||||
shiftp->v3warn(
|
// Shift larger than the width of the type (overshift) is undefined behavour in C++
|
||||||
E_UNSUPPORTED,
|
// (in practice will shift by the wrapped shift amount). These are requierd to go to
|
||||||
"Unsupported: Shifting of by over 32-bit number isn't supported."
|
// zero/msbs, so replacing them here.
|
||||||
<< " (This isn't a shift of 32 bits, but a shift of 2^32, or 4 billion!)\n");
|
FileLine* const flp = nodep->fileline();
|
||||||
}
|
if (const AstConst* const shiftp = VN_CAST(nodep->rhsp(), Const)) {
|
||||||
if (nodep->widthMin() <= 64 // Else we'll use large operators which work right
|
// Shift amount known to be constant. If oversized shift, replace with zero/msbs.
|
||||||
// C operator's width must be < maximum shift which is
|
// Otherwise we can leave the original shifts which have better constant folding
|
||||||
// based on Verilog width
|
// than the *Ovr versions.
|
||||||
&& nodep->width() < (1LL << nodep->rhsp()->widthMin())) {
|
const bool isOversized = shiftp->num().mostSetBitP1() > 32 //
|
||||||
AstNode* newp;
|
|| (shiftp->num().toSQuad() >= nodep->width());
|
||||||
if (VN_IS(nodep, ShiftL)) {
|
if (isOversized) {
|
||||||
newp = new AstShiftLOvr{nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
|
AstNodeExpr* newp = nullptr;
|
||||||
nodep->rhsp()->unlinkFrBack()};
|
if (VN_IS(nodep, ShiftRS)) {
|
||||||
} else if (VN_IS(nodep, ShiftR)) {
|
AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||||
newp = new AstShiftROvr{nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
|
AstNodeExpr* const msbp = new AstSel{flp, lhsp, nodep->width() - 1, 1};
|
||||||
nodep->rhsp()->unlinkFrBack()};
|
newp = new AstExtendS{flp, msbp, nodep->width()};
|
||||||
} else {
|
} else {
|
||||||
UASSERT_OBJ(VN_IS(nodep, ShiftRS), nodep, "Bad case");
|
newp = new AstConst{flp, AstConst::DTyped{}, nodep->dtypep()};
|
||||||
newp = new AstShiftRSOvr{nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
|
}
|
||||||
nodep->rhsp()->unlinkFrBack()};
|
nodep->replaceWithKeepDType(newp);
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Shift amount not known at compile time. Convert to *Ovr version. Don't need to do
|
||||||
|
// if it would use a wide operation which works correctly at runtime, of if the max
|
||||||
|
// value of the shift amount is less than the with of the shifted value.
|
||||||
|
if (nodep->widthMin() <= VL_QUADSIZE && (nodep->width() < (1LL << nodep->rhsp()->widthMin()))) {
|
||||||
|
AstNodeExpr* const lhsp = nodep->lhsp()->unlinkFrBack();
|
||||||
|
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
|
||||||
|
AstNodeExpr* newp = nullptr;
|
||||||
|
if (VN_IS(nodep, ShiftL)) {
|
||||||
|
newp = new AstShiftLOvr{flp, lhsp, rhsp};
|
||||||
|
} else if (VN_IS(nodep, ShiftR)) {
|
||||||
|
newp = new AstShiftROvr{flp, lhsp, rhsp};
|
||||||
|
} else {
|
||||||
|
newp = new AstShiftRSOvr{flp, lhsp, rhsp};
|
||||||
|
}
|
||||||
|
nodep->replaceWithKeepDType(newp);
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
nodep->replaceWithKeepDType(newp);
|
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
checkNode(nodep);
|
checkNode(nodep);
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ test.compile(verilator_flags2=["-Wno-UNOPTTHREADS", "-fno-dfg", "--stats", test.
|
||||||
test.execute()
|
test.execute()
|
||||||
|
|
||||||
if test.vlt:
|
if test.vlt:
|
||||||
test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 48)
|
test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 50)
|
||||||
test.file_grep(test.stats, r'SplitVar, packed variables split automatically\s+(\d+)', 1)
|
test.file_grep(test.stats, r'SplitVar, packed variables split automatically\s+(\d+)', 1)
|
||||||
|
|
||||||
test.passes()
|
test.passes()
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ test.compile(verilator_flags2=["-Wno-UNOPTTHREADS", "--stats", test.pli_filename
|
||||||
test.execute()
|
test.execute()
|
||||||
|
|
||||||
if test.vlt:
|
if test.vlt:
|
||||||
test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 38)
|
test.file_grep(test.stats, r'Optimizations, Const bit op reduction\s+(\d+)', 40)
|
||||||
test.file_grep(test.stats, r'SplitVar, packed variables split automatically\s+(\d+)', 1)
|
test.file_grep(test.stats, r'SplitVar, packed variables split automatically\s+(\d+)', 1)
|
||||||
|
|
||||||
test.passes()
|
test.passes()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue