From 2285e5b6dac6ab271fbe5e5b3d4bdf615bf0104d Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sun, 5 Jul 2026 09:24:01 +0100 Subject: [PATCH] Optimize more always blocks in Dfg (#7775) Optimize always blocks that: - drive an unused variable (so logic can be pruned) - write only a single variable (regardless of CFG size) --- src/V3DfgPasses.cpp | 8 +++++++- src/V3DfgSynthesize.cpp | 11 +++++++---- src/V3DfgVertices.h | 3 +++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/V3DfgPasses.cpp b/src/V3DfgPasses.cpp index afca00589..7fc4b4100 100644 --- a/src/V3DfgPasses.cpp +++ b/src/V3DfgPasses.cpp @@ -78,7 +78,13 @@ void V3DfgPasses::removeUnobservable(DfgGraph& dfg, V3DfgContext& dfgCtx) { && !vVtxp->hasExtWrRefs() // && !vVtxp->hasModWrRefs(); VL_DO_DANGLING(vVtxp->unlinkDelete(dfg), vVtxp); - if (srcp) VL_DO_DANGLING(srcp->unlinkDelete(dfg), srcp); + if (srcp) { + srcp->foreachSource([&](DfgVertex& src) { + src.as()->setDrivesUnusedVars(); + return false; + }); + VL_DO_DANGLING(srcp->unlinkDelete(dfg), srcp); + } if (delAst) { VL_DO_DANGLING(vscp->unlinkFrBack()->deleteTree(), vscp); ++ctx.m_varsDeleted; diff --git a/src/V3DfgSynthesize.cpp b/src/V3DfgSynthesize.cpp index c0f5bdc99..a23b19c4b 100644 --- a/src/V3DfgSynthesize.cpp +++ b/src/V3DfgSynthesize.cpp @@ -2005,6 +2005,11 @@ static void dfgSelectLogicForSynthesis(DfgGraph& dfg) { for (DfgVertex& vtx : dfg.opVertices()) { DfgLogic* const logicp = vtx.cast(); if (!logicp) continue; + // If drives an unused variable, synthesize it so the partial logic can be removed + if (logicp->drivesUnusedVars()) { + worklist.push_front(*logicp); + continue; + } // Blocks corresponding to continuous assignments if (logicp->nodep()->keyword() == VAlwaysKwd::CONT_ASSIGN) { worklist.push_front(*logicp); @@ -2016,10 +2021,8 @@ static void dfgSelectLogicForSynthesis(DfgGraph& dfg) { worklist.push_front(*logicp); continue; } - // Simple blocks driving exactly 1 variable, e.g if (rst) a = b else a = c; - if (!logicp->hasMultipleSinks() && cfg.nBlocks() <= 4 && cfg.nEdges() <= 4) { - worklist.push_front(*logicp); - } + // Blocks driving exactly 1 variable + if (!logicp->hasMultipleSinks()) worklist.push_front(*logicp); } // Now expand to cover all logic driving the same set of variables and mark diff --git a/src/V3DfgVertices.h b/src/V3DfgVertices.h index d932de1a3..dd51a58a9 100644 --- a/src/V3DfgVertices.h +++ b/src/V3DfgVertices.h @@ -512,6 +512,7 @@ class DfgLogic final : public DfgVertexVariadic { AstScope* const m_scopep; // The AstScope m_nodep is under, iff scoped const std::unique_ptr m_cfgp; std::vector m_synth; // Vertices this logic was synthesized into + bool m_drivesUnusedVars = false; // Logic drives unused variables bool m_selectedForSynthesis = false; // Logic selected for synthesis bool m_nonSynthesizable = false; // Logic is not synthesizeable (by DfgSynthesis) bool m_reverted = false; // Logic was synthesized (in part if non-synthesizable) then reverted @@ -538,6 +539,8 @@ public: const CfgGraph& cfg() const { return *m_cfgp; } std::vector& synth() { return m_synth; } const std::vector& synth() const { return m_synth; } + bool drivesUnusedVars() const { return m_drivesUnusedVars; } + void setDrivesUnusedVars() { m_drivesUnusedVars = true; } bool selectedForSynthesis() const { return m_selectedForSynthesis; } void setSelectedForSynthesis() { m_selectedForSynthesis = true; } bool nonSynthesizable() const { return m_nonSynthesizable; }