From 9455dddab4c477c0e33d364bea735c541f6ca982 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Fri, 29 May 2026 11:26:07 +0100 Subject: [PATCH] Optimize if branches with same trailing statements (#7674) If the same statements appears in both branches of an 'if', put a single copy after the 'if', apply recursively. This also has the effect of getting rid of conditionals with identical branches, but is more widely applicable. --- src/V3Ast.h | 8 ++++++++ src/V3Const.cpp | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+) 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); } }