Macro Placement on the IBM/ICCAD04 Benchmarks

Adam Holmes · code on GitHub

A chip is millions of tiny logic cells plus a few hundred big fixed blocks — memory units and other prebuilt components. Macro placement is deciding where those big blocks go, and it largely sets how good the finished chip is. This is my solver for a benchmark challenge that grades each placement with a single number — mostly wirelength, plus density and routing congestion; lower is better, no blocks may overlap. The animations replay real runs: the reference placement each benchmark comes with (left), my placer working (middle), and the score per frame (right; dashed line = reference). Big blocks are rectangles, cell clusters are dots. The small late bumps are schedule transients — the loss weights ramp up sharply near the end and the score briefly rises while the layout reorganizes.

ibm01: reference | optimization | score curve ibm09: reference | optimization | score curve ibm17: reference | optimization | score curve ibm18: reference | optimization | score curve

Result. From random starting placements, my pipeline averages 1.0137 over all 17 benchmarks — 31% below the provided reference (avg 1.477, a RePlAce-quality baseline; RePlAce itself scores 1.458, simulated annealing 2.125), beating it on every design with zero overlaps. The design goal was generality: the global placer optimizes any differentiable loss, so a new objective drops into the same GPU engine unchanged.

Compute. A candidate takes ~3–6 min (GPU global stage ~80 s + CPU polish 1–5 min); the 1.0137 keeps the best of ~45 candidates per benchmark, generated within the challenge's 1-hour GPU budget with the polish in parallel on CPU cores. A single candidate averages ~1.1. Scope: the score is dominated by the movable standard-cell clusters — co-optimizing them drives ~98% of the gain, moving the big fixed blocks only ~0.2%.

per-benchmark comparison

How it works

The score is 1.0·wirelength + 0.5·density + 0.5·congestion. Three stages, then a selection step:

The tuned configuration

Two rounds of Bayesian optimization on 3 designs (ibm01/13/17 — easy/medium/hard; the other 14 held out), scoring by average ratio to the reference. A first ~230-trial search on single-seed placements found the right region; a warm-started ~115-trial second round then scored each candidate the way it's used — best of 3 seeds, after the greedy polish — with the winner confirmed at best-of-16:

settingvalue
wirelength sharpness2.44 (higher = closer to exact wirelength)
schedule back-loading3.99 (spread early, tighten late)
density weight (final / start)0.074 / ~3% of it  ·  target fill 0.65, smoothing 0.17
wirelength weight at start73% of full  ·  learning rate 0.39
overlap-tolerance windowdeep-overlap penalty off for the first 6% of the run, full by 65%
same-size swapsannealed swaps of equal-footprint macro pairs, active for the first third
diffusion termsearched, tuned to ≈0 (off)
gradient steps5000 in search → 15000 deployed (the knee of a later sweep; 30000 adds ≤1%)
not usedcongestion term in the loss, electrostatic density, in-loss overlap resolution (appendix)
second-round search trajectory

The second-round search. Squares = window/swaps/diffusion off, dots = on; the search plateaus once differences between good configurations fall below the seed noise.

What I learned

Appendix — what didn't work

All paired experiments (identical seeds across arms) to cancel the ~2–6% seed noise.