Fix VarRef lookup for module-level variables (#6741) (#6882)

This commit is contained in:
Yilou Wang 2026-01-05 16:39:22 +01:00 committed by GitHub
parent 883ff01d21
commit 7023f38d12
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 74 additions and 6 deletions

View File

@ -53,7 +53,8 @@ class ScopeVisitor final : public VNVisitor {
AstCell* m_aboveCellp = nullptr; // Cell that instantiates this module
AstScope* m_aboveScopep = nullptr; // Scope that instantiates this scope
std::unordered_map<AstNodeModule*, AstScope*> m_packageScopes; // Scopes for each package
std::unordered_map<AstNodeModule*, AstScope*>
m_classOrPackageScopes; // Scopes for each class or package
VarScopeMap m_varScopes; // Varscopes created for each scope and var
std::set<std::pair<AstVarRef*, AstScope*>>
m_varRefScopes; // Varrefs-in-scopes needing fixup when done
@ -64,9 +65,12 @@ class ScopeVisitor final : public VNVisitor {
for (const auto& itr : m_varRefScopes) {
AstVarRef* const nodep = itr.first;
AstScope* scopep = itr.second;
if (nodep->classOrPackagep()) {
const auto it2 = m_packageScopes.find(nodep->classOrPackagep());
UASSERT_OBJ(it2 != m_packageScopes.end(), nodep, "Can't locate package scope");
if (nodep->classOrPackagep()
&& !VN_IS(nodep->classOrPackagep(),
Module)) { // Module scopes are not in m_classOrPackageScopes
const auto it2 = m_classOrPackageScopes.find(nodep->classOrPackagep());
UASSERT_OBJ(it2 != m_classOrPackageScopes.end(), nodep,
"Can't locate class or package scope");
scopep = it2->second;
}
// Search up the scope hierarchy for the variable
@ -114,7 +118,7 @@ class ScopeVisitor final : public VNVisitor {
(m_aboveCellp ? static_cast<AstNode*>(m_aboveCellp) : static_cast<AstNode*>(nodep))
->fileline(),
nodep, scopename, m_aboveScopep, m_aboveCellp};
if (VN_IS(nodep, Package)) m_packageScopes.emplace(nodep, m_scopep);
if (VN_IS(nodep, Package)) m_classOrPackageScopes.emplace(nodep, m_scopep);
// Get list of cells before we edit, to avoid excess visits (issue #6059)
std::deque<AstCell*> cells;
@ -180,7 +184,7 @@ class ScopeVisitor final : public VNVisitor {
= (m_aboveCellp ? static_cast<AstNode*>(m_aboveCellp) : static_cast<AstNode*>(nodep));
m_scopep
= new AstScope{abovep->fileline(), m_modp, scopename, m_aboveScopep, m_aboveCellp};
m_packageScopes.emplace(nodep, m_scopep);
m_classOrPackageScopes.emplace(nodep, m_scopep);
// Create scope for the current usage of this cell
AstNode::user1ClearTree();

View File

@ -0,0 +1,21 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2026 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')
if not test.have_solver:
test.skip("No constraint solver installed")
test.compile()
test.execute()
test.passes()

View File

@ -0,0 +1,43 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2026 by PlanV GmbH.
// SPDX-License-Identifier: CC0-1.0
module t_randomize_module_var;
int golden_queue[$];
class Cls;
rand bit deq;
constraint valid_enq {
if (golden_queue.size() == 0) {deq == 0;}
}
endclass
Cls tr;
initial begin
tr = new;
// Test 1: Empty queue - deq must be 0
if (tr.randomize() == 0) begin
$stop;
end
if (tr.deq != 0) begin
$display("Error: Expected deq=0 when queue is empty, got %0d", tr.deq);
$stop;
end
// Test 2: Non-empty queue - deq can be 0 or 1
golden_queue.push_back(42);
if (tr.randomize() == 0) begin
$stop;
end
// deq can be 0 or 1, both are valid
$write("*-* All Finished *-*\n");
$finish;
end
endmodule