Optimize dead functions without references (#6380)
This commit is contained in:
parent
a364704e3a
commit
905c0c4f6d
|
|
@ -37,6 +37,8 @@
|
||||||
|
|
||||||
#include "V3Dead.h"
|
#include "V3Dead.h"
|
||||||
|
|
||||||
|
#include "V3Stats.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||||
|
|
@ -51,6 +53,7 @@ class DeadVisitor final : public VNVisitor {
|
||||||
// AstVar::user1() -> int. Count of number of references
|
// AstVar::user1() -> int. Count of number of references
|
||||||
// AstVarScope::user1() -> int. Count of number of references
|
// AstVarScope::user1() -> int. Count of number of references
|
||||||
// AstNodeDType::user1() -> int. Count of number of references
|
// AstNodeDType::user1() -> int. Count of number of references
|
||||||
|
// AstNodeFTask::user1() -> int. Non-zero if ever referenced (called)
|
||||||
const VNUser1InUse m_inuser1;
|
const VNUser1InUse m_inuser1;
|
||||||
|
|
||||||
// TYPES
|
// TYPES
|
||||||
|
|
@ -69,6 +72,7 @@ class DeadVisitor final : public VNVisitor {
|
||||||
std::vector<AstCell*> m_cellsp;
|
std::vector<AstCell*> m_cellsp;
|
||||||
std::vector<AstClass*> m_classesp;
|
std::vector<AstClass*> m_classesp;
|
||||||
std::vector<AstTypedef*> m_typedefsp;
|
std::vector<AstTypedef*> m_typedefsp;
|
||||||
|
std::vector<AstNodeFTask*> m_tasksp; // All the tasks that could be removed if not called
|
||||||
AssignMap m_assignMap; // List of all simple assignments for each variable
|
AssignMap m_assignMap; // List of all simple assignments for each variable
|
||||||
bool m_sideEffect = false; // Side effects discovered in assign RHS
|
bool m_sideEffect = false; // Side effects discovered in assign RHS
|
||||||
|
|
||||||
|
|
@ -78,6 +82,9 @@ class DeadVisitor final : public VNVisitor {
|
||||||
AstNodeModule* m_modp = nullptr; // Current module
|
AstNodeModule* m_modp = nullptr; // Current module
|
||||||
AstSelLoopVars* m_selloopvarsp = nullptr; // Current loop vars
|
AstSelLoopVars* m_selloopvarsp = nullptr; // Current loop vars
|
||||||
|
|
||||||
|
// STATE - Statistic tracking
|
||||||
|
VDouble0 m_statFTasksDeadified;
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
|
|
||||||
void deleting(AstNode* nodep) {
|
void deleting(AstNode* nodep) {
|
||||||
|
|
@ -166,6 +173,7 @@ class DeadVisitor final : public VNVisitor {
|
||||||
void visit(AstNodeFTaskRef* nodep) override {
|
void visit(AstNodeFTaskRef* nodep) override {
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
checkAll(nodep);
|
checkAll(nodep);
|
||||||
|
if (nodep->taskp()) nodep->taskp()->user1(1);
|
||||||
if (nodep->classOrPackagep()) {
|
if (nodep->classOrPackagep()) {
|
||||||
if (m_elimCells) {
|
if (m_elimCells) {
|
||||||
nodep->classOrPackagep(nullptr);
|
nodep->classOrPackagep(nullptr);
|
||||||
|
|
@ -174,9 +182,10 @@ class DeadVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void visit(AstMethodCall* nodep) override {
|
void visit(AstModportFTaskRef* nodep) override {
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
checkAll(nodep);
|
checkAll(nodep);
|
||||||
|
if (nodep->ftaskp()) nodep->ftaskp()->user1(1);
|
||||||
}
|
}
|
||||||
void visit(AstRefDType* nodep) override {
|
void visit(AstRefDType* nodep) override {
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
|
|
@ -312,6 +321,19 @@ class DeadVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
if (assignInAssign) m_sideEffect = true; // Parent assign shouldn't optimize
|
if (assignInAssign) m_sideEffect = true; // Parent assign shouldn't optimize
|
||||||
}
|
}
|
||||||
|
void visit(AstNodeFTask* nodep) override {
|
||||||
|
iterateChildren(nodep);
|
||||||
|
checkAll(nodep);
|
||||||
|
if (!nodep->taskPublic() && !nodep->dpiExport() && !nodep->dpiImport())
|
||||||
|
m_tasksp.push_back(nodep);
|
||||||
|
if (nodep->classOrPackagep()) {
|
||||||
|
if (m_elimCells) {
|
||||||
|
nodep->classOrPackagep(nullptr);
|
||||||
|
} else {
|
||||||
|
nodep->classOrPackagep()->user1Inc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//-----
|
//-----
|
||||||
void visit(AstClockingItem* nodep) override {
|
void visit(AstClockingItem* nodep) override {
|
||||||
|
|
@ -342,6 +364,15 @@ class DeadVisitor final : public VNVisitor {
|
||||||
return m_elimCells && !typedefp->attrPublic();
|
return m_elimCells && !typedefp->attrPublic();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void deadCheckTasks() {
|
||||||
|
for (AstNodeFTask* taskp : m_tasksp) {
|
||||||
|
if (!taskp->user1() && !taskp->classMethod()) {
|
||||||
|
deleting(taskp);
|
||||||
|
m_statFTasksDeadified++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void deadCheckMod() {
|
void deadCheckMod() {
|
||||||
// Kill any unused modules
|
// Kill any unused modules
|
||||||
// V3LinkCells has a graph that is capable of this too, but we need to do it
|
// V3LinkCells has a graph that is capable of this too, but we need to do it
|
||||||
|
|
@ -515,7 +546,7 @@ class DeadVisitor final : public VNVisitor {
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
DeadVisitor(AstNetlist* nodep, bool elimUserVars, bool elimDTypes, bool elimScopes,
|
DeadVisitor(AstNetlist* nodep, bool elimUserVars, bool elimDTypes, bool elimScopes,
|
||||||
bool elimCells, bool elimTopIfaces)
|
bool elimCells, bool elimTopIfaces, bool elimTasks)
|
||||||
: m_elimUserVars{elimUserVars}
|
: m_elimUserVars{elimUserVars}
|
||||||
, m_elimDTypes{elimDTypes}
|
, m_elimDTypes{elimDTypes}
|
||||||
, m_elimCells{elimCells} {
|
, m_elimCells{elimCells} {
|
||||||
|
|
@ -534,6 +565,7 @@ public:
|
||||||
if (itr.first->user1()) itr.second->user1Inc();
|
if (itr.first->user1()) itr.second->user1Inc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (elimTasks) deadCheckTasks();
|
||||||
deadCheckTypedefs();
|
deadCheckTypedefs();
|
||||||
deadCheckVar();
|
deadCheckVar();
|
||||||
// We only eliminate scopes when in a flattened structure
|
// We only eliminate scopes when in a flattened structure
|
||||||
|
|
@ -549,7 +581,9 @@ public:
|
||||||
nodep->typeTablep()->repairCache();
|
nodep->typeTablep()->repairCache();
|
||||||
VIsCached::clearCacheTree(); // Removing assignments may affect isPure
|
VIsCached::clearCacheTree(); // Removing assignments may affect isPure
|
||||||
}
|
}
|
||||||
~DeadVisitor() override = default;
|
~DeadVisitor() override {
|
||||||
|
V3Stats::addStatSum("Optimizations, deadified FTasks", m_statFTasksDeadified);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
@ -558,31 +592,31 @@ public:
|
||||||
void V3Dead::deadifyModules(AstNetlist* nodep) {
|
void V3Dead::deadifyModules(AstNetlist* nodep) {
|
||||||
UINFO(2, __FUNCTION__ << ":");
|
UINFO(2, __FUNCTION__ << ":");
|
||||||
{ // node, elimUserVars, elimDTypes, elimScopes, elimCells, elimTopIfaces
|
{ // node, elimUserVars, elimDTypes, elimScopes, elimCells, elimTopIfaces
|
||||||
DeadVisitor{nodep, false, false, false, false, !v3Global.opt.topIfacesSupported()};
|
DeadVisitor{nodep, false, false, false, false, !v3Global.opt.topIfacesSupported(), false};
|
||||||
} // Destruct before checking
|
} // Destruct before checking
|
||||||
V3Global::dumpCheckGlobalTree("deadModules", 0, dumpTreeEitherLevel() >= 6);
|
V3Global::dumpCheckGlobalTree("deadModules", 0, dumpTreeEitherLevel() >= 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
void V3Dead::deadifyDTypes(AstNetlist* nodep) {
|
void V3Dead::deadifyDTypes(AstNetlist* nodep) {
|
||||||
UINFO(2, __FUNCTION__ << ":");
|
UINFO(2, __FUNCTION__ << ":");
|
||||||
{ DeadVisitor{nodep, false, true, false, false, false}; } // Destruct before checking
|
{ DeadVisitor{nodep, false, true, false, false, false, true}; } // Destruct before checking
|
||||||
V3Global::dumpCheckGlobalTree("deadDtypes", 0, dumpTreeEitherLevel() >= 3);
|
V3Global::dumpCheckGlobalTree("deadDtypes", 0, dumpTreeEitherLevel() >= 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void V3Dead::deadifyDTypesScoped(AstNetlist* nodep) {
|
void V3Dead::deadifyDTypesScoped(AstNetlist* nodep) {
|
||||||
UINFO(2, __FUNCTION__ << ":");
|
UINFO(2, __FUNCTION__ << ":");
|
||||||
{ DeadVisitor{nodep, false, true, true, false, false}; } // Destruct before checking
|
{ DeadVisitor{nodep, false, true, true, false, false, false}; } // Destruct before checking
|
||||||
V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0, dumpTreeEitherLevel() >= 3);
|
V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0, dumpTreeEitherLevel() >= 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void V3Dead::deadifyAll(AstNetlist* nodep) {
|
void V3Dead::deadifyAll(AstNetlist* nodep) {
|
||||||
UINFO(2, __FUNCTION__ << ":");
|
UINFO(2, __FUNCTION__ << ":");
|
||||||
{ DeadVisitor{nodep, true, true, false, true, false}; } // Destruct before checking
|
{ DeadVisitor{nodep, true, true, false, true, false, false}; } // Destruct before checking
|
||||||
V3Global::dumpCheckGlobalTree("deadAll", 0, dumpTreeEitherLevel() >= 3);
|
V3Global::dumpCheckGlobalTree("deadAll", 0, dumpTreeEitherLevel() >= 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void V3Dead::deadifyAllScoped(AstNetlist* nodep) {
|
void V3Dead::deadifyAllScoped(AstNetlist* nodep) {
|
||||||
UINFO(2, __FUNCTION__ << ":");
|
UINFO(2, __FUNCTION__ << ":");
|
||||||
{ DeadVisitor{nodep, true, true, true, true, false}; } // Destruct before checking
|
{ DeadVisitor{nodep, true, true, true, true, false, false}; } // Destruct before checking
|
||||||
V3Global::dumpCheckGlobalTree("deadAllScoped", 0, dumpTreeEitherLevel() >= 3);
|
V3Global::dumpCheckGlobalTree("deadAllScoped", 0, dumpTreeEitherLevel() >= 3);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4582,11 +4582,6 @@ class WidthVisitor final : public VNVisitor {
|
||||||
// Either made explicitly or V3LinkDot made implicitly
|
// Either made explicitly or V3LinkDot made implicitly
|
||||||
classp->v3fatalSrc("Can't find class's new");
|
classp->v3fatalSrc("Can't find class's new");
|
||||||
}
|
}
|
||||||
if (classp->isVirtual() || classp->isInterfaceClass()) {
|
|
||||||
nodep->v3error("Illegal to call 'new' using an abstract virtual class "
|
|
||||||
+ AstNode::prettyNameQ(classp->origName())
|
|
||||||
+ " (IEEE 1800-2023 8.21)");
|
|
||||||
}
|
|
||||||
} else { // super.new case
|
} else { // super.new case
|
||||||
// in this case class and taskp() should be properly linked in V3LinkDot.cpp during
|
// in this case class and taskp() should be properly linked in V3LinkDot.cpp during
|
||||||
// "super" reference resolution
|
// "super" reference resolution
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,11 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
||||||
class WidthCommitVisitor final : public VNVisitor {
|
class WidthCommitVisitor final : public VNVisitor {
|
||||||
// NODE STATE
|
// NODE STATE
|
||||||
// AstVar::user1p -> bool, processed
|
// AstVar::user1p -> bool, processed
|
||||||
|
// AstNodeFTask::user2() -> int. Non-zero if ever referenced (called)
|
||||||
|
// AstNew::user2() -> int. Count of number of references, minus references in
|
||||||
|
// functions never called
|
||||||
const VNUser1InUse m_inuser1;
|
const VNUser1InUse m_inuser1;
|
||||||
|
const VNUser2InUse m_inuser2;
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
AstNodeModule* m_modp = nullptr;
|
AstNodeModule* m_modp = nullptr;
|
||||||
|
|
@ -47,6 +51,8 @@ class WidthCommitVisitor final : public VNVisitor {
|
||||||
= false; // Writing a dynamically-sized array element, not the array itself
|
= false; // Writing a dynamically-sized array element, not the array itself
|
||||||
VMemberMap m_memberMap; // Member names cached for fast lookup
|
VMemberMap m_memberMap; // Member names cached for fast lookup
|
||||||
bool m_underSel = false; // Whether is currently under AstMemberSel or AstSel
|
bool m_underSel = false; // Whether is currently under AstMemberSel or AstSel
|
||||||
|
std::vector<AstNew*> m_virtualNewsp; // Instantiations of virtual classes
|
||||||
|
std::vector<AstNodeFTask*> m_tasksp; // All the tasks, we will check if they are ever called
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// METHODS
|
// METHODS
|
||||||
|
|
@ -151,6 +157,20 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void deadCheckTasks() {
|
||||||
|
for (AstNodeFTask* taskp : m_tasksp) {
|
||||||
|
if (!taskp->user2()) {
|
||||||
|
taskp->foreach([](AstNew* newp) { newp->user2Inc(-1); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (AstNew* newp : m_virtualNewsp) {
|
||||||
|
if (newp->user2() > 0)
|
||||||
|
newp->v3error("Illegal to call 'new' using an abstract virtual class "
|
||||||
|
+ AstNode::prettyNameQ(newp->classOrPackagep()->origName())
|
||||||
|
+ " (IEEE 1800-2023 8.21)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
void visit(AstNodeModule* nodep) override {
|
void visit(AstNodeModule* nodep) override {
|
||||||
VL_RESTORER(m_modp);
|
VL_RESTORER(m_modp);
|
||||||
|
|
@ -291,6 +311,8 @@ private:
|
||||||
nodep->virtRefDType2p(editOneDType(nodep->virtRefDType2p()));
|
nodep->virtRefDType2p(editOneDType(nodep->virtRefDType2p()));
|
||||||
}
|
}
|
||||||
void visit(AstNodeFTask* nodep) override {
|
void visit(AstNodeFTask* nodep) override {
|
||||||
|
if (!nodep->taskPublic() && !nodep->dpiExport() && !nodep->dpiImport())
|
||||||
|
m_tasksp.push_back(nodep);
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
editDType(nodep);
|
editDType(nodep);
|
||||||
{
|
{
|
||||||
|
|
@ -371,6 +393,16 @@ private:
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
editDType(nodep);
|
editDType(nodep);
|
||||||
classEncapCheck(nodep, nodep->taskp(), VN_CAST(nodep->classOrPackagep(), Class));
|
classEncapCheck(nodep, nodep->taskp(), VN_CAST(nodep->classOrPackagep(), Class));
|
||||||
|
if (nodep->taskp()) nodep->taskp()->user2(1);
|
||||||
|
if (AstNew* const newp = VN_CAST(nodep, New)) {
|
||||||
|
if (!VN_IS(newp->backp(), Assign)) return;
|
||||||
|
if (AstClass* const classp = VN_CAST(newp->classOrPackagep(), Class)) {
|
||||||
|
if (classp->isVirtual() || classp->isInterfaceClass()) {
|
||||||
|
m_virtualNewsp.push_back(newp);
|
||||||
|
newp->user2Inc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void visit(AstMemberSel* nodep) override {
|
void visit(AstMemberSel* nodep) override {
|
||||||
{
|
{
|
||||||
|
|
@ -430,6 +462,7 @@ public:
|
||||||
// Were changing widthMin's, so the table is now somewhat trashed
|
// Were changing widthMin's, so the table is now somewhat trashed
|
||||||
nodep->typeTablep()->clearCache();
|
nodep->typeTablep()->clearCache();
|
||||||
iterate(nodep);
|
iterate(nodep);
|
||||||
|
deadCheckTasks();
|
||||||
// Don't want to AstTypeTable::repairCache, as all needed nodes
|
// Don't want to AstTypeTable::repairCache, as all needed nodes
|
||||||
// have been added back in; a repair would prevent dead nodes from
|
// have been added back in; a repair would prevent dead nodes from
|
||||||
// being detected
|
// being detected
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
%Error: t/t_class_param_virtual_bad.v:13:11: Illegal to call 'new' using an abstract virtual class 'VBase' (IEEE 1800-2023 8.21)
|
|
||||||
: ... note: In instance 't'
|
|
||||||
13 | t = new;
|
|
||||||
| ^~~
|
|
||||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
|
||||||
%Error: t/t_class_param_virtual_bad.v:23:28: Illegal to call 'new' using an abstract virtual class 'ClsVirt' (IEEE 1800-2023 8.21)
|
%Error: t/t_class_param_virtual_bad.v:23:28: Illegal to call 'new' using an abstract virtual class 'ClsVirt' (IEEE 1800-2023 8.21)
|
||||||
: ... note: In instance 't'
|
: ... note: In instance 't'
|
||||||
23 | ClsVirt#(VBase) cv = new;
|
23 | ClsVirt#(VBase) cv = new;
|
||||||
| ^~~
|
| ^~~
|
||||||
|
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||||
|
%Error: t/t_class_param_virtual_bad.v:13:11: Illegal to call 'new' using an abstract virtual class 'VBase' (IEEE 1800-2023 8.21)
|
||||||
|
: ... note: In instance 't'
|
||||||
|
13 | t = new;
|
||||||
|
| ^~~
|
||||||
%Error: Exiting due to
|
%Error: Exiting due to
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
test.scenarios('vlt')
|
||||||
|
|
||||||
|
test.lint()
|
||||||
|
|
||||||
|
test.compile()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2025 by Antmicro.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
class cl #(type T= int);
|
||||||
|
function void f();
|
||||||
|
T obj = new;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
virtual class vcl;
|
||||||
|
endclass;
|
||||||
|
module t;
|
||||||
|
cl #(vcl) c = new;
|
||||||
|
initial begin
|
||||||
|
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
%Error: t/t_func_virt_new_bad.v:9:13: Illegal to call 'new' using an abstract virtual class 'vcl' (IEEE 1800-2023 8.21)
|
||||||
|
: ... note: In instance 't'
|
||||||
|
9 | T obj = new;
|
||||||
|
| ^~~
|
||||||
|
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||||
|
%Error: Exiting due to
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
test.scenarios('vlt')
|
||||||
|
|
||||||
|
test.lint(fails=True, expect_filename=test.golden_filename)
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2025 by Antmicro.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
class cl #(type T= int);
|
||||||
|
function void f();
|
||||||
|
T obj = new;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
virtual class vcl;
|
||||||
|
endclass;
|
||||||
|
module t;
|
||||||
|
cl #(vcl) c = new;
|
||||||
|
initial begin
|
||||||
|
c.f();
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
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.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2025 by Antmicro.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t (input clk);
|
||||||
|
// AstLet and AstProperty are also NodeFTasks, but lets are substituted earlier and properties should be "used" by their asserts so also not deadified
|
||||||
|
let nclk = ~clk;
|
||||||
|
assert property(@(posedge clk)1);
|
||||||
|
|
||||||
|
function void livefunc();
|
||||||
|
endfunction
|
||||||
|
task livetask;
|
||||||
|
endtask
|
||||||
|
// Tasks/functions that are called somewhere will not be deadified
|
||||||
|
initial begin
|
||||||
|
livefunc();
|
||||||
|
livetask();
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
// These should be deadified
|
||||||
|
function deadfunc();
|
||||||
|
endfunction
|
||||||
|
task deadtask;
|
||||||
|
endtask
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue