aboutsummaryrefslogtreecommitdiffstats
path: root/passes/opt/opt_clean.cc
diff options
context:
space:
mode:
Diffstat (limited to 'passes/opt/opt_clean.cc')
-rw-r--r--passes/opt/opt_clean.cc115
1 files changed, 85 insertions, 30 deletions
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 6a7e6051d..6600ffa25 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -2,11 +2,11 @@
* yosys -- Yosys Open SYnthesis Suite
*
* Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
- *
+ *
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
@@ -30,7 +30,55 @@ PRIVATE_NAMESPACE_BEGIN
using RTLIL::id2cstr;
-CellTypes ct, ct_reg, ct_all;
+struct keep_cache_t
+{
+ Design *design;
+ dict<Module*, bool> cache;
+
+ void reset(Design *design = nullptr)
+ {
+ this->design = design;
+ cache.clear();
+ }
+
+ bool query(Module *module)
+ {
+ log_assert(design != nullptr);
+
+ if (module == nullptr)
+ return false;
+
+ if (cache.count(module))
+ return cache.at(module);
+
+ cache[module] = true;
+ if (!module->get_bool_attribute("\\keep")) {
+ bool found_keep = false;
+ for (auto cell : module->cells())
+ if (query(cell)) found_keep = true;
+ cache[module] = found_keep;
+ }
+
+ return cache[module];
+ }
+
+ bool query(Cell *cell)
+ {
+ if (cell->type.in("$memwr", "$meminit", "$assert", "$assume"))
+ return true;
+
+ if (cell->has_keep_attr())
+ return true;
+
+ if (cell->module && cell->module->design)
+ return query(cell->module->design->module(cell->type));
+
+ return false;
+ }
+};
+
+keep_cache_t keep_cache;
+CellTypes ct_reg, ct_all;
int count_rm_cells, count_rm_wires;
void rmunused_module_cells(Module *module, bool verbose)
@@ -42,12 +90,12 @@ void rmunused_module_cells(Module *module, bool verbose)
for (auto &it : module->cells_) {
Cell *cell = it.second;
for (auto &it2 : cell->connections()) {
- if (!ct.cell_input(cell->type, it2.first))
+ if (!ct_all.cell_known(cell->type) || ct_all.cell_output(cell->type, it2.first))
for (auto bit : sigmap(it2.second))
if (bit.wire != nullptr)
wire2driver[bit].insert(cell);
}
- if (cell->type == "$memwr" || cell->type == "$assert" || cell->has_keep_attr())
+ if (keep_cache.query(cell))
queue.insert(cell);
else
unused.insert(cell);
@@ -67,7 +115,7 @@ void rmunused_module_cells(Module *module, bool verbose)
pool<SigBit> bits;
for (auto cell : queue)
for (auto &it : cell->connections())
- if (!ct.cell_output(cell->type, it.first))
+ if (!ct_all.cell_known(cell->type) || ct_all.cell_input(cell->type, it.first))
for (auto bit : sigmap(it.second))
bits.insert(bit);
@@ -108,6 +156,9 @@ bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs, SigPoo
if (w1->port_input != w2->port_input)
return w2->port_input;
+ if ((w1->port_input && w1->port_output) != (w2->port_input && w2->port_output))
+ return !(w2->port_input && w2->port_output);
+
if (w1->name[0] == '\\' && w2->name[0] == '\\') {
if (regs.check_any(s1) != regs.check_any(s2))
return regs.check_any(s2);
@@ -129,7 +180,7 @@ bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs, SigPoo
if (attrs1 != attrs2)
return attrs2 > attrs1;
- return w2->name < w1->name;
+ return strcmp(w2->name.c_str(), w1->name.c_str()) < 0;
}
bool check_public_name(RTLIL::IdString id)
@@ -159,7 +210,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
for (auto &it2 : cell->connections())
connected_signals.add(it2.second);
}
-
+
SigMap assign_map(module);
pool<RTLIL::SigSpec> direct_sigs;
pool<RTLIL::Wire*> direct_wires;
@@ -193,7 +244,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
for (auto &it2 : cell->connections_) {
assign_map.apply(it2.second);
used_signals.add(it2.second);
- if (!ct.cell_output(cell->type, it2.first))
+ if (!ct_all.cell_output(cell->type, it2.first))
used_signals_nodrivers.add(it2.second);
}
}
@@ -216,7 +267,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos
std::vector<RTLIL::Wire*> maybe_del_wires;
for (auto wire : module->wires())
{
- if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0 || wire->get_bool_attribute("\\keep")) {
+ if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0 || wire->get_bool_attribute("\\keep") || wire->attributes.count("\\init")) {
RTLIL::SigSpec s1 = RTLIL::SigSpec(wire), s2 = s1;
assign_map.apply(s2);
if (!used_signals.check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute("\\keep")) {
@@ -296,8 +347,14 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose)
module->connect(y, a);
delcells.push_back(cell);
}
- for (auto cell : delcells)
+ for (auto cell : delcells) {
+ if (verbose)
+ log(" removing buffer cell `%s': %s = %s\n", cell->name.c_str(),
+ log_signal(cell->getPort("\\Y")), log_signal(cell->getPort("\\A")));
module->remove(cell);
+ }
+ if (!delcells.empty())
+ module->design->scratchpad_set_bool("opt.did_something", true);
rmunused_module_cells(module, verbose);
rmunused_module_signals(module, purge_mode, verbose);
@@ -326,7 +383,7 @@ struct OptCleanPass : public Pass {
{
bool purge_mode = false;
- log_header("Executing OPT_CLEAN pass (remove unused cells and wires).\n");
+ log_header(design, "Executing OPT_CLEAN pass (remove unused cells and wires).\n");
log_push();
size_t argidx;
@@ -339,26 +396,30 @@ struct OptCleanPass : public Pass {
}
extra_args(args, argidx, design);
- ct.setup_internals();
- ct.setup_internals_mem();
- ct.setup_stdcells();
- ct.setup_stdcells_mem();
+ keep_cache.reset(design);
ct_reg.setup_internals_mem();
ct_reg.setup_stdcells_mem();
+ ct_all.setup(design);
+
for (auto module : design->selected_whole_modules_warn()) {
if (module->has_processes_warn())
continue;
rmunused_module(module, purge_mode, true);
}
- ct.clear();
+ design->optimize();
+ design->sort();
+ design->check();
+
+ keep_cache.reset();
ct_reg.clear();
+ ct_all.clear();
log_pop();
}
} OptCleanPass;
-
+
struct CleanPass : public Pass {
CleanPass() : Pass("clean", "remove unused cells and wires") { }
virtual void help()
@@ -391,10 +452,7 @@ struct CleanPass : public Pass {
if (argidx < args.size())
extra_args(args, argidx, design);
- ct.setup_internals();
- ct.setup_internals_mem();
- ct.setup_stdcells();
- ct.setup_stdcells_mem();
+ keep_cache.reset(design);
ct_reg.setup_internals_mem();
ct_reg.setup_stdcells_mem();
@@ -404,13 +462,10 @@ struct CleanPass : public Pass {
count_rm_cells = 0;
count_rm_wires = 0;
- for (auto mod : design->selected_whole_modules()) {
- if (mod->has_processes())
+ for (auto module : design->selected_whole_modules()) {
+ if (module->has_processes())
continue;
- do {
- design->scratchpad_unset("opt.did_something");
- rmunused_module(mod, purge_mode, false);
- } while (design->scratchpad_get_bool("opt.did_something"));
+ rmunused_module(module, purge_mode, false);
}
if (count_rm_cells > 0 || count_rm_wires > 0)
@@ -420,10 +475,10 @@ struct CleanPass : public Pass {
design->sort();
design->check();
- ct.clear();
+ keep_cache.reset();
ct_reg.clear();
ct_all.clear();
}
} CleanPass;
-
+
PRIVATE_NAMESPACE_END