yosys-master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
opt_clean.cc
Go to the documentation of this file.
1 /*
2  * yosys -- Yosys Open SYnthesis Suite
3  *
4  * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  *
18  */
19 
20 #include "kernel/register.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/log.h"
23 #include "kernel/celltypes.h"
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <set>
27 
30 
31 using RTLIL::id2cstr;
32 
35 
37 {
38  SigMap sigmap(module);
39  std::set<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> queue, unused;
40 
41  SigSet<RTLIL::Cell*> wire2driver;
42  for (auto &it : module->cells_) {
43  RTLIL::Cell *cell = it.second;
44  for (auto &it2 : cell->connections()) {
45  if (!ct.cell_input(cell->type, it2.first))
46  wire2driver.insert(sigmap(it2.second), cell);
47  }
48  if (cell->type == "$memwr" || cell->type == "$assert" || cell->has_keep_attr())
49  queue.insert(cell);
50  unused.insert(cell);
51  }
52 
53  for (auto &it : module->wires_) {
54  RTLIL::Wire *wire = it.second;
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)
59  queue.insert(cell);
60  }
61  }
62 
63  while (!queue.empty())
64  {
65  std::set<RTLIL::Cell*, RTLIL::sort_by_name_id<RTLIL::Cell>> new_queue;
66  for (auto cell : queue)
67  unused.erase(cell);
68  for (auto cell : queue) {
69  for (auto &it : cell->connections()) {
70  if (!ct.cell_output(cell->type, it.first)) {
71  std::set<RTLIL::Cell*> cell_list;
72  wire2driver.find(sigmap(it.second), cell_list);
73  for (auto c : cell_list) {
74  if (unused.count(c))
75  new_queue.insert(c);
76  }
77  }
78  }
79  }
80  queue.swap(new_queue);
81  }
82 
83  for (auto cell : unused) {
84  if (verbose)
85  log(" removing unused `%s' cell `%s'.\n", cell->type.c_str(), cell->name.c_str());
86  module->design->scratchpad_set_bool("opt.did_something", true);
87  module->remove(cell);
89  }
90 }
91 
93 {
94  int count = w->attributes.size();
95  count -= w->attributes.count("\\src");
96  count -= w->attributes.count("\\unused_bits");
97  return count;
98 }
99 
100 bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs, SigPool &conns, std::set<RTLIL::Wire*> &direct_wires)
101 {
102  RTLIL::Wire *w1 = s1.wire;
103  RTLIL::Wire *w2 = s2.wire;
104 
105  if (w1 == NULL || w2 == NULL)
106  return w2 == NULL;
107 
108  if (w1->port_input != w2->port_input)
109  return w2->port_input;
110 
111  if (w1->name[0] == '\\' && w2->name[0] == '\\') {
112  if (regs.check_any(s1) != regs.check_any(s2))
113  return regs.check_any(s2);
114  if (direct_wires.count(w1) != direct_wires.count(w2))
115  return direct_wires.count(w2) != 0;
116  if (conns.check_any(s1) != conns.check_any(s2))
117  return conns.check_any(s2);
118  }
119 
120  if (w1->port_output != w2->port_output)
121  return w2->port_output;
122 
123  if (w1->name[0] != w2->name[0])
124  return w2->name[0] == '\\';
125 
126  int attrs1 = count_nontrivial_wire_attrs(w1);
127  int attrs2 = count_nontrivial_wire_attrs(w2);
128 
129  if (attrs1 != attrs2)
130  return attrs2 > attrs1;
131 
132  return w2->name < w1->name;
133 }
134 
136 {
137  const std::string &id_str = id.str();
138  if (id_str[0] == '$')
139  return false;
140  if (id_str.substr(0, 2) == "\\_" && (id_str[id_str.size()-1] == '_' || id_str.find("_[") != std::string::npos))
141  return false;
142  if (id_str.find(".$") != std::string::npos)
143  return false;
144  return true;
145 }
146 
147 void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose)
148 {
149  SigPool register_signals;
150  SigPool connected_signals;
151 
152  if (!purge_mode)
153  for (auto &it : module->cells_) {
154  RTLIL::Cell *cell = it.second;
155  if (ct_reg.cell_known(cell->type))
156  for (auto &it2 : cell->connections())
157  if (ct_reg.cell_output(cell->type, it2.first))
158  register_signals.add(it2.second);
159  for (auto &it2 : cell->connections())
160  connected_signals.add(it2.second);
161  }
162 
163  SigMap assign_map(module);
164  std::set<RTLIL::SigSpec> direct_sigs;
165  std::set<RTLIL::Wire*> direct_wires;
166  for (auto &it : module->cells_) {
167  RTLIL::Cell *cell = it.second;
168  if (ct_all.cell_known(cell->type))
169  for (auto &it2 : cell->connections())
170  if (ct_all.cell_output(cell->type, it2.first))
171  direct_sigs.insert(assign_map(it2.second));
172  }
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);
176  }
177 
178  for (auto &it : module->wires_) {
179  RTLIL::Wire *wire = it.second;
180  for (int i = 0; i < wire->width; i++) {
181  RTLIL::SigBit s1 = RTLIL::SigBit(wire, i), s2 = assign_map(s1);
182  if (!compare_signals(s1, s2, register_signals, connected_signals, direct_wires))
183  assign_map.add(s1);
184  }
185  }
186 
187  module->connections_.clear();
188 
189  SigPool used_signals;
190  SigPool used_signals_nodrivers;
191  for (auto &it : module->cells_) {
192  RTLIL::Cell *cell = it.second;
193  for (auto &it2 : cell->connections_) {
194  assign_map.apply(it2.second);
195  used_signals.add(it2.second);
196  if (!ct.cell_output(cell->type, it2.first))
197  used_signals_nodrivers.add(it2.second);
198  }
199  }
200  for (auto &it : module->wires_) {
201  RTLIL::Wire *wire = it.second;
202  if (wire->port_id > 0) {
203  RTLIL::SigSpec sig = RTLIL::SigSpec(wire);
204  assign_map.apply(sig);
205  used_signals.add(sig);
206  if (!wire->port_input)
207  used_signals_nodrivers.add(sig);
208  }
209  if (wire->get_bool_attribute("\\keep")) {
210  RTLIL::SigSpec sig = RTLIL::SigSpec(wire);
211  assign_map.apply(sig);
212  used_signals.add(sig);
213  }
214  }
215 
216  std::vector<RTLIL::Wire*> maybe_del_wires;
217  for (auto wire : module->wires())
218  {
219  if ((!purge_mode && check_public_name(wire->name)) || wire->port_id != 0 || wire->get_bool_attribute("\\keep")) {
220  RTLIL::SigSpec s1 = RTLIL::SigSpec(wire), s2 = s1;
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);
224  } else {
225  log_assert(GetSize(s1) == GetSize(s2));
226  RTLIL::SigSig new_conn;
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]);
231  }
232  if (new_conn.first.size() > 0) {
233  used_signals.add(new_conn.first);
234  used_signals.add(new_conn.second);
235  module->connect(new_conn);
236  }
237  }
238  } else {
239  if (!used_signals.check_any(RTLIL::SigSpec(wire)))
240  maybe_del_wires.push_back(wire);
241  }
242 
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)
248  continue;
249  if (!used_signals_nodrivers.check(sig[i])) {
250  if (!unused_bits.empty())
251  unused_bits += " ";
252  unused_bits += stringf("%d", i);
253  }
254  }
255  if (unused_bits.empty() || wire->port_id != 0)
256  wire->attributes.erase("\\unused_bits");
257  else
258  wire->attributes["\\unused_bits"] = RTLIL::Const(unused_bits);
259  } else {
260  wire->attributes.erase("\\unused_bits");
261  }
262  }
263 
264 
265  std::set<RTLIL::Wire*> del_wires;
266 
267  int del_wires_count = 0;
268  for (auto wire : maybe_del_wires)
269  if (!used_signals.check_any(RTLIL::SigSpec(wire))) {
270  if (check_public_name(wire->name) && verbose) {
271  log(" removing unused non-port wire %s.\n", wire->name.c_str());
272  del_wires_count++;
273  }
274  del_wires.insert(wire);
275  }
276 
277  module->remove(del_wires);
278  count_rm_wires += del_wires.size();;
279 
280  if (del_wires_count > 0)
281  log(" removed %d unused temporary wires.\n", del_wires_count);
282 }
283 
284 void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose)
285 {
286  if (verbose)
287  log("Finding unused cells or wires in module %s..\n", module->name.c_str());
288 
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();
293  RTLIL::SigSpec a = cell->getPort("\\A");
294  RTLIL::SigSpec y = cell->getPort("\\Y");
295  a.extend_u0(GetSize(y), is_signed);
296  module->connect(y, a);
297  delcells.push_back(cell);
298  }
299  for (auto cell : delcells)
300  module->remove(cell);
301 
302  rmunused_module_cells(module, verbose);
303  rmunused_module_signals(module, purge_mode, verbose);
304 }
305 
306 struct OptCleanPass : public Pass {
307  OptCleanPass() : Pass("opt_clean", "remove unused cells and wires") { }
308  virtual void help()
309  {
310  // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
311  log("\n");
312  log(" opt_clean [options] [selection]\n");
313  log("\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");
318  log("\n");
319  log("This pass only operates on completely selected modules without processes.\n");
320  log("\n");
321  log(" -purge\n");
322  log(" also remove internal nets if they have a public name\n");
323  log("\n");
324  }
325  virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
326  {
327  bool purge_mode = false;
328 
329  log_header("Executing OPT_CLEAN pass (remove unused cells and wires).\n");
330  log_push();
331 
332  size_t argidx;
333  for (argidx = 1; argidx < args.size(); argidx++) {
334  if (args[argidx] == "-purge") {
335  purge_mode = true;
336  continue;
337  }
338  break;
339  }
340  extra_args(args, argidx, design);
341 
342  ct.setup_internals();
343  ct.setup_internals_mem();
344  ct.setup_stdcells();
345  ct.setup_stdcells_mem();
346 
347  ct_reg.setup_internals_mem();
348  ct_reg.setup_stdcells_mem();
349 
350  for (auto &mod_it : design->modules_) {
351  if (!design->selected_whole_module(mod_it.first)) {
352  if (design->selected(mod_it.second))
353  log("Skipping module %s as it is only partially selected.\n", id2cstr(mod_it.second->name));
354  continue;
355  }
356  if (mod_it.second->processes.size() > 0) {
357  log("Skipping module %s as it contains processes.\n", mod_it.second->name.c_str());
358  } else {
359  rmunused_module(mod_it.second, purge_mode, true);
360  }
361  }
362 
363  ct.clear();
364  ct_reg.clear();
365  log_pop();
366  }
367 } OptCleanPass;
368 
369 struct CleanPass : public Pass {
370  CleanPass() : Pass("clean", "remove unused cells and wires") { }
371  virtual void help()
372  {
373  // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
374  log("\n");
375  log(" clean [options] [selection]\n");
376  log("\n");
377  log("This is identical to 'opt_clean', but less verbose.\n");
378  log("\n");
379  log("When commands are separated using the ';;' token, this command will be executed\n");
380  log("between the commands.\n");
381  log("\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");
384  log("\n");
385  }
386  virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
387  {
388  bool purge_mode = false;
389 
390  size_t argidx;
391  for (argidx = 1; argidx < args.size(); argidx++) {
392  if (args[argidx] == "-purge") {
393  purge_mode = true;
394  continue;
395  }
396  break;
397  }
398  if (argidx < args.size())
399  extra_args(args, argidx, design);
400 
401  ct.setup_internals();
402  ct.setup_internals_mem();
403  ct.setup_stdcells();
404  ct.setup_stdcells_mem();
405 
406  ct_reg.setup_internals_mem();
407  ct_reg.setup_stdcells_mem();
408 
409  ct_all.setup(design);
410 
411  count_rm_cells = 0;
412  count_rm_wires = 0;
413 
414  for (auto &mod_it : design->modules_) {
415  if (design->selected_whole_module(mod_it.first) && mod_it.second->processes.size() == 0)
416  do {
417  design->scratchpad_unset("opt.did_something");
418  rmunused_module(mod_it.second, purge_mode, false);
419  } while (design->scratchpad_get_bool("opt.did_something"));
420  }
421 
422  if (count_rm_cells > 0 || count_rm_wires > 0)
423  log("Removed %d unused cells and %d unused wires.\n", count_rm_cells, count_rm_wires);
424 
425  ct.clear();
426  ct_reg.clear();
427  ct_all.clear();
428  }
429 } CleanPass;
430 
const char * c_str() const
Definition: rtlil.h:178
bool selected(T1 *module) const
Definition: rtlil.h:551
CellTypes ct_reg
Definition: opt_clean.cc:33
RTLIL::Wire * wire
Definition: rtlil.h:907
void clear()
Definition: celltypes.h:183
CleanPass CleanPass
void setup_stdcells()
Definition: celltypes.h:132
std::string stringf(const char *fmt,...)
Definition: yosys.cc:58
void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose)
Definition: opt_clean.cc:147
OptCleanPass OptCleanPass
int count_nontrivial_wire_attrs(RTLIL::Wire *w)
Definition: opt_clean.cc:92
void setup_internals_mem()
Definition: celltypes.h:115
void log_header(const char *format,...)
Definition: log.cc:188
void rmunused_module_cells(RTLIL::Module *module, bool verbose)
Definition: opt_clean.cc:36
void setup(RTLIL::Design *design=NULL)
Definition: celltypes.h:47
CellTypes ct
Definition: opt_clean.cc:33
CellTypes ct_all
Definition: opt_clean.cc:33
std::map< RTLIL::IdString, RTLIL::Wire * > wires_
Definition: rtlil.h:595
void scratchpad_unset(std::string varname)
Definition: rtlil.cc:286
bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs, SigPool &conns, std::set< RTLIL::Wire * > &direct_wires)
Definition: opt_clean.cc:100
bool port_input
Definition: rtlil.h:827
RTLIL::ObjRange< RTLIL::Wire * > wires()
Definition: rtlil.h:640
int width
Definition: rtlil.h:826
void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose)
Definition: opt_clean.cc:284
RTLIL::Module * module
Definition: abc.cc:94
virtual void help()
Definition: opt_clean.cc:371
int port_id
Definition: rtlil.h:826
RTLIL::IdString type
Definition: rtlil.h:854
void log_pop()
Definition: log.cc:237
void extend_u0(int width, bool is_signed=false)
Definition: rtlil.cc:2612
std::vector< RTLIL::SigSig > connections_
Definition: rtlil.h:597
virtual void help()
Definition: opt_clean.cc:308
void apply(RTLIL::SigBit &bit) const
Definition: sigtools.h:383
SigMap assign_map
Definition: abc.cc:93
bool port_output
Definition: rtlil.h:827
bool check_public_name(RTLIL::IdString id)
Definition: opt_clean.cc:135
bool cell_known(RTLIL::IdString type)
Definition: celltypes.h:188
bool check_any(RTLIL::SigSpec sig)
Definition: sigtools.h:100
void connect(const RTLIL::SigSig &conn)
Definition: rtlil.cc:1278
#define PRIVATE_NAMESPACE_BEGIN
Definition: yosys.h:97
bool cell_output(RTLIL::IdString type, RTLIL::IdString port)
Definition: celltypes.h:193
int GetSize(RTLIL::Wire *wire)
Definition: yosys.cc:334
#define log_assert(_assert_expr_)
Definition: log.h:85
RTLIL::IdString name
Definition: rtlil.h:599
virtual void execute(std::vector< std::string > args, RTLIL::Design *design)
Definition: opt_clean.cc:386
bool selected_whole_module(RTLIL::IdString mod_name) const
Definition: rtlil.cc:388
bool scratchpad_get_bool(std::string varname, bool default_value=false) const
Definition: rtlil.cc:324
#define PRIVATE_NAMESPACE_END
Definition: yosys.h:98
Definition: register.h:27
RTLIL::IdString name
Definition: rtlil.h:825
static const char * id2cstr(const RTLIL::IdString &str)
Definition: rtlil.h:267
void add(RTLIL::SigSpec sig)
Definition: sigtools.h:41
#define USING_YOSYS_NAMESPACE
Definition: yosys.h:102
RTLIL::ObjRange< RTLIL::Cell * > cells()
Definition: rtlil.h:641
std::map< RTLIL::IdString, RTLIL::Module * > modules_
Definition: rtlil.h:507
int count_rm_cells
Definition: opt_clean.cc:34
bool check(RTLIL::SigBit bit)
Definition: sigtools.h:95
#define NULL
std::map< RTLIL::IdString, RTLIL::Cell * > cells_
Definition: rtlil.h:596
void remove(const std::set< RTLIL::Wire * > &wires)
Definition: rtlil.cc:1158
int count_rm_wires
Definition: opt_clean.cc:34
void log(const char *format,...)
Definition: log.cc:180
void setup_internals()
Definition: celltypes.h:83
void scratchpad_set_bool(std::string varname, bool value)
Definition: rtlil.cc:296
void log_push()
Definition: log.cc:232
void setup_stdcells_mem()
Definition: celltypes.h:149
void add(RTLIL::SigSpec from, RTLIL::SigSpec to)
Definition: sigtools.h:347
bool cell_input(RTLIL::IdString type, RTLIL::IdString port)
Definition: celltypes.h:199
std::map< RTLIL::IdString, RTLIL::SigSpec > connections_
Definition: rtlil.h:855
RTLIL::Design * design
Definition: rtlil.h:589
void extra_args(std::vector< std::string > args, size_t argidx, RTLIL::Design *design, bool select=true)
Definition: register.cc:128
virtual void execute(std::vector< std::string > args, RTLIL::Design *design)
Definition: opt_clean.cc:325
std::pair< SigSpec, SigSpec > SigSig
Definition: rtlil.h:71
const std::map< RTLIL::IdString, RTLIL::SigSpec > & connections() const
Definition: rtlil.cc:1814
void find(RTLIL::SigSpec sig, std::set< T > &result)
Definition: sigtools.h:187
void insert(RTLIL::SigSpec sig, T data)
Definition: sigtools.h:152
bool has_keep_attr() const
Definition: rtlil.h:875