diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index 4bf326637..824557341 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -246,6 +246,7 @@ class DeadVisitor final : public VNVisitor { // Entire Netlist: // AstNodeModule::user1() -> int. Count of number of cells referencing this module. // AstVar::user1() -> int. Count of number of references + // AstVar::user2() -> bool. Is a formal function argument // AstVarScope::user1() -> int. Count of number of references // AstNodeDType::user1() -> int. Count of number of references const VNUser1InUse m_inuser1; @@ -279,6 +280,7 @@ class DeadVisitor final : public VNVisitor { AstNodeModule* m_modp = nullptr; // Current module AstForeachHeader* m_foreachHeaderp = nullptr; // Current foreach header AstNode* m_containingFTaskRefp = nullptr; // Parent of ftaskref (e.g. task/module) + bool m_inFTask = false; // Under an AstNodeFTask // STATE - Statistic tracking VDouble0 m_statFTasksDemoted; @@ -351,6 +353,16 @@ class DeadVisitor final : public VNVisitor { iterateChildren(nodep); checkAll(nodep); if (nodep->scopep()) nodep->scopep()->user1Inc(); + // Keep formal arguments + for (AstVar* varp = nodep->argsp(); varp; varp = VN_AS(varp->nextp(), Var)) { + varp->user1Inc(); + varp->user2(1); + } + } + void visit(AstPin* nodep) override { + iterateChildren(nodep); + checkAll(nodep); + if (nodep->modVarp()) nodep->modVarp()->user1Inc(); } void visit(AstScope* nodep) override { iterateChildren(nodep); @@ -400,6 +412,11 @@ class DeadVisitor final : public VNVisitor { checkAll(nodep); needsTask(nodep->ftaskp(), m_containingFTaskRefp); } + void visit(AstModportVarRef* nodep) override { + iterateChildren(nodep); + checkAll(nodep); + if (nodep->varp()) nodep->varp()->user1Inc(); + } void visit(AstRefDType* nodep) override { iterateChildren(nodep); checkDType(nodep); @@ -510,6 +527,11 @@ class DeadVisitor final : public VNVisitor { iterateChildren(nodep); checkAll(nodep); if (m_foreachHeaderp) nodep->user1Inc(); + // Keep formal arguments + if (m_inFTask && nodep->isIO()) { + nodep->user1Inc(); + nodep->user2(1); + } if (mightElimVar(nodep)) { m_varsp.push_back(nodep); } else { @@ -549,7 +571,9 @@ class DeadVisitor final : public VNVisitor { m_graph.findNewRemovableVertex(nodep, removable); // VL_RESTORER(m_containingFTaskRefp); + VL_RESTORER(m_inFTask); m_containingFTaskRefp = nodep; + m_inFTask = true; iterateChildren(nodep); checkAll(nodep); if (nodep->isVirtual()) m_graph.funcVirtual(nodep); @@ -668,7 +692,7 @@ class DeadVisitor final : public VNVisitor { } bool mightElimVar(const AstVar* nodep) const { if (nodep->isSigPublic()) return false; // Can't elim publics! - if (nodep->isIO() || nodep->isClassMember() || nodep->sensIfacep()) return false; + if (nodep->isPrimaryIO() || nodep->isClassMember() || nodep->sensIfacep()) return false; if (nodep->isTemp() && !nodep->isTrace()) return true; return m_elimUserVars; // Post-Trace can kill most anything } @@ -720,6 +744,8 @@ class DeadVisitor final : public VNVisitor { void deadCheckVar() { // Delete any unused varscopes for (AstVarScope* vscp : m_vscsp) { + // Keep formal arguments + if (vscp->varp()->user2()) continue; if (vscp->user1() == 0) { UINFO(4, " Dead " << vscp); const std::pair eqrange diff --git a/test_regress/t/t_inst_tree_inl0_pub0.py b/test_regress/t/t_inst_tree_inl0_pub0.py index a5bc9523b..0e93f779f 100755 --- a/test_regress/t/t_inst_tree_inl0_pub0.py +++ b/test_regress/t/t_inst_tree_inl0_pub0.py @@ -23,12 +23,10 @@ if test.vlt_all: r'{"type":"MODULE","name":"l2",.*"loc":"\w,62:[^"]*",.*"origName":"l2"') test.file_grep(out_filename, r'{"type":"MODULE","name":"l3",.*"loc":"\w,69:[^"]*",.*"origName":"l3"') - test.file_grep(out_filename, - r'{"type":"MODULE","name":"l4",.*"loc":"\w,76:[^"]*",.*"origName":"l4"') - test.file_grep(out_filename, - r'{"type":"MODULE","name":"l5__P1",.*"loc":"\w,83:[^"]*",.*"origName":"l5"') - test.file_grep(out_filename, - r'{"type":"MODULE","name":"l5__P2",.*"loc":"\w,83:[^"]*",.*"origName":"l5"') + # l4 and l5 hold nothing but combinational logic feeding their single reader, + # so they are optimized away entirely, even though they are marked no_inline + test.file_grep_not(out_filename, r'{"type":"MODULE","name":"l4"') + test.file_grep_not(out_filename, r'{"type":"MODULE","name":"l5__P') test.execute() test.file_grep(test.run_log_filename, r"\] (%m|.*t\.ps): Clocked") diff --git a/test_regress/t/t_protect_ids_key.out b/test_regress/t/t_protect_ids_key.out index ae8b6431c..fed5d3d6b 100644 --- a/test_regress/t/t_protect_ids_key.out +++ b/test_regress/t/t_protect_ids_key.out @@ -50,7 +50,6 @@ -