The-OpenROAD-Project / The-OpenROAD-Project/OpenROAD

mpl: should updateChildrenRealLocation shift IO clusters, whose positions are already absolute?

Open
#11,247 0 comments 0 reactions 1 assignee View on GitHub

@joaomai is already working on this.

Since Aug 27, 2026.

mpl
Dominant language
Verilog
Stars
3.1k
Forks
1k
Avg merge
2d 23h
Merged PRs (30d)
136

Description

While evaluating mpl's placement stage we traced a coordinate path we cannot convince ourselves is intended, and we would rather ask than assume. All references are to 945a9f48dc6e5cc91d865daa92c45a1094cb682c.

The chain

Four steps, each reasonable on its own:

  1. An IO cluster's position is absolute. ClusteringEngine::createIOBundle builds it from die.xMin() / xMax() / yMin() / yMax() and hands it to Cluster::setAsIOBundle, which constructs the cluster's own SoftMacro there (object.cpp ~296). setAsIOPadCluster and setAsClusterOfUnplacedIOPins do the same.

  2. HierRTLMP::placeChildren rebases it onto the parent's outline for the annealer's macro list — io_cluster->getX() - outline.xMin() (hier_rtlmp.cpp ~1362). That new SoftMacro lives in the local macros vector; the cluster's own is untouched.

  3. updateChildrenShapesAndLocations deliberately skips IO clusters (hier_rtlmp.cpp ~2193), with a comment explaining that their shapes and locations should not be updated. So the cluster's own SoftMacro still holds the absolute position from step 1.

  4. updateChildrenRealLocation then adds the outline's origin to every child (hier_rtlmp.cpp ~2204). Cluster::setX writes through to soft_macro_, and an IO cluster has one — so it becomes absolute + origin.

Why we think it is observable

We first assumed this was latent, because in the mpl regression suite nothing reads an IO cluster's position afterwards. That turned out to be a property of the test designs rather than of mpl:

  • -max_num_level defaults to 2;
  • ClusteringEngine::setBaseThresholds resets it to 1 only when the design has 150 macros or fewer, or has fixed macros;
  • every design in src/mpl/test has between one and four macros, so all 31 cluster placements we traced are on the root and only the root.

On a two-level tree, placeChildren recurses into a mixed child, and that call reaches createFixedTerminals with a non-null parent->getParent(). It then walks the root's other children — IO clusters among them — and turns each into a fixed terminal from cluster->getCenter(), or from getX/getY/getWidth/getHeight for a cluster of unplaced IO pins. Those are the step-4 coordinates, and they feed the wirelength term of the child cluster's placement.

The offset is the root outline's lower-left corner, i.e. the core's. A core at the die origin makes it zero; a core inset from the die makes it the inset.

What we checked

After placeChildren, nothing else reads a cluster position rather than a HardMacro's:

stage reads a cluster position?
boundary push (pusher.cpp) no — macro-cluster boxes, hard-macro boxes, and io_blockages_
orientation correction no — HardMacro and its dbInst throughout
commit (updateMacrosOnDb, commitMacroPlacementToDb) no — getRealX / getRealY / getOrientation / getBBox

So createFixedTerminals on a deeper level looks like the only consumer, which is exactly the path the current tests do not exercise.

The question

Is updateChildrenRealLocation meant to shift IO clusters at all? Step 3 excludes them from the shape-and-location update because their geometry is authoritative; step 4 includes them without an equivalent exclusion, and we could not tell from the source whether that is deliberate.

If it is not, we would be glad to contribute a regression case — a design large enough to build a two-level tree, with a core inset from the die and at least one IO bundle, asserting the fixed-terminal positions a deeper placeChildren sees. Happy to shape it however you would find most useful.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.