diff options
Diffstat (limited to 'passes/opt/opt_clean.cc')
-rw-r--r-- | passes/opt/opt_clean.cc | 115 |
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 ®s, 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 ®s, 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 |