Skip to content

dpl: enhance initial snap - #11121

Open
gudeh wants to merge 24 commits into
The-OpenROAD-Project:masterfrom
gudeh:dpl-enhance-initial-snap
Open

dpl: enhance initial snap#11121
gudeh wants to merge 24 commits into
The-OpenROAD-Project:masterfrom
gudeh:dpl-enhance-initial-snap

Conversation

@gudeh

@gudeh gudeh commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR modifies the initial snapping performed by the Negotiation legalizer at DPL. With these modifications we attempt to avoid issues coming from other tools.

Issues and motivations:

  • RSZ may introduce new instances on top of macros which require snapping to the closest valid row.
  • MPL may create vertical/horizontal small channels with only a few sites/rows.
    • In addition, a small space may be crowded with fixed instances. Which is usually the case around macros (endcaps).
  • GPL may place top-level (regionless) instances inside regions.

New behavior for initial snapping:

  • Use standalone diamond search for closer snapping.
  • Snap after site capacity is calculated to account for fixed instances. Do not snap to fixed instances positions (capacity == 0).
  • Snap after regions are initiated. Consider instance regions properly with NegotiationLegalizer::respectsFence(). Previous behavior did not account for top-level instances.

Additions after PR creation:

  • Round to closest pixel instead of truncating (previously would always go to the leftmost site).
  • Equalize width and height site weight when calculating costs.

Type of Change

  • New feature

Impact

Avoid other tools generated issues.

Old and new behavior on the upf_aes test. Previously, top-level (regionless) instances were only snapped out of the regions at the very end, by the diamond search fallback, once negotiation had failed to find valid positions for them.

Now we snap them first, so negotiation can make the necessary moves properly and account more fairly for the competition for space, since all top-level instances are present from the start.
image

Also, now we avoid bad snappings like this one:
image

Now we allow diagonal snapping such as these:
image

Verification

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

Related Issues

This branch includes changes from #11089, and should be merged after it.

This PR addresses issues:

gudeh added 10 commits July 31, 2026 16:25
consider available space for initial snapping

Signed-off-by: Augusto Berndt <augusto.berndt@precisioninno.com>
should provide better QoR (instances snapped to closer position), with controlled runtime.

Signed-off-by: Augusto Berndt <augusto.berndt@precisioninno.com>
Signed-off-by: Augusto Berndt <augusto.berndt@precisioninno.com>
Signed-off-by: Augusto Berndt <augusto.berndt@precisioninno.com>
@gudeh
gudeh requested a review from a team as a code owner August 11, 2026 00:48
@gudeh
gudeh requested a review from osamahammad21 August 11, 2026 00:48

@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 refactors the NegotiationLegalizer by centralizing the snapping logic of movable cells into a new initialSnap() method, and updates how cell padding is handled during negotiation. Feedback on the changes highlights two potential issues in the new initialSnap() method: a potential out-of-bounds array access if the grid height is smaller than the cell height, and a potential signed integer overflow when doubling the search budget.

Comment on lines +618 to +622
const int max_budget
= grid_w_ * site_width_
+ std::max(init_y_dbu - dpl_grid->gridYToDbu(GridY{0}).v,
dpl_grid->gridYToDbu(GridY{grid_h_ - cell.height}).v
- init_y_dbu);

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.

high

If grid_h_ is less than cell.height (e.g., in extremely small grids or with exceptionally tall cells), grid_h_ - cell.height will be negative. Passing a negative value to GridY and then to gridYToDbu will result in an out-of-bounds array access, causing undefined behavior or a crash. Consider guarding this calculation to ensure a non-negative row index is used.

Suggested change
const int max_budget
= grid_w_ * site_width_
+ std::max(init_y_dbu - dpl_grid->gridYToDbu(GridY{0}).v,
dpl_grid->gridYToDbu(GridY{grid_h_ - cell.height}).v
- init_y_dbu);
const int max_budget
= grid_w_ * site_width_
+ std::max(init_y_dbu - dpl_grid->gridYToDbu(GridY{0}).v,
(grid_h_ >= cell.height)
? dpl_grid->gridYToDbu(GridY{grid_h_ - cell.height}).v - init_y_dbu
: 0);

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.

Not a bad suggestion to follow

Comment on lines +629 to +630
for (int budget = site_width_; !found;
budget = std::min(budget * 2, max_budget)) {

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

If max_budget is very large (e.g., in extremely large designs), budget * 2 can exceed INT_MAX, leading to signed integer overflow (undefined behavior in C++). If it overflows to a negative value, std::min will select the negative value, potentially causing an infinite loop. Capping the budget before multiplying avoids this potential overflow.

Suggested change
for (int budget = site_width_; !found;
budget = std::min(budget * 2, max_budget)) {
for (int budget = site_width_; !found;
budget = (budget > max_budget / 2) ? max_budget : budget * 2) {

@gudeh
gudeh requested review from a team as code owners August 17, 2026 18:53
@gudeh
gudeh requested review from arthurjolo and jfgava August 17, 2026 18:53
@github-actions github-actions Bot added size/L and removed size/M labels Aug 17, 2026
@github-actions github-actions Bot added size/XL and removed size/L labels Aug 19, 2026
@gudeh

gudeh commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

@eder-matheus Secure-CI shows a routing congestion DRC at 5-1 with nangate45/swerv for this change:
image

@gudeh

gudeh commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

I found a bug!

Here is what DPL is doing at CTS (Stage 5-1 fails before the first DPL call):
image

We obviously should be moving this instance on the closer available site by the left, not all the way to the top.

Extra:
Comparing the logs, master by the left. values overall are quite similar
image

@gudeh

gudeh commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

No more fatals now

@gudeh

gudeh commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

We are getting some nice improvements in displacement and HPWL with this branch:
DPL displacement
image
DPL HPWL
image

And it does reflect in improvement in HPWL later on. GRT HPWL:
image

Signed-off-by: Augusto Berndt <augusto.berndt@precisioninno.com>
@gudeh
gudeh requested review from a team as code owners August 24, 2026 19:16
@gudeh
gudeh requested a review from precisionmoon August 24, 2026 19:16
@github-actions github-actions Bot added size/XL and removed size/L labels Aug 24, 2026
gudeh added 4 commits August 24, 2026 22:44
The merged master reports [INFO GPL-1018] Final HPWL after global
placement.  All six occurrences in this test come from
"global_placement -incremental" runs that follow detailed_placement, so
their values track the negotiation legalizer's result and the numbers
master recorded no longer apply.

Regenerated from the bazel run of the merged tree; the rest of the
golden is unchanged.

Signed-off-by: Augusto Berndt <augusto.berndt@precisioninno.com>
save_flow_metrics_limits re-derives every limit from the run it is given
(limit = value * 1.2 and friends), so running it over a local ctest/CMake
run ratchets the limits down to whatever that build happened to produce.
The CMake and Bazel builds differ substantially on flow QoR -- aes_nangate45
reports 1 hold buffer under CMake and 74 under Bazel -- so the regenerated
limits were unreachable for the Bazel build CI runs: the new hold buffer
limit of 1 fails there, where the previous limit of 93 passes.

Restore the seven limits files.  The remaining flow failures under Bazel
are then real QoR deltas against master rather than lost headroom, and
can be judged on their merits.

Signed-off-by: Augusto Berndt <augusto.berndt@precisioninno.com>
Signed-off-by: Augusto Berndt <augusto.berndt@precisioninno.com>

@maliberty maliberty 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.

Approving on Cho's behalf for rsz. I didn't look at the rest

@gudeh

gudeh commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

@arthurjolo @osamahammad21 we need your reviews on this one for merging

Comment on lines +677 to +678
cell.init_x = best_x;
cell.init_y = best_y;

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 do we overwrite the initial positions here? Can't we just update the cell.x& cell.y?

// positions
cell.init_x = dpl_grid->gridX(DbuX{db_x - die_xlo_}).v;
// Snap to grid, findBestLocation() iterates over grid positions
cell.init_x = dpl_grid->gridRoundX(DbuX{db_x - die_xlo_}).v;

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.

What motivates this change?

Comment on lines +618 to +622
const int max_budget
= grid_w_ * site_width_
+ std::max(init_y_dbu - dpl_grid->gridYToDbu(GridY{0}).v,
dpl_grid->gridYToDbu(GridY{grid_h_ - cell.height}).v
- init_y_dbu);

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.

Not a bad suggestion to follow

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.

5 participants