Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

opt_expr: limit effort to reduce runtime on anomalous designs #4782

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 60 additions & 34 deletions passes/opt/opt_expr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

bool did_something;
int sort_fails = 0;

void replace_undriven(RTLIL::Module *module, const CellTypes &ct)
{
Expand Down Expand Up @@ -393,7 +394,7 @@ int get_highest_hot_index(RTLIL::SigSpec signal)
return -1;
}

void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc, bool noclkinv)
void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool consume_x, bool mux_undef, bool mux_bool, bool do_fine, bool keepdc, bool noclkinv, int effort)
{
SigMap assign_map(module);
dict<RTLIL::SigSpec, RTLIL::SigSpec> invert_map;
Expand Down Expand Up @@ -490,35 +491,51 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
handle_clkpol_celltype_swap(cell, "$_DLATCHSR_??N_", "$_DLATCHSR_??P_", ID::R, assign_map, invert_map);
}

TopoSort<RTLIL::Cell*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Cell>> cells;
dict<RTLIL::SigBit, Cell*> outbit_to_cell;

for (auto cell : module->cells())
if (design->selected(module, cell) && yosys_celltypes.cell_evaluable(cell->type)) {
for (auto &conn : cell->connections())
if (yosys_celltypes.cell_output(cell->type, conn.first))
for (auto bit : assign_map(conn.second))
outbit_to_cell[bit] = cell;
cells.node(cell);
}

for (auto cell : module->cells())
if (design->selected(module, cell) && yosys_celltypes.cell_evaluable(cell->type)) {
const int r_index = cells.node(cell);
for (auto &conn : cell->connections())
if (yosys_celltypes.cell_input(cell->type, conn.first))
for (auto bit : assign_map(conn.second))
if (outbit_to_cell.count(bit))
cells.edge(cells.node(outbit_to_cell.at(bit)), r_index);
}

if (!cells.sort()) {
// There might be a combinational loop, or there might be constants on the output of cells. 'check' may find out more.
// ...unless this is a coarse-grained cell loop, but not a bit loop, in which case it won't, and all is good.
log("Couldn't topologically sort cells, optimizing module %s may take a longer time.\n", log_id(module));
}

for (auto cell : cells.sorted)
std::vector<Cell*> module_cells = module->cells();
auto iterator = [&](auto&& replace_cell) {
if (sort_fails >= effort) {
// log("Running on unsorted")
for (auto cell : module_cells)
if (design->selected(module, cell) && yosys_celltypes.cell_evaluable(cell->type))
replace_cell(cell);
} else {
TopoSort<RTLIL::Cell*, RTLIL::IdString::compare_ptr_by_name<RTLIL::Cell>> cells;
dict<RTLIL::SigBit, Cell*> outbit_to_cell;

for (auto cell : module->cells())
if (design->selected(module, cell) && yosys_celltypes.cell_evaluable(cell->type)) {
for (auto &conn : cell->connections())
if (yosys_celltypes.cell_output(cell->type, conn.first))
for (auto bit : assign_map(conn.second))
outbit_to_cell[bit] = cell;
cells.node(cell);
}

for (auto cell : module->cells())
if (design->selected(module, cell) && yosys_celltypes.cell_evaluable(cell->type)) {
const int r_index = cells.node(cell);
for (auto &conn : cell->connections())
if (yosys_celltypes.cell_input(cell->type, conn.first))
for (auto bit : assign_map(conn.second))
if (outbit_to_cell.count(bit))
cells.edge(cells.node(outbit_to_cell.at(bit)), r_index);
}

if (sort_fails < effort && !cells.sort()) {
// There might be a combinational loop, or there might be constants on the output of cells. 'check' may find out more.
// ...unless this is a coarse-grained cell loop, but not a bit loop, in which case it won't, and all is good.
log("Couldn't topologically sort cells, optimizing module %s may take a longer time.\n", log_id(module));
sort_fails++;
if (sort_fails >= effort)
log("Effort of %d exceeded, no longer attempting toposort on module %s.\n",
effort, log_id(module));
}
for (auto cell : cells.sorted) {
replace_cell(cell);
}
}
};
iterator([&](auto& cell)
{
#define ACTION_DO(_p_, _s_) do { cover("opt.opt_expr.action_" S__LINE__); replace_cell(assign_map, module, cell, input.as_string(), _p_, _s_); goto next_cell; } while (0)
#define ACTION_DO_Y(_v_) ACTION_DO(ID::Y, RTLIL::SigSpec(RTLIL::State::S ## _v_))
Expand Down Expand Up @@ -2198,7 +2215,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons
#undef ACTION_DO_Y
#undef FOLD_1ARG_CELL
#undef FOLD_2ARG_CELL
}
});
}

void replace_const_connections(RTLIL::Module *module) {
Expand Down Expand Up @@ -2253,6 +2270,10 @@ struct OptExprPass : public Pass {
log(" all result bits to be set to x. this behavior changes when 'a+0' is\n");
log(" replaced by 'a'. the -keepdc option disables all such optimizations.\n");
log("\n");
log(" -effort N\n");
log(" allow toposort to fail in N iterations on each module before giving up\n");
log(" on sorting for that module. Default value is 5\n");
log("\n");
}
void execute(std::vector<std::string> args, RTLIL::Design *design) override
{
Expand All @@ -2262,7 +2283,7 @@ struct OptExprPass : public Pass {
bool noclkinv = false;
bool do_fine = false;
bool keepdc = false;

int effort = 5;
log_header(design, "Executing OPT_EXPR pass (perform const folding).\n");
log_push();

Expand Down Expand Up @@ -2299,6 +2320,10 @@ struct OptExprPass : public Pass {
keepdc = true;
continue;
}
if (args[argidx] == "-effort" && argidx + 1 < args.size()) {
effort = atoi(args[++argidx].c_str());
continue;
}
break;
}
extra_args(args, argidx, design);
Expand All @@ -2315,15 +2340,16 @@ struct OptExprPass : public Pass {
design->scratchpad_set_bool("opt.did_something", true);
}

sort_fails = 0;
do {
do {
did_something = false;
replace_const_cells(design, module, false /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, noclkinv);
replace_const_cells(design, module, false /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, noclkinv, effort);
if (did_something)
design->scratchpad_set_bool("opt.did_something", true);
} while (did_something);
if (!keepdc)
replace_const_cells(design, module, true /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, noclkinv);
replace_const_cells(design, module, true /* consume_x */, mux_undef, mux_bool, do_fine, keepdc, noclkinv, effort);
if (did_something)
design->scratchpad_set_bool("opt.did_something", true);
} while (did_something);
Expand Down
Loading