Skip to content

Comments

odb: Add swapMaster sanity checker and fix net internality logic#9505

Open
openroad-ci wants to merge 23 commits intoThe-OpenROAD-Project:masterfrom
The-OpenROAD-Project-staging:secure-fix-swap-master
Open

odb: Add swapMaster sanity checker and fix net internality logic#9505
openroad-ci wants to merge 23 commits intoThe-OpenROAD-Project:masterfrom
The-OpenROAD-Project-staging:secure-fix-swap-master

Conversation

@openroad-ci
Copy link
Collaborator

Fixes #9489

Summary

  • Add dbSwapMasterSanityChecker class that validates hierarchical netlist integrity after swapMaster operations, running 8 comprehensive checks: structural integrity, port/pin matching, hierarchical net connectivity, flat net connectivity, instance hierarchy, hash table integrity, dangling object detection, and combinational loop detection.
  • Refine dbNet::isInternalTo logic in copyModuleInsts to correctly skip external nets that cross module boundaries (nets with a parent ModNet), preventing duplicate net creation during hierarchical module replacement.
  • Add dbModNet::getFirstParentModNet() API to traverse the parent module hierarchy for connected ModNets.
  • The sanity checker is gated behind set_debug_level ODB replace_design_check_sanity 1 and enabled in all replace_hier_module / replace_arith_module regression tests.

Test plan

  • All existing replace_hier_mod{1..6}, replace_hier_mod_report_checks, replace_hier_mod_undo2 regressions updated with sanity checker output
  • All replace_arith_modules{1..3} regressions updated with sanity checker output
  • TestSwapMasterUnusedPort C++ unit test enables sanity checker
  • Golden .ok files updated to include [INFO ODB-0496] swapMaster sanity check passed (0 failures) messages

🤖 Generated with Claude Code

jhkim-pii and others added 15 commits February 19, 2026 23:08
… integrity after `swapMaster` operations and refine `dbNet::isInternalTo` logic

Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
…ressions using replace_hier_module or replace_arith_module commands

Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
…lement iterative DFS for combinational loop detection, and initialize member pointers.

Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
Occurrences of `sta_->cmdMode()` should be read as TODOs for proper
multi-mode handling later.

Signed-off-by: Martin Povišer <povik@cutebit.org>
Now that the command has different behavior (drops constraints) it was
breaking the tests.

Signed-off-by: Martin Povišer <povik@cutebit.org>
Signed-off-by: Martin Povišer <povik@cutebit.org>
Signed-off-by: Martin Povišer <povik@cutebit.org>
…egrity failures to prevent invalid pointer dereferences and remove redundant dangling `dbModNet` checks.

Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
Signed-off-by: Martin Povišer <povik@cutebit.org>
Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
Replace std::string concatenation with fmt::format for improved
readability, reduced temporary allocations, and elimination of
std::to_string calls.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
- Convert warn()/error() to variadic templates that accept fmt-style
  format strings directly, eliminating explicit fmt::format() at all
  call sites.
- Replace magic int constants (0/1/2) for DFS state with a local
  DfsState enum for clarity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
Add NOLINT suppression for spdlog/fmt/fmt.h include which is used
by the variadic warn/error templates but not recognized as direct
usage by misc-include-cleaner.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
@github-actions
Copy link
Contributor

clang-tidy review says "All clean, LGTM! 👍"

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

The pull request introduces a dbSwapMasterSanityChecker class to validate hierarchical netlist integrity after swapMaster operations. It also refines dbNet::isInternalTo logic and adds dbModNet::getFirstParentModNet() for improved hierarchical net handling. The sanity checker is integrated into dbModInst::swapMaster and enabled in various regression tests. The changes enhance code quality by adding robust integrity checks and improving hierarchical netlist management.

