Merge pull request #48 from YosysHQ/placer_speedup
placer: low hanging speedups
This commit is contained in:
commit
2e02f2d616
@ -70,6 +70,19 @@ class SAPlacer
|
|||||||
fast_bels.at(type_idx).at(loc.x).at(loc.y).push_back(bel);
|
fast_bels.at(type_idx).at(loc.x).at(loc.y).push_back(bel);
|
||||||
}
|
}
|
||||||
diameter = std::max(max_x, max_y) + 1;
|
diameter = std::max(max_x, max_y) + 1;
|
||||||
|
|
||||||
|
costs.resize(ctx->nets.size());
|
||||||
|
old_udata.reserve(ctx->nets.size());
|
||||||
|
decltype(NetInfo::udata) n = 0;
|
||||||
|
for (auto &net : ctx->nets) {
|
||||||
|
old_udata.emplace_back(net.second->udata);
|
||||||
|
net.second->udata = n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~SAPlacer() {
|
||||||
|
for (auto &net : ctx->nets)
|
||||||
|
net.second->udata = old_udata[net.second->udata];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool place()
|
bool place()
|
||||||
@ -149,7 +162,7 @@ class SAPlacer
|
|||||||
curr_tns = 0;
|
curr_tns = 0;
|
||||||
for (auto &net : ctx->nets) {
|
for (auto &net : ctx->nets) {
|
||||||
wirelen_t wl = get_net_metric(ctx, net.second.get(), MetricType::COST, curr_tns);
|
wirelen_t wl = get_net_metric(ctx, net.second.get(), MetricType::COST, curr_tns);
|
||||||
metrics[net.first] = wl;
|
costs[net.second->udata] = CostChange{wl, -1};
|
||||||
curr_metric += wl;
|
curr_metric += wl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,7 +263,7 @@ class SAPlacer
|
|||||||
curr_tns = 0;
|
curr_tns = 0;
|
||||||
for (auto &net : ctx->nets) {
|
for (auto &net : ctx->nets) {
|
||||||
wirelen_t wl = get_net_metric(ctx, net.second.get(), MetricType::COST, curr_tns);
|
wirelen_t wl = get_net_metric(ctx, net.second.get(), MetricType::COST, curr_tns);
|
||||||
metrics[net.first] = wl;
|
costs[net.second->udata] = CostChange{wl, -1};
|
||||||
curr_metric += wl;
|
curr_metric += wl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,10 +352,8 @@ class SAPlacer
|
|||||||
// Attempt a SA position swap, return true on success or false on failure
|
// Attempt a SA position swap, return true on success or false on failure
|
||||||
bool try_swap_position(CellInfo *cell, BelId newBel)
|
bool try_swap_position(CellInfo *cell, BelId newBel)
|
||||||
{
|
{
|
||||||
static std::unordered_set<NetInfo *> update;
|
static std::vector<NetInfo*> updates;
|
||||||
static std::vector<std::pair<IdString, wirelen_t>> new_lengths;
|
updates.clear();
|
||||||
new_lengths.clear();
|
|
||||||
update.clear();
|
|
||||||
BelId oldBel = cell->bel;
|
BelId oldBel = cell->bel;
|
||||||
CellInfo *other_cell = ctx->getBoundBelCell(newBel);
|
CellInfo *other_cell = ctx->getBoundBelCell(newBel);
|
||||||
if (other_cell != nullptr && other_cell->belStrength > STRENGTH_WEAK) {
|
if (other_cell != nullptr && other_cell->belStrength > STRENGTH_WEAK) {
|
||||||
@ -358,14 +369,23 @@ class SAPlacer
|
|||||||
ctx->unbindBel(newBel);
|
ctx->unbindBel(newBel);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &port : cell->ports)
|
for (const auto &port : cell->ports) {
|
||||||
if (port.second.net != nullptr)
|
if (port.second.net != nullptr) {
|
||||||
update.insert(port.second.net);
|
auto &cost = costs[port.second.net->udata];
|
||||||
|
if (cost.new_cost == 0) continue;
|
||||||
|
cost.new_cost = 0;
|
||||||
|
updates.emplace_back(port.second.net);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (other_cell != nullptr) {
|
if (other_cell != nullptr) {
|
||||||
for (const auto &port : other_cell->ports)
|
for (const auto &port : other_cell->ports)
|
||||||
if (port.second.net != nullptr)
|
if (port.second.net != nullptr) {
|
||||||
update.insert(port.second.net);
|
auto &cost = costs[port.second.net->udata];
|
||||||
|
if (cost.new_cost == 0) continue;
|
||||||
|
cost.new_cost = 0;
|
||||||
|
updates.emplace_back(port.second.net);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->bindBel(newBel, cell, STRENGTH_WEAK);
|
ctx->bindBel(newBel, cell, STRENGTH_WEAK);
|
||||||
@ -383,12 +403,13 @@ class SAPlacer
|
|||||||
new_metric = curr_metric;
|
new_metric = curr_metric;
|
||||||
|
|
||||||
// Recalculate metrics for all nets touched by the peturbation
|
// Recalculate metrics for all nets touched by the peturbation
|
||||||
for (auto net : update) {
|
for (const auto &net : updates) {
|
||||||
new_metric -= metrics.at(net->name);
|
auto &c = costs[net->udata];
|
||||||
|
new_metric -= c.curr_cost;
|
||||||
float temp_tns = 0;
|
float temp_tns = 0;
|
||||||
wirelen_t net_new_wl = get_net_metric(ctx, net, MetricType::COST, temp_tns);
|
wirelen_t net_new_wl = get_net_metric(ctx, net, MetricType::COST, temp_tns);
|
||||||
new_metric += net_new_wl;
|
new_metric += net_new_wl;
|
||||||
new_lengths.push_back(std::make_pair(net->name, net_new_wl));
|
c.new_cost = net_new_wl;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_dist = get_constraints_distance(ctx, cell);
|
new_dist = get_constraints_distance(ctx, cell);
|
||||||
@ -407,8 +428,10 @@ class SAPlacer
|
|||||||
goto swap_fail;
|
goto swap_fail;
|
||||||
}
|
}
|
||||||
curr_metric = new_metric;
|
curr_metric = new_metric;
|
||||||
for (auto new_wl : new_lengths)
|
for (const auto &net : updates) {
|
||||||
metrics.at(new_wl.first) = new_wl.second;
|
auto &c = costs[net->udata];
|
||||||
|
c = CostChange{c.new_cost, -1};
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
swap_fail:
|
swap_fail:
|
||||||
@ -416,6 +439,8 @@ class SAPlacer
|
|||||||
if (other_cell != nullptr) {
|
if (other_cell != nullptr) {
|
||||||
ctx->bindBel(newBel, other_cell, STRENGTH_WEAK);
|
ctx->bindBel(newBel, other_cell, STRENGTH_WEAK);
|
||||||
}
|
}
|
||||||
|
for (const auto &net : updates)
|
||||||
|
costs[net->udata].new_cost = -1;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -444,7 +469,6 @@ class SAPlacer
|
|||||||
}
|
}
|
||||||
|
|
||||||
Context *ctx;
|
Context *ctx;
|
||||||
std::unordered_map<IdString, wirelen_t> metrics;
|
|
||||||
wirelen_t curr_metric = std::numeric_limits<wirelen_t>::max();
|
wirelen_t curr_metric = std::numeric_limits<wirelen_t>::max();
|
||||||
float curr_tns = 0;
|
float curr_tns = 0;
|
||||||
float temp = 1000;
|
float temp = 1000;
|
||||||
@ -459,6 +483,13 @@ class SAPlacer
|
|||||||
const float post_legalise_temp = 10;
|
const float post_legalise_temp = 10;
|
||||||
const float post_legalise_dia_scale = 1.5;
|
const float post_legalise_dia_scale = 1.5;
|
||||||
Placer1Cfg cfg;
|
Placer1Cfg cfg;
|
||||||
|
|
||||||
|
struct CostChange {
|
||||||
|
wirelen_t curr_cost;
|
||||||
|
wirelen_t new_cost;
|
||||||
|
};
|
||||||
|
std::vector<CostChange> costs;
|
||||||
|
std::vector<decltype(NetInfo::udata)> old_udata;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool placer1(Context *ctx, Placer1Cfg cfg)
|
bool placer1(Context *ctx, Placer1Cfg cfg)
|
||||||
|
@ -812,7 +812,7 @@ struct Arch : BaseCtx
|
|||||||
bool isBelLocationValid(BelId bel) const;
|
bool isBelLocationValid(BelId bel) const;
|
||||||
|
|
||||||
// Helper function for above
|
// Helper function for above
|
||||||
bool logicCellsCompatible(const std::vector<const CellInfo *> &cells) const;
|
bool logicCellsCompatible(const CellInfo** it, const size_t size) const;
|
||||||
|
|
||||||
// -------------------------------------------------
|
// -------------------------------------------------
|
||||||
// Assign architecure-specific arguments to nets and cells, which must be
|
// Assign architecure-specific arguments to nets and cells, which must be
|
||||||
|
@ -23,15 +23,17 @@
|
|||||||
#include "nextpnr.h"
|
#include "nextpnr.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <boost/range/iterator_range.hpp>
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
bool Arch::logicCellsCompatible(const std::vector<const CellInfo *> &cells) const
|
bool Arch::logicCellsCompatible(const CellInfo** it, const size_t size) const
|
||||||
{
|
{
|
||||||
bool dffs_exist = false, dffs_neg = false;
|
bool dffs_exist = false, dffs_neg = false;
|
||||||
const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr;
|
const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr;
|
||||||
int locals_count = 0;
|
int locals_count = 0;
|
||||||
|
|
||||||
for (auto cell : cells) {
|
for (auto cell : boost::make_iterator_range(it, it+size)) {
|
||||||
NPNR_ASSERT(cell->belType == id_ICESTORM_LC);
|
NPNR_ASSERT(cell->belType == id_ICESTORM_LC);
|
||||||
if (cell->lcInfo.dffEnable) {
|
if (cell->lcInfo.dffEnable) {
|
||||||
if (!dffs_exist) {
|
if (!dffs_exist) {
|
||||||
@ -71,15 +73,15 @@ bool Arch::logicCellsCompatible(const std::vector<const CellInfo *> &cells) cons
|
|||||||
bool Arch::isBelLocationValid(BelId bel) const
|
bool Arch::isBelLocationValid(BelId bel) const
|
||||||
{
|
{
|
||||||
if (getBelType(bel) == id_ICESTORM_LC) {
|
if (getBelType(bel) == id_ICESTORM_LC) {
|
||||||
std::vector<const CellInfo *> bel_cells;
|
std::array<const CellInfo *, 8> bel_cells;
|
||||||
|
size_t num_cells = 0;
|
||||||
Loc bel_loc = getBelLocation(bel);
|
Loc bel_loc = getBelLocation(bel);
|
||||||
for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) {
|
for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) {
|
||||||
CellInfo *ci_other = getBoundBelCell(bel_other);
|
CellInfo *ci_other = getBoundBelCell(bel_other);
|
||||||
if (ci_other != nullptr) {
|
if (ci_other != nullptr)
|
||||||
bel_cells.push_back(ci_other);
|
bel_cells[num_cells++] = ci_other;
|
||||||
}
|
}
|
||||||
}
|
return logicCellsCompatible(bel_cells.data(), num_cells);
|
||||||
return logicCellsCompatible(bel_cells);
|
|
||||||
} else {
|
} else {
|
||||||
CellInfo *ci = getBoundBelCell(bel);
|
CellInfo *ci = getBoundBelCell(bel);
|
||||||
if (ci == nullptr)
|
if (ci == nullptr)
|
||||||
@ -94,17 +96,18 @@ bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const
|
|||||||
if (cell->type == id_ICESTORM_LC) {
|
if (cell->type == id_ICESTORM_LC) {
|
||||||
NPNR_ASSERT(getBelType(bel) == id_ICESTORM_LC);
|
NPNR_ASSERT(getBelType(bel) == id_ICESTORM_LC);
|
||||||
|
|
||||||
std::vector<const CellInfo *> bel_cells;
|
std::array<const CellInfo *, 8> bel_cells;
|
||||||
|
size_t num_cells = 0;
|
||||||
|
|
||||||
Loc bel_loc = getBelLocation(bel);
|
Loc bel_loc = getBelLocation(bel);
|
||||||
for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) {
|
for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) {
|
||||||
CellInfo *ci_other = getBoundBelCell(bel_other);
|
CellInfo *ci_other = getBoundBelCell(bel_other);
|
||||||
if (ci_other != nullptr && bel_other != bel) {
|
if (ci_other != nullptr && bel_other != bel)
|
||||||
bel_cells.push_back(ci_other);
|
bel_cells[num_cells++] = ci_other;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bel_cells.push_back(cell);
|
bel_cells[num_cells++] = cell;
|
||||||
return logicCellsCompatible(bel_cells);
|
return logicCellsCompatible(bel_cells.data(), num_cells);
|
||||||
} else if (cell->type == id_SB_IO) {
|
} else if (cell->type == id_SB_IO) {
|
||||||
// Do not allow placement of input SB_IOs on blocks where there a PLL is outputting to.
|
// Do not allow placement of input SB_IOs on blocks where there a PLL is outputting to.
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ class ChainConstrainer
|
|||||||
}
|
}
|
||||||
tile.push_back(cell);
|
tile.push_back(cell);
|
||||||
chains.back().cells.push_back(cell);
|
chains.back().cells.push_back(cell);
|
||||||
bool split_chain = (!ctx->logicCellsCompatible(tile)) || (int(chains.back().cells.size()) > max_length);
|
bool split_chain = (!ctx->logicCellsCompatible(tile.data(), tile.size())) || (int(chains.back().cells.size()) > max_length);
|
||||||
if (split_chain) {
|
if (split_chain) {
|
||||||
CellInfo *passout = make_carry_pass_out(cell->ports.at(ctx->id("COUT")));
|
CellInfo *passout = make_carry_pass_out(cell->ports.at(ctx->id("COUT")));
|
||||||
tile.pop_back();
|
tile.pop_back();
|
||||||
|
Loading…
Reference in New Issue
Block a user