mirror of
https://github.com/verilator/verilator.git
synced 2025-05-04 22:46:57 +00:00
Simplify AND(CONST,OR(_,_)) with redundant terms
V3Expand generates a lot of OR nodes that are under a clearing mask, and have redundant terms, e.g.: 0xff & (a << 8 | b >> 24). The 'a << 8' term in there is redundant as it's bottom bits are all zero where the mask is non-zero. V3Const now removes these redundant terms.
This commit is contained in:
parent
e5e5bc0fa3
commit
0c93c3844f
@ -710,6 +710,48 @@ private:
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
return true;
|
||||
}
|
||||
bool matchMaskedOr(AstAnd* nodep) {
|
||||
// Masking an OR with terms that have no bits set under the mask is replaced with masking
|
||||
// only the remaining terms. Canonical example as generated by V3Expand is:
|
||||
// 0xff & (a << 8 | b >> 24) --> 0xff & (b >> 24)
|
||||
|
||||
// Compute how many significant bits are in the mask
|
||||
const AstConst* const constp = VN_CAST(nodep->lhsp(), Const);
|
||||
const uint32_t significantBits = constp->num().widthMin();
|
||||
|
||||
AstOr* const orp = VN_CAST(nodep->rhsp(), Or);
|
||||
|
||||
// Predicate for checking whether the bottom 'significantBits' bits of the given expression
|
||||
// are all zeroes.
|
||||
const auto checkBottomClear = [=](const AstNode* nodep) -> bool {
|
||||
if (const AstShiftL* const shiftp = VN_CAST_CONST(nodep, ShiftL)) {
|
||||
if (const AstConst* const scp = VN_CAST_CONST(shiftp->rhsp(), Const)) {
|
||||
return scp->num().toUInt() >= significantBits;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const bool orLIsRedundant = checkBottomClear(orp->lhsp());
|
||||
const bool orRIsRedundant = checkBottomClear(orp->rhsp());
|
||||
|
||||
if (orLIsRedundant && orRIsRedundant) {
|
||||
nodep->replaceWith(
|
||||
new AstConst(nodep->fileline(), AstConst::DtypedValue(), nodep->dtypep(), 0));
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
return true;
|
||||
} else if (orLIsRedundant) {
|
||||
orp->replaceWith(orp->rhsp()->unlinkFrBack());
|
||||
VL_DO_DANGLING(orp->deleteTree(), orp);
|
||||
return false; // input node is still valid, keep going
|
||||
} else if (orRIsRedundant) {
|
||||
orp->replaceWith(orp->lhsp()->unlinkFrBack());
|
||||
VL_DO_DANGLING(orp->deleteTree(), orp);
|
||||
return false; // input node is still valid, keep going
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool matchBitOpTree(AstNode* nodep) {
|
||||
if (!v3Global.opt.oConstBitOpTree()) return false;
|
||||
|
||||
@ -2964,9 +3006,10 @@ private:
|
||||
TREEOPV("AstConcat{$lhsp.castSel, $rhsp.castSel, ifAdjacentSel(VN_CAST($lhsp,,Sel),,VN_CAST($rhsp,,Sel))}", "replaceConcatSel(nodep)");
|
||||
TREEOPV("AstConcat{ifConcatMergeableBiop($lhsp), concatMergeable($lhsp,,$rhsp)}", "replaceConcatMerge(nodep)");
|
||||
// Common two-level operations that can be simplified
|
||||
TREEOP ("AstAnd {$lhsp.castConst,matchAndCond(nodep)}", "DONE");
|
||||
TREEOP ("AstAnd {$lhsp.castOr, $rhsp.castOr, operandAndOrSame(nodep)}", "replaceAndOr(nodep)");
|
||||
TREEOP ("AstOr {$lhsp.castAnd,$rhsp.castAnd,operandAndOrSame(nodep)}", "replaceAndOr(nodep)");
|
||||
TREEOP ("AstAnd {$lhsp.castConst,matchAndCond(nodep)}", "DONE");
|
||||
TREEOP ("AstAnd {$lhsp.castConst, $rhsp.castOr, matchMaskedOr(nodep)}", "DONE");
|
||||
TREEOP ("AstAnd {$lhsp.castOr, $rhsp.castOr, operandAndOrSame(nodep)}", "replaceAndOr(nodep)");
|
||||
TREEOP ("AstOr {$lhsp.castAnd,$rhsp.castAnd,operandAndOrSame(nodep)}", "replaceAndOr(nodep)");
|
||||
TREEOP ("AstOr {matchOrAndNot(nodep)}", "DONE");
|
||||
TREEOP ("AstAnd {operandShiftSame(nodep)}", "replaceShiftSame(nodep)");
|
||||
TREEOP ("AstOr {operandShiftSame(nodep)}", "replaceShiftSame(nodep)");
|
||||
|
Loading…
Reference in New Issue
Block a user