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:
Geza Lore 2021-06-18 16:18:30 +01:00
parent e5e5bc0fa3
commit 0c93c3844f

View File

@ -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)");