Skip to content

rsz: Prevent hold repair from buffering internal output arcs#10236

Merged
maliberty merged 5 commits into
The-OpenROAD-Project:masterfrom
The-OpenROAD-Project-staging:secure-fix-repair-hold
Apr 27, 2026
Merged

rsz: Prevent hold repair from buffering internal output arcs#10236
maliberty merged 5 commits into
The-OpenROAD-Project:masterfrom
The-OpenROAD-Project-staging:secure-fix-repair-hold

Conversation

@openroad-ci

Copy link
Copy Markdown
Member

Fixes #10213

Summary

  • asap7 full adder liberty cell `` has a weird output-to-output timing arc.
  • Root-cause: Due to the weird timing arc defined in .lib, the timing edge traversal to find load cell instances with a driver pin picked a wrong load instance, which produced ODB-1200 error.
  • Solution: Filter internal output pins from RepairHold load collection before calling insertBufferBeforeLoads to avoid detecting wrong load instances.

Root Cause

The failing ASAP7 full-adder instance has multiple output pins. The target repair net is driven by one output pin, but the Liberty timing graph also exposes an output-to-output arc from that driver output to another output pin on the same instance, for example CON -> SN.

Before this fix, hold repair effectively treated every timing-graph fanout as a physical net load:

for each timing edge from path_vertex:
  load_pin = edge.to()->pin();
  load_pins.push_back(load_pin);

insertBufferBeforeLoads(drvr_net, load_pins, ...);

That is wrong for an internal output pin reached through an output-to-output timing arc. In the crash case, SN is not connected to the target driver net, so OpenDB rejects buffering it as a load on that net and reports ODB-1200.

Fix

Filter internal output pins while collecting hold-repair loads. Top-level output ports remain valid loads, but output pins on internal instances are not load pins for the target net.

               sta::Slack fanout_hold_slack = sta_->slack(fanout, min_);
               sta::Pin* load_pin = fanout->pin();
+              if (load_pin == nullptr) {
+                continue;
+              }
+              if (network_->direction(load_pin)->isAnyOutput()
+                  && !network_->isTopLevelPort(load_pin)) {
+                continue;
+              }
               if (fanout_hold_slack < hold_margin) {
                 load_pins.push_back(load_pin);
                 Slacks fanout_slacks;

Testing

  • clang-format -i src/rsz/src/RepairHold.cc
  • clang-tidy src/rsz/src/RepairHold.cc -p build --quiet
  • cmake --build build --target openroad -j 8
  • ctest --test-dir build -R 'rsz\.repair_hold_multi_output_load\.tcl$' --output-on-failure -j 1
  • ctest --test-dir build -R 'rsz\.(gcd_resize|repair_hold.*)\.tcl$' --output-on-failure -j 4

ASAP7 full-adder cells expose output-to-output timing arcs such as
CON -> SN.  RepairHold was treating every timing-graph fanout from a
driver vertex as a physical net load, so an internal output pin could be
passed to insertBufferBeforeLoads for the driver's net.  OpenDB correctly
rejects that with ODB-1200 because the output pin is not connected to the
net being split.

The fix filters internal output pins while preserving top-level output
ports as valid loads.  A reduced netlist regression exercises the failing
post-CTS hold repair path without relying on a saved ODB snapshot.

Constraint: ASAP7 liberty includes output-to-output timing groups that OpenSTA represents as graph edges
Rejected: Pass loads_on_diff_nets=true | would mask invalid load collection and let repair_hold split unrelated nets
Rejected: Saved ODB regression | too brittle for OpenROAD architecture refactors
Confidence: high
Scope-risk: narrow
Directive: Do not treat timing graph fanout as physical net loads without direction/connectivity intent checks
Tested: clang-format on src/rsz/src/RepairHold.cc
Tested: clang-tidy src/rsz/src/RepairHold.cc -p build --quiet
Tested: cmake --build build --target openroad -j 8
Tested: ctest --test-dir build -R 'rsz\.repair_hold_multi_output_load\.tcl$' --output-on-failure -j 1
Tested: ctest --test-dir build -R 'rsz\.(gcd_resize|repair_hold.*)\.tcl$' --output-on-failure -j 4
Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request addresses a bug in hold timing repair where internal output pins of multi-output cells were incorrectly treated as load pins. The changes introduce filtering for these pins, add safety checks for empty load sets, and simplify the driver net lookup process. A new regression test is provided to ensure correct behavior. The review feedback suggests a more robust pin filtering condition—checking for the absence of an input direction rather than the presence of an output direction—to avoid incorrectly skipping valid inout pins.

Comment thread src/rsz/src/RepairHold.cc Outdated
Comment on lines +583 to +586
if (network_->direction(load_pin)->isAnyOutput()
&& !network_->isTopLevelPort(load_pin)) {
continue;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The current check using isAnyOutput() will filter out internal inout pins, which are valid load pins. To correctly filter only pure output pins (which are the ones causing the issue with internal timing arcs), it is safer to check if the pin lacks an input component.

Suggested change
if (network_->direction(load_pin)->isAnyOutput()
&& !network_->isTopLevelPort(load_pin)) {
continue;
}
if (!network_->isTopLevelPort(load_pin)
&& !network_->direction(load_pin)->isAnyInput()) {
continue;
}

@github-actions

Copy link
Copy Markdown
Contributor

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

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

Copy link
Copy Markdown
Contributor

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

@jhkim-pii jhkim-pii requested a review from maliberty April 23, 2026 12:29
@jhkim-pii

Copy link
Copy Markdown
Contributor

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is not a good test. It is not minimal in data size nor in command scope (running a complete flow from .v will be susceptible to changes in all the previous commands results).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reduced the test case.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This concern is still not full addressed. It depends on initialize_floorplan and detailed_placement. It would be more natural to have an input def file that is already placed and drop the .v. Look at most of the other tests.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I assume this is AI generated so perhaps some guidance in agents.md would be helpful.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reduced the new test case again.

Add OR & ORFS PRs.

Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
@github-actions github-actions Bot added size/S and removed size/XL labels Apr 24, 2026
@github-actions

Copy link
Copy Markdown
Contributor

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

@jhkim-pii jhkim-pii requested a review from maliberty April 24, 2026 03:43
Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
@github-actions

Copy link
Copy Markdown
Contributor

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

Comment thread src/rsz/src/RepairHold.cc
#include "sta/Graph.hh"
#include "sta/GraphClass.hh"
#include "sta/GraphDelayCalc.hh"
#include "sta/InputDrive.hh"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Lint fix

Comment thread src/rsz/src/RepairHold.cc
} else {
drvr_dbnet = static_cast<odb::dbITerm*>(drvr_db_pin)->getNet();
}
odb::dbNet* drvr_dbnet = db_network_->findFlatDbNet(drvr_pin);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Minor refactoring

Comment thread src/rsz/src/RepairHold.cc
if (network_->direction(load_pin)->isAnyOutput()
&& !network_->isTopLevelPort(load_pin)) {
continue;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is the fix.
Output pin cannot be a load pin.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reduced the test case.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reduced the new test case again.

Add OR & ORFS PRs.

@maliberty maliberty merged commit 940703b into The-OpenROAD-Project:master Apr 27, 2026
16 checks passed
@maliberty maliberty deleted the secure-fix-repair-hold branch April 27, 2026 17:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

repair_timing hold repair crashes with ODB-1200 InsertBufferBeforeLoads due to stale load pin / net mismatch

3 participants