Fix "tee" handling of log_streams
[yosys.git] / passes / opt / opt_clean.cc
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
28 USING_YOSYS_NAMESPACE
29 PRIVATE_NAMESPACE_BEGIN
30
31 using RTLIL::id2cstr;
32
33 struct keep_cache_t
34 {
35 Design *design;
36 dict<Module*, bool> cache;
37
38 void reset(Design *design = nullptr)
39 {
40 this->design = design;
41 cache.clear();
42 }
43
44 bool query(Module *module)
45 {
46 log_assert(design != nullptr);
47
48 if (module == nullptr)
49 return false;
50
51 if (cache.count(module))
52 return cache.at(module);
53
54 cache[module] = true;
55 if (!module->get_bool_attribute("\\keep")) {
56 bool found_keep = false;
57 for (auto cell : module->cells())
58 if (query(cell)) found_keep = true;
59 cache[module] = found_keep;
60 }
61
62 return cache[module];
63 }
64
65 bool query(Cell *cell)
66 {
67 if (cell->type.in("$memwr", "$meminit", "$assert", "$assume", "$live", "$fair", "$cover", "$specify2", "$specify3", "$specrule"))
68 return true;
69
70 if (cell->has_keep_attr())
71 return true;
72
73 if (cell->module && cell->module->design)
74 return query(cell->module->design->module(cell->type));
75
76 return false;
77 }
78 };
79
80 keep_cache_t keep_cache;
81 CellTypes ct_reg, ct_all;
82 int count_rm_cells, count_rm_wires;
83
84 void rmunused_module_cells(Module *module, bool verbose)
85 {
86 SigMap sigmap(module);
87 pool<Cell*> queue, unused;
88 pool<SigBit> used_raw_bits;
89 dict<SigBit, pool<Cell*>> wire2driver;
90 dict<SigBit, vector<string>> driver_driver_logs;
91
92 SigMap raw_sigmap;
93 for (auto &it : module->connections_) {
94 for (int i = 0; i < GetSize(it.second); i++) {
95 if (it.second[i].wire != nullptr)
96 raw_sigmap.add(it.first[i], it.second[i]);
97 }
98 }
99
100 for (auto &it : module->cells_) {
101 Cell *cell = it.second;
102 for (auto &it2 : cell->connections()) {
103 if (ct_all.cell_known(cell->type) && !ct_all.cell_output(cell->type, it2.first))
104 continue;
105 for (auto raw_bit : it2.second) {
106 if (raw_bit.wire == nullptr)
107 continue;
108 auto bit = sigmap(raw_bit);
109 if (bit.wire == nullptr)
110 driver_driver_logs[raw_sigmap(raw_bit)].push_back(stringf("Driver-driver conflict "
111 "for %s between cell %s.%s and constant %s in %s: Resolved using constant.",
112 log_signal(raw_bit), log_id(cell), log_id(it2.first), log_signal(bit), log_id(module)));
113 if (bit.wire != nullptr)
114 wire2driver[bit].insert(cell);
115 }
116 }
117 if (keep_cache.query(cell))
118 queue.insert(cell);
119 else
120 unused.insert(cell);
121 }
122
123 for (auto &it : module->wires_) {
124 Wire *wire = it.second;
125 if (wire->port_output || wire->get_bool_attribute("\\keep")) {
126 for (auto bit : sigmap(wire))
127 for (auto c : wire2driver[bit])
128 queue.insert(c), unused.erase(c);
129 for (auto raw_bit : SigSpec(wire))
130 used_raw_bits.insert(raw_sigmap(raw_bit));
131 }
132 }
133
134 while (!queue.empty())
135 {
136 pool<SigBit> bits;
137 for (auto cell : queue)
138 for (auto &it : cell->connections())
139 if (!ct_all.cell_known(cell->type) || ct_all.cell_input(cell->type, it.first))
140 for (auto bit : sigmap(it.second))
141 bits.insert(bit);
142
143 queue.clear();
144 for (auto bit : bits)
145 for (auto c : wire2driver[bit])
146 if (unused.count(c))
147 queue.insert(c), unused.erase(c);
148 }
149
150 unused.sort(RTLIL::sort_by_name_id<RTLIL::Cell>());
151
152 for (auto cell : unused) {
153 if (verbose)
154 log_debug(" removing unused `%s' cell `%s'.\n", cell->type.c_str(), cell->name.c_str());
155 module->design->scratchpad_set_bool("opt.did_something", true);
156 module->remove(cell);
157 count_rm_cells++;
158 }
159
160 for (auto &it : module->cells_) {
161 Cell *cell = it.second;
162 for (auto &it2 : cell->connections()) {
163 if (ct_all.cell_known(cell->type) && !ct_all.cell_input(cell->type, it2.first))
164 continue;
165 for (auto raw_bit : raw_sigmap(it2.second))
166 used_raw_bits.insert(raw_bit);
167 }
168 }
169
170 for (auto it : driver_driver_logs) {
171 if (used_raw_bits.count(it.first))
172 for (auto msg : it.second)
173 log_warning("%s\n", msg.c_str());
174 }
175 }
176
177 int count_nontrivial_wire_attrs(RTLIL::Wire *w)
178 {
179 int count = w->attributes.size();
180 count -= w->attributes.count("\\src");
181 count -= w->attributes.count("\\unused_bits");
182 return count;
183 }
184
185 bool compare_signals(RTLIL::SigBit &s1, RTLIL::SigBit &s2, SigPool &regs, SigPool &conns, pool<RTLIL::Wire*> &direct_wires)
186 {
187 RTLIL::Wire *w1 = s1.wire;
188 RTLIL::Wire *w2 = s2.wire;
189
190 if (w1 == NULL || w2 == NULL)
191 return w2 == NULL;
192
193 if (w1->port_input != w2->port_input)
194 return w2->port_input;
195
196 if ((w1->port_input && w1->port_output) != (w2->port_input && w2->port_output))
197 return !(w2->port_input && w2->port_output);
198
199 if (w1->name[0] == '\\' && w2->name[0] == '\\') {
200 if (regs.check_any(s1) != regs.check_any(s2))
201 return regs.check_any(s2);
202 if (direct_wires.count(w1) != direct_wires.count(w2))
203 return direct_wires.count(w2) != 0;
204 if (conns.check_any(s1) != conns.check_any(s2))
205 return conns.check_any(s2);
206 }
207
208 if (w1->port_output != w2->port_output)
209 return w2->port_output;
210
211 if (w1->name[0] != w2->name[0])
212 return w2->name[0] == '\\';
213
214 int attrs1 = count_nontrivial_wire_attrs(w1);
215 int attrs2 = count_nontrivial_wire_attrs(w2);
216
217 if (attrs1 != attrs2)
218 return attrs2 > attrs1;
219
220 return strcmp(w2->name.c_str(), w1->name.c_str()) < 0;
221 }
222
223 bool check_public_name(RTLIL::IdString id)
224 {
225 const std::string &id_str = id.str();
226 if (id_str[0] == '$')
227 return false;
228 if (id_str.substr(0, 2) == "\\_" && (id_str[id_str.size()-1] == '_' || id_str.find("_[") != std::string::npos))
229 return false;
230 if (id_str.find(".$") != std::string::npos)
231 return false;
232 return true;
233 }
234
235 bool rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbose)
236 {
237 SigPool register_signals;
238 SigPool connected_signals;
239
240 if (!purge_mode)
241 for (auto &it : module->cells_) {
242 RTLIL::Cell *cell = it.second;
243 if (ct_reg.cell_known(cell->type))
244 for (auto &it2 : cell->connections())
245 if (ct_reg.cell_output(cell->type, it2.first))
246 register_signals.add(it2.second);
247 for (auto &it2 : cell->connections())
248 connected_signals.add(it2.second);
249 }
250
251 SigMap assign_map(module);
252 pool<RTLIL::SigSpec> direct_sigs;
253 pool<RTLIL::Wire*> direct_wires;
254 for (auto &it : module->cells_) {
255 RTLIL::Cell *cell = it.second;
256 if (ct_all.cell_known(cell->type))
257 for (auto &it2 : cell->connections())
258 if (ct_all.cell_output(cell->type, it2.first))
259 direct_sigs.insert(assign_map(it2.second));
260 }
261 for (auto &it : module->wires_) {
262 if (direct_sigs.count(assign_map(it.second)) || it.second->port_input)
263 direct_wires.insert(it.second);
264 }
265
266 for (auto &it : module->wires_) {
267 RTLIL::Wire *wire = it.second;
268 for (int i = 0; i < wire->width; i++) {
269 RTLIL::SigBit s1 = RTLIL::SigBit(wire, i), s2 = assign_map(s1);
270 if (!compare_signals(s1, s2, register_signals, connected_signals, direct_wires))
271 assign_map.add(s1);
272 }
273 }
274
275 module->connections_.clear();
276
277 SigPool used_signals;
278 SigPool raw_used_signals;
279 SigPool used_signals_nodrivers;
280 for (auto &it : module->cells_) {
281 RTLIL::Cell *cell = it.second;
282 for (auto &it2 : cell->connections_) {
283 assign_map.apply(it2.second);
284 raw_used_signals.add(it2.second);
285 used_signals.add(it2.second);
286 if (!ct_all.cell_output(cell->type, it2.first))
287 used_signals_nodrivers.add(it2.second);
288 }
289 }
290 for (auto &it : module->wires_) {
291 RTLIL::Wire *wire = it.second;
292 if (wire->port_id > 0) {
293 RTLIL::SigSpec sig = RTLIL::SigSpec(wire);
294 raw_used_signals.add(sig);
295 assign_map.apply(sig);
296 used_signals.add(sig);
297 if (!wire->port_input)
298 used_signals_nodrivers.add(sig);
299 }
300 if (wire->get_bool_attribute("\\keep")) {
301 RTLIL::SigSpec sig = RTLIL::SigSpec(wire);
302 assign_map.apply(sig);
303 used_signals.add(sig);
304 }
305 }
306
307 pool<RTLIL::Wire*> del_wires_queue;
308 for (auto wire : module->wires())
309 {
310 SigSpec s1 = SigSpec(wire), s2 = assign_map(s1);
311 log_assert(GetSize(s1) == GetSize(s2));
312
313 Const initval;
314 if (wire->attributes.count("\\init"))
315 initval = wire->attributes.at("\\init");
316 if (GetSize(initval) != GetSize(wire))
317 initval.bits.resize(GetSize(wire), State::Sx);
318 if (initval.is_fully_undef())
319 wire->attributes.erase("\\init");
320
321 if (GetSize(wire) == 0) {
322 // delete zero-width wires, unless they are module ports
323 if (wire->port_id == 0)
324 goto delete_this_wire;
325 } else
326 if (wire->port_id != 0 || wire->get_bool_attribute("\\keep") || !initval.is_fully_undef()) {
327 // do not delete anything with "keep" or module ports or initialized wires
328 } else
329 if (!purge_mode && check_public_name(wire->name)) {
330 // do not get rid of public names unless in purge mode
331 } else
332 if (!raw_used_signals.check_any(s1)) {
333 // delete wires that aren't used by anything directly
334 goto delete_this_wire;
335 } else
336 if (!used_signals.check_any(s2)) {
337 // delete wires that aren't used by anything indirectly, even though other wires may alias it
338 goto delete_this_wire;
339 }
340
341 if (0)
342 {
343 delete_this_wire:
344 del_wires_queue.insert(wire);
345 }
346 else
347 {
348 RTLIL::SigSig new_conn;
349 for (int i = 0; i < GetSize(s1); i++)
350 if (s1[i] != s2[i]) {
351 if (s2[i] == State::Sx && (initval[i] == State::S0 || initval[i] == State::S1)) {
352 s2[i] = initval[i];
353 initval[i] = State::Sx;
354 }
355 new_conn.first.append_bit(s1[i]);
356 new_conn.second.append_bit(s2[i]);
357 }
358 if (new_conn.first.size() > 0) {
359 if (initval.is_fully_undef())
360 wire->attributes.erase("\\init");
361 else
362 wire->attributes.at("\\init") = initval;
363 used_signals.add(new_conn.first);
364 used_signals.add(new_conn.second);
365 module->connect(new_conn);
366 }
367
368 if (!used_signals_nodrivers.check_all(s2)) {
369 std::string unused_bits;
370 for (int i = 0; i < GetSize(s2); i++) {
371 if (s2[i].wire == NULL)
372 continue;
373 if (!used_signals_nodrivers.check(s2[i])) {
374 if (!unused_bits.empty())
375 unused_bits += " ";
376 unused_bits += stringf("%d", i);
377 }
378 }
379 if (unused_bits.empty() || wire->port_id != 0)
380 wire->attributes.erase("\\unused_bits");
381 else
382 wire->attributes["\\unused_bits"] = RTLIL::Const(unused_bits);
383 } else {
384 wire->attributes.erase("\\unused_bits");
385 }
386 }
387 }
388
389 int del_temp_wires_count = 0;
390 for (auto wire : del_wires_queue) {
391 if (ys_debug() || (check_public_name(wire->name) && verbose))
392 log_debug(" removing unused non-port wire %s.\n", wire->name.c_str());
393 else
394 del_temp_wires_count++;
395 }
396
397 module->remove(del_wires_queue);
398 count_rm_wires += GetSize(del_wires_queue);
399
400 if (verbose && del_temp_wires_count)
401 log_debug(" removed %d unused temporary wires.\n", del_temp_wires_count);
402
403 return !del_wires_queue.empty();
404 }
405
406 bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose)
407 {
408 bool did_something = false;
409 CellTypes fftypes;
410 fftypes.setup_internals_mem();
411
412 SigMap sigmap(module);
413 dict<SigBit, State> qbits;
414
415 for (auto cell : module->cells())
416 if (fftypes.cell_known(cell->type) && cell->hasPort("\\Q"))
417 {
418 SigSpec sig = cell->getPort("\\Q");
419
420 for (int i = 0; i < GetSize(sig); i++)
421 {
422 SigBit bit = sig[i];
423
424 if (bit.wire == nullptr || bit.wire->attributes.count("\\init") == 0)
425 continue;
426
427 Const init = bit.wire->attributes.at("\\init");
428
429 if (i >= GetSize(init) || init[i] == State::Sx || init[i] == State::Sz)
430 continue;
431
432 sigmap.add(bit);
433 qbits[bit] = init[i];
434 }
435 }
436
437 for (auto wire : module->wires())
438 {
439 if (!purge_mode && wire->name[0] == '\\')
440 continue;
441
442 if (wire->attributes.count("\\init") == 0)
443 continue;
444
445 Const init = wire->attributes.at("\\init");
446
447 for (int i = 0; i < GetSize(wire) && i < GetSize(init); i++)
448 {
449 if (init[i] == State::Sx || init[i] == State::Sz)
450 continue;
451
452 SigBit wire_bit = SigBit(wire, i);
453 SigBit mapped_wire_bit = sigmap(wire_bit);
454
455 if (wire_bit == mapped_wire_bit)
456 goto next_wire;
457
458 if (qbits.count(sigmap(SigBit(wire, i))) == 0)
459 goto next_wire;
460
461 if (qbits.at(sigmap(SigBit(wire, i))) != init[i])
462 goto next_wire;
463 }
464
465 if (verbose)
466 log_debug(" removing redundant init attribute on %s.\n", log_id(wire));
467
468 wire->attributes.erase("\\init");
469 did_something = true;
470 next_wire:;
471 }
472
473 return did_something;
474 }
475
476 void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool rminit)
477 {
478 if (verbose)
479 log("Finding unused cells or wires in module %s..\n", module->name.c_str());
480
481 std::vector<RTLIL::Cell*> delcells;
482 for (auto cell : module->cells())
483 if (cell->type.in("$pos", "$_BUF_")) {
484 bool is_signed = cell->type == "$pos" && cell->getParam("\\A_SIGNED").as_bool();
485 RTLIL::SigSpec a = cell->getPort("\\A");
486 RTLIL::SigSpec y = cell->getPort("\\Y");
487 a.extend_u0(GetSize(y), is_signed);
488 module->connect(y, a);
489 delcells.push_back(cell);
490 }
491 for (auto cell : delcells) {
492 if (verbose)
493 log_debug(" removing buffer cell `%s': %s = %s\n", cell->name.c_str(),
494 log_signal(cell->getPort("\\Y")), log_signal(cell->getPort("\\A")));
495 module->remove(cell);
496 }
497 if (!delcells.empty())
498 module->design->scratchpad_set_bool("opt.did_something", true);
499
500 rmunused_module_cells(module, verbose);
501 while (rmunused_module_signals(module, purge_mode, verbose)) { }
502
503 if (rminit && rmunused_module_init(module, purge_mode, verbose))
504 while (rmunused_module_signals(module, purge_mode, verbose)) { }
505 }
506
507 struct OptCleanPass : public Pass {
508 OptCleanPass() : Pass("opt_clean", "remove unused cells and wires") { }
509 void help() YS_OVERRIDE
510 {
511 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
512 log("\n");
513 log(" opt_clean [options] [selection]\n");
514 log("\n");
515 log("This pass identifies wires and cells that are unused and removes them. Other\n");
516 log("passes often remove cells but leave the wires in the design or reconnect the\n");
517 log("wires but leave the old cells in the design. This pass can be used to clean up\n");
518 log("after the passes that do the actual work.\n");
519 log("\n");
520 log("This pass only operates on completely selected modules without processes.\n");
521 log("\n");
522 log(" -purge\n");
523 log(" also remove internal nets if they have a public name\n");
524 log("\n");
525 }
526 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
527 {
528 bool purge_mode = false;
529
530 log_header(design, "Executing OPT_CLEAN pass (remove unused cells and wires).\n");
531 log_push();
532
533 size_t argidx;
534 for (argidx = 1; argidx < args.size(); argidx++) {
535 if (args[argidx] == "-purge") {
536 purge_mode = true;
537 continue;
538 }
539 break;
540 }
541 extra_args(args, argidx, design);
542
543 keep_cache.reset(design);
544
545 ct_reg.setup_internals_mem();
546 ct_reg.setup_stdcells_mem();
547
548 ct_all.setup(design);
549
550 count_rm_cells = 0;
551 count_rm_wires = 0;
552
553 for (auto module : design->selected_whole_modules_warn()) {
554 if (module->has_processes_warn())
555 continue;
556 rmunused_module(module, purge_mode, true, true);
557 }
558
559 if (count_rm_cells > 0 || count_rm_wires > 0)
560 log("Removed %d unused cells and %d unused wires.\n", count_rm_cells, count_rm_wires);
561
562 design->optimize();
563 design->sort();
564 design->check();
565
566 keep_cache.reset();
567 ct_reg.clear();
568 ct_all.clear();
569 log_pop();
570 }
571 } OptCleanPass;
572
573 struct CleanPass : public Pass {
574 CleanPass() : Pass("clean", "remove unused cells and wires") { }
575 void help() YS_OVERRIDE
576 {
577 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
578 log("\n");
579 log(" clean [options] [selection]\n");
580 log("\n");
581 log("This is identical to 'opt_clean', but less verbose.\n");
582 log("\n");
583 log("When commands are separated using the ';;' token, this command will be executed\n");
584 log("between the commands.\n");
585 log("\n");
586 log("When commands are separated using the ';;;' token, this command will be executed\n");
587 log("in -purge mode between the commands.\n");
588 log("\n");
589 }
590 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
591 {
592 bool purge_mode = false;
593
594 size_t argidx;
595 for (argidx = 1; argidx < args.size(); argidx++) {
596 if (args[argidx] == "-purge") {
597 purge_mode = true;
598 continue;
599 }
600 break;
601 }
602 if (argidx < args.size())
603 extra_args(args, argidx, design);
604
605 keep_cache.reset(design);
606
607 ct_reg.setup_internals_mem();
608 ct_reg.setup_stdcells_mem();
609
610 ct_all.setup(design);
611
612 count_rm_cells = 0;
613 count_rm_wires = 0;
614
615 for (auto module : design->selected_whole_modules()) {
616 if (module->has_processes())
617 continue;
618 rmunused_module(module, purge_mode, ys_debug(), false);
619 }
620
621 log_suppressed();
622 if (count_rm_cells > 0 || count_rm_wires > 0)
623 log("Removed %d unused cells and %d unused wires.\n", count_rm_cells, count_rm_wires);
624
625 design->optimize();
626 design->sort();
627 design->check();
628
629 keep_cache.reset();
630 ct_reg.clear();
631 ct_all.clear();
632 }
633 } CleanPass;
634
635 PRIVATE_NAMESPACE_END