Skip to content

odb: decompose non-rectilinear LEF polygons into rectangles (#10256)#10715

Open
saurav-fermions wants to merge 2 commits into
The-OpenROAD-Project:masterfrom
Fermions-ASI:fix/10256
Open

odb: decompose non-rectilinear LEF polygons into rectangles (#10256)#10715
saurav-fermions wants to merge 2 commits into
The-OpenROAD-Project:masterfrom
Fermions-ASI:fix/10256

Conversation

@saurav-fermions

Copy link
Copy Markdown
Contributor

Summary

Non-rectilinear (45°/sloped) LEF polygons (e.g. octagonal IO pads) were corrupted during decomposition; rectilinear polygons were already handled correctly. This decomposes sloped polygons into rectangles, leaving the already-working rectilinear path byte-for-byte identical.

Type of Change

  • Bug fix

Impact

Sloped LEF polygon geometry is preserved; rectilinear decomposition unchanged.

Verification

  • Local build succeeds.
  • Relevant tests pass (rebuilt from source): ctest -R '^odb\.' -E '\.py' 82/82 (tcl+cpp).
  • Code follows the repository's formatting guidelines.
  • I have signed my commits (DCO).

Related Issues

Fixes #10256


Developed with SAIGE, Fermions' autonomous RTL/EDA debugging agent; root-caused, tested, and signed off by the submitter (@saurav-fermions).

…ROAD-Project#10256)

LEF POLYGON ingestion and the polygon->box->consumer chain were already
intact, and rectilinear (Manhattan) polygons decomposed correctly. The
real defect was non-rectilinear (45-degree/sloped) polygons: decompose_polygon
fed them into Boost.Polygon's polygon_90 machinery, which only models
axis-aligned geometry and corrupted sloped shapes (both dropping real metal
and filling empty corners). This produced wrong obstruction/pin geometry for
octagonal IO pads (e.g. sky130_ef_io__gpiov2_pad), causing the missing-geometry
shorts/DRC violations vs KLayout.

Fix: keep the exact polygon_90 path for rectilinear polygons (unchanged
output), and for non-rectilinear polygons fracture into horizontal trapezoids
and staircase each into axis-aligned rectangles, rounding outward so the
result fully covers the sloped edges (never leaving gaps/shorts).

Add TestGeom unit tests: rectangle, rectilinear L-shape (regression-guard the
already-working path), and an octagon coverage test that fails before / passes
after.

Signed-off-by: Saurav Singh <saurav.singh@fermions.co>
@saurav-fermions saurav-fermions requested a review from a team as a code owner June 21, 2026 05:16

@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 introduces support for decomposing non-rectilinear (e.g., 45-degree or octagonal) polygons into axis-aligned rectangles by fracturing them into horizontal trapezoids and staircasing them, while preserving the fast, exact path for Manhattan polygons. Unit tests have been added to verify the correctness of the decomposition. The reviewer suggested a performance optimization in staircaseTrapezoid to bypass the unit-by-unit Y loop when a trapezoid is purely rectangular (has no sloped edges).

y_lo = std::min(y_lo, gtl::y(p));
y_hi = std::max(y_hi, gtl::y(p));
}

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

For horizontal trapezoids that do not contain any sloped edges (i.e., they are purely rectangular), we can avoid the unit-by-unit Y loop entirely. This is a significant performance optimization because non-rectilinear polygons (like octagons) often decompose into a mix of sloped and purely rectangular trapezoids, and the rectangular parts can be quite tall in DBUs, leading to thousands of unnecessary iterations and floating-point operations.

  bool has_sloped_edge = false;
  for (int i = 0; i < n; ++i) {
    const auto& a = v[i];
    const auto& b = v[(i + 1) % n];
    if (gtl::x(a) != gtl::x(b) && gtl::y(a) != gtl::y(b)) {
      has_sloped_edge = true;
      break;
    }
  }

  if (!has_sloped_edge) {
    int x_lo = std::numeric_limits<int>::max();
    int x_hi = std::numeric_limits<int>::min();
    for (const auto& p : v) {
      x_lo = std::min(x_lo, gtl::x(p));
      x_hi = std::max(x_hi, gtl::x(p));
    }
    if (x_lo < x_hi && y_lo < y_hi) {
      if (!rects.empty() && rects.back().xMin() == x_lo
          && rects.back().xMax() == x_hi && rects.back().yMax() == y_lo) {
        rects.back().set_yhi(y_hi);
      } else {
        rects.emplace_back(x_lo, y_lo, x_hi, y_hi);
      }
    }
    return;
  }

@maliberty

Copy link
Copy Markdown
Member

What motivates this PR?

@saurav-fermions

Copy link
Copy Markdown
Contributor Author

Hi @maliberty — this one's from #10256: sky130's gpiov2_pad and similar octagonal IO pads have 45° POLYGON geometry that OpenROAD draws wrong vs KLayout, which the reporter showed causing DRC violations and shorts.

Rectilinear polygons already decompose fine — it's the sloped ones that get mangled. This PR fixes just that case and leaves the rectilinear path untouched; odb tests still pass. Glad to add a regression test for the pad if you'd like.

I wasn't totally sure which angle your question was getting at though — if you had something specific in mind (scope, the approach, a particular concern), point me at it and I'll address it directly.

For context: we're Fermions (fermions.co) — this came out of a human + AI workflow with our agent SAIGE (benchmarked on NVIDIA CVDP and RTLLM 2.0).

Non-rectilinear polygons fracture into a mix of sloped and purely
rectangular horizontal trapezoids. The rectangular ones (e.g. the
straight body of an octagonal pad) can be thousands of DBU tall, and
the per-DBU band loop iterated over every row only to coalesce them
back into one rectangle. Detect the no-sloped-edge case and emit the
rectangle directly. Output is unchanged.

Addresses gemini-code-assist review on The-OpenROAD-Project#10715.

Signed-off-by: Saurav Singh <saurav.singh@fermions.co>
@saurav-fermions

Copy link
Copy Markdown
Contributor Author

Thanks. Motivation (from above): sky130 octagonal IO pads have 45° polygon geometry that was being drawn wrong vs KLayout, causing DRC violations/shorts — this fixes the sloped case and leaves the rectilinear path untouched. I took the performance suggestion: rectangular sub-trapezoids (the straight body of a pad) now emit a single rectangle instead of iterating per-DBU; output is identical (the existing decompose_octagon_covers_polygon gtest still shows zero under/over-coverage). That octagon gtest already serves as the pad regression test.

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.

POLYGON statements dropped from LEF

2 participants