diff --git a/src/V3Case.cpp b/src/V3Case.cpp index 65386df2a..80dffba68 100644 --- a/src/V3Case.cpp +++ b/src/V3Case.cpp @@ -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 matchPattern(const AstCase* /*casep*/, + const AstConst* condp) { + // As one to encourage NRVO/move + std::pair 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}}); } } diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 2ff6a0a80..0098f1d94 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -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"); diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 8adf7ce78..58bb2740b 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -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); diff --git a/src/V3Number.h b/src/V3Number.h index 771f5edd4..df726e496 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -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 diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp index d0a4aff84..57e12e478 100644 --- a/src/V3Unknown.cpp +++ b/src/V3Unknown.cpp @@ -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,