Skip to content

Commit 3d693bd

Browse files
committed
pad: switch to use rtrees for obstructions to make checks faster
Signed-off-by: Peter Gadfort <[email protected]>
1 parent 3bcda77 commit 3d693bd

File tree

5 files changed

+205
-76
lines changed

5 files changed

+205
-76
lines changed

src/pad/src/ICeWall.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ void ICeWall::placePad(odb::dbMaster* master,
632632
}
633633
}
634634

635-
const SingleInstPadPlacer placer(logger_, getBlock(), getRowEdge(row), row);
635+
SingleInstPadPlacer placer(logger_, getBlock(), getRowEdge(row), row);
636636
placer.place(inst, location, orient.getOrient());
637637
}
638638

@@ -814,7 +814,7 @@ void ICeWall::placeFiller(
814814
use_height = true;
815815
}
816816

817-
const SingleInstPadPlacer placer(logger_, block, getRowEdge(row), row);
817+
SingleInstPadPlacer placer(logger_, block, getRowEdge(row), row);
818818

819819
const odb::dbTransform row_xform(row->getOrient());
820820

src/pad/src/PadPlacer.cpp

Lines changed: 158 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ PadPlacer::PadPlacer(utl::Logger* logger,
3232
: logger_(logger), block_(block), insts_(insts), edge_(edge), row_(row)
3333
{
3434
populateInstWidths();
35+
populateObstructions();
3536
}
3637

3738
void PadPlacer::populateInstWidths()
@@ -301,89 +302,181 @@ int PadPlacer::placeInstance(int index,
301302
return next_pos;
302303
}
303304

304-
std::optional<std::pair<odb::dbInst*, odb::Rect>>
305-
PadPlacer::checkInstancePlacement(odb::dbInst* inst) const
305+
PadPlacer::LayerTermObsTree PadPlacer::getInstanceObstructions(
306+
odb::dbInst* inst,
307+
bool bloat) const
308+
{
309+
std::map<odb::dbTechLayer*, std::vector<TermObsValue>> shapes;
310+
311+
// populate map as needed
312+
const auto xform = inst->getTransform();
313+
for (auto* obs : inst->getMaster()->getObstructions()) {
314+
odb::Rect obs_rect = obs->getBox();
315+
xform.apply(obs_rect);
316+
odb::dbTechLayer* layer = obs->getTechLayer();
317+
if (bloat && layer != nullptr) {
318+
odb::Rect bloat_rect;
319+
obs_rect.bloat(layer->getSpacing(), bloat_rect);
320+
obs_rect = bloat_rect;
321+
}
322+
shapes[obs->getTechLayer()].emplace_back(obs_rect, nullptr, inst);
323+
}
324+
for (auto* iterm : inst->getITerms()) {
325+
for (const auto& [layer, box] : iterm->getGeometries()) {
326+
odb::Rect term_rect = box;
327+
if (bloat && layer != nullptr) {
328+
odb::Rect bloat_rect;
329+
box.bloat(layer->getSpacing(), bloat_rect);
330+
term_rect = bloat_rect;
331+
}
332+
shapes[layer].emplace_back(term_rect, iterm->getNet(), inst);
333+
}
334+
}
335+
336+
LayerTermObsTree rshapes;
337+
for (const auto& [layer, layer_shapes] : shapes) {
338+
if (layer == nullptr) {
339+
continue;
340+
}
341+
rshapes[layer] = TermObsTree(layer_shapes.begin(), layer_shapes.end());
342+
}
343+
return rshapes;
344+
}
345+
346+
void PadPlacer::populateObstructions()
306347
{
348+
blockage_obstructions_.clear();
349+
instance_obstructions_.clear();
350+
term_obstructions_.clear();
351+
352+
const odb::Rect row = row_->getBBox();
353+
307354
std::set<odb::dbInst*> covers;
308355
auto* block = getBlock();
309356
if (block) {
310-
const odb::Rect inst_rect = inst->getBBox()->getBox();
357+
// Get placement blockages
311358
for (odb::dbBlockage* blockage : block->getBlockages()) {
312-
if (blockage->getBBox()->getBox().overlaps(inst_rect)) {
313-
return std::make_pair(
314-
nullptr, blockage->getBBox()->getBox().intersect(inst_rect));
359+
if (blockage->getBBox()->getBox().overlaps(row)) {
360+
blockage_obstructions_.insert(blockage->getBBox()->getBox());
315361
}
316362
}
317-
for (auto* check_inst : block->getInsts()) {
318-
if (check_inst == inst) {
319-
continue;
363+
// Get obstructions that might interfere with RDL routing
364+
for (odb::dbObstruction* obs : block->getObstructions()) {
365+
if (obs->getBBox()->getBox().overlaps(row)) {
366+
term_obstructions_[obs->getBBox()->getTechLayer()].insert(
367+
{obs->getBBox()->getBox(), nullptr, nullptr});
320368
}
369+
}
370+
for (auto* check_inst : block->getInsts()) {
321371
if (!check_inst->isFixed()) {
322372
continue;
323373
}
324-
if (check_inst->getMaster()->isCover()) {
325-
covers.insert(check_inst);
326-
continue;
327-
}
328-
if (check_inst->getBBox()->getBox().overlaps(inst_rect)) {
329-
return std::make_pair(
330-
check_inst, check_inst->getBBox()->getBox().intersect(inst_rect));
374+
if (check_inst->getBBox()->getBox().overlaps(row)) {
375+
if (check_inst->getMaster()->isCover()) {
376+
covers.insert(check_inst);
377+
continue;
378+
} else {
379+
instance_obstructions_.insert(
380+
{check_inst->getBBox()->getBox(), check_inst});
381+
}
331382
}
332383
}
333384
}
334385

335-
// Check if inst overlaps with bumps
336-
std::map<odb::dbTechLayer*, std::set<std::pair<odb::Rect, odb::dbNet*>>>
337-
check_shapes;
338-
if (!covers.empty()) {
339-
// populate map as needed
340-
const auto xform = inst->getTransform();
341-
for (auto* obs : inst->getMaster()->getObstructions()) {
342-
odb::Rect obs_rect = obs->getBox();
343-
xform.apply(obs_rect);
344-
odb::dbTechLayer* layer = obs->getTechLayer();
345-
if (layer != nullptr) {
346-
odb::Rect bloat;
347-
obs_rect.bloat(layer->getSpacing(), bloat);
348-
obs_rect = bloat;
349-
}
350-
check_shapes[obs->getTechLayer()].emplace(obs_rect, nullptr);
386+
for (odb::dbInst* check_inst : covers) {
387+
for (const auto& [layer, shapes] : getInstanceObstructions(check_inst)) {
388+
term_obstructions_[layer].insert(shapes.begin(), shapes.end());
351389
}
352-
for (auto* iterm : inst->getITerms()) {
353-
for (const auto& [layer, box] : iterm->getGeometries()) {
354-
odb::Rect term_rect = box;
355-
if (layer != nullptr) {
356-
odb::Rect bloat;
357-
box.bloat(layer->getSpacing(), bloat);
358-
term_rect = bloat;
359-
}
360-
check_shapes[layer].emplace(term_rect, iterm->getNet());
361-
}
390+
}
391+
}
392+
393+
void PadPlacer::addInstanceObstructions(odb::dbInst* inst)
394+
{
395+
instance_obstructions_.insert({inst->getBBox()->getBox(), inst});
396+
if (inst->getMaster()->isCover()) {
397+
for (const auto& [layer, shapes] : getInstanceObstructions(inst)) {
398+
term_obstructions_[layer].insert(shapes.begin(), shapes.end());
362399
}
363400
}
401+
}
364402

365-
for (odb::dbInst* check_inst : covers) {
366-
const auto xform = check_inst->getTransform();
367-
for (auto* obs : check_inst->getMaster()->getObstructions()) {
368-
odb::Rect obs_rect = obs->getBox();
369-
xform.apply(obs_rect);
370-
for (const auto& [inst_rect, check_net] :
371-
check_shapes[obs->getTechLayer()]) {
372-
if (inst_rect.intersects(obs_rect)) {
373-
return std::make_pair(check_inst, inst_rect.intersect(obs_rect));
374-
}
403+
std::optional<std::pair<odb::dbInst*, odb::Rect>>
404+
PadPlacer::checkInstancePlacement(odb::dbInst* inst,
405+
bool return_intersect) const
406+
{
407+
const odb::Rect inst_rect = inst->getBBox()->getBox();
408+
for (auto itr = blockage_obstructions_.qbegin(
409+
boost::geometry::index::intersects(inst_rect));
410+
itr != blockage_obstructions_.qend();
411+
itr++) {
412+
if (itr->overlaps(inst_rect)) {
413+
debugPrint(getLogger(),
414+
utl::PAD,
415+
"Check",
416+
2,
417+
"{} blocked by blockage: {}",
418+
inst->getName(),
419+
*itr);
420+
return std::make_pair(
421+
nullptr, return_intersect ? itr->intersect(inst_rect) : *itr);
422+
}
423+
}
424+
for (auto itr = instance_obstructions_.qbegin(
425+
boost::geometry::index::intersects(inst_rect));
426+
itr != instance_obstructions_.qend();
427+
itr++) {
428+
const auto& [check_rect, check_inst] = *itr;
429+
if (check_rect.overlaps(inst_rect)) {
430+
if (check_inst == inst) {
431+
continue;
375432
}
433+
debugPrint(getLogger(),
434+
utl::PAD,
435+
"Check",
436+
2,
437+
"{} blocked by fixed instance: {}",
438+
inst->getName(),
439+
check_inst->getName());
440+
return std::make_pair(
441+
check_inst,
442+
return_intersect ? check_rect.intersect(inst_rect) : check_rect);
443+
}
444+
}
445+
446+
for (const auto& [layer, term_shapes] : getInstanceObstructions(inst, true)) {
447+
if (term_obstructions_.find(layer) == term_obstructions_.end()) {
448+
continue;
376449
}
377450

378-
for (auto* iterm : check_inst->getITerms()) {
379-
for (const auto& [layer, box] : iterm->getGeometries()) {
380-
for (const auto& [inst_rect, check_net] : check_shapes[layer]) {
381-
const bool nets_match
382-
= iterm->getNet() == check_net
383-
&& (check_net != nullptr || iterm->getNet() != nullptr);
384-
if (!nets_match && inst_rect.intersects(box)) {
385-
return std::make_pair(check_inst, inst_rect.intersect(box));
386-
}
451+
const auto& obs_layer = term_obstructions_.at(layer);
452+
453+
for (const auto& [term_shape, term_net, term_inst] : term_shapes) {
454+
for (auto itr
455+
= obs_layer.qbegin(boost::geometry::index::intersects(term_shape));
456+
itr != obs_layer.qend();
457+
itr++) {
458+
const auto& [check_rect, check_net, check_inst] = *itr;
459+
if (check_inst == inst) {
460+
continue;
461+
}
462+
const bool nets_match
463+
= term_net == check_net
464+
&& (check_net != nullptr || term_net != nullptr);
465+
if (!nets_match) {
466+
debugPrint(
467+
getLogger(),
468+
utl::PAD,
469+
"Check",
470+
2,
471+
"{} ({} / {}) blocked by terminal obstruction: {} / {}",
472+
inst->getName(),
473+
term_shape,
474+
term_net == nullptr ? "unconnected" : term_net->getName(),
475+
check_rect,
476+
check_net == nullptr ? "unconnected" : check_net->getName());
477+
return std::make_pair(
478+
check_inst,
479+
return_intersect ? check_rect.intersect(inst_rect) : check_rect);
387480
}
388481
}
389482
}
@@ -444,6 +537,7 @@ void UniformPadPlacer::place()
444537
odb::dbOrientType::R0,
445538
/* allow_overlap */ false,
446539
/* allow_shift */ true);
540+
addInstanceObstructions(inst);
447541
offset += getInstWidths().at(inst);
448542
offset += target_spacing;
449543

@@ -480,9 +574,10 @@ SingleInstPadPlacer::SingleInstPadPlacer(utl::Logger* logger,
480574
void SingleInstPadPlacer::place(odb::dbInst* inst,
481575
int location,
482576
const odb::dbOrientType& base_orient,
483-
bool allow_overlap) const
577+
bool allow_overlap)
484578
{
485579
placeInstance(snapToRowSite(location), inst, base_orient, allow_overlap);
580+
addInstanceObstructions(inst);
486581
}
487582

488583
///////////////////////////////////////////
@@ -578,6 +673,7 @@ void BumpAlignedPadPlacer::place()
578673
* getRow()->getSpacing();
579674

580675
performPadFlip(ginst);
676+
addInstanceObstructions(ginst);
581677

582678
if (gui_debug) {
583679
gui::Gui::get()->pause();

src/pad/src/PadPlacer.h

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@
1010
#include <utility>
1111
#include <vector>
1212

13+
#include "boost/geometry/index/rtree.hpp"
1314
#include "odb/db.h"
1415
#include "odb/dbTypes.h"
1516
#include "odb/geom.h"
17+
#include "odb/geom_boost.h"
1618
#include "odb/isotropy.h"
1719

1820
namespace odb {
@@ -53,18 +55,36 @@ class PadPlacer
5355
int getTotalInstWidths() const;
5456

5557
protected:
58+
using InstObsValue = std::pair<odb::Rect, odb::dbInst*>;
59+
using TermObsValue = std::tuple<odb::Rect, odb::dbNet*, odb::dbInst*>;
60+
using BlockageObsTree
61+
= boost::geometry::index::rtree<odb::Rect,
62+
boost::geometry::index::quadratic<16>>;
63+
using InstObsTree
64+
= boost::geometry::index::rtree<InstObsValue,
65+
boost::geometry::index::quadratic<16>>;
66+
using TermObsTree
67+
= boost::geometry::index::rtree<TermObsValue,
68+
boost::geometry::index::quadratic<16>>;
69+
using LayerTermObsTree = std::map<odb::dbTechLayer*, TermObsTree>;
70+
5671
int placeInstance(int index,
5772
odb::dbInst* inst,
5873
const odb::dbOrientType& base_orient,
5974
bool allow_overlap = false,
6075
bool allow_shift = false) const;
76+
void populateObstructions();
6177
std::optional<std::pair<odb::dbInst*, odb::Rect>> checkInstancePlacement(
62-
odb::dbInst* inst) const;
78+
odb::dbInst* inst,
79+
bool return_intersect = true) const;
6380
int snapToRowSite(int location) const;
6481
const std::map<odb::dbInst*, int>& getInstWidths() const
6582
{
6683
return inst_widths_;
6784
}
85+
LayerTermObsTree getInstanceObstructions(odb::dbInst* inst,
86+
bool bloat = false) const;
87+
void addInstanceObstructions(odb::dbInst* inst);
6888

6989
private:
7090
void populateInstWidths();
@@ -77,6 +97,11 @@ class PadPlacer
7797

7898
// Computed values
7999
std::map<odb::dbInst*, int> inst_widths_;
100+
101+
// Fixed obstructions
102+
BlockageObsTree blockage_obstructions_;
103+
InstObsTree instance_obstructions_;
104+
LayerTermObsTree term_obstructions_;
80105
};
81106

82107
class CheckerOnlyPadPlacer : public PadPlacer
@@ -110,7 +135,7 @@ class SingleInstPadPlacer : public PadPlacer
110135
void place(odb::dbInst* inst,
111136
int location,
112137
const odb::dbOrientType& base_orient,
113-
bool allow_overlap = false) const;
138+
bool allow_overlap = false);
114139
};
115140

116141
class UniformPadPlacer : public PadPlacer

0 commit comments

Comments
 (0)