HeAP: Cut finder for spreading
Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
parent
4d2906378f
commit
8a791e8309
@ -207,6 +207,7 @@ class HeAPPlacer
|
|||||||
struct CellLocation
|
struct CellLocation
|
||||||
{
|
{
|
||||||
int x, y;
|
int x, y;
|
||||||
|
double rawx, rawy;
|
||||||
bool locked, global;
|
bool locked, global;
|
||||||
};
|
};
|
||||||
std::unordered_map<IdString, CellLocation> cell_locs;
|
std::unordered_map<IdString, CellLocation> cell_locs;
|
||||||
@ -414,11 +415,11 @@ class HeAPPlacer
|
|||||||
for (auto child : cell->constr_children) {
|
for (auto child : cell->constr_children) {
|
||||||
chain_size[root->name]++;
|
chain_size[root->name]++;
|
||||||
if (child->constr_x != child->UNCONSTR)
|
if (child->constr_x != child->UNCONSTR)
|
||||||
cell_locs[child->name].x = base.x + child->constr_x;
|
cell_locs[child->name].x = std::min(max_x, base.x + child->constr_x);
|
||||||
else
|
else
|
||||||
cell_locs[child->name].x = base.x; // better handling of UNCONSTR?
|
cell_locs[child->name].x = base.x; // better handling of UNCONSTR?
|
||||||
if (child->constr_y != child->UNCONSTR)
|
if (child->constr_y != child->UNCONSTR)
|
||||||
cell_locs[child->name].y = base.y + child->constr_y;
|
cell_locs[child->name].y = std::min(max_y, base.y + child->constr_y);
|
||||||
else
|
else
|
||||||
cell_locs[child->name].y = base.y; // better handling of UNCONSTR?
|
cell_locs[child->name].y = base.y; // better handling of UNCONSTR?
|
||||||
chain_root[cell->name] = root;
|
chain_root[cell->name] = root;
|
||||||
@ -531,19 +532,21 @@ class HeAPPlacer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build the system of equations for either X or Y
|
// Build the system of equations for either X or Y
|
||||||
void solve_equations(EquationSystem<double> &es, bool yaxis)
|
void solve_equations(EquationSystem<double> &es, bool yaxis) {
|
||||||
{
|
|
||||||
// Return the x or y position of a cell, depending on ydir
|
// Return the x or y position of a cell, depending on ydir
|
||||||
auto cell_pos = [&](CellInfo *cell) { return yaxis ? cell_locs.at(cell->name).y : cell_locs.at(cell->name).x; };
|
auto cell_pos = [&](CellInfo *cell) { return yaxis ? cell_locs.at(cell->name).y : cell_locs.at(cell->name).x; };
|
||||||
std::vector<double> vals;
|
std::vector<double> vals;
|
||||||
std::transform(solve_cells.begin(), solve_cells.end(), std::back_inserter(vals), cell_pos);
|
std::transform(solve_cells.begin(), solve_cells.end(), std::back_inserter(vals), cell_pos);
|
||||||
es.solve(vals);
|
es.solve(vals);
|
||||||
for (size_t i = 0; i < vals.size(); i++)
|
for (size_t i = 0; i < vals.size(); i++)
|
||||||
if (yaxis)
|
if (yaxis) {
|
||||||
|
cell_locs.at(solve_cells.at(i)->name).rawy = vals.at(i);
|
||||||
cell_locs.at(solve_cells.at(i)->name).y = std::min(max_y, std::max(0, int(vals.at(i) + 0.5)));
|
cell_locs.at(solve_cells.at(i)->name).y = std::min(max_y, std::max(0, int(vals.at(i) + 0.5)));
|
||||||
else
|
} else {
|
||||||
|
cell_locs.at(solve_cells.at(i)->name).rawx = vals.at(i);
|
||||||
cell_locs.at(solve_cells.at(i)->name).x = std::min(max_x, std::max(0, int(vals.at(i) + 0.5)));
|
cell_locs.at(solve_cells.at(i)->name).x = std::min(max_x, std::max(0, int(vals.at(i) + 0.5)));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Compute HPWL
|
// Compute HPWL
|
||||||
wirelen_t total_hpwl()
|
wirelen_t total_hpwl()
|
||||||
@ -724,10 +727,15 @@ class HeAPPlacer
|
|||||||
std::vector<std::vector<int>> occupancy;
|
std::vector<std::vector<int>> occupancy;
|
||||||
std::vector<std::vector<int>> groups;
|
std::vector<std::vector<int>> groups;
|
||||||
std::vector<std::vector<ChainExtent>> chaines;
|
std::vector<std::vector<ChainExtent>> chaines;
|
||||||
|
std::map<IdString, ChainExtent> cell_extents;
|
||||||
|
|
||||||
std::vector<std::vector<std::vector<BelId>>> &fb;
|
std::vector<std::vector<std::vector<BelId>>> &fb;
|
||||||
|
|
||||||
std::vector<LegaliserRegion> regions;
|
std::vector<LegaliserRegion> regions;
|
||||||
std::unordered_set<int> merged_regions;
|
std::unordered_set<int> merged_regions;
|
||||||
|
// Cells at a location, sorted by real (not integer) x and y
|
||||||
|
std::vector<std::vector<std::vector<CellInfo*>>> cells_at_location_sx;
|
||||||
|
std::vector<std::vector<std::vector<CellInfo*>>> cells_at_location_sy;
|
||||||
|
|
||||||
int occ_at(int x, int y) { return occupancy.at(x).at(y); }
|
int occ_at(int x, int y) { return occupancy.at(x).at(y); }
|
||||||
|
|
||||||
@ -738,12 +746,12 @@ class HeAPPlacer
|
|||||||
return int(fb.at(x).at(y).size());
|
return int(fb.at(x).at(y).size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void init()
|
void init() {
|
||||||
{
|
|
||||||
occupancy.resize(p->max_x + 1, std::vector<int>(p->max_y + 1, 0));
|
occupancy.resize(p->max_x + 1, std::vector<int>(p->max_y + 1, 0));
|
||||||
groups.resize(p->max_x + 1, std::vector<int>(p->max_y + 1, -1));
|
groups.resize(p->max_x + 1, std::vector<int>(p->max_y + 1, -1));
|
||||||
chaines.resize(p->max_x + 1, std::vector<ChainExtent>(p->max_y + 1));
|
chaines.resize(p->max_x + 1, std::vector<ChainExtent>(p->max_y + 1));
|
||||||
|
cells_at_location_sx.resize(p->max_x + 1, std::vector<std::vector<CellInfo *>>(p->max_y + 1));
|
||||||
|
cells_at_location_sy.resize(p->max_x + 1, std::vector<std::vector<CellInfo *>>(p->max_y + 1));
|
||||||
for (int x = 0; x <= p->max_x; x++)
|
for (int x = 0; x <= p->max_x; x++)
|
||||||
for (int y = 0; y <= p->max_y; y++) {
|
for (int y = 0; y <= p->max_y; y++) {
|
||||||
occupancy.at(x).at(y) = 0;
|
occupancy.at(x).at(y) = 0;
|
||||||
@ -751,16 +759,15 @@ class HeAPPlacer
|
|||||||
chaines.at(x).at(y) = {x, y, x, y};
|
chaines.at(x).at(y) = {x, y, x, y};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<IdString, ChainExtent> cr_extents;
|
|
||||||
|
|
||||||
auto set_chain_ext = [&](IdString cell, int x, int y) {
|
auto set_chain_ext = [&](IdString cell, int x, int y) {
|
||||||
if (!cr_extents.count(cell))
|
if (!cell_extents.count(cell))
|
||||||
cr_extents[cell] = {x, y, x, y};
|
cell_extents[cell] = {x, y, x, y};
|
||||||
else {
|
else {
|
||||||
cr_extents[cell].x0 = std::min(cr_extents[cell].x0, x);
|
cell_extents[cell].x0 = std::min(cell_extents[cell].x0, x);
|
||||||
cr_extents[cell].y0 = std::min(cr_extents[cell].y0, y);
|
cell_extents[cell].y0 = std::min(cell_extents[cell].y0, y);
|
||||||
cr_extents[cell].x1 = std::max(cr_extents[cell].x1, x);
|
cell_extents[cell].x1 = std::max(cell_extents[cell].x1, x);
|
||||||
cr_extents[cell].y1 = std::max(cr_extents[cell].y1, y);
|
cell_extents[cell].y1 = std::max(cell_extents[cell].y1, y);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -778,9 +785,9 @@ class HeAPPlacer
|
|||||||
// Transfer chain extents to the actual chaines structure
|
// Transfer chain extents to the actual chaines structure
|
||||||
ChainExtent *ce = nullptr;
|
ChainExtent *ce = nullptr;
|
||||||
if (p->chain_root.count(cell.first))
|
if (p->chain_root.count(cell.first))
|
||||||
ce = &(cr_extents.at(p->chain_root.at(cell.first)->name));
|
ce = &(cell_extents.at(p->chain_root.at(cell.first)->name));
|
||||||
else if (!ctx->cells.at(cell.first)->constr_children.empty())
|
else if (!ctx->cells.at(cell.first)->constr_children.empty())
|
||||||
ce = &(cr_extents.at(cell.first));
|
ce = &(cell_extents.at(cell.first));
|
||||||
if (ce) {
|
if (ce) {
|
||||||
auto &lce = chaines.at(cell.second.x).at(cell.second.y);
|
auto &lce = chaines.at(cell.second.x).at(cell.second.y);
|
||||||
lce.x0 = std::min(lce.x0, ce->x0);
|
lce.x0 = std::min(lce.x0, ce->x0);
|
||||||
@ -789,6 +796,20 @@ class HeAPPlacer
|
|||||||
lce.y1 = std::max(lce.y1, ce->y1);
|
lce.y1 = std::max(lce.y1, ce->y1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (auto cell : p->solve_cells) {
|
||||||
|
cells_at_location_sx.at(p->cell_locs.at(cell->name).x).at(p->cell_locs.at(cell->name).y).push_back(cell);
|
||||||
|
cells_at_location_sy.at(p->cell_locs.at(cell->name).x).at(p->cell_locs.at(cell->name).y).push_back(cell);
|
||||||
|
}
|
||||||
|
for (auto &col : cells_at_location_sx)
|
||||||
|
for (auto &loc : col)
|
||||||
|
std::sort(loc.begin(), loc.end(), [&](const CellInfo *a, const CellInfo *b){
|
||||||
|
return p->cell_locs.at(a->name).rawx < p->cell_locs.at(b->name).rawx;
|
||||||
|
});
|
||||||
|
for (auto &col : cells_at_location_sy)
|
||||||
|
for (auto &loc : col)
|
||||||
|
std::sort(loc.begin(), loc.end(), [&](const CellInfo *a, const CellInfo *b){
|
||||||
|
return p->cell_locs.at(a->name).rawy < p->cell_locs.at(b->name).rawy;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
void merge_regions(LegaliserRegion &merged, LegaliserRegion &mergee)
|
void merge_regions(LegaliserRegion &merged, LegaliserRegion &mergee)
|
||||||
{
|
{
|
||||||
@ -950,6 +971,97 @@ class HeAPPlacer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implementation of the recursive cut-based spreading as described in the HeAP paper
|
||||||
|
// Note we use "left" to mean "-x/-y" depending on dir and "right" to mean "+x/+y" depending on dir
|
||||||
|
|
||||||
|
std::vector<CellInfo *> cut_cells;
|
||||||
|
|
||||||
|
void cut_region(LegaliserRegion &r, bool dir) {
|
||||||
|
cut_cells.clear();
|
||||||
|
auto &cal = dir ? cells_at_location_sy : cells_at_location_sx;
|
||||||
|
for (int x = r.x0; x <= r.x1; x++) {
|
||||||
|
for (int y = r.y0; y <= r.y1; y++) {
|
||||||
|
std::copy(cal.at(x).at(y).begin(), cal.at(x).at(y).end(), std::back_inserter(cut_cells));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Find the cells midpoint, counting chains in terms of their total size - making the initial source cut
|
||||||
|
int pivot_cells = 0;
|
||||||
|
int pivot = 0;
|
||||||
|
for (auto &cell : cut_cells) {
|
||||||
|
pivot_cells += p->chain_size.count(cell->name) ? p->chain_size.at(cell->name) : 1;
|
||||||
|
if (pivot_cells >= r.cells / 2)
|
||||||
|
break;
|
||||||
|
pivot++;
|
||||||
|
}
|
||||||
|
// Find the clearance required either side of the pivot
|
||||||
|
int clearance_l = 0, clearance_r = 0;
|
||||||
|
for (size_t i = 0; i < cut_cells.size(); i++) {
|
||||||
|
int size;
|
||||||
|
if (cell_extents.count(cut_cells.at(i)->name)) {
|
||||||
|
auto &ce = cell_extents.at(cut_cells.at(i)->name);
|
||||||
|
size = dir ? (ce.y1 - ce.y0 + 1) : (ce.x1 - ce.x0 + 1);
|
||||||
|
} else {
|
||||||
|
size = 1;
|
||||||
|
}
|
||||||
|
if (i < pivot)
|
||||||
|
clearance_l = std::max(clearance_l, size);
|
||||||
|
else
|
||||||
|
clearance_r = std::max(clearance_r, size);
|
||||||
|
}
|
||||||
|
// Find the target cut that minimises difference in utilisation, whilst trying to ensure that all chains
|
||||||
|
// still fit
|
||||||
|
|
||||||
|
// First trim the boundaries of the region in the axis-of-interest, skipping any rows/cols without any
|
||||||
|
// bels of the appropriate type
|
||||||
|
int trimmed_l = dir ? r.y0 : r.x0, trimmed_r = dir ? r.y1 : r.x1;
|
||||||
|
while (trimmed_l < (dir ? r.y1 : r.x1)) {
|
||||||
|
bool have_bels = false;
|
||||||
|
for (int i = dir ? r.x0 : r.y0; i <= (dir ? r.x1 : r.y1); i++)
|
||||||
|
if (bels_at(dir ? i : trimmed_l, dir ? trimmed_l : i) > 0) {
|
||||||
|
have_bels = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (have_bels)
|
||||||
|
break;
|
||||||
|
trimmed_l++;
|
||||||
|
}
|
||||||
|
while (trimmed_r > (dir ? r.y0 : r.x0)) {
|
||||||
|
bool have_bels = false;
|
||||||
|
for (int i = dir ? r.x0 : r.y0; i <= (dir ? r.x1 : r.y1); i++)
|
||||||
|
if (bels_at(dir ? i : trimmed_l, dir ? trimmed_l : i) > 0) {
|
||||||
|
have_bels = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (have_bels)
|
||||||
|
break;
|
||||||
|
trimmed_r--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now find the initial target cut that minimises utilisation imbalance, whilst
|
||||||
|
// meeting the clearance requirements for any large macros
|
||||||
|
int left_cells = pivot_cells, right_cells = r.cells - pivot_cells;
|
||||||
|
int left_bels = 0, right_bels = r.bels;
|
||||||
|
int best_tgt_cut = -1;
|
||||||
|
double best_deltaU = std::numeric_limits<double>::max();
|
||||||
|
|
||||||
|
for (int i = trimmed_l; i <= trimmed_r; i++) {
|
||||||
|
int slither_bels = 0;
|
||||||
|
for (int j = dir ? r.x0 : r.y0; j <= (dir ? r.x1 : r.y1); j++) {
|
||||||
|
slither_bels += dir ? bels_at(j, i) : bels_at(i, j);
|
||||||
|
}
|
||||||
|
left_bels += slither_bels;
|
||||||
|
right_bels -= slither_bels;
|
||||||
|
if (((i - trimmed_l) + 1) >= clearance_l && ((trimmed_r - i) + 1) >= clearance_r) {
|
||||||
|
// Solution is potentially valid
|
||||||
|
double aU = std::abs(double(left_cells) / double(left_bels) - double(right_bels) / double(right_cells));
|
||||||
|
if (aU < best_deltaU) {
|
||||||
|
best_deltaU = aU;
|
||||||
|
best_tgt_cut = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef decltype(CellInfo::udata) cell_udata_t;
|
typedef decltype(CellInfo::udata) cell_udata_t;
|
||||||
|
Loading…
Reference in New Issue
Block a user