Fix deleting unused parameterized classes (#4150)

This commit is contained in:
Ryszard Rozak 2023-04-28 13:20:25 +02:00 committed by GitHub
parent ee5c0a2902
commit 09e856d2f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 131 additions and 20 deletions

View File

@ -2118,6 +2118,7 @@ class AstClass final : public AstNodeModule {
bool m_interfaceClass = false; // Interface class
bool m_needRNG = false; // Need RNG, uses srandom/randomize
bool m_virtual = false; // Virtual class
bool m_parameterized = false; // Parameterized class
void insertCache(AstNode* nodep);
public:
@ -2151,6 +2152,8 @@ public:
void isVirtual(bool flag) { m_virtual = flag; }
bool needRNG() const { return m_needRNG; }
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)
// Accepts nullptrs
static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp);

View File

@ -161,7 +161,6 @@ private:
bool m_forPrimary; // First link
bool m_forPrearray; // Compress cell__[array] refs
bool m_forScopeCreation; // Remove VarXRefs for V3Scope
bool m_removeVoidParamedClasses; // Remove classes with void params
public:
// METHODS
@ -208,7 +207,6 @@ public:
m_forPrimary = (step == LDS_PRIMARY);
m_forPrearray = (step == LDS_PARAMED || step == LDS_PRIMARY);
m_forScopeCreation = (step == LDS_SCOPED);
m_removeVoidParamedClasses = (step == LDS_PARAMED);
s_errorThisp = this;
V3Error::errorExitCb(preErrorDumpHandler); // If get error, dump self
}
@ -222,7 +220,6 @@ public:
bool forPrimary() const { return m_forPrimary; }
bool forPrearray() const { return m_forPrearray; }
bool forScopeCreation() const { return m_forScopeCreation; }
bool removeVoidParamedClasses() const { return m_removeVoidParamedClasses; }
// METHODS
static string nodeTextType(AstNode* nodep) {
@ -916,18 +913,6 @@ class LinkDotFindVisitor final : public VNVisitor {
void visit(AstClass* nodep) override {
UASSERT_OBJ(m_curSymp, nodep, "Class not under module/package/$unit");
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_classOrPackagep);
VL_RESTORER(m_modSymp);

View File

@ -567,8 +567,9 @@ class ParamProcessor final {
// 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.
AstNodeModule* const newmodp = srcModp->cloneTree(false);
if (VN_IS(srcModp, Class)) {
replaceRefsRecurse(newmodp->stmtsp(), VN_AS(newmodp, Class), VN_AS(srcModp, Class));
if (AstClass* const newClassp = VN_CAST(newmodp, Class)) {
newClassp->isParameterized(false);
replaceRefsRecurse(newmodp->stmtsp(), newClassp, VN_AS(srcModp, Class));
}
newmodp->name(newname);
@ -809,6 +810,9 @@ class ParamProcessor final {
if (!any_overrides) {
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
= m_hierBlocks.findByParams(srcModpr->name(), paramsp, m_modp)) {
paramedModp->dead(false);
@ -916,7 +920,7 @@ public:
class ParamVisitor final : public VNVisitor {
// NODE STATE
// AstNodeModule::user1 -> bool: already fixed level
// AstClass::user2 -> bool: Referenced (value read only in parameterized classes)
// STATE
ParamProcessor m_processor; // De-parameterize a cell, build modules
UnrollStateful m_unroller; // Loop unroller
@ -928,6 +932,7 @@ class ParamVisitor final : public VNVisitor {
std::vector<AstDot*> m_dots; // Dot references to process
std::multimap<bool, AstNode*> m_cellps; // Cells left to process (in current module)
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.
std::unordered_map<AstNodeModule*, std::unordered_set<AstNodeModule*>> m_parentps;
@ -1047,6 +1052,14 @@ class ParamVisitor final : public VNVisitor {
void visit(AstNodeModule* nodep) override {
if (nodep->recursiveClone()) nodep->dead(true); // Fake, made for recursive elimination
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
UINFO(4, " MOD-under-MOD. " << nodep << endl);
@ -1363,6 +1376,17 @@ public:
// Re-insert modules
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;

View File

@ -6775,6 +6775,7 @@ class_declaration<nodep>: // ==IEEE: part of class_declaration
}
/*cont*/ class_itemListE yENDCLASS endLabelE
{ $$ = $1; $1->addMembersp($2);
if ($2) $1->isParameterized(true);
$1->addExtendsp($3);
$1->addExtendsp($4);
$1->addMembersp($7);

View File

@ -1,5 +1,5 @@
%Error: t/t_class_extends_int_param_bad.v:9:23: Attempting to extend using non-class
: ... In instance t
9 | class bar #(type T=int) extends T;
9 | class Bar #(type T=int) extends T;
| ^~~
%Error: Exiting due to

View File

@ -6,10 +6,11 @@
module t (/*AUTOARG*/);
class bar #(type T=int) extends T;
class Bar #(type T=int) extends T;
endclass
initial begin
Bar#() bar;
$stop;
end
endmodule

View File

@ -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;

View File

@ -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

View File

@ -90,6 +90,16 @@ class ExtendsMyInt #(type T=MyInt1) extends T;
endfunction
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*/);
initial begin
@ -112,6 +122,8 @@ module t (/*AUTOARG*/);
automatic ExtendsMyInt#() ext1 = new;
automatic ExtendsMyInt#(MyInt2) ext2 = new;
automatic GetStaticXVal#(StaticX) get_statix_x_val = new;
typedef bit my_bit_t;
Bar#(.A(my_bit_t)) bar_a_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 (ext2.get_this_type_x() != 2) $stop;
if (get_statix_x_val.get() != 1) $stop;
$write("*-* All Finished *-*\n");
$finish;
end

View File

@ -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;

View File

@ -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