Fix deleting unused parameterized classes (#4150)
This commit is contained in:
parent
ee5c0a2902
commit
09e856d2f3
|
|
@ -2118,6 +2118,7 @@ class AstClass final : public AstNodeModule {
|
||||||
bool m_interfaceClass = false; // Interface class
|
bool m_interfaceClass = false; // Interface class
|
||||||
bool m_needRNG = false; // Need RNG, uses srandom/randomize
|
bool m_needRNG = false; // Need RNG, uses srandom/randomize
|
||||||
bool m_virtual = false; // Virtual class
|
bool m_virtual = false; // Virtual class
|
||||||
|
bool m_parameterized = false; // Parameterized class
|
||||||
void insertCache(AstNode* nodep);
|
void insertCache(AstNode* nodep);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -2151,6 +2152,8 @@ public:
|
||||||
void isVirtual(bool flag) { m_virtual = flag; }
|
void isVirtual(bool flag) { m_virtual = flag; }
|
||||||
bool needRNG() const { return m_needRNG; }
|
bool needRNG() const { return m_needRNG; }
|
||||||
void needRNG(bool flag) { m_needRNG = flag; }
|
void needRNG(bool flag) { m_needRNG = flag; }
|
||||||
|
bool isParameterized() const { return m_parameterized; }
|
||||||
|
void isParameterized(bool flag) { m_parameterized = flag; }
|
||||||
// Return true if this class is an extension of base class (SLOW)
|
// Return true if this class is an extension of base class (SLOW)
|
||||||
// Accepts nullptrs
|
// Accepts nullptrs
|
||||||
static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp);
|
static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp);
|
||||||
|
|
|
||||||
|
|
@ -161,7 +161,6 @@ private:
|
||||||
bool m_forPrimary; // First link
|
bool m_forPrimary; // First link
|
||||||
bool m_forPrearray; // Compress cell__[array] refs
|
bool m_forPrearray; // Compress cell__[array] refs
|
||||||
bool m_forScopeCreation; // Remove VarXRefs for V3Scope
|
bool m_forScopeCreation; // Remove VarXRefs for V3Scope
|
||||||
bool m_removeVoidParamedClasses; // Remove classes with void params
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// METHODS
|
// METHODS
|
||||||
|
|
@ -208,7 +207,6 @@ public:
|
||||||
m_forPrimary = (step == LDS_PRIMARY);
|
m_forPrimary = (step == LDS_PRIMARY);
|
||||||
m_forPrearray = (step == LDS_PARAMED || step == LDS_PRIMARY);
|
m_forPrearray = (step == LDS_PARAMED || step == LDS_PRIMARY);
|
||||||
m_forScopeCreation = (step == LDS_SCOPED);
|
m_forScopeCreation = (step == LDS_SCOPED);
|
||||||
m_removeVoidParamedClasses = (step == LDS_PARAMED);
|
|
||||||
s_errorThisp = this;
|
s_errorThisp = this;
|
||||||
V3Error::errorExitCb(preErrorDumpHandler); // If get error, dump self
|
V3Error::errorExitCb(preErrorDumpHandler); // If get error, dump self
|
||||||
}
|
}
|
||||||
|
|
@ -222,7 +220,6 @@ public:
|
||||||
bool forPrimary() const { return m_forPrimary; }
|
bool forPrimary() const { return m_forPrimary; }
|
||||||
bool forPrearray() const { return m_forPrearray; }
|
bool forPrearray() const { return m_forPrearray; }
|
||||||
bool forScopeCreation() const { return m_forScopeCreation; }
|
bool forScopeCreation() const { return m_forScopeCreation; }
|
||||||
bool removeVoidParamedClasses() const { return m_removeVoidParamedClasses; }
|
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
static string nodeTextType(AstNode* nodep) {
|
static string nodeTextType(AstNode* nodep) {
|
||||||
|
|
@ -916,18 +913,6 @@ class LinkDotFindVisitor final : public VNVisitor {
|
||||||
void visit(AstClass* nodep) override {
|
void visit(AstClass* nodep) override {
|
||||||
UASSERT_OBJ(m_curSymp, nodep, "Class not under module/package/$unit");
|
UASSERT_OBJ(m_curSymp, nodep, "Class not under module/package/$unit");
|
||||||
UINFO(8, " " << nodep << endl);
|
UINFO(8, " " << nodep << endl);
|
||||||
// Remove classes that have void params, as they were only used for the parameterization
|
|
||||||
// step and will not be instantiated
|
|
||||||
if (m_statep->removeVoidParamedClasses()) {
|
|
||||||
for (auto* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
|
||||||
if (auto* dtypep = VN_CAST(stmtp, ParamTypeDType)) {
|
|
||||||
if (VN_IS(dtypep->subDTypep(), VoidDType)) {
|
|
||||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
VL_RESTORER(m_scope);
|
VL_RESTORER(m_scope);
|
||||||
VL_RESTORER(m_classOrPackagep);
|
VL_RESTORER(m_classOrPackagep);
|
||||||
VL_RESTORER(m_modSymp);
|
VL_RESTORER(m_modSymp);
|
||||||
|
|
|
||||||
|
|
@ -567,8 +567,9 @@ class ParamProcessor final {
|
||||||
// Note all module internal variables will be re-linked to the new modules by clone
|
// Note all module internal variables will be re-linked to the new modules by clone
|
||||||
// However links outside the module (like on the upper cells) will not.
|
// However links outside the module (like on the upper cells) will not.
|
||||||
AstNodeModule* const newmodp = srcModp->cloneTree(false);
|
AstNodeModule* const newmodp = srcModp->cloneTree(false);
|
||||||
if (VN_IS(srcModp, Class)) {
|
if (AstClass* const newClassp = VN_CAST(newmodp, Class)) {
|
||||||
replaceRefsRecurse(newmodp->stmtsp(), VN_AS(newmodp, Class), VN_AS(srcModp, Class));
|
newClassp->isParameterized(false);
|
||||||
|
replaceRefsRecurse(newmodp->stmtsp(), newClassp, VN_AS(srcModp, Class));
|
||||||
}
|
}
|
||||||
|
|
||||||
newmodp->name(newname);
|
newmodp->name(newname);
|
||||||
|
|
@ -809,6 +810,9 @@ class ParamProcessor final {
|
||||||
|
|
||||||
if (!any_overrides) {
|
if (!any_overrides) {
|
||||||
UINFO(8, "Cell parameters all match original values, skipping expansion.\n");
|
UINFO(8, "Cell parameters all match original values, skipping expansion.\n");
|
||||||
|
// Mark that the defeult instance is used.
|
||||||
|
// It will be checked only if srcModpr is a class.
|
||||||
|
srcModpr->user2(true);
|
||||||
} else if (AstNodeModule* const paramedModp
|
} else if (AstNodeModule* const paramedModp
|
||||||
= m_hierBlocks.findByParams(srcModpr->name(), paramsp, m_modp)) {
|
= m_hierBlocks.findByParams(srcModpr->name(), paramsp, m_modp)) {
|
||||||
paramedModp->dead(false);
|
paramedModp->dead(false);
|
||||||
|
|
@ -916,7 +920,7 @@ public:
|
||||||
class ParamVisitor final : public VNVisitor {
|
class ParamVisitor final : public VNVisitor {
|
||||||
// NODE STATE
|
// NODE STATE
|
||||||
// AstNodeModule::user1 -> bool: already fixed level
|
// AstNodeModule::user1 -> bool: already fixed level
|
||||||
|
// AstClass::user2 -> bool: Referenced (value read only in parameterized classes)
|
||||||
// STATE
|
// STATE
|
||||||
ParamProcessor m_processor; // De-parameterize a cell, build modules
|
ParamProcessor m_processor; // De-parameterize a cell, build modules
|
||||||
UnrollStateful m_unroller; // Loop unroller
|
UnrollStateful m_unroller; // Loop unroller
|
||||||
|
|
@ -928,6 +932,7 @@ class ParamVisitor final : public VNVisitor {
|
||||||
std::vector<AstDot*> m_dots; // Dot references to process
|
std::vector<AstDot*> m_dots; // Dot references to process
|
||||||
std::multimap<bool, AstNode*> m_cellps; // Cells left to process (in current module)
|
std::multimap<bool, AstNode*> m_cellps; // Cells left to process (in current module)
|
||||||
std::multimap<int, AstNodeModule*> m_workQueue; // Modules left to process
|
std::multimap<int, AstNodeModule*> m_workQueue; // Modules left to process
|
||||||
|
std::vector<AstClass*> m_paramClasses; // Parameterized classes
|
||||||
|
|
||||||
// Map from AstNodeModule to set of all AstNodeModules that instantiates it.
|
// Map from AstNodeModule to set of all AstNodeModules that instantiates it.
|
||||||
std::unordered_map<AstNodeModule*, std::unordered_set<AstNodeModule*>> m_parentps;
|
std::unordered_map<AstNodeModule*, std::unordered_set<AstNodeModule*>> m_parentps;
|
||||||
|
|
@ -1047,6 +1052,14 @@ class ParamVisitor final : public VNVisitor {
|
||||||
void visit(AstNodeModule* nodep) override {
|
void visit(AstNodeModule* nodep) override {
|
||||||
if (nodep->recursiveClone()) nodep->dead(true); // Fake, made for recursive elimination
|
if (nodep->recursiveClone()) nodep->dead(true); // Fake, made for recursive elimination
|
||||||
if (nodep->dead()) return; // Marked by LinkDot (and above)
|
if (nodep->dead()) return; // Marked by LinkDot (and above)
|
||||||
|
if (AstClass* const classp = VN_CAST(nodep, Class)) {
|
||||||
|
if (classp->isParameterized()) {
|
||||||
|
// Don't enter into a definition.
|
||||||
|
// If a class is used, it will be visited through a reference
|
||||||
|
m_paramClasses.push_back(classp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_iterateModule) { // Iterating body
|
if (m_iterateModule) { // Iterating body
|
||||||
UINFO(4, " MOD-under-MOD. " << nodep << endl);
|
UINFO(4, " MOD-under-MOD. " << nodep << endl);
|
||||||
|
|
@ -1363,6 +1376,17 @@ public:
|
||||||
|
|
||||||
// Re-insert modules
|
// Re-insert modules
|
||||||
for (AstNodeModule* const modp : modps) netlistp->addModulesp(modp);
|
for (AstNodeModule* const modp : modps) netlistp->addModulesp(modp);
|
||||||
|
|
||||||
|
for (AstClass* const classp : m_paramClasses) {
|
||||||
|
if (!classp->user2()) {
|
||||||
|
// Unreferenced, so it can be removed
|
||||||
|
VL_DO_DANGLING(pushDeletep(classp->unlinkFrBack()), classp);
|
||||||
|
} else {
|
||||||
|
// Referenced. classp became a specialized class with the default
|
||||||
|
// values of parameters and is not a parameterized class anymore
|
||||||
|
classp->isParameterized(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
~ParamVisitor() override = default;
|
~ParamVisitor() override = default;
|
||||||
|
|
|
||||||
|
|
@ -6775,6 +6775,7 @@ class_declaration<nodep>: // ==IEEE: part of class_declaration
|
||||||
}
|
}
|
||||||
/*cont*/ class_itemListE yENDCLASS endLabelE
|
/*cont*/ class_itemListE yENDCLASS endLabelE
|
||||||
{ $$ = $1; $1->addMembersp($2);
|
{ $$ = $1; $1->addMembersp($2);
|
||||||
|
if ($2) $1->isParameterized(true);
|
||||||
$1->addExtendsp($3);
|
$1->addExtendsp($3);
|
||||||
$1->addExtendsp($4);
|
$1->addExtendsp($4);
|
||||||
$1->addMembersp($7);
|
$1->addMembersp($7);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
%Error: t/t_class_extends_int_param_bad.v:9:23: Attempting to extend using non-class
|
%Error: t/t_class_extends_int_param_bad.v:9:23: Attempting to extend using non-class
|
||||||
: ... In instance t
|
: ... In instance t
|
||||||
9 | class bar #(type T=int) extends T;
|
9 | class Bar #(type T=int) extends T;
|
||||||
| ^~~
|
| ^~~
|
||||||
%Error: Exiting due to
|
%Error: Exiting due to
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,11 @@
|
||||||
|
|
||||||
module t (/*AUTOARG*/);
|
module t (/*AUTOARG*/);
|
||||||
|
|
||||||
class bar #(type T=int) extends T;
|
class Bar #(type T=int) extends T;
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
|
Bar#() bar;
|
||||||
$stop;
|
$stop;
|
||||||
end
|
end
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2020 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
|
||||||
|
|
||||||
|
scenarios(simulator => 1);
|
||||||
|
|
||||||
|
compile(
|
||||||
|
);
|
||||||
|
|
||||||
|
execute(
|
||||||
|
check_finished => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2023 by Antmicro Ltd.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
class Foo#(type T = logic) extends T;
|
||||||
|
endclass
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/);
|
||||||
|
initial begin
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -90,6 +90,16 @@ class ExtendsMyInt #(type T=MyInt1) extends T;
|
||||||
endfunction
|
endfunction
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
|
class StaticX;
|
||||||
|
static int val = 1;
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class GetStaticXVal #(type T = int);
|
||||||
|
static function int get;
|
||||||
|
return T::val;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
module t (/*AUTOARG*/);
|
module t (/*AUTOARG*/);
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
|
|
@ -112,6 +122,8 @@ module t (/*AUTOARG*/);
|
||||||
automatic ExtendsMyInt#() ext1 = new;
|
automatic ExtendsMyInt#() ext1 = new;
|
||||||
automatic ExtendsMyInt#(MyInt2) ext2 = new;
|
automatic ExtendsMyInt#(MyInt2) ext2 = new;
|
||||||
|
|
||||||
|
automatic GetStaticXVal#(StaticX) get_statix_x_val = new;
|
||||||
|
|
||||||
typedef bit my_bit_t;
|
typedef bit my_bit_t;
|
||||||
Bar#(.A(my_bit_t)) bar_a_bit = new;
|
Bar#(.A(my_bit_t)) bar_a_bit = new;
|
||||||
Bar#(.B(my_bit_t)) bar_b_bit = new;
|
Bar#(.B(my_bit_t)) bar_b_bit = new;
|
||||||
|
|
@ -145,6 +157,8 @@ module t (/*AUTOARG*/);
|
||||||
if (ext1.get_this_type_x() != 1) $stop;
|
if (ext1.get_this_type_x() != 1) $stop;
|
||||||
if (ext2.get_this_type_x() != 2) $stop;
|
if (ext2.get_this_type_x() != 2) $stop;
|
||||||
|
|
||||||
|
if (get_statix_x_val.get() != 1) $stop;
|
||||||
|
|
||||||
$write("*-* All Finished *-*\n");
|
$write("*-* All Finished *-*\n");
|
||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2020 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
|
||||||
|
|
||||||
|
scenarios(simulator => 1);
|
||||||
|
|
||||||
|
compile(
|
||||||
|
);
|
||||||
|
|
||||||
|
execute(
|
||||||
|
check_finished => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2023 by Antmicro Ltd.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
class Bar#(type T = int);
|
||||||
|
T t;
|
||||||
|
function new;
|
||||||
|
t = new;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class Baz;
|
||||||
|
int x = 1;
|
||||||
|
endclass
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/);
|
||||||
|
initial begin
|
||||||
|
Bar#(Baz) bar_baz = new;
|
||||||
|
if (bar_baz.t.x != 1) $stop;
|
||||||
|
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue