Internals: Minor cleanup of case statement lowering
- Factor out match mask construction - Rename V3Number method to reflect behaviour
This commit is contained in:
parent
b581f73843
commit
f11c4084d1
|
|
@ -174,6 +174,21 @@ class CaseVisitor final : public VNVisitor {
|
|||
return constp->num().isFourState();
|
||||
}
|
||||
|
||||
// Returns the matching mask and bits for a case item constant condition
|
||||
// TODO: with 'neverItem' checked, this is alway the same for all types of cases
|
||||
// 4-state will have to fix this up
|
||||
static std::pair<V3Number, V3Number> matchPattern(const AstCase* /*casep*/,
|
||||
const AstConst* condp) {
|
||||
// As one to encourage NRVO/move
|
||||
std::pair<V3Number, V3Number> pairMaskBits{
|
||||
std::piecewise_construct, //
|
||||
std::forward_as_tuple(condp->fileline(), condp->width(), 0),
|
||||
std::forward_as_tuple(condp->fileline(), condp->width(), 0)};
|
||||
pairMaskBits.first.opBitsNonXZ(condp->num());
|
||||
pairMaskBits.second.opBitsOne(condp->num());
|
||||
return pairMaskBits;
|
||||
}
|
||||
|
||||
// Determine whether we should check case items are complete
|
||||
// Returns enum's dtype if should check, nullptr if shouldn't
|
||||
static const AstEnumDType* getEnumCompletionCheckDType(const AstCase* const nodep) {
|
||||
|
|
@ -191,18 +206,13 @@ class CaseVisitor final : public VNVisitor {
|
|||
bool checkExhaustiveEnum(const AstCase* const nodep, const AstEnumDType* const enump) {
|
||||
const uint32_t numCases = 1UL << nodep->exprp()->width();
|
||||
for (AstEnumItem* eip = enump->itemsp(); eip; eip = VN_AS(eip->nextp(), EnumItem)) {
|
||||
AstConst* const econstp = VN_AS(eip->valuep(), Const);
|
||||
V3Number nummask{eip, econstp->width()};
|
||||
nummask.opBitsNonX(econstp->num());
|
||||
V3Number numval{eip, econstp->width()};
|
||||
numval.opBitsOne(econstp->num());
|
||||
|
||||
const uint32_t mask = nummask.toUInt();
|
||||
const uint32_t val = numval.toUInt();
|
||||
const auto& match = matchPattern(nodep, VN_AS(eip->valuep(), Const));
|
||||
const uint32_t mask = match.first.toUInt();
|
||||
const uint32_t bits = match.second.toUInt();
|
||||
|
||||
// Check all cases to see if they cover this enum value/pattern
|
||||
for (uint32_t i = 0; i < numCases; ++i) {
|
||||
if ((i & mask) != val) continue; // This case is not for this enum value
|
||||
if ((i & mask) != bits) continue; // This case is not for this enum value
|
||||
if (m_caseDetails.records[i].itemp) continue; // Covered case
|
||||
// Warn unless unique0 case which allows no-match
|
||||
if (!nodep->unique0Pragma()) {
|
||||
|
|
@ -278,19 +288,15 @@ class CaseVisitor final : public VNVisitor {
|
|||
// Some items can never match due to 2-state simulation
|
||||
if (neverItem(nodep, iconstp)) continue;
|
||||
|
||||
V3Number nummask{itemp, iconstp->width()};
|
||||
nummask.opBitsNonX(iconstp->num());
|
||||
V3Number numval{itemp, iconstp->width()};
|
||||
numval.opBitsOne(iconstp->num());
|
||||
|
||||
const uint32_t mask = nummask.toUInt();
|
||||
const uint32_t val = numval.toUInt();
|
||||
const auto& match = matchPattern(nodep, iconstp);
|
||||
const uint32_t mask = match.first.toUInt();
|
||||
const uint32_t bits = match.second.toUInt();
|
||||
|
||||
bool foundNewCase = false;
|
||||
const AstConst* firstOverlapConstp = nullptr;
|
||||
uint32_t firstOverlapValue = 0;
|
||||
for (uint32_t i = 0; i < numValues; ++i) {
|
||||
if ((i & mask) != val) continue;
|
||||
if ((i & mask) != bits) continue;
|
||||
|
||||
CaseRecord& caseRecord = m_caseDetails.records[i];
|
||||
|
||||
|
|
@ -498,17 +504,14 @@ class CaseVisitor final : public VNVisitor {
|
|||
if (itemConstp->num().isFourState()
|
||||
&& (nodep->casex() || nodep->casez() || nodep->caseInside())) {
|
||||
// Wildcard match, make 'caseExpr' & 'mask' == 'itemExpr' & 'mask'
|
||||
V3Number numMask{itemp, itemConstp->width()};
|
||||
numMask.opBitsNonX(itemConstp->num());
|
||||
V3Number numOne{itemp, itemConstp->width()};
|
||||
numOne.opBitsOne(itemConstp->num());
|
||||
V3Number numRhs{itemp, itemConstp->width()};
|
||||
numRhs.opAnd(numOne, numMask);
|
||||
const auto& match = matchPattern(nodep, itemConstp);
|
||||
const V3Number& matchMask = match.first;
|
||||
const V3Number& matchBits = match.second;
|
||||
VL_DO_DANGLING2(itemExprp->deleteTree(), itemExprp, itemConstp);
|
||||
return AstEq::newTyped(
|
||||
flp, //
|
||||
new AstConst{flp, numRhs},
|
||||
new AstAnd{flp, caseExprp, new AstConst{flp, numMask}});
|
||||
new AstConst{flp, matchBits},
|
||||
new AstAnd{flp, caseExprp, new AstConst{flp, matchMask}});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -286,7 +286,7 @@ class ConstBitOpTreeVisitor final : public VNVisitorConst {
|
|||
|
||||
// Get the mask that selects the bits that are relevant in this term
|
||||
V3Number maskNum{srcp, m_width, 0};
|
||||
maskNum.opBitsNonX(m_bitPolarity); // 'x' -> 0, 0->1, 1->1
|
||||
maskNum.opBitsNonXZ(m_bitPolarity); // 'x' -> 0, 0->1, 1->1
|
||||
const uint64_t maskVal = maskNum.toUQuad();
|
||||
UASSERT_OBJ(maskVal != 0, m_refp,
|
||||
"Should have been recognized as having const 0 result");
|
||||
|
|
|
|||
|
|
@ -1310,7 +1310,7 @@ uint32_t V3Number::mostSetBitP1() const {
|
|||
}
|
||||
//======================================================================
|
||||
|
||||
V3Number& V3Number::opBitsNonX(const V3Number& lhs) { // 0/1->1, X/Z->0
|
||||
V3Number& V3Number::opBitsNonXZ(const V3Number& lhs) { // 0/1->1, X/Z->0
|
||||
// Correct number of zero bits/width matters
|
||||
// op i, L(lhs) bit return
|
||||
NUM_ASSERT_OP_ARGS1(lhs);
|
||||
|
|
|
|||
|
|
@ -741,7 +741,7 @@ public:
|
|||
|
||||
// MATH
|
||||
// "this" is the output, as we need the output width before some computations
|
||||
V3Number& opBitsNonX(const V3Number& lhs); // 0/1->1, X/Z->0
|
||||
V3Number& opBitsNonXZ(const V3Number& lhs); // 0/1->1, X/Z->0
|
||||
V3Number& opBitsOne(const V3Number& lhs); // 1->1, 0/X/Z->0
|
||||
V3Number& opBitsXZ(const V3Number& lhs); // 0/1->0, X/Z->1
|
||||
V3Number& opBitsZ(const V3Number& lhs); // Z->1, 0/1/X->0
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ class UnknownVisitor final : public VNVisitor {
|
|||
} else {
|
||||
// X or Z's become mask, ala case statements.
|
||||
V3Number nummask{rhsp, rhsp->width()};
|
||||
nummask.opBitsNonX(VN_AS(rhsp, Const)->num());
|
||||
nummask.opBitsNonXZ(VN_AS(rhsp, Const)->num());
|
||||
V3Number numval{rhsp, rhsp->width()};
|
||||
numval.opBitsOne(VN_AS(rhsp, Const)->num());
|
||||
AstNodeExpr* const and1p = new AstAnd{nodep->fileline(), lhsp,
|
||||
|
|
|
|||
Loading…
Reference in New Issue