Skip to content

Commit 377bf64

Browse files
authored
Merge pull request #8833 from gadfort/pad-rtree-obs
pad: switch to use rtrees for obstructions to make checks faster
2 parents a43c6df + edd6437 commit 377bf64

5 files changed

Lines changed: 208 additions & 76 deletions

File tree

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: 159 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111
#include <map>
1212
#include <optional>
1313
#include <set>
14+
#include <tuple>
1415
#include <utility>
1516
#include <vector>
1617

18+
#include "boost/geometry/index/predicates.hpp"
1719
#include "gui/gui.h"
1820
#include "odb/db.h"
1921
#include "odb/dbTransform.h"
@@ -32,6 +34,7 @@ PadPlacer::PadPlacer(utl::Logger* logger,
3234
: logger_(logger), block_(block), insts_(insts), edge_(edge), row_(row)
3335
{
3436
populateInstWidths();
37+
populateObstructions();
3538
}
3639

3740
void PadPlacer::populateInstWidths()
@@ -301,89 +304,180 @@ int PadPlacer::placeInstance(int index,
301304
return next_pos;
302305
}
303306

304-
std::optional<std::pair<odb::dbInst*, odb::Rect>>
305-
PadPlacer::checkInstancePlacement(odb::dbInst* inst) const
307+
PadPlacer::LayerTermObsTree PadPlacer::getInstanceObstructions(
308+
odb::dbInst* inst,
309+
bool bloat) const
310+
{
311+
std::map<odb::dbTechLayer*, std::vector<TermObsValue>> shapes;
312+
313+
// populate map as needed
314+
const auto xform = inst->getTransform();
315+
for (auto* obs : inst->getMaster()->getObstructions()) {
316+
odb::Rect obs_rect = obs->getBox();
317+
xform.apply(obs_rect);
318+
odb::dbTechLayer* layer = obs->getTechLayer();
319+
if (bloat && layer != nullptr) {
320+
odb::Rect bloat_rect;
321+
obs_rect.bloat(layer->getSpacing(), bloat_rect);
322+
obs_rect = bloat_rect;
323+
}
324+
shapes[obs->getTechLayer()].emplace_back(obs_rect, nullptr, inst);
325+
}
326+
for (auto* iterm : inst->getITerms()) {
327+
for (const auto& [layer, box] : iterm->getGeometries()) {
328+
odb::Rect term_rect = box;
329+
if (bloat && layer != nullptr) {
330+
odb::Rect bloat_rect;
331+
box.bloat(layer->getSpacing(), bloat_rect);
332+
term_rect = bloat_rect;
333+
}
334+
shapes[layer].emplace_back(term_rect, iterm->getNet(), inst);
335+
}
336+
}
337+
338+
LayerTermObsTree rshapes;
339+
for (const auto& [layer, layer_shapes] : shapes) {
340+
if (layer == nullptr) {
341+
continue;
342+
}
343+
rshapes[layer] = TermObsTree(layer_shapes.begin(), layer_shapes.end());
344+
}
345+
return rshapes;
346+
}
347+
348+
void PadPlacer::populateObstructions()
306349
{
350+
blockage_obstructions_.clear();
351+
instance_obstructions_.clear();
352+
term_obstructions_.clear();
353+
354+
const odb::Rect row = row_->getBBox();
355+
307356
std::set<odb::dbInst*> covers;
308357
auto* block = getBlock();
309358
if (block) {
310-
const odb::Rect inst_rect = inst->getBBox()->getBox();
359+
// Get placement blockages
311360
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));
361+
if (blockage->getBBox()->getBox().overlaps(row)) {
362+
blockage_obstructions_.insert(blockage->getBBox()->getBox());
315363
}
316364
}
317-
for (auto* check_inst : block->getInsts()) {
318-
if (check_inst == inst) {
319-
continue;
365+
// Get obstructions that might interfere with RDL routing
366+
for (odb::dbObstruction* obs : block->getObstructions()) {
367+
if (obs->getBBox()->getBox().overlaps(row)) {
368+
term_obstructions_[obs->getBBox()->getTechLayer()].insert(
369+
{obs->getBBox()->getBox(), nullptr, nullptr});
320370
}
371+
}
372+
for (auto* check_inst : block->getInsts()) {
321373
if (!check_inst->isFixed()) {
322374
continue;
323375
}
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));
376+
if (check_inst->getBBox()->getBox().overlaps(row)) {
377+
if (check_inst->getMaster()->isCover()) {
378+
covers.insert(check_inst);
379+
continue;
380+
}
381+
instance_obstructions_.insert(
382+
{check_inst->getBBox()->getBox(), check_inst});
331383
}
332384
}
333385
}
334386

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);
387+
for (odb::dbInst* check_inst : covers) {
388+
for (const auto& [layer, shapes] : getInstanceObstructions(check_inst)) {
389+
term_obstructions_[layer].insert(shapes.begin(), shapes.end());
351390
}
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-
}
391+
}
392+
}
393+
394+
void PadPlacer::addInstanceObstructions(odb::dbInst* inst)
395+
{
396+
instance_obstructions_.insert({inst->getBBox()->getBox(), inst});
397+
if (inst->getMaster()->isCover()) {
398+
for (const auto& [layer, shapes] : getInstanceObstructions(inst)) {
399+
term_obstructions_[layer].insert(shapes.begin(), shapes.end());
362400
}
363401
}
402+
}
364403

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-
}
404+
std::optional<std::pair<odb::dbInst*, odb::Rect>>
405+
PadPlacer::checkInstancePlacement(odb::dbInst* inst,
406+
bool return_intersect) const
407+
{
408+
const odb::Rect inst_rect = inst->getBBox()->getBox();
409+
for (auto itr = blockage_obstructions_.qbegin(
410+
boost::geometry::index::intersects(inst_rect));
411+
itr != blockage_obstructions_.qend();
412+
itr++) {
413+
if (itr->overlaps(inst_rect)) {
414+
debugPrint(getLogger(),
415+
utl::PAD,
416+
"Check",
417+
2,
418+
"{} blocked by blockage: {}",
419+
inst->getName(),
420+
*itr);
421+
return std::make_pair(
422+
nullptr, return_intersect ? itr->intersect(inst_rect) : *itr);
423+
}
424+
}
425+
for (auto itr = instance_obstructions_.qbegin(
426+
boost::geometry::index::intersects(inst_rect));
427+
itr != instance_obstructions_.qend();
428+
itr++) {
429+
const auto& [check_rect, check_inst] = *itr;
430+
if (check_rect.overlaps(inst_rect)) {
431+
if (check_inst == inst) {
432+
continue;
375433
}
434+
debugPrint(getLogger(),
435+
utl::PAD,
436+
"Check",
437+
2,
438+
"{} blocked by fixed instance: {}",
439+
inst->getName(),
440+
check_inst->getName());
441+
return std::make_pair(
442+
check_inst,
443+
return_intersect ? check_rect.intersect(inst_rect) : check_rect);
444+
}
445+
}
446+
447+
for (const auto& [layer, term_shapes] : getInstanceObstructions(inst, true)) {
448+
if (term_obstructions_.find(layer) == term_obstructions_.end()) {
449+
continue;
376450
}
377451

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-
}
452+
const auto& obs_layer = term_obstructions_.at(layer);
453+
454+
for (const auto& [term_shape, term_net, term_inst] : term_shapes) {
455+
for (auto itr
456+
= obs_layer.qbegin(boost::geometry::index::intersects(term_shape));
457+
itr != obs_layer.qend();
458+
itr++) {
459+
const auto& [check_rect, check_net, check_inst] = *itr;
460+
if (check_inst == inst) {
461+
continue;
462+
}
463+
const bool nets_match
464+
= term_net == check_net
465+
&& (check_net != nullptr || term_net != nullptr);
466+
if (!nets_match) {
467+
debugPrint(
468+
getLogger(),
469+
utl::PAD,
470+
"Check",
471+
2,
472+
"{} ({} / {}) blocked by terminal obstruction: {} / {}",
473+
inst->getName(),
474+
term_shape,
475+
term_net == nullptr ? "unconnected" : term_net->getName(),
476+
check_rect,
477+
check_net == nullptr ? "unconnected" : check_net->getName());
478+
return std::make_pair(
479+
check_inst,
480+
return_intersect ? check_rect.intersect(inst_rect) : check_rect);
387481
}
388482
}
389483
}
@@ -444,6 +538,7 @@ void UniformPadPlacer::place()
444538
odb::dbOrientType::R0,
445539
/* allow_overlap */ false,
446540
/* allow_shift */ true);
541+
addInstanceObstructions(inst);
447542
offset += getInstWidths().at(inst);
448543
offset += target_spacing;
449544

@@ -480,9 +575,10 @@ SingleInstPadPlacer::SingleInstPadPlacer(utl::Logger* logger,
480575
void SingleInstPadPlacer::place(odb::dbInst* inst,
481576
int location,
482577
const odb::dbOrientType& base_orient,
483-
bool allow_overlap) const
578+
bool allow_overlap)
484579
{
485580
placeInstance(snapToRowSite(location), inst, base_orient, allow_overlap);
581+
addInstanceObstructions(inst);
486582
}
487583

488584
///////////////////////////////////////////
@@ -578,6 +674,7 @@ void BumpAlignedPadPlacer::place()
578674
* getRow()->getSpacing();
579675

580676
performPadFlip(ginst);
677+
addInstanceObstructions(ginst);
581678

582679
if (gui_debug) {
583680
gui::Gui::get()->pause();

src/pad/src/PadPlacer.h

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@
77
#include <map>
88
#include <optional>
99
#include <set>
10+
#include <tuple>
1011
#include <utility>
1112
#include <vector>
1213

14+
#include "boost/geometry/index/parameters.hpp"
15+
#include "boost/geometry/index/rtree.hpp"
1316
#include "odb/db.h"
1417
#include "odb/dbTypes.h"
1518
#include "odb/geom.h"
19+
#include "odb/geom_boost.h"
1620
#include "odb/isotropy.h"
1721

1822
namespace odb {
@@ -53,18 +57,36 @@ class PadPlacer
5357
int getTotalInstWidths() const;
5458

5559
protected:
60+
using InstObsValue = std::pair<odb::Rect, odb::dbInst*>;
61+
using TermObsValue = std::tuple<odb::Rect, odb::dbNet*, odb::dbInst*>;
62+
using BlockageObsTree
63+
= boost::geometry::index::rtree<odb::Rect,
64+
boost::geometry::index::quadratic<16>>;
65+
using InstObsTree
66+
= boost::geometry::index::rtree<InstObsValue,
67+
boost::geometry::index::quadratic<16>>;
68+
using TermObsTree
69+
= boost::geometry::index::rtree<TermObsValue,
70+
boost::geometry::index::quadratic<16>>;
71+
using LayerTermObsTree = std::map<odb::dbTechLayer*, TermObsTree>;
72+
5673
int placeInstance(int index,
5774
odb::dbInst* inst,
5875
const odb::dbOrientType& base_orient,
5976
bool allow_overlap = false,
6077
bool allow_shift = false) const;
78+
void populateObstructions();
6179
std::optional<std::pair<odb::dbInst*, odb::Rect>> checkInstancePlacement(
62-
odb::dbInst* inst) const;
80+
odb::dbInst* inst,
81+
bool return_intersect = true) const;
6382
int snapToRowSite(int location) const;
6483
const std::map<odb::dbInst*, int>& getInstWidths() const
6584
{
6685
return inst_widths_;
6786
}
87+
LayerTermObsTree getInstanceObstructions(odb::dbInst* inst,
88+
bool bloat = false) const;
89+
void addInstanceObstructions(odb::dbInst* inst);
6890

6991
private:
7092
void populateInstWidths();
@@ -77,6 +99,11 @@ class PadPlacer
7799

78100
// Computed values
79101
std::map<odb::dbInst*, int> inst_widths_;
102+
103+
// Fixed obstructions
104+
BlockageObsTree blockage_obstructions_;
105+
InstObsTree instance_obstructions_;
106+
LayerTermObsTree term_obstructions_;
80107
};
81108

82109
class CheckerOnlyPadPlacer : public PadPlacer
@@ -110,7 +137,7 @@ class SingleInstPadPlacer : public PadPlacer
110137
void place(odb::dbInst* inst,
111138
int location,
112139
const odb::dbOrientType& base_orient,
113-
bool allow_overlap = false) const;
140+
bool allow_overlap = false);
114141
};
115142

116143
class UniformPadPlacer : public PadPlacer

0 commit comments

Comments
 (0)