Comment on lines +163 to +167
dbModITerm* parent_iterm = bterm->getParentModITerm();
if (parent_iterm == nullptr) {
error(
"{}: ModBTerm '{}' has null parent ModITerm", ctx, bterm->getName());
continue;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

A null parent_iterm for a ModBTerm means the master's port is not correctly connected to the instance's port, which is a critical error in hierarchical connectivity.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. So the sanity checker will report it as an error.

Comment on lines +529 to +547
if (state[v] == kInPath) {
// Found a cycle — collect instances in the loop
std::string loop_path;
bool in_loop = false;
for (int idx : path) {
if (idx == v) {
in_loop = true;
}
if (in_loop) {
if (loop_path.empty() == false) {
loop_path += " -> ";
}
loop_path += insts[idx]->getName();
}
}
loop_path += " -> ";
loop_path += insts[v]->getName();
error("{}: combinational loop detected: {}", ctx, loop_path);
return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The DFS-based cycle detection correctly identifies combinational loops and constructs a detailed loop_path for error reporting. This is a critical check for functional correctness, as combinational loops can lead to unpredictable behavior.

Comment on lines +321 to +326
if (net->getBlock() != block) {
error("{}: ITerm '{}' of inst '{}' connected to net in wrong block",
ctx,
iterm->getName(),
inst->getName());
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

An ITerm connected to a net in the wrong block is a fundamental data integrity issue, indicating a severe problem in netlist construction or manipulation.

Comment on lines +176 to +181
if (iterm_count != bterm_count) {
error("{}: ModITerm count ({}) != ModBTerm count ({})",
ctx,
iterm_count,
bterm_count);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

A mismatch in ModITerm and ModBTerm counts is a strong indicator of a structural problem in the module's port definition or instance mapping.

Comment on lines +348 to +351
if (child->getMaster() == nullptr) {
error("{}: child ModInst '{}' has null master", ctx, child->getName());
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

A null master for a child ModInst is a critical structural error, indicating that the instance is not properly defined.

puts "number instances in verilog is $num_instances"

#set_debug_level RSZ replace_arith 1
set_debug_level ODB replace_design_check_sanity 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Enabling the replace_design_check_sanity debug level here ensures that the new sanity checker is active during the replace_arith_modules command, which is good for testing the new feature.

Comment on lines +22 to +85
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The repeated swapMaster sanity check passed (0 failures) messages confirm that the sanity checker is being run for each arithmetic module replacement and is consistently passing. This is good validation for the new feature.


#set_debug_level RSZ replace_arith 1
#set_debug_level ODB replace_design 10
set_debug_level ODB replace_design_check_sanity 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Enabling the replace_design_check_sanity debug level here ensures that the new sanity checker is active during the replace_arith_modules command, which is good for testing the new feature.

Comment on lines +89 to +152
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
[INFO ODB-0496] swapMaster sanity check passed (0 failures)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The repeated swapMaster sanity check passed (0 failures) messages confirm that the sanity checker is being run for each arithmetic module replacement and is consistently passing. This is good validation for the new feature.

set num_instances [llength [get_cells -hier *]]
puts "number instances in verilog is $num_instances"

set_debug_level ODB replace_design_check_sanity 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Enabling the replace_design_check_sanity debug level here ensures that the new sanity checker is active during the replace_arith_modules command, which is good for testing the new feature.

@gemini-code-assist
Copy link
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

povik and others added 5 commits February 20, 2026 16:45
Related net lookup for modnets existed in two variants: slow which
performed consistency checking and fast without checking. Transition
isPower/isGround to using the fast variant, and rename the slow
variant to emphasize its checking purpose.

Signed-off-by: Martin Povišer <povik@cutebit.org>
Provide an alias for a method renamed in OpenSTA 3.0 to fix some
bazel-orfs tests.

Signed-off-by: Martin Povišer <povik@cutebit.org>
Signed-off-by: Martin Povišer <povik@cutebit.org>
Signed-off-by: Martin Povišer <povik@cutebit.org>
@github-actions
Copy link
Contributor

clang-tidy review says "All clean, LGTM! 👍"

@jhkim-pii
Copy link
Contributor

Gemini added a bunch of useless comments in this PR.

Comment on lines 417 to 419
for ([[maybe_unused]] dbModInst* mi : new_master_->getModInsts()) {
++set_modinst_count;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use new_master_->getModInsts().size() ? Likewise elsewhere.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Comment on lines 125 to 88
-2.52 slack (VIOLATED)
-0.76 slack (VIOLATED)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this PR change the timing? If it is expected then a secure CI is needed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the related ORFS PR.
The-OpenROAD-Project/OpenROAD-flow-scripts#3906

  • Fortunately, there was no failure in both public & private PDKs.

I'll refresh the OR & ORFS PRs since the MCMM update is merged.

Replace manual counter increments with direct .size() calls for
iterm_count and hash table set counts. Remove now-unnecessary
loops that only existed for counting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
Merge latest master which includes STA MCMM update and various
module changes. Regoldenized odb replace_hier_mod2.ok test output
to reflect updated timing results.

Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>

# Conflicts:
#	src/odb/test/replace_hier_mod2.ok
@github-actions
Copy link
Contributor

clang-tidy review says "All clean, LGTM! 👍"

1 similar comment
@github-actions
Copy link
Contributor

clang-tidy review says "All clean, LGTM! 👍"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

odb: replace_hier_module command causes a loop in the netlist

4 participants