Skip to content

Commit f94fb71

Browse files
committed
Merge remote-tracking branch 'private/master' into dpl-dpo-load-macro-flipping
2 parents 7a1216d + 5c5380c commit f94fb71

150 files changed

Lines changed: 10101 additions & 470 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.bazelrc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ build:asan --copt=-O1
108108
build:asan --copt=-g
109109
build:asan --copt=-fno-omit-frame-pointer
110110
build:asan --linkopt=-fsanitize=address
111+
# TCMalloc is incompatible with ASan: __asan_init's interceptor setup calls
112+
# dlsym -> malloc before TCMalloc is initialized, segfaulting at startup.
113+
# Override the per-target malloc attribute to use the system allocator, which
114+
# ASan intercepts cleanly.
115+
build:asan --custom_malloc=@bazel_tools//tools/cpp:malloc
111116

112117
# Flags with enough debug symbols to get useful outputs with Linux `perf`
113118
build:profile --strip=never

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
# source control.
77

88
Andrew Kennings
9+
Antmicro
910
Federal University of Rio Grande do Sul (UFRGS)
1011
Google LLC
1112
Iowa State University

CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ option(USE_SYSTEM_ABC "Use system shared ABC library" OFF)
4242
# Allow disabling tests
4343
option(ENABLE_TESTS "Enable OpenROAD tests" ON)
4444

45+
# Opt-in GPU acceleration via Kokkos. The actual compute backend (CUDA, HIP,
46+
# SYCL, or host-only OpenMP/Threads) is determined by the installed Kokkos
47+
# package; OpenROAD inspects Kokkos_ENABLE_* and turns on the matching CMake
48+
# language and dependencies automatically. See the per-module CMakeLists for
49+
# how individual subsystems wire their GPU sources.
50+
option(ENABLE_GPU "Enable GPU acceleration via Kokkos" OFF)
51+
4552
# Allow enabling address sanitizer
4653
option(ASAN "Enable Address Sanitizer" OFF)
4754

@@ -88,6 +95,13 @@ if(NOT CMAKE_BUILD_TYPE)
8895
set(CMAKE_BUILD_TYPE RELEASE)
8996
endif()
9097

98+
# GPU backend wiring (opt-in). All Kokkos / CUDA / HIP / SYCL detection,
99+
# compiler probing, and language enablement live in cmake/KokkosBackend.cmake
100+
# and are loaded only when the user opts in via ENABLE_GPU=ON.
101+
if(ENABLE_GPU)
102+
include(KokkosBackend)
103+
endif()
104+
91105
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
92106
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "8.3.0")
93107
message(FATAL_ERROR "Insufficient gcc version. Found ${CMAKE_CXX_COMPILER_VERSION}, but require >= 8.3.0.")

