Fix tracing without module inlining to match with inlining (#7041)

This is an attempt to generate an identical trace file scope hierarchy
both with and without -fno-inline. Primarily because it's needed for
testing in upcoming patch, but also improves consitency prior to #7001
This commit is contained in:
Geza Lore 2026-02-10 21:05:41 +00:00 committed by GitHub
parent 021e0ba81b
commit a031dd1a22
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 13607 additions and 13586 deletions

View File

@ -51,32 +51,37 @@ public:
, m_emit{emit} {}
// Emit Prefix adjustments until the current path is 'newPath'
void adjust(const string& newPath) {
void adjust(const string& newPath, AstCell* cellp, AstVarScope* vscp) {
// Move up to enclosing path
unsigned toPop = 0;
while (!VString::startsWith(newPath, m_stack.back())) {
++toPop;
m_emit(new AstTracePopPrefix{m_flp});
m_stack.pop_back();
}
while (toPop--) m_emit(new AstTracePopPrefix{m_flp});
if (newPath == m_stack.back()) return;
const VTracePrefixType lastScopeType = //
(cellp && VN_IS(cellp->modp(), Iface))
|| (vscp && VN_IS(vscp->dtypep(), IfaceRefDType))
? VTracePrefixType::SCOPE_INTERFACE
: VTracePrefixType::SCOPE_MODULE;
const std::string extraPrefix = newPath.substr(m_stack.back().size());
size_t begin = 0;
size_t last = extraPrefix.rfind(SEPARATOR);
// Move down, one path element at a time
if (newPath != m_stack.back()) {
const string& extraPrefix = newPath.substr(m_stack.back().size());
size_t begin = 0;
while (true) {
const size_t end = extraPrefix.find(SEPARATOR, begin);
if (end == string::npos) break;
const string& extra = extraPrefix.substr(begin, end - begin);
while (true) {
const size_t end = extraPrefix.find(SEPARATOR, begin);
if (end == string::npos) break;
const string& extra = extraPrefix.substr(begin, end - begin);
if (end == last) {
m_emit(new AstTracePushPrefix{m_flp, extra, lastScopeType});
} else {
m_emit(new AstTracePushPrefix{m_flp, extra, VTracePrefixType::SCOPE_MODULE});
m_stack.push_back(m_stack.back() + extra + SEPARATOR);
begin = end + 1;
}
const string& extra = extraPrefix.substr(begin);
if (!extra.empty()) {
m_emit(new AstTracePushPrefix{m_flp, extra, VTracePrefixType::SCOPE_MODULE});
m_stack.push_back(m_stack.back() + extra);
}
m_stack.push_back(m_stack.back() + extra + SEPARATOR);
begin = end + 1;
}
UASSERT(begin == extraPrefix.size(), "Should have consumed all of extraPrefix");
}
// Emit Prefix adjustments to unwind the path back to its original state
@ -124,29 +129,38 @@ class TraceDeclVisitor final : public VNVisitor {
AstCell* m_cellp = nullptr; // Sub scope (as AstCell) under scope being traced
std::string m_path; // Path to enclosing module in original hierarchy
std::string m_name; // Name of signal/subscope
bool m_rootio = false; // Is part of $rootio, if model at runtime uses name()=""
void init(const std::string& name) {
void init(const std::string& name, AstNode* nodep) {
// Compute path in hierarchy and item name
const std::string& vcdName = AstNode::vcdName(name);
const size_t pos = vcdName.rfind(' ');
const size_t pathLen = pos == std::string::npos ? 0 : pos + 1;
m_path = vcdName.substr(0, pathLen);
m_name = vcdName.substr(pathLen);
AstVar* const varp = VN_CAST(nodep, Var);
if (VN_IS(nodep, Cell) || VN_IS(varp->dtypep(), IfaceRefDType)) {
// Cell or interface reference
m_path = vcdName + " ";
m_name.clear();
} else if (varp->isPrimaryIO()) {
// Primary IO variable
m_path = "$rootio ";
m_name = vcdName;
} else {
// Other Variable
const size_t pos = vcdName.rfind(' ');
const size_t pathLen = pos == std::string::npos ? 0 : pos + 1;
m_path = vcdName.substr(0, pathLen);
m_name = vcdName.substr(pathLen);
}
}
public:
explicit TraceEntry(AstVarScope* vscp)
: m_vscp{vscp} {
init(vscp->varp()->name());
init(vscp->varp()->name(), vscp->varp());
}
explicit TraceEntry(AstCell* cellp)
: m_cellp{cellp} {
init(cellp->name());
init(cellp->name(), cellp);
}
int operatorCompare(const TraceEntry& b) const {
if (rootio() && !b.rootio()) return true;
if (!rootio() && b.rootio()) return false;
if (const int cmp = path().compare(b.path())) return cmp < 0;
if (const int cmp = fileline().operatorCompare(b.fileline())) return cmp < 0;
return name() < b.name();
@ -157,8 +171,6 @@ class TraceDeclVisitor final : public VNVisitor {
void path(const std::string& path) { m_path = path; }
const std::string& name() const { return m_name; }
FileLine& fileline() const { return m_vscp ? *m_vscp->fileline() : *m_cellp->fileline(); }
bool rootio() const { return m_rootio; }
void rootio(bool flag) { m_rootio = flag; }
};
std::vector<TraceEntry> m_entries; // Trace entries under current scope
AstVarScope* m_traVscp = nullptr; // Current AstVarScope we are constructing AstTraceDecls for
@ -267,37 +279,17 @@ class TraceDeclVisitor final : public VNVisitor {
const AstScope* const scopep = it->second;
FileLine* const flp = placeholderp->fileline();
// Pick up the last path element. The prefixes have already been pushed
// when building the initialization.
// We still need to find __DOT__ as cell names may have such.
const std::string dot = "__DOT__";
const size_t pos = path.rfind(dot);
const std::string name = path.substr(pos == string::npos ? 0 : pos + dot.size());
// Compute the type of the scope being fixed up
const AstCell* const cellp = scopep->aboveCellp();
const VTracePrefixType scopeType
= cellp ? (VN_IS((cellp->modp()), Iface) ? VTracePrefixType::SCOPE_INTERFACE
: VTracePrefixType::SCOPE_MODULE)
: VTracePrefixType::SCOPE_MODULE;
// Push the scope prefix
AstNodeStmt* const pushp
= new AstTracePushPrefix{flp, AstNode::prettyName(name), scopeType};
// Call the initialization functions for the scope
AstNode* stmtp = nullptr;
for (AstCFunc* const subFuncp : m_scopeInitFuncps.at(scopep)) {
AstCCall* const callp = new AstCCall{flp, subFuncp};
callp->dtypeSetVoid();
callp->argTypes("tracep");
pushp->addNext(callp->makeStmt());
stmtp = AstNode::addNext(stmtp, callp->makeStmt());
}
// Pop the scope prefix
pushp->addNext(new AstTracePopPrefix{flp});
// Add after the placeholder
placeholderp->addNextHere(pushp);
if (stmtp) placeholderp->addNextHere(stmtp);
}
// Delete the placeholder
placeholderp->unlinkFrBack();
@ -384,16 +376,8 @@ class TraceDeclVisitor final : public VNVisitor {
}
if (!m_entries.empty()) {
if (nodep->name() == "TOP") {
UINFO(9, " Add $rootio " << nodep);
for (TraceEntry& entry : m_entries) {
if (entry.path() == "" && entry.vscp()) entry.rootio(true);
}
}
// Sort trace entries, first by if a $root io, then by enclosing instance
// (necessary for single traversal of hierarchy during initialization), then
// by source location, then by name.
// Sort trace entries, by enclosing instance (necessary for single traversal of
// hierarchy during initialization), then by source location, then by name.
std::stable_sort(
m_entries.begin(), m_entries.end(),
[](const TraceEntry& a, const TraceEntry& b) { return a.operatorCompare(b); });
@ -406,7 +390,7 @@ class TraceDeclVisitor final : public VNVisitor {
UINFO(9, "path='" << entry.path() << "' name='" << entry.name() << "' "
<< (entry.cellp() ? static_cast<AstNode*>(entry.cellp())
: static_cast<AstNode*>(entry.vscp())));
pathAdjustor.adjust(entry.rootio() ? "$rootio" : entry.path());
pathAdjustor.adjust(entry.path(), entry.cellp(), entry.vscp());
m_traName = entry.name();

File diff suppressed because it is too large Load Diff

View File

@ -125,7 +125,7 @@ test.file_grep_not(test.obj_dir + "/" + test.vm_prefix + "_classes.mk", "vm_clas
test.file_grep_not(test.obj_dir + "/" + test.vm_prefix + "_classes.mk", "vm_classes_2")
# Check combine count
test.file_grep(test.stats, r'Node count, CFILE + (\d+)', (272 if test.vltmt else 255))
test.file_grep(test.stats, r'Node count, CFILE + (\d+)', (279 if test.vltmt else 262))
test.file_grep(test.stats, r'Makefile targets, VM_CLASSES_FAST + (\d+)', 2)
test.file_grep(test.stats, r'Makefile targets, VM_CLASSES_SLOW + (\d+)', 2)

View File

@ -1,5 +1,5 @@
$date
Mon Nov 10 12:31:08 2025
Tue Feb 10 19:22:45 2026
$end
$version
@ -354,23 +354,7 @@ $var wire 1 `! clk $end
$var wire 8 a! in [7:0] $end
$var wire 8 b! out [7:0] $end
$var logic 8 c! ff [7:0] $end
$scope interface in_ifs $end
$var wire 1 `! clk $end
$var logic 8 c! data [7:0] $end
$upscope $end
$scope interface out_ifs $end
$var wire 1 `! clk $end
$var logic 8 d! data [7:0] $end
$upscope $end
$scope module i_sub3 $end
$scope interface in $end
$var wire 1 `! clk $end
$var logic 8 c! data [7:0] $end
$upscope $end
$scope interface out $end
$var wire 1 `! clk $end
$var logic 8 d! data [7:0] $end
$upscope $end
$var wire 8 c! in_wire [7:0] $end
$var wire 8 d! out_1 [7:0] $end
$var wire 8 e! out_2 [7:0] $end
@ -774,6 +758,22 @@ $upscope $end
$upscope $end
$upscope $end
$upscope $end
$scope interface in $end
$var wire 1 `! clk $end
$var logic 8 c! data [7:0] $end
$upscope $end
$scope interface out $end
$var wire 1 `! clk $end
$var logic 8 d! data [7:0] $end
$upscope $end
$upscope $end
$scope interface in_ifs $end
$var wire 1 `! clk $end
$var logic 8 c! data [7:0] $end
$upscope $end
$scope interface out_ifs $end
$var wire 1 `! clk $end
$var logic 8 d! data [7:0] $end
$upscope $end
$upscope $end
$upscope $end

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
$date
Mon Nov 10 12:27:19 2025
Tue Feb 10 19:21:54 2026
$end
$version
@ -355,23 +355,7 @@ $var wire 1 `! clk $end
$var wire 8 a! in [7:0] $end
$var wire 8 b! out [7:0] $end
$var logic 8 c! ff [7:0] $end
$scope interface in_ifs $end
$var wire 1 `! clk $end
$var logic 8 c! data [7:0] $end
$upscope $end
$scope interface out_ifs $end
$var wire 1 `! clk $end
$var logic 8 d! data [7:0] $end
$upscope $end
$scope module i_sub3 $end
$scope interface in $end
$var wire 1 `! clk $end
$var logic 8 c! data [7:0] $end
$upscope $end
$scope interface out $end
$var wire 1 `! clk $end
$var logic 8 d! data [7:0] $end
$upscope $end
$var wire 8 c! in_wire [7:0] $end
$var wire 8 d! out_1 [7:0] $end
$var wire 8 e! out_2 [7:0] $end
@ -775,6 +759,22 @@ $upscope $end
$upscope $end
$upscope $end
$upscope $end
$scope interface in $end
$var wire 1 `! clk $end
$var logic 8 c! data [7:0] $end
$upscope $end
$scope interface out $end
$var wire 1 `! clk $end
$var logic 8 d! data [7:0] $end
$upscope $end
$upscope $end
$scope interface in_ifs $end
$var wire 1 `! clk $end
$var logic 8 c! data [7:0] $end
$upscope $end
$scope interface out_ifs $end
$var wire 1 `! clk $end
$var logic 8 d! data [7:0] $end
$upscope $end
$upscope $end
$upscope $end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
#!/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.top_filename = "t/t_trace_complex.v"
test.compile(verilator_flags2=['--cc --trace-vcd -fno-inline'])
test.execute()
test.file_grep(test.trace_filename, r' v_arrp ')
test.file_grep(test.trace_filename, r' v_arrp_arrp ')
test.file_grep(test.trace_filename, r' v_arrp_strp ')
test.file_grep(test.trace_filename, r' v_arru\[')
test.file_grep(test.trace_filename, r' v_arru_arrp\[')
test.file_grep(test.trace_filename, r' v_arru_arru\[')
test.file_grep(test.trace_filename, r' v_arru_strp\[')
test.file_grep(test.trace_filename, r' v_strp ')
test.file_grep(test.trace_filename, r' v_strp_strp ')
# Should match with module inlining
test.vcd_identical(test.trace_filename, "t/t_trace_complex.out")
test.passes()

View File

@ -1,5 +1,5 @@
$date
Sat Apr 5 13:56:28 2025
Tue Feb 10 13:05:32 2026
$end
$version
@ -12,16 +12,18 @@ $scope module top $end
$attrbegin misc 07 $unit::state_t 4 VAL_A VAL_B VAL_C VAL_D 00 01 10 11 1 $end
$attrbegin misc 07 t.other_state_t 3 VAL_X VAL_Y VAL_Z 00 01 10 2 $end
$var wire 1 ! clk $end
$scope module $unit $end
$upscope $end
$scope module t $end
$var wire 1 ! clk $end
$attrbegin misc 07 "" 1 $end
$var logic 2 " v_enumed [1:0] $end
$attrbegin misc 07 "" 2 $end
$var logic 2 # v_other_enumed [1:0] $end
$scope interface sink $end
$attrbegin misc 07 "" 1 $end
$var logic 2 " state [1:0] $end
$var logic 2 $ state [1:0] $end
$upscope $end
$attrbegin misc 07 "" 1 $end
$var logic 2 # v_enumed [1:0] $end
$attrbegin misc 07 "" 2 $end
$var logic 2 $ v_other_enumed [1:0] $end
$upscope $end
$upscope $end
$enddefinitions $end

View File

@ -10,6 +10,8 @@
(NET
(clk (T0 10) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 1))
)
(INSTANCE $unit
)
(INSTANCE t
(NET
(clk (T0 10) (T1 0) (TZ 0) (TX 0) (TB 0) (TC 1))

View File

@ -1,28 +1,28 @@
$version Generated by VerilatedVcd $end
$timescale 1ps $end
$scope module top $end
$var wire 1 5 CLK $end
$var wire 1 6 RESET $end
$var wire 1 4 CLK $end
$var wire 1 5 RESET $end
$scope module t $end
$var wire 1 5 CLK $end
$var wire 1 # RESET $end
$var wire 1 4 CLK $end
$var wire 1 " RESET $end
$var wire 2 # vec[3] [2:1] $end
$var wire 2 $ vec[4] [2:1] $end
$var wire 32 % val [31:0] $end
$scope module glbl $end
$var wire 1 7 GSR $end
$var wire 1 6 GSR $end
$upscope $end
$var wire 2 $ vec[3] [2:1] $end
$var wire 2 % vec[4] [2:1] $end
$var wire 32 & val [31:0] $end
$scope module little $end
$var wire 1 5 clk $end
$var wire 8 ' i8 [0:7] $end
$var wire 49 ( i48 [1:49] $end
$var wire 128 * i128 [63:190] $end
$var wire 1 4 clk $end
$var wire 8 & i8 [0:7] $end
$var wire 49 ' i48 [1:49] $end
$var wire 128 ) i128 [63:190] $end
$upscope $end
$scope module neg $end
$var wire 1 5 clk $end
$var wire 8 . i8 [0:-7] $end
$var wire 48 / i48 [-1:-48] $end
$var wire 128 1 i128 [63:-64] $end
$var wire 1 4 clk $end
$var wire 8 - i8 [0:-7] $end
$var wire 48 . i48 [-1:-48] $end
$var wire 128 0 i128 [63:-64] $end
$upscope $end
$upscope $end
$upscope $end
@ -30,52 +30,52 @@ $enddefinitions $end
#0
1#
1"
b00 #
b00 $
b00 %
b00000000000000000000000000000000 &
b00000000 '
b0000000000000000000000000000000000000000000000000 (
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 *
b00000000 .
b000000000000000000000000000000000000000000000000 /
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1
05
b00000000000000000000000000000000 %
b00000000 &
b0000000000000000000000000000000000000000000000000 '
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 )
b00000000 -
b000000000000000000000000000000000000000000000000 .
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0
04
15
16
17
#3
b11111111 '
b1111111111111111111111111111111111111111111111111 (
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 *
b11111111 .
b111111111111111111111111111111111111111111111111 /
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 1
15
b11111111 &
b1111111111111111111111111111111111111111111111111 '
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 )
b11111111 -
b111111111111111111111111111111111111111111111111 .
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 0
14
#6
05
04
#7
07
#9
0#
b00000000 '
b0000000000000000000000000000000000000000000000000 (
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 *
b00000000 .
b000000000000000000000000000000000000000000000000 /
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 1
15
06
#9
0"
b00000000 &
b0000000000000000000000000000000000000000000000000 '
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 )
b00000000 -
b000000000000000000000000000000000000000000000000 .
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0
14
05
#12
05
04
#15
b00000000000000000000000000000001 &
b11111111 '
b1111111111111111111111111111111111111111111111111 (
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 *
b11111111 .
b111111111111111111111111111111111111111111111111 /
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 1
15
b00000000000000000000000000000001 %
b11111111 &
b1111111111111111111111111111111111111111111111111 '
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 )
b11111111 -
b111111111111111111111111111111111111111111111111 .
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 0
14
#18
05
04
#20