Skip to content

grt: implement CUGR net merge mirroring FastRoute path#10899

Open
sparsh-karna wants to merge 8 commits into
The-OpenROAD-Project:masterfrom
sparsh-karna:cugr-merge-net
Open

grt: implement CUGR net merge mirroring FastRoute path#10899
sparsh-karna wants to merge 8 commits into
The-OpenROAD-Project:masterfrom
sparsh-karna:cugr-merge-net

Conversation

@sparsh-karna

Copy link
Copy Markdown
Contributor

Summary

When GlobalRouter::mergeNetsRouting() fires for the CUGR path, this PR enables attempting to stitch the two existing route segments at the former buffer pin position (connectCUGRRouting) rather than ripping up and rerouting the survivor from scratch.

Key changes:

  • GlobalRouter::connectCUGRRouting(preserved, removed): Mirrors connectRouting() but uses cugr_->hasAvailableResources() instead of fastroute_->hasAvailableResources() for the capacity check. Reuses the existing geometry helpers findBufferPinPostions, findTopLayerOverPosition, and createConnectionForPositions, which are FastRoute-agnostic.

  • GlobalRouter::mergeNetsRouting() (CUGR branch): If stitching succeeds, calls cugr_->mergeNet() to transfer tree ownership and save guides. On failure, falls back to addDirtyNet() so the survivor is rerouted incrementally (matching the previous safe behavior).

  • CUGR::mergeNet(preserved, removed): Attaches the removed net's GRTreeNode subtree as a child of the preserved net's routing tree so getRoutes() emits all wire segments. Inserts the removed net into merged_nets_ so removeNet() knows not to decrement GridGraph demand for it (the wires are still physically there, just owned by the preserved net).

  • CUGR::removeNet() (merged-net guard): Skips removeTreeUsage() for nets that were transferred via mergeNet, preventing double-decrement of GridGraph congestion numbers.

  • CUGR::hasAvailableResources(layer, tile_x, tile_y): A thin wrapper over GridGraph::getEdge().getResource() >= 1.0, equivalent to FastRouteCore::hasAvailableResources().

Type of Change

  • New feature

Impact

Improves QoR (Quality of Results) and runtime during incremental routing by preserving existing routing topology during buffer removal ECOs when using CUGR, matching FastRoute's behavior.

Verification

  • I have verified that the local build succeeds (./etc/Build.sh).
  • I have run the relevant tests and they pass. (All 143 GRT regression tests pass.)
  • My code follows the repository's formatting guidelines.
  • I have included tests to prevent regressions.
  • I have signed my commits (DCO).

Related Issues

None.

When GlobalRouter::mergeNetsRouting() fires for the CUGR path, attempt
to stitch the two existing route segments at the former buffer pin
position (connectCUGRRouting) rather than ripping up and rerouting the
survivor from scratch.

Key changes:

  GlobalRouter::connectCUGRRouting(preserved, removed)
    Mirrors connectRouting() but uses cugr_->hasAvailableResources()
    instead of fastroute_->hasAvailableResources() for the capacity
    check.  Reuses the existing geometry helpers findBufferPinPostions,
    findTopLayerOverPosition, and createConnectionForPositions which are
    FastRoute-agnostic.

  GlobalRouter::mergeNetsRouting() -- CUGR branch
    If stitching succeeds, call cugr_->mergeNet() to transfer tree
    ownership and save guides.  On failure, fall back to addDirtyNet so
    the survivor is rerouted incrementally (matching the previous safe
    behaviour).

  CUGR::mergeNet(preserved, removed)
    Attaches the removed net's GRTreeNode subtree as a child of the
    preserved net's routing tree so getRoutes() emits all wire segments.
    Inserts the removed net into merged_nets_ so removeNet() knows not
    to decrement GridGraph demand for it (the wires are still there,
    now owned by the preserved net).

  CUGR::removeNet() -- merged-net guard
    Skips removeTreeUsage() for nets that were transferred via mergeNet,
    preventing double-decrement of GridGraph congestion numbers.

  CUGR::hasAvailableResources(layer, tile_x, tile_y)
    Thin wrapper over GridGraph::getEdge().getResource() >= 1.0,
    equivalent to FastRouteCore::hasAvailableResources.

All 143 GRT regression tests pass.

Signed-off-by: Sparsh Karna <sparsh2005karna@gmail.com>
@sparsh-karna
sparsh-karna requested a review from a team as a code owner July 13, 2026 17:17
@sparsh-karna
sparsh-karna requested a review from jfgava July 13, 2026 17:17

@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 implements support for merging nets in CUGR rather than always falling back to a full dirty-net reroute. It introduces connectCUGRRouting to stitch two CUGR routes together at the former buffer pin position and perform capacity checks against the CUGR GridGraph, and updates the CUGR class to handle routing tree ownership transfer during net merges. Feedback was provided to add an early return check if either route is empty to prevent a potential crash when finding the top layer over a position.

Comment thread src/grt/src/GlobalRouter.cpp Outdated
@eder-matheus

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 98e1a41ad8

ℹ️ 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".

Comment thread src/grt/src/cugr/src/CUGR.cpp Outdated
@eder-matheus
eder-matheus self-requested a review July 13, 2026 17:29
Signed-off-by: Sparsh Karna <sparsh2005karna@gmail.com>
Signed-off-by: Sparsh Karna <sparsh2005karna@gmail.com>
Signed-off-by: Sparsh Karna <sparsh2005karna@gmail.com>

@eder-matheus eder-matheus left a comment

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.

Please include unit tests in this PR. You can use the existing remove_buffer tests to create the new tests for the CUGR path.

Comment thread src/grt/src/GlobalRouter.cpp Outdated
Comment thread src/grt/src/GlobalRouter.cpp Outdated
Comment thread src/grt/src/cugr/src/CUGR.cpp
Comment thread src/grt/src/cugr/src/CUGR.cpp Outdated
Remove the standalone connectCUGRRouting() function and fold the
CUGR-specific capacity check (against GridGraph) into the existing
connectRouting() function via a use_cugr_ branch.  A new optional
connection_out parameter receives the stitching segments when the
caller needs to update the CUGR routing tree.

The mergeNetsRouting() function now uses a single connectRouting() call.

Signed-off-by: Sparsh Karna <sparsh2005karna@gmail.com>
Consolidate mergeNetsRouting() to use a single connectRouting() logic
block for both FastRoute and CUGR paths, applying CUGR-specific capacity
checks inside connectRouting() and performing the final CUGR tree merge
conditionally after routing is connected.

Signed-off-by: Sparsh Karna <sparsh2005karna@gmail.com>
Add error logging with ID 705 to prevent negative layer indices from
failing silently in CUGR::hasAvailableResources().

Signed-off-by: Sparsh Karna <sparsh2005karna@gmail.com>
Rename nodeA/B, target_layerA/B, target_xA/B, target_yA/B, and
findPath to snake_case equivalent to comply with OpenROAD coding
guidelines.

Signed-off-by: Sparsh Karna <sparsh2005karna@gmail.com>
} else {
// After failing to connect the routing, the survivor net still has
// uncovered pins and needs to be re-routed
net1->setDirtyNet(true);

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.

Why is this FastRoute exclusive? Shouldn't this be marked on the CUGR path as well?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You're right, it shouldn't be disjointed. The reason for the split is that setDirtyNet(true) toggles a boolean flag on FastRoute's internal GRNet struct (which CUGR ignores), whereas CUGR requires us to explicitly enqueue the net via addDirtyNet() . However, we can definitely clean this up. We should be able to unify this fallback block to handle both the FastRoute internal state and the CUGR queue consistently without this verbose branching. I'll update it to be cleaner.

Comment on lines +5565 to +5569
net1->setIsMergedNet(true);
net1->setMergedNet(db_net2);
net1->setDirtyNet(false);
net2->setIsMergedNet(true);
net2->setMergedNet(db_net1);

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.

Should this be exclusive to FastRoute path?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, this should be exclusive to the FastRoute path. Those methods manipulate the GRNet struct, which is FastRoute's internal data model. CUGR has its own tracking for merged nets (which gets updated inside cugr_->mergeNet() ). Setting these GRNet flags when using CUGR wouldn't break anything, but it would be dead code since CUGR doesn't read them. Restricting it to the FastRoute path makes it much clearer which internal data model is actively driving the routing.

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 don't think this is correct. net1 and net2 are GlobalRouter::Net* objects, and these functions are only touching this representation. This "merged nets" related flags are important for other steps of the incremental flow to not reroute the nets by accident.

if (connectRouting(db_net1, db_net2, &connection_segs)) {
saveGuides({db_net1});
if (use_cugr_) {
cugr_->mergeNet(db_net1, db_net2, connection_segs);

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.

Why don't you call this inside the connectRouting function? This would remove the need for this extra argument for the connection_segs, and would make all the merge/connection between nets contained to a single function.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'll move it there.

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.

2 participants