diff --git a/src/V3Ast.h b/src/V3Ast.h index 7e0d2a73d..2963987f2 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -541,6 +541,14 @@ public: AstNode* backp() const VL_MT_STABLE { return m_backp; } AstNode* abovep() const; // Get parent node above, only for list head and tail AstNode* aboveLoopp() const; // Get parent node above, may have performance issues as loops + AstNode* lastp() const { // Get last node in list, only for list head + UASSERT_OBJ(m_backp->m_nextp != this, this, "lastp() only allowed on head of list"); + return m_headtailp; + } + AstNode* prevp() const { // Previous node in list, nullptr for head of list + if (m_backp->m_nextp != this) return nullptr; + return m_backp; + } AstNode* op1p() const VL_MT_STABLE { return m_op1p; } AstNode* op2p() const VL_MT_STABLE { return m_op2p; } AstNode* op3p() const VL_MT_STABLE { return m_op3p; } diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 2d5a07faf..949ef9f79 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1230,6 +1230,24 @@ class ConstVisitor final : public VNVisitor { } } + void matchIfSameLast(AstNodeIf* nodep) { + if (!nodep->thensp()) return; + if (!nodep->elsesp()) return; + // Iterate bodies in reverse + AstNode* tp = nodep->thensp()->lastp(); + AstNode* ep = nodep->elsesp()->lastp(); + while (tp && ep && tp->sameTree(ep)) { + UASSERT_OBJ(!tp->nextp(), tp, "Expected no nextp"); + UASSERT_OBJ(!ep->nextp(), ep, "Expected no nextp"); + AstNode* const tPrevp = tp->prevp(); + AstNode* const ePrevp = ep->prevp(); + nodep->addNextHere(tp->unlinkFrBack()); + VL_DO_DANGLING(pushDeletep(ep->unlinkFrBack()), ep); + tp = tPrevp; + ep = ePrevp; + } + } + 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: @@ -3636,6 +3654,7 @@ class ConstVisitor final : public VNVisitor { } else { // Optimizations that don't reform the IF itself if (operandBoolShift(nodep->condp())) replaceBoolShift(nodep->condp()); + matchIfSameLast(nodep); matchIfCondCond(nodep); } }