Fix segmentation fault on parameters (#8102) (#8149)

Co-authored-by: Sumanth Kadiyala <sumanth@hudson-trading.com>
This commit is contained in:
Sumanth Kadiyala 2026-08-19 02:45:35 -04:00 committed by GitHub
parent 7628a540af
commit 88e87b8abb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 69 additions and 9 deletions

View File

@ -252,7 +252,8 @@ class ParamProcessor final {
// AstNodeModule::user2() // bool True if processed
// AstGenFor::user2() // bool True if processed
// AstVar::user2() // bool True if constant propagated
// AstCell::user2p() // string* Generate portion of hierarchical name
// AstIfaceRefDType::user2() // bool True if visited
// AstClassRefDType::user2() // bool True if visited
// AstNodeModule:user4p() // AstNodeModule* Parametrized copy with default parameters
const VNUser2InUse m_inuser2;
const VNUser3InUse m_inuser3;
@ -2498,7 +2499,7 @@ class ParamVisitor final : public VNVisitor {
bool m_iterateModule = false; // Iterating module body
string m_unlinkedTxt; // Text for AstUnlinkedRef
std::multimap<bool, AstNode*> m_cellps; // Cells left to process (in current module)
std::deque<std::string> m_strings; // Allocator for temporary strings
std::unordered_map<const AstNode*, std::string> m_genHierNames; // Maps ast nodes to generated hierarchy names
std::map<const AstRefDType*, bool>
m_isCircular; // Stores information whether `AstRefDType` is circular
using VarsByName = std::unordered_map<std::string, AstVar*>;
@ -2565,6 +2566,14 @@ class ParamVisitor final : public VNVisitor {
AstNode* const cellp = itim->second;
m_cellps.erase(itim);
// Consume the generated hierarchy name for the node
string genHierName;
const auto genHierIt = m_genHierNames.find(cellp);
if (genHierIt != m_genHierNames.end()) {
genHierName = std::move(genHierIt->second);
m_genHierNames.erase(genHierIt);
}
AstNodeModule* srcModp = nullptr;
if (const AstCell* modCellp = VN_CAST(cellp, Cell)) {
srcModp = modCellp->modp();
@ -2582,11 +2591,7 @@ class ParamVisitor final : public VNVisitor {
if (!srcModp) continue;
// Update path
string someInstanceName = modp->someInstanceName();
if (const string* const genHierNamep = cellp->user2u().to<string*>()) {
someInstanceName += *genHierNamep;
cellp->user2p(nullptr);
}
const string someInstanceName = modp->someInstanceName() + genHierName;
// Apply parameter specialization
if (AstNodeModule* const newModp
@ -2801,8 +2806,7 @@ class ParamVisitor final : public VNVisitor {
// A generic visitor for cells and class refs
void visitCellOrClassRef(AstNode* nodep, bool isIface) {
// Must do ifaces first, so push to list and do in proper order
m_strings.emplace_back(m_generateHierName);
nodep->user2p(&m_strings.back());
m_genHierNames.emplace(nodep, m_generateHierName);
// Deparameterize iface cells early so types are available for lparams.
if (isIface && VN_CAST(nodep, Cell) && VN_CAST(nodep, Cell)->paramsp()) {
@ -2882,6 +2886,9 @@ class ParamVisitor final : public VNVisitor {
&& (VN_IS(nodep->subDTypep()->skipRefOrNullp(), IfaceRefDType)
|| VN_IS(nodep->subDTypep()->skipRefOrNullp(), ClassRefDType))
&& !nodep->skipRefp()->user2SetOnce()) {
// The visit() function for every valid nodep->skipRefp() type below
// must include a `user2SetOnce()` check to avoid adding duplicate
// nodes to m_cellps
iterate(nodep->skipRefp());
}
iterateChildren(nodep);
@ -2892,9 +2899,11 @@ class ParamVisitor final : public VNVisitor {
visitCellOrClassRef(nodep, VN_IS(nodep->modp(), Iface));
}
void visit(AstIfaceRefDType* nodep) override {
nodep->skipRefp()->user2SetOnce();
if (nodep->ifacep()) visitCellOrClassRef(nodep, true);
}
void visit(AstClassRefDType* nodep) override {
nodep->skipRefp()->user2SetOnce();
checkParamNotHierRecurse(nodep->paramsp());
visitCellOrClassRef(nodep, false);
}

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# 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-FileCopyrightText: 2026 Wilson Snyder
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('simulator')
test.compile(verilator_flags2=["--binary"])
test.execute()
test.passes()

View File

@ -0,0 +1,33 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// 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-FileCopyrightText: 2026 Wilson Snyder
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
// A typedef of a parameterized class produces an AstRefDType whose skipRefp()
// is the AstClassRefDType, which V3Param also reaches directly. This validates
// that the AstClassRefDType is not enqueued to mcell_ps twice
class Wrap #(type T = int);
int m_v;
endclass
class L0;
typedef Wrap#(L0) w_t;
w_t m_w;
function new();
m_w = new;
m_w.m_v = 42;
endfunction
endclass
module t;
L0 l0;
initial begin
l0 = new;
if (l0.m_w.m_v != 42) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule