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
|
||||
{
|
||||
int x, y;
|
||||
double rawx, rawy;
|
||||
bool locked, global;
|
||||
};
|
||||
std::unordered_map<IdString, CellLocation> cell_locs;
|
||||
@ -414,11 +415,11 @@ class HeAPPlacer
|
||||
for (auto child : cell->constr_children) {
|
||||
chain_size[root->name]++;
|
||||
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
|
||||
cell_locs[child->name].x = base.x; // better handling of 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
|
||||
cell_locs[child->name].y = base.y; // better handling of UNCONSTR?
|
||||
chain_root[cell->name] = root;
|
||||
@ -531,18 +532,20 @@ class HeAPPlacer
|
||||
}
|
||||
|
||||
// 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
|
||||
auto cell_pos = [&](CellInfo *cell) { return yaxis ? cell_locs.at(cell->name).y : cell_locs.at(cell->name).x; };
|
||||
std::vector<double> vals;
|
||||
std::transform(solve_cells.begin(), solve_cells.end(), std::back_inserter(vals), cell_pos);
|
||||
es.solve(vals);
|
||||
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)));
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
// Compute HPWL
|
||||
@ -724,10 +727,15 @@ class HeAPPlacer
|
||||
std::vector<std::vector<int>> occupancy;
|
||||
std::vector<std::vector<int>> groups;
|
||||
std::vector<std::vector<ChainExtent>> chaines;
|
||||
std::map<IdString, ChainExtent> cell_extents;
|
||||
|
||||
std::vector<std::vector<std::vector<BelId>>> &fb;
|
||||
|
||||
std::vector<LegaliserRegion> 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); }
|
||||
|
||||
@ -738,12 +746,12 @@ class HeAPPlacer
|
||||
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));
|
||||
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));
|
||||
|
||||
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 y = 0; y <= p->max_y; y++) {
|
||||
occupancy.at(x).at(y) = 0;
|
||||
@ -751,16 +759,15 @@ class HeAPPlacer
|
||||
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) {
|
||||
if (!cr_extents.count(cell))
|
||||
cr_extents[cell] = {x, y, x, y};
|
||||
if (!cell_extents.count(cell))
|
||||
cell_extents[cell] = {x, y, x, y};
|
||||
else {
|
||||
cr_extents[cell].x0 = std::min(cr_extents[cell].x0, x);
|
||||
cr_extents[cell].y0 = std::min(cr_extents[cell].y0, y);
|
||||
cr_extents[cell].x1 = std::max(cr_extents[cell].x1, x);
|
||||
cr_extents[cell].y1 = std::max(cr_extents[cell].y1, y);
|
||||
cell_extents[cell].x0 = std::min(cell_extents[cell].x0, x);
|
||||
cell_extents[cell].y0 = std::min(cell_extents[cell].y0, y);
|
||||
cell_extents[cell].x1 = std::max(cell_extents[cell].x1, x);
|
||||
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
|
||||
ChainExtent *ce = nullptr;
|
||||
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())
|
||||
ce = &(cr_extents.at(cell.first));
|
||||
ce = &(cell_extents.at(cell.first));
|
||||
if (ce) {
|
||||
auto &lce = chaines.at(cell.second.x).at(cell.second.y);
|
||||
lce.x0 = std::min(lce.x0, ce->x0);
|
||||
@ -789,6 +796,20 @@ class HeAPPlacer
|
||||
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)
|
||||
{
|
||||
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user