yosys-master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
wreduce.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/yosys.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/modtools.h"
23 
25 using namespace RTLIL;
26 
28 
30 {
31  std::set<IdString> supported_cell_types;
32 
34  {
35  supported_cell_types = std::set<IdString>({
36  "$not", "$pos", "$neg",
37  "$and", "$or", "$xor", "$xnor",
38  "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx",
39  "$lt", "$le", "$eq", "$ne", "$eqx", "$nex", "$ge", "$gt",
40  "$add", "$sub", // "$mul", "$div", "$mod", "$pow",
41  "$mux", "$pmux"
42  });
43  }
44 };
45 
47 {
51 
52  std::set<Cell*, IdString::compare_ptr_by_name<Cell>> work_queue_cells;
53  std::set<SigBit> work_queue_bits;
54 
56  config(config), module(module), mi(module) { }
57 
58  void run_cell_mux(Cell *cell)
59  {
60  // Reduce size of MUX if inputs agree on a value for a bit or a output bit is unused
61 
62  SigSpec sig_a = mi.sigmap(cell->getPort("\\A"));
63  SigSpec sig_b = mi.sigmap(cell->getPort("\\B"));
64  SigSpec sig_s = mi.sigmap(cell->getPort("\\S"));
65  SigSpec sig_y = mi.sigmap(cell->getPort("\\Y"));
66  std::vector<SigBit> bits_removed;
67 
68  for (int i = GetSize(sig_y)-1; i >= 0; i--)
69  {
70  auto info = mi.query(sig_y[i]);
71  if (!info->is_output && GetSize(info->ports) <= 1) {
72  bits_removed.push_back(Sx);
73  continue;
74  }
75 
76  SigBit ref = sig_a[i];
77  for (int k = 0; k < GetSize(sig_s); k++) {
78  if (ref != Sx && sig_b[k*GetSize(sig_a) + i] != Sx && ref != sig_b[k*GetSize(sig_a) + i])
79  goto no_match_ab;
80  if (sig_b[k*GetSize(sig_a) + i] != Sx)
81  ref = sig_b[k*GetSize(sig_a) + i];
82  }
83  if (0)
84  no_match_ab:
85  break;
86  bits_removed.push_back(ref);
87  }
88 
89  if (bits_removed.empty())
90  return;
91 
92  SigSpec sig_removed;
93  for (int i = GetSize(bits_removed)-1; i >= 0; i--)
94  sig_removed.append_bit(bits_removed[i]);
95 
96  if (GetSize(bits_removed) == GetSize(sig_y)) {
97  log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type));
98  module->connect(sig_y, sig_removed);
99  module->remove(cell);
100  return;
101  }
102 
103  log("Removed top %d bits (of %d) from mux cell %s.%s (%s).\n",
104  GetSize(sig_removed), GetSize(sig_y), log_id(module), log_id(cell), log_id(cell->type));
105 
106  int n_removed = GetSize(sig_removed);
107  int n_kept = GetSize(sig_y) - GetSize(sig_removed);
108 
109  SigSpec new_work_queue_bits;
110  new_work_queue_bits.append(sig_a.extract(n_kept, n_removed));
111  new_work_queue_bits.append(sig_y.extract(n_kept, n_removed));
112 
113  SigSpec new_sig_a = sig_a.extract(0, n_kept);
114  SigSpec new_sig_y = sig_y.extract(0, n_kept);
115  SigSpec new_sig_b;
116 
117  for (int k = 0; k < GetSize(sig_s); k++) {
118  new_sig_b.append(sig_b.extract(k*GetSize(sig_a), n_kept));
119  new_work_queue_bits.append(sig_b.extract(k*GetSize(sig_a) + n_kept, n_removed));
120  }
121 
122  for (auto bit : new_work_queue_bits)
123  work_queue_bits.insert(bit);
124 
125  cell->setPort("\\A", new_sig_a);
126  cell->setPort("\\B", new_sig_b);
127  cell->setPort("\\Y", new_sig_y);
128  cell->fixup_parameters();
129 
130  module->connect(sig_y.extract(n_kept, n_removed), sig_removed);
131  }
132 
133  void run_reduce_inport(Cell *cell, char port, int max_port_size, bool &port_signed, bool &did_something)
134  {
135  port_signed = cell->getParam(stringf("\\%c_SIGNED", port)).as_bool();
136  SigSpec sig = mi.sigmap(cell->getPort(stringf("\\%c", port)));
137 
138  if (port == 'B' && cell->type.in("$shl", "$shr", "$sshl", "$sshr"))
139  port_signed = false;
140 
141  int bits_removed = 0;
142  if (GetSize(sig) > max_port_size) {
143  bits_removed = GetSize(sig) - max_port_size;
144  for (auto bit : sig.extract(max_port_size, bits_removed))
145  work_queue_bits.insert(bit);
146  sig = sig.extract(0, max_port_size);
147  }
148 
149  if (port_signed) {
150  while (GetSize(sig) > 1 && sig[GetSize(sig)-1] == sig[GetSize(sig)-2])
151  work_queue_bits.insert(sig[GetSize(sig)-1]), sig.remove(GetSize(sig)-1), bits_removed++;
152  } else {
153  while (GetSize(sig) > 1 && sig[GetSize(sig)-1] == S0)
154  work_queue_bits.insert(sig[GetSize(sig)-1]), sig.remove(GetSize(sig)-1), bits_removed++;
155  }
156 
157  if (bits_removed) {
158  log("Removed top %d bits (of %d) from port %c of cell %s.%s (%s).\n",
159  bits_removed, GetSize(sig) + bits_removed, port, log_id(module), log_id(cell), log_id(cell->type));
160  cell->setPort(stringf("\\%c", port), sig);
161  did_something = true;
162  }
163  }
164 
165  void run_cell(Cell *cell)
166  {
167  bool did_something = false;
168 
169  if (!cell->type.in(config->supported_cell_types))
170  return;
171 
172  if (cell->type.in("$mux", "$pmux"))
173  return run_cell_mux(cell);
174 
175 
176  // Reduce size of ports A and B based on constant input bits and size of output port
177 
178  int max_port_a_size = cell->hasPort("\\A") ? GetSize(cell->getPort("\\A")) : -1;
179  int max_port_b_size = cell->hasPort("\\B") ? GetSize(cell->getPort("\\B")) : -1;
180 
181  if (cell->type.in("$not", "$pos", "$neg", "$and", "$or", "$xor", "$add", "$sub")) {
182  max_port_a_size = std::min(max_port_a_size, GetSize(cell->getPort("\\Y")));
183  max_port_b_size = std::min(max_port_b_size, GetSize(cell->getPort("\\Y")));
184  }
185 
186  bool port_a_signed = false;
187  bool port_b_signed = false;
188 
189  if (max_port_a_size >= 0 && cell->type != "$shiftx")
190  run_reduce_inport(cell, 'A', max_port_a_size, port_a_signed, did_something);
191 
192  if (max_port_b_size >= 0)
193  run_reduce_inport(cell, 'B', max_port_b_size, port_b_signed, did_something);
194 
195 
196  // Reduce size of port Y based on sizes for A and B and unused bits in Y
197 
198  SigSpec sig = mi.sigmap(cell->getPort("\\Y"));
199 
200  int bits_removed = 0;
201  if (port_a_signed && cell->type == "$shr") {
202  // do not reduce size of output on $shr cells with signed A inputs
203  } else {
204  while (GetSize(sig) > 0)
205  {
206  auto info = mi.query(sig[GetSize(sig)-1]);
207 
208  if (info->is_output || GetSize(info->ports) > 1)
209  break;
210 
211  sig.remove(GetSize(sig)-1);
212  bits_removed++;
213  }
214  }
215 
216  if (cell->type.in("$pos", "$add", "$mul", "$and", "$or", "$xor"))
217  {
218  bool is_signed = cell->getParam("\\A_SIGNED").as_bool();
219 
220  int a_size = 0, b_size = 0;
221  if (cell->hasPort("\\A")) a_size = GetSize(cell->getPort("\\A"));
222  if (cell->hasPort("\\B")) b_size = GetSize(cell->getPort("\\B"));
223 
224  int max_y_size = std::max(a_size, b_size);
225 
226  if (cell->type == "$add")
227  max_y_size++;
228 
229  if (cell->type == "$mul")
230  max_y_size = a_size + b_size;
231 
232  while (GetSize(sig) > 1 && GetSize(sig) > max_y_size) {
233  module->connect(sig[GetSize(sig)-1], is_signed ? sig[GetSize(sig)-2] : S0);
234  sig.remove(GetSize(sig)-1);
235  bits_removed++;
236  }
237  }
238 
239  if (GetSize(sig) == 0) {
240  log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type));
241  module->remove(cell);
242  return;
243  }
244 
245  if (bits_removed) {
246  log("Removed top %d bits (of %d) from port Y of cell %s.%s (%s).\n",
247  bits_removed, GetSize(sig) + bits_removed, log_id(module), log_id(cell), log_id(cell->type));
248  cell->setPort("\\Y", sig);
249  did_something = true;
250  }
251 
252  if (did_something) {
253  cell->fixup_parameters();
254  run_cell(cell);
255  }
256  }
257 
259  {
260  int count = w->attributes.size();
261  count -= w->attributes.count("\\src");
262  count -= w->attributes.count("\\unused_bits");
263  return count;
264  }
265 
266  void run()
267  {
268  for (auto c : module->selected_cells())
269  work_queue_cells.insert(c);
270 
271  while (!work_queue_cells.empty())
272  {
273  work_queue_bits.clear();
274  for (auto c : work_queue_cells)
275  run_cell(c);
276 
277  work_queue_cells.clear();
278  for (auto bit : work_queue_bits)
279  for (auto port : mi.query_ports(bit))
280  if (module->selected(port.cell))
281  work_queue_cells.insert(port.cell);
282  }
283 
284  for (auto w : module->selected_wires())
285  {
286  int unused_top_bits = 0;
287 
288  if (w->port_id > 0 || count_nontrivial_wire_attrs(w) > 0)
289  continue;
290 
291  for (int i = GetSize(w)-1; i >= 0; i--) {
292  SigBit bit(w, i);
293  auto info = mi.query(bit);
294  if (info && (info->is_input || info->is_output || GetSize(info->ports) > 0))
295  break;
296  unused_top_bits++;
297  }
298 
299  if (0 < unused_top_bits && unused_top_bits < GetSize(w)) {
300  log("Removed top %d bits (of %d) from wire %s.%s.\n", unused_top_bits, GetSize(w), log_id(module), log_id(w));
301  Wire *nw = module->addWire(NEW_ID, w);
302  nw->width = GetSize(w) - unused_top_bits;
303  module->connect(nw, SigSpec(w).extract(0, GetSize(nw)));
304  module->swap_names(w, nw);
305  }
306  }
307  }
308 };
309 
310 struct WreducePass : public Pass {
311  WreducePass() : Pass("wreduce", "reduce the word size of operations is possible") { }
312  virtual void help()
313  {
314  // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
315  log("\n");
316  log(" wreduce [options] [selection]\n");
317  log("\n");
318  log("This command reduces the word size of operations. For example it will replace\n");
319  log("the 32 bit adders in the following code with adders of more appropriate widths:\n");
320  log("\n");
321  log(" module test(input [3:0] a, b, c, output [7:0] y);\n");
322  log(" assign y = a + b + c + 1;\n");
323  log(" endmodule\n");
324  log("\n");
325  }
326  virtual void execute(std::vector<std::string> args, Design *design)
327  {
328  WreduceConfig config;
329 
330  log_header("Executing WREDUCE pass (reducing word size of cells).\n");
331 
332  size_t argidx;
333  for (argidx = 1; argidx < args.size(); argidx++) {
334  break;
335  }
336  extra_args(args, argidx, design);
337 
338  for (auto module : design->selected_modules())
339  {
340  if (module->has_processes_warn())
341  continue;
342 
343  WreduceWorker worker(&config, module);
344  worker.run();
345  }
346  }
347 } WreducePass;
348 
350 
void fixup_parameters(bool set_a_signed=false, bool set_b_signed=false)
Definition: rtlil.cc:1847
bool as_bool() const
Definition: rtlil.cc:96
std::set< Cell *, IdString::compare_ptr_by_name< Cell > > work_queue_cells
Definition: wreduce.cc:52
Module * module
Definition: wreduce.cc:49
std::string stringf(const char *fmt,...)
Definition: yosys.cc:58
ModIndex mi
Definition: wreduce.cc:50
int count_nontrivial_wire_attrs(RTLIL::Wire *w)
Definition: opt_clean.cc:92
virtual void help()
Definition: wreduce.cc:312
void log_header(const char *format,...)
Definition: log.cc:188
void setPort(RTLIL::IdString portname, RTLIL::SigSpec signal)
Definition: rtlil.cc:1789
int width
Definition: rtlil.h:826
RTLIL::Module * module
Definition: abc.cc:94
void swap_names(RTLIL::Wire *w1, RTLIL::Wire *w2)
Definition: rtlil.cc:1214
RTLIL::IdString type
Definition: rtlil.h:854
void remove(const RTLIL::SigSpec &pattern)
Definition: rtlil.cc:2342
bool in(T first, Args...rest)
Definition: rtlil.h:241
bool has_processes_warn() const
Definition: rtlil.cc:1086
void run()
Definition: wreduce.cc:266
USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN bool did_something
Definition: opt_const.cc:32
std::set< IdString > supported_cell_types
Definition: wreduce.cc:31
void connect(const RTLIL::SigSig &conn)
Definition: rtlil.cc:1278
void append_bit(const RTLIL::SigBit &bit)
Definition: rtlil.cc:2562
bool selected(T *member) const
Definition: rtlil.h:633
#define PRIVATE_NAMESPACE_BEGIN
Definition: yosys.h:97
RTLIL_ATTRIBUTE_MEMBERS bool hasPort(RTLIL::IdString portname) const
Definition: rtlil.cc:1766
void run_cell(Cell *cell)
Definition: wreduce.cc:165
const RTLIL::SigSpec & getPort(RTLIL::IdString portname) const
Definition: rtlil.cc:1809
int GetSize(RTLIL::Wire *wire)
Definition: yosys.cc:334
std::vector< RTLIL::Wire * > selected_wires() const
Definition: rtlil.cc:1093
virtual void execute(std::vector< std::string > args, Design *design)
Definition: wreduce.cc:326
RTLIL::Wire * addWire(RTLIL::IdString name, int width=1)
Definition: rtlil.cc:1331
#define NEW_ID
Definition: yosys.h:166
std::vector< RTLIL::Cell * > selected_cells() const
Definition: rtlil.cc:1103
#define PRIVATE_NAMESPACE_END
Definition: yosys.h:98
void run_cell_mux(Cell *cell)
Definition: wreduce.cc:58
Definition: register.h:27
#define USING_YOSYS_NAMESPACE
Definition: yosys.h:102
void run_reduce_inport(Cell *cell, char port, int max_port_size, bool &port_signed, bool &did_something)
Definition: wreduce.cc:133
void remove(const std::set< RTLIL::Wire * > &wires)
Definition: rtlil.cc:1158
WreduceWorker(WreduceConfig *config, Module *module)
Definition: wreduce.cc:55
void log(const char *format,...)
Definition: log.cc:180
WreducePass WreducePass
const RTLIL::Const & getParam(RTLIL::IdString paramname) const
Definition: rtlil.cc:1834
RTLIL::SigSpec extract(const RTLIL::SigSpec &pattern, const RTLIL::SigSpec *other=NULL) const
Definition: rtlil.cc:2414
static int count_nontrivial_wire_attrs(RTLIL::Wire *w)
Definition: wreduce.cc:258
void append(const RTLIL::SigSpec &signal)
Definition: rtlil.cc:2523
std::vector< RTLIL::Module * > selected_modules() const
Definition: rtlil.cc:416
std::set< SigBit > work_queue_bits
Definition: wreduce.cc:53
const char * log_id(RTLIL::IdString str)
Definition: log.cc:283
WreduceConfig * config
Definition: wreduce.cc:48