diff --git a/src/V3Const.cpp b/src/V3Const.cpp index b9d81fef4..2d3f7e364 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -168,6 +168,34 @@ private: return (lp && VN_IS(lp->lhsp(), Const) && VN_IS(np->rhsp(), Const) && lp->width() == np->width()); } + bool matchRedundantClean(AstAnd* andp) { + // Remove And with constant one inserted by V3Clean + // 1 & (a == b) -> (IData)(a == b) + // When bool is casted to int, the value is either 0 or 1 + AstConst* constp = VN_CAST(andp->lhsp(), Const); + UASSERT_OBJ(constp && constp->isOne(), andp->lhsp(), "TRREEOPC must meet this condition"); + AstNode* rhsp = andp->rhsp(); + AstCCast* ccastp = nullptr; + auto isEqOrNeq + = [](AstNode* nodep) -> bool { return VN_IS(nodep, Eq) || VN_IS(nodep, Neq); }; + if (isEqOrNeq(rhsp)) { + ccastp = new AstCCast{andp->fileline(), rhsp->unlinkFrBack(), andp}; + } else if (AstCCast* tmpp = VN_CAST(rhsp, CCast)) { + if (isEqOrNeq(tmpp->lhsp())) { + if (tmpp->width() == andp->width()) { + tmpp->unlinkFrBack(); + ccastp = tmpp; + } else { + ccastp = new AstCCast{andp->fileline(), tmpp->lhsp()->unlinkFrBack(), andp}; + } + } + } + if (ccastp) { + andp->replaceWith(ccastp); + VL_DO_DANGLING(andp->deleteTree(), andp); + } + return ccastp; + } static bool operandAndOrSame(const AstNode* nodep) { // OR( AND(VAL,x), AND(VAL,y)) -> AND(VAL,OR(x,y)) @@ -2291,6 +2319,7 @@ private: TREEOP ("AstModDiv{$lhsp, operandIsPowTwo($rhsp)}", "replaceModAnd(nodep)"); // a % 2^n -> a&(2^n-1) TREEOP ("AstPow {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<castAdd()->lhsp(),$rhsp}, $lhsp->castAdd()->rhsp()}"); // ((a+x)-y) -> (a+(x-y)) + TREEOPC("AstAnd {$lhsp.isOne, matchRedundantClean(nodep)}", "DONE") // 1 & (a == b) -> (IData)(a == b) // Trinary ops // Note V3Case::Sel requires Cond to always be conditionally executed in C to prevent core dump! TREEOP ("AstNodeCond{$condp.isZero, $expr1p, $expr2p}", "replaceWChild(nodep,$expr2p)");