39 std::set<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> queue, unused;
42 for (
auto &it : module->
cells_) {
46 wire2driver.
insert(sigmap(it2.second), cell);
53 for (
auto &it : module->
wires_) {
55 if (wire->
port_output || wire->get_bool_attribute(
"\\keep")) {
56 std::set<RTLIL::Cell*> cell_list;
57 wire2driver.
find(sigmap(wire), cell_list);
58 for (
auto cell : cell_list)
63 while (!queue.empty())
65 std::set<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> new_queue;
66 for (
auto cell : queue)
68 for (
auto cell : queue) {
69 for (
auto &it : cell->connections()) {
71 std::set<RTLIL::Cell*> cell_list;
72 wire2driver.
find(sigmap(it.second), cell_list);
73 for (
auto c : cell_list) {
80 queue.swap(new_queue);
83 for (
auto cell : unused) {
85 log(
" removing unused `%s' cell `%s'.\n", cell->type.c_str(), cell->name.c_str());
94 int count = w->attributes.size();
95 count -= w->attributes.count(
"\\src");
96 count -= w->attributes.count(
"\\unused_bits");
111 if (w1->
name[0] ==
'\\' && w2->
name[0] ==
'\\') {
114 if (direct_wires.count(w1) != direct_wires.count(w2))
115 return direct_wires.count(w2) != 0;
124 return w2->
name[0] ==
'\\';
129 if (attrs1 != attrs2)
130 return attrs2 > attrs1;
137 const std::string &id_str =
id.str();
138 if (id_str[0] ==
'$')
140 if (id_str.substr(0, 2) ==
"\\_" && (id_str[id_str.size()-1] ==
'_' || id_str.find(
"_[") != std::string::npos))
142 if (id_str.find(
".$") != std::string::npos)
153 for (
auto &it : module->
cells_) {
158 register_signals.
add(it2.second);
160 connected_signals.
add(it2.second);
164 std::set<RTLIL::SigSpec> direct_sigs;
165 std::set<RTLIL::Wire*> direct_wires;
166 for (
auto &it : module->
cells_) {
171 direct_sigs.insert(assign_map(it2.second));
173 for (
auto &it : module->
wires_) {
174 if (direct_sigs.count(assign_map(it.second)) || it.second->port_input)
175 direct_wires.insert(it.second);
178 for (
auto &it : module->
wires_) {
180 for (
int i = 0; i < wire->
width; i++) {
182 if (!
compare_signals(s1, s2, register_signals, connected_signals, direct_wires))
190 SigPool used_signals_nodrivers;
191 for (
auto &it : module->
cells_) {
194 assign_map.
apply(it2.second);
195 used_signals.
add(it2.second);
197 used_signals_nodrivers.
add(it2.second);
200 for (
auto &it : module->
wires_) {
204 assign_map.
apply(sig);
205 used_signals.
add(sig);
207 used_signals_nodrivers.
add(sig);
209 if (wire->get_bool_attribute(
"\\keep")) {
211 assign_map.
apply(sig);
212 used_signals.
add(sig);
216 std::vector<RTLIL::Wire*> maybe_del_wires;
217 for (
auto wire : module->
wires())
219 if ((!purge_mode &&
check_public_name(wire->name)) || wire->port_id != 0 || wire->get_bool_attribute(
"\\keep")) {
221 assign_map.
apply(s2);
222 if (!used_signals.
check_any(s2) && wire->port_id == 0 && !wire->get_bool_attribute(
"\\keep")) {
223 maybe_del_wires.push_back(wire);
227 for (
int i = 0; i <
GetSize(s1); i++)
228 if (s1[i] != s2[i]) {
229 new_conn.first.append_bit(s1[i]);
230 new_conn.second.append_bit(s2[i]);
232 if (new_conn.first.size() > 0) {
233 used_signals.
add(new_conn.first);
234 used_signals.
add(new_conn.second);
240 maybe_del_wires.push_back(wire);
244 if (!used_signals_nodrivers.
check_any(sig)) {
245 std::string unused_bits;
246 for (
int i = 0; i <
GetSize(sig); i++) {
247 if (sig[i].wire ==
NULL)
249 if (!used_signals_nodrivers.
check(sig[i])) {
250 if (!unused_bits.empty())
252 unused_bits +=
stringf(
"%d", i);
255 if (unused_bits.empty() || wire->port_id != 0)
256 wire->attributes.erase(
"\\unused_bits");
258 wire->attributes[
"\\unused_bits"] =
RTLIL::Const(unused_bits);
260 wire->attributes.erase(
"\\unused_bits");
265 std::set<RTLIL::Wire*> del_wires;
267 int del_wires_count = 0;
268 for (
auto wire : maybe_del_wires)
271 log(
" removing unused non-port wire %s.\n", wire->name.c_str());
274 del_wires.insert(wire);
277 module->
remove(del_wires);
280 if (del_wires_count > 0)
281 log(
" removed %d unused temporary wires.\n", del_wires_count);
287 log(
"Finding unused cells or wires in module %s..\n", module->
name.
c_str());
289 std::vector<RTLIL::Cell*> delcells;
290 for (
auto cell : module->
cells())
291 if (cell->type.in(
"$pos",
"$_BUF_")) {
292 bool is_signed = cell->type ==
"$pos" && cell->getParam(
"\\A_SIGNED").as_bool();
297 delcells.push_back(cell);
299 for (
auto cell : delcells)
312 log(
" opt_clean [options] [selection]\n");
314 log(
"This pass identifies wires and cells that are unused and removes them. Other\n");
315 log(
"passes often remove cells but leave the wires in the design or reconnect the\n");
316 log(
"wires but leave the old cells in the design. This pass can be used to clean up\n");
317 log(
"after the passes that do the actual work.\n");
319 log(
"This pass only operates on completely selected modules without processes.\n");
322 log(
" also remove internal nets if they have a public name\n");
327 bool purge_mode =
false;
329 log_header(
"Executing OPT_CLEAN pass (remove unused cells and wires).\n");
333 for (argidx = 1; argidx < args.size(); argidx++) {
334 if (args[argidx] ==
"-purge") {
350 for (
auto &mod_it : design->
modules_) {
352 if (design->
selected(mod_it.second))
353 log(
"Skipping module %s as it is only partially selected.\n",
id2cstr(mod_it.second->name));
356 if (mod_it.second->processes.size() > 0) {
357 log(
"Skipping module %s as it contains processes.\n", mod_it.second->name.c_str());
375 log(
" clean [options] [selection]\n");
377 log(
"This is identical to 'opt_clean', but less verbose.\n");
379 log(
"When commands are separated using the ';;' token, this command will be executed\n");
380 log(
"between the commands.\n");
382 log(
"When commands are separated using the ';;;' token, this command will be executed\n");
383 log(
"in -purge mode between the commands.\n");
388 bool purge_mode =
false;
391 for (argidx = 1; argidx < args.size(); argidx++) {
392 if (args[argidx] ==
"-purge") {
398 if (argidx < args.size())
409 ct_all.
setup(design);
414 for (
auto &mod_it : design->
modules_) {
const char * c_str() const
bool selected(T1 *module) const
std::string stringf(const char *fmt,...)
void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose)
OptCleanPass OptCleanPass
int count_nontrivial_wire_attrs(RTLIL::Wire *w)
void setup_internals_mem()
void log_header(const char *format,...)
void rmunused_module_cells(RTLIL::Module *module, bool verbose)
void setup(RTLIL::Design *design=NULL)
std::map< RTLIL::IdString, RTLIL::Wire * > wires_
void scratchpad_unset(std::string varname)
bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool ®s, SigPool &conns, std::set< RTLIL::Wire * > &direct_wires)
RTLIL::ObjRange< RTLIL::Wire * > wires()
void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose)
void extend_u0(int width, bool is_signed=false)
std::vector< RTLIL::SigSig > connections_
void apply(RTLIL::SigBit &bit) const
bool check_public_name(RTLIL::IdString id)
bool cell_known(RTLIL::IdString type)
bool check_any(RTLIL::SigSpec sig)
void connect(const RTLIL::SigSig &conn)
#define PRIVATE_NAMESPACE_BEGIN
bool cell_output(RTLIL::IdString type, RTLIL::IdString port)
int GetSize(RTLIL::Wire *wire)
#define log_assert(_assert_expr_)
virtual void execute(std::vector< std::string > args, RTLIL::Design *design)
bool selected_whole_module(RTLIL::IdString mod_name) const
bool scratchpad_get_bool(std::string varname, bool default_value=false) const
#define PRIVATE_NAMESPACE_END
static const char * id2cstr(const RTLIL::IdString &str)
void add(RTLIL::SigSpec sig)
#define USING_YOSYS_NAMESPACE
RTLIL::ObjRange< RTLIL::Cell * > cells()
std::map< RTLIL::IdString, RTLIL::Module * > modules_
bool check(RTLIL::SigBit bit)
std::map< RTLIL::IdString, RTLIL::Cell * > cells_
void remove(const std::set< RTLIL::Wire * > &wires)
void log(const char *format,...)
void scratchpad_set_bool(std::string varname, bool value)
void setup_stdcells_mem()
void add(RTLIL::SigSpec from, RTLIL::SigSpec to)
bool cell_input(RTLIL::IdString type, RTLIL::IdString port)
std::map< RTLIL::IdString, RTLIL::SigSpec > connections_
void extra_args(std::vector< std::string > args, size_t argidx, RTLIL::Design *design, bool select=true)
virtual void execute(std::vector< std::string > args, RTLIL::Design *design)
std::pair< SigSpec, SigSpec > SigSig
const std::map< RTLIL::IdString, RTLIL::SigSpec > & connections() const
void find(RTLIL::SigSpec sig, std::set< T > &result)
void insert(RTLIL::SigSpec sig, T data)
bool has_keep_attr() const