cmake/KokkosBackend.cmake

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# SPDX-License-Identifier: BSD-3-Clause
2+
# Copyright (c) 2026, The OpenROAD Authors
3+
4+
# Kokkos GPU backend wiring for OpenROAD. Included from the root
5+
# CMakeLists.txt only when ENABLE_GPU=ON; not loaded otherwise.
6+
#
7+
# Discovers the user's Kokkos install, inherits its compute backend, turns
8+
# on the matching CMake language so downstream targets can mark kernel
9+
# sources with set_source_files_properties(... LANGUAGE CUDA|HIP), and
10+
# applies the small set of nvcc / fmt / host-compiler workarounds that the
11+
# CUDA backend currently needs in modern Linux toolchains. Per-module
12+
# CMakeLists (e.g. src/gpl) key off ENABLE_GPU and Kokkos_ENABLE_*; they
13+
# do not need to call find_package(Kokkos) or enable_language() themselves.
14+
15+
find_package(Kokkos QUIET)
16+
if(NOT Kokkos_FOUND)
17+
message(FATAL_ERROR
18+
"OpenROAD: ENABLE_GPU=ON requires the Kokkos package to be "
19+
"installed and discoverable by CMake, but Kokkos was not found.\n"
20+
" - If Kokkos is already installed: pass "
21+
"-DKokkos_ROOT=/path/to/kokkos (or extend CMAKE_PREFIX_PATH).\n"
22+
" - If not: build and install Kokkos from "
23+
"https://github.com/kokkos/kokkos with the desired backend "
24+
"(CUDA / HIP / SYCL / OpenMP) and a target architecture that "
25+
"matches the host GPU.\n"
26+
" - A future etc/DependencyInstaller.sh -gpu option will "
27+
"automate this step.")
28+
endif()
29+
30+
# KokkosFFT — required by the gpl GPU FFT backend (src/gpl/src/gpu/dct.cpp).
31+
# A separate package from Kokkos core.
32+
find_package(KokkosFFT QUIET)
33+
if(NOT KokkosFFT_FOUND)
34+
message(FATAL_ERROR
35+
"ENABLE_GPU=ON requires KokkosFFT, which was not found.\n"
36+
" - Install KokkosFFT (https://github.com/kokkos/kokkos-fft) against\n"
37+
" your Kokkos build, then re-configure with -DKokkosFFT_ROOT=<prefix>.\n"
38+
" - A future etc/DependencyInstaller.sh -gpu will install Kokkos and\n"
39+
" KokkosFFT together.")
40+
endif()
41+
42+
message(STATUS "OpenROAD: GPU acceleration enabled (Kokkos ${Kokkos_VERSION})")
43+
44+
if(Kokkos_ENABLE_CUDA)
45+
# Auto-discover nvcc when the user has CUDA installed at a standard
46+
# location but their environment does not expose it on PATH (common
47+
# with IDE-launched configures: the bundled CMake does not inherit
48+
# the shell PATH). enable_language(CUDA) below would otherwise abort
49+
# with "No CMAKE_CUDA_COMPILER could be found" even though Kokkos's
50+
# find_package already located the toolkit.
51+
if(NOT DEFINED CMAKE_CUDA_COMPILER AND NOT DEFINED ENV{CUDACXX})
52+
find_program(_OPENROAD_NVCC nvcc
53+
HINTS ENV CUDA_HOME ENV CUDA_PATH ENV CUDA_ROOT
54+
/usr/local/cuda/bin
55+
/usr/local/cuda-13.0/bin
56+
/usr/local/cuda-12.8/bin /usr/local/cuda-12.0/bin
57+
/opt/cuda/bin
58+
)
59+
if(_OPENROAD_NVCC)
60+
set(CMAKE_CUDA_COMPILER "${_OPENROAD_NVCC}" CACHE FILEPATH "")
61+
message(STATUS "OpenROAD: auto-discovered nvcc at ${_OPENROAD_NVCC}")
62+
endif()
63+
endif()
64+
# nvcc < 13 cannot parse glibc 2.38+'s _Float128 type that ships with
65+
# gcc 13+'s C++ standard library headers (math.h template specialization
66+
# for __iseqsig_type<_Float128>). When a known-broken pairing is detected,
67+
# pin a compatible older g++ as the CUDA host compiler (the system C++
68+
# compiler stays unchanged for non-CUDA TUs). Override is always
69+
# available via -DCMAKE_CUDA_HOST_COMPILER or CUDAHOSTCXX.
70+
if(NOT DEFINED CMAKE_CUDA_HOST_COMPILER AND NOT DEFINED ENV{CUDAHOSTCXX}
71+
AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
72+
AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "13.0"
73+
AND _OPENROAD_NVCC)
74+
execute_process(
75+
COMMAND "${_OPENROAD_NVCC}" --version
76+
OUTPUT_VARIABLE _OPENROAD_NVCC_VERSION_OUTPUT
77+
ERROR_QUIET
78+
OUTPUT_STRIP_TRAILING_WHITESPACE)
79+
if(_OPENROAD_NVCC_VERSION_OUTPUT MATCHES "release ([0-9]+)")
80+
set(_OPENROAD_NVCC_MAJOR "${CMAKE_MATCH_1}")
81+
if(_OPENROAD_NVCC_MAJOR LESS 13)
82+
foreach(_OPENROAD_GXX_VER 12 11)
83+
find_program(_OPENROAD_CUDAHOST g++-${_OPENROAD_GXX_VER}
84+
HINTS /usr/bin /usr/local/bin)
85+
if(_OPENROAD_CUDAHOST)
86+
set(CMAKE_CUDA_HOST_COMPILER "${_OPENROAD_CUDAHOST}"
87+
CACHE FILEPATH "")
88+
message(STATUS
89+
"OpenROAD: pinning CUDA host compiler to "
90+
"${_OPENROAD_CUDAHOST} (nvcc ${_OPENROAD_NVCC_MAJOR}.x + "
91+
"glibc/gcc 13+ _Float128 compat)")
92+
break()
93+
endif()
94+
unset(_OPENROAD_CUDAHOST CACHE)
95+
endforeach()
96+
if(NOT DEFINED CMAKE_CUDA_HOST_COMPILER)
97+
message(FATAL_ERROR
98+
"OpenROAD: nvcc ${_OPENROAD_NVCC_MAJOR}.x cannot parse "
99+
"_Float128 declarations in glibc 2.38+ system headers used "
100+
"by gcc ${CMAKE_CXX_COMPILER_VERSION}, and no compatible "
101+
"g++-12 / g++-11 was found in /usr/bin or /usr/local/bin. "
102+
"Install one (e.g. apt install g++-12) or set "
103+
"-DCMAKE_CUDA_HOST_COMPILER=/path/to/older-g++ explicitly.")
104+
endif()
105+
endif()
106+
endif()
107+
endif()
108+
if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES OR "${CMAKE_CUDA_ARCHITECTURES}" STREQUAL "")
109+
if(DEFINED Kokkos_CUDA_ARCHITECTURES
110+
AND NOT "${Kokkos_CUDA_ARCHITECTURES}" STREQUAL "")
111+
set(CMAKE_CUDA_ARCHITECTURES "${Kokkos_CUDA_ARCHITECTURES}")
112+
else()
113+
message(FATAL_ERROR
114+
"OpenROAD: ENABLE_GPU=ON with Kokkos CUDA backend, but the "
115+
"Kokkos package does not advertise Kokkos_CUDA_ARCHITECTURES "
116+
"and CMAKE_CUDA_ARCHITECTURES was not provided. Set "
117+
"-DCMAKE_CUDA_ARCHITECTURES=<arch> explicitly (e.g. 89 for "
118+
"RTX 4070, 120 for RTX 5090) or rebuild Kokkos with the "
119+
"target architecture baked in.")
120+
endif()
121+
endif()
122+
enable_language(CUDA)
123+
find_package(CUDAToolkit REQUIRED)
124+
message(STATUS "OpenROAD: CUDA backend (arch=${CMAKE_CUDA_ARCHITECTURES})")
125+
# A GPU driver (the kernel module exposing libcuda.so.1) is needed only to
126+
# *run* CUDA code, never to build it -- nvcc cross-compiles device code on a
127+
# host with no GPU. Note its absence so the resulting libcuda.so.1 load
128+
# errors on this host (e.g. ctest, or running openroad) read as expected
129+
# rather than as a misconfiguration. This is informational only: a GPU build
130+
# on a driverless host is a supported cross-compile workflow, not an error.
131+
if(NOT EXISTS "/proc/driver/nvidia")
132+
message(STATUS
133+
"OpenROAD: no NVIDIA driver on this host -- GPU code is being "
134+
"cross-compiled. Run the GPU binaries and tests on a GPU machine.")
135+
endif()
136+
# nvcc 12.8 cannot parse fmt 11's nontype-template-parameter user-defined
137+
# literals (fmt/bundled/format.h: operator""_a with fixed_string). The
138+
# legacy literal fallback is still available; opt into it for CUDA TUs
139+
# only. Project-wide CXX compilation is unaffected.
140+
add_compile_definitions(
141+
$<$<COMPILE_LANGUAGE:CUDA>:FMT_USE_NONTYPE_TEMPLATE_ARGS=0>)
142+
# On aarch64, Boost's unordered_flat_map detects __ARM_NEON and includes
143+
# <arm_neon.h> for SIMD-accelerated hashing. nvcc cannot parse gcc's
144+
# arm_neon.h (it contains gcc-specific intrinsics), so disable the NEON
145+
# path for CUDA TUs. The CPU TUs (compiled by g++) are unaffected.
146+
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|ARM64")
147+
add_compile_definitions(
148+
$<$<COMPILE_LANGUAGE:CUDA>:BOOST_UNORDERED_DISABLE_NEON>)
149+
endif()
150+
elseif(Kokkos_ENABLE_HIP)
151+
enable_language(HIP)
152+
message(STATUS "OpenROAD: HIP backend")
153+
elseif(Kokkos_ENABLE_SYCL)
154+
message(STATUS "OpenROAD: SYCL backend (driven by Kokkos host compiler)")
155+
else()
156+
message(STATUS
157+
"OpenROAD: host-only Kokkos backend (Serial / OpenMP / Threads)")
158+
endif()

src/dpl/src/NegotiationLegalizer.cpp

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <cstddef>
1111
#include <functional>
1212
#include <limits>
13+
#include <map>
1314
#include <queue>
1415
#include <tuple>
1516
#include <unordered_map>
@@ -523,13 +524,8 @@ bool NegotiationLegalizer::initFromDb()
523524
die_xhi_ = core_area.xMax();
524525
die_yhi_ = core_area.yMax();
525526

526-
// Site width from the DPL grid; row height from the first DB row.
527527
site_width_ = dpl_grid->getSiteWidth().v;
528-
for (auto* row : block->getRows()) {
529-
row_height_ = row->getSite()->getHeight();
530-
break;
531-
}
532-
assert(site_width_ > 0 && row_height_ > 0);
528+
assert(site_width_ > 0);
533529

534530
// Grid dimensions from the DPL grid (accounts for actual DB rows).
535531
grid_w_ = dpl_grid->getRowSiteCount().v;
@@ -578,10 +574,7 @@ bool NegotiationLegalizer::initFromDb()
578574
1,
579575
static_cast<int>(
580576
std::round(static_cast<double>(master->getWidth()) / site_width_)));
581-
cell.height = std::max(
582-
1,
583-
static_cast<int>(std::round(static_cast<double>(master->getHeight())
584-
/ row_height_)));
577+
cell.height = dpl_grid->gridHeight(master).v;
585578

586579
// Clamp to valid grid range – gridRoundY can return grid_h_ when the
587580
// instance is near the top edge. Use (grid_w_ - width) so the full
@@ -647,9 +640,9 @@ bool NegotiationLegalizer::initFromDb()
647640
for (auto* box : odb_region->getBoundaries()) {
648641
RegionRectInline r;
649642
r.xlo = (box->xMin() - die_xlo_) / site_width_;
650-
r.ylo = (box->yMin() - die_ylo_) / row_height_;
643+
r.ylo = dpl_grid->gridEndY(DbuY{box->yMin() - die_ylo_}).v;
651644
r.xhi = (box->xMax() - die_xlo_) / site_width_;
652-
r.yhi = (box->yMax() - die_ylo_) / row_height_;
645+
r.yhi = dpl_grid->gridSnapDownY(DbuY{box->yMax() - die_ylo_}).v;
653646
rects.push_back(r);
654647
}
655648
it = region_rect_cache.emplace(odb_region, std::move(rects)).first;
@@ -684,11 +677,12 @@ bool NegotiationLegalizer::initFromDb()
684677
db_x,
685678
db_y,
686679
die_xlo_ + cell.init_x * site_width_,
687-
die_ylo_ + cell.init_y * row_height_);
680+
die_ylo_ + dpl_grid->gridYToDbu(GridY{cell.init_y}).v);
688681

689682
// Priority queue keyed on physical Manhattan distance (DBU) so the
690683
// search expands in true physical proximity, not grid-unit proximity.
691-
// One step in X = site_width_ DBU; one step in Y = row_height_ DBU.
684+
// One step in X = site_width_ DBU; Y distance is computed via the
685+
// DPL grid since pixel rows may have non-uniform heights.
692686
using PQEntry = std::tuple<int, int, int>; // physDist, gx, gy
693687
std::
694688
priority_queue<PQEntry, std::vector<PQEntry>, std::greater<PQEntry>>
@@ -704,8 +698,10 @@ bool NegotiationLegalizer::initFromDb()
704698
if (!visited.insert(gy * grid_w_ + gx).second) {
705699
return;
706700
}
707-
const int dist = std::abs(gx - cell.init_x) * site_width_
708-
+ std::abs(gy - cell.init_y) * row_height_;
701+
const int dy_dbu = dpl_grid->gridYToDbu(GridY{gy}).v
702+
- dpl_grid->gridYToDbu(GridY{cell.init_y}).v;
703+
const int dist
704+
= std::abs(gx - cell.init_x) * site_width_ + std::abs(dy_dbu);
709705
pq.emplace(dist, gx, gy);
710706
};
711707

@@ -745,6 +741,19 @@ bool NegotiationLegalizer::initFromDb()
745741
cells_.push_back(cell);
746742
}
747743

744+
std::map<int, int> neg_height_counts;
745+
for (const NegCell& c : cells_) {
746+
neg_height_counts[c.height]++;
747+
}
748+
logger_->info(
749+
utl::DPL,
750+
392,
751+
"Negotiation cell height distribution ({} unique row-count(s)):",
752+
neg_height_counts.size());
753+
for (const auto& [height, count] : neg_height_counts) {
754+
logger_->info(utl::DPL, 393, " height {} row(s): {} cells", height, count);
755+
}
756+
748757
return true;
749758
}
750759

@@ -813,12 +822,13 @@ void NegotiationLegalizer::initFenceRegions()
813822
FenceRegion fr;
814823
fr.id = region->getId();
815824

825+
const Grid* dpl_grid = opendp_->grid_.get();
816826
for (auto* box : region->getBoundaries()) {
817827
FenceRect r;
818828
r.xlo = (box->xMin() - die_xlo_) / site_width_;
819-
r.ylo = (box->yMin() - die_ylo_) / row_height_;
829+
r.ylo = dpl_grid->gridEndY(DbuY{box->yMin() - die_ylo_}).v;
820830
r.xhi = (box->xMax() - die_xlo_) / site_width_;
821-
r.yhi = (box->yMax() - die_ylo_) / row_height_;
831+
r.yhi = dpl_grid->gridSnapDownY(DbuY{box->yMax() - die_ylo_}).v;
822832
fr.rects.push_back(r);
823833
}
824834

src/dpl/src/NegotiationLegalizer.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,6 @@ class NegotiationLegalizer
233233
Network* network_{nullptr};
234234

235235
int site_width_{0};
236-
int row_height_{0};
237236
int die_xlo_{0};
238237
int die_ylo_{0};
239238
int die_xhi_{0};

src/dpl/src/NegotiationLegalizerPass.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -418,9 +418,10 @@ void NegotiationLegalizer::place(int cell_idx, int x, int y)
418418
pushNegotiationPixels();
419419
const NegCell& c = cells_[cell_idx];
420420
const int orig_x_dbu = die_xlo_ + c.init_x * site_width_;
421-
const int orig_y_dbu = die_ylo_ + c.init_y * row_height_;
421+
const int orig_y_dbu
422+
= die_ylo_ + opendp_->grid_->gridYToDbu(GridY{c.init_y}).v;
422423
const int tgt_x_dbu = die_xlo_ + c.x * site_width_;
423-
const int tgt_y_dbu = die_ylo_ + c.y * row_height_;
424+
const int tgt_y_dbu = die_ylo_ + opendp_->grid_->gridYToDbu(GridY{c.y}).v;
424425
logger_->report(
425426
"Pause at placing of cell {}. orig=({},{}) target=({},{}) dbu. "
426427
"rowidx={}.",

src/dpl/src/dbToOpendp.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,22 @@ void Opendp::importDb()
187187
createNetwork();
188188
createArchitecture();
189189
setUpPlacementGroups();
190+
191+
if (logger_->debugCheck(utl::DPL, "hybrid", 1)) {
192+
std::map<int, int> height_counts;
193+
for (const auto& node : network_->getNodes()) {
194+
if (node->getType() != Node::CELL) {
195+
continue;
196+
}
197+
height_counts[node->getHeight().v]++;
198+
}
199+
logger_->report("Cell height distribution ({} unique micron height(s)):",
200+
height_counts.size());
201+
for (const auto& [height, count] : height_counts) {
202+
logger_->report(
203+
" height {:.3f} um: {} cells", block_->dbuToMicrons(height), count);
204+
}
205+
}
190206
}
191207

192208
void Opendp::importClear()

src/dpl/test/negotiation01.ok

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
[INFO DPL-0006] Core area: 14266.91 um^2, Instances area: 637.60 um^2, Utilization: 4.5%
77
[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically.
88
[INFO DPL-1102] Legalizing using negotiation legalizer.
9+
[INFO DPL-0392] Negotiation cell height distribution (1 unique row-count(s)):
10+
[INFO DPL-0393] height 1 row(s): 549 cells
911
Negotiation iteration 0: total overflow 12.
1012
Negotiation iteration 1: total overflow 0.
1113
Placement Analysis

src/dpl/test/negotiation_one_site_gap.ok

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
[INFO DPL-0006] Core area: 16.49 um^2, Instances area: 3.72 um^2, Utilization: 22.6%
77
[INFO DPL-0005] Diamond search max displacement: +/- 500 sites horizontally, +/- 100 rows vertically.
88
[INFO DPL-1102] Legalizing using negotiation legalizer.
9+
[INFO DPL-0392] Negotiation cell height distribution (1 unique row-count(s)):
10+
[INFO DPL-0393] height 1 row(s): 4 cells
911
Negotiation iteration 0: total overflow 0.
1012
Placement Analysis
1113
---------------------------------

0 commit comments

Comments
 (0)