From 08be65a7dd76dc1a3074f1d2d83b8d8c5a4282ab Mon Sep 17 00:00:00 2001 From: Artur Bieniek Date: Fri, 19 Sep 2025 15:36:57 +0200 Subject: [PATCH] Optimize dead functions in more cases (#6430) Signed-off-by: Artur Bieniek --- src/V3Dead.cpp | 26 ++++++++++++++++++-------- test_regress/t/t_opt_dead_task.py | 2 +- test_regress/t/t_opt_dead_task.v | 14 ++++++++++++++ 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index cf548f880..97cd5d36e 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -39,6 +39,7 @@ #include "V3Stats.h" +#include #include VL_DEFINE_DEBUG_FUNCTIONS; @@ -53,7 +54,7 @@ class DeadVisitor final : public VNVisitor { // AstVar::user1() -> int. Count of number of references // AstVarScope::user1() -> int. Count of number of references // AstNodeDType::user1() -> int. Count of number of references - // AstNodeFTask::user1() -> int. Non-zero if ever referenced (called) + // AstNodeFTask::user1() -> int. Count of number of references (via AstNodeFTaskRefs) const VNUser1InUse m_inuser1; // TYPES @@ -72,7 +73,7 @@ class DeadVisitor final : public VNVisitor { std::vector m_cellsp; std::vector m_classesp; std::vector m_typedefsp; - std::vector m_tasksp; // All the tasks that could be removed if not called + std::queue m_tasksp; // All the tasks that could be removed if not called AssignMap m_assignMap; // List of all simple assignments for each variable bool m_sideEffect = false; // Side effects discovered in assign RHS @@ -173,7 +174,7 @@ class DeadVisitor final : public VNVisitor { void visit(AstNodeFTaskRef* nodep) override { iterateChildren(nodep); checkAll(nodep); - if (nodep->taskp()) nodep->taskp()->user1(1); + if (nodep->taskp()) nodep->taskp()->user1Inc(); if (nodep->classOrPackagep()) { if (m_elimCells) { nodep->classOrPackagep(nullptr); @@ -325,7 +326,7 @@ class DeadVisitor final : public VNVisitor { iterateChildren(nodep); checkAll(nodep); if (!nodep->taskPublic() && !nodep->dpiExport() && !nodep->dpiImport()) - m_tasksp.push_back(nodep); + m_tasksp.push(nodep); if (nodep->classOrPackagep()) { if (m_elimCells) { nodep->classOrPackagep(nullptr); @@ -365,8 +366,17 @@ class DeadVisitor final : public VNVisitor { } void deadCheckTasks() { - for (AstNodeFTask* taskp : m_tasksp) { - if (!taskp->user1() && !taskp->classMethod()) { + while (!m_tasksp.empty()) { + AstNodeFTask* taskp = m_tasksp.front(); + m_tasksp.pop(); + if (taskp->user1() == 0 && !taskp->classMethod()) { + taskp->foreach([this](AstNodeFTaskRef* ftaskrefp) { + AstNodeFTask* task2p = ftaskrefp->taskp(); + if (!task2p) return; + task2p->user1Inc(-1); + if (task2p->user1() == 0) m_tasksp.push(task2p); + }); + taskp->user1(-1); // we don't want to try deleting twice deleting(taskp); m_statFTasksDeadified++; } @@ -611,12 +621,12 @@ void V3Dead::deadifyDTypesScoped(AstNetlist* nodep) { void V3Dead::deadifyAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ":"); - { DeadVisitor{nodep, true, true, false, true, false, false}; } // Destruct before checking + { DeadVisitor{nodep, true, true, false, true, false, true}; } // Destruct before checking V3Global::dumpCheckGlobalTree("deadAll", 0, dumpTreeEitherLevel() >= 3); } void V3Dead::deadifyAllScoped(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ":"); - { DeadVisitor{nodep, true, true, true, true, false, false}; } // Destruct before checking + { DeadVisitor{nodep, true, true, true, true, false, true}; } // Destruct before checking V3Global::dumpCheckGlobalTree("deadAllScoped", 0, dumpTreeEitherLevel() >= 3); } diff --git a/test_regress/t/t_opt_dead_task.py b/test_regress/t/t_opt_dead_task.py index 95f680736..84ef5c5e2 100755 --- a/test_regress/t/t_opt_dead_task.py +++ b/test_regress/t/t_opt_dead_task.py @@ -14,7 +14,7 @@ test.scenarios('simulator') test.compile(verilator_flags2=["--stats"]) if test.vlt_all: - test.file_grep(test.stats, r'Optimizations, deadified FTasks\s+(\d+)', 2) + test.file_grep(test.stats, r'Optimizations, deadified FTasks\s+(\d+)', 6) test.execute() diff --git a/test_regress/t/t_opt_dead_task.v b/test_regress/t/t_opt_dead_task.v index 0be4aa58a..fe9e1aeba 100644 --- a/test_regress/t/t_opt_dead_task.v +++ b/test_regress/t/t_opt_dead_task.v @@ -22,7 +22,21 @@ module t (input clk); // These should be deadified function deadfunc(); + deeptask2(); endfunction task deadtask; + deeptask1(); + endtask + // A chain of dead tasks calling each other to ensure V3Dead can remove chained dead tasks + task deeptask1; + deeptask2(); + endtask + task deeptask2; + deeptask3(); + endtask + task deeptask3; + deeptask4(); + endtask + task deeptask4; endtask endmodule