opt_clean: Better memory handling.

Previously, `$memwr` and `$meminit` cells were always preserved (along
with the memory itself).  With this change, they are instead part of the
main cell mark-and-sweep pass: a memory (and its `$meminit` and `$memwr`
cells) is only preserved iff any associated `$memrd` cell needs to be
preserved.
This commit is contained in:
Marcelina Kościelnicka 2020-10-08 13:33:47 +02:00
parent fd306b0520
commit 7670a89e1f
2 changed files with 94 additions and 8 deletions

View File

@ -55,7 +55,7 @@ struct keep_cache_t
if (!module->get_bool_attribute(ID::keep)) {
bool found_keep = false;
for (auto cell : module->cells())
if (query(cell, true /* ignore_specify_mem */)) {
if (query(cell, true /* ignore_specify */)) {
found_keep = true;
break;
}
@ -70,12 +70,12 @@ struct keep_cache_t
return cache[module];
}
bool query(Cell *cell, bool ignore_specify_mem = false)
bool query(Cell *cell, bool ignore_specify = false)
{
if (cell->type.in(ID($assert), ID($assume), ID($live), ID($fair), ID($cover)))
return true;
if (!ignore_specify_mem && cell->type.in(ID($memwr), ID($meminit), ID($specify2), ID($specify3), ID($specrule)))
if (!ignore_specify && cell->type.in(ID($specify2), ID($specify3), ID($specrule)))
return true;
if (cell->has_keep_attr())
@ -95,6 +95,8 @@ int count_rm_cells, count_rm_wires;
void rmunused_module_cells(Module *module, bool verbose)
{
SigMap sigmap(module);
dict<IdString, pool<Cell*>> mem2cells;
pool<IdString> mem_unused;
pool<Cell*> queue, unused;
pool<SigBit> used_raw_bits;
dict<SigBit, pool<Cell*>> wire2driver;
@ -108,6 +110,17 @@ void rmunused_module_cells(Module *module, bool verbose)
}
}
for (auto &it : module->memories) {
mem_unused.insert(it.first);
}
for (Cell *cell : module->cells()) {
if (cell->type.in(ID($memwr), ID($meminit))) {
IdString mem_id = cell->getParam(ID::MEMID).decode_string();
mem2cells[mem_id].insert(cell);
}
}
for (auto &it : module->cells_) {
Cell *cell = it.second;
for (auto &it2 : cell->connections()) {
@ -145,17 +158,33 @@ void rmunused_module_cells(Module *module, bool verbose)
while (!queue.empty())
{
pool<SigBit> bits;
for (auto cell : queue)
for (auto &it : cell->connections())
if (!ct_all.cell_known(cell->type) || ct_all.cell_input(cell->type, it.first))
for (auto bit : sigmap(it.second))
bits.insert(bit);
pool<IdString> mems;
for (auto cell : queue) {
for (auto &it : cell->connections())
if (!ct_all.cell_known(cell->type) || ct_all.cell_input(cell->type, it.first))
for (auto bit : sigmap(it.second))
bits.insert(bit);
if (cell->type == ID($memrd)) {
IdString mem_id = cell->getParam(ID::MEMID).decode_string();
if (mem_unused.count(mem_id)) {
mem_unused.erase(mem_id);
mems.insert(mem_id);
}
}
}
queue.clear();
for (auto bit : bits)
for (auto c : wire2driver[bit])
if (unused.count(c))
queue.insert(c), unused.erase(c);
for (auto mem : mems)
for (auto c : mem2cells[mem])
if (unused.count(c))
queue.insert(c), unused.erase(c);
}
unused.sort(RTLIL::sort_by_name_id<RTLIL::Cell>());
@ -168,6 +197,14 @@ void rmunused_module_cells(Module *module, bool verbose)
count_rm_cells++;
}
for (auto it : mem_unused)
{
if (verbose)
log_debug(" removing unused memory `%s'.\n", it.c_str());
delete module->memories.at(it);
module->memories.erase(it);
}
for (auto &it : module->cells_) {
Cell *cell = it.second;
for (auto &it2 : cell->connections()) {

View File

@ -0,0 +1,49 @@
read_verilog <<EOT
module top(...);
input [7:0] wa;
input [7:0] ra1;
input [7:0] ra2;
input [7:0] wd;
input clk;
wire [7:0] rd1;
wire [7:0] rd2;
reg [7:0] mem[0:7];
always @(posedge clk)
mem[wa] <= wd;
assign rd1 = mem[ra1];
assign rd2 = mem[ra2];
initial mem[8'h12] = 8'h34;
endmodule
EOT
proc
memory_dff
select -assert-count 2 t:$memrd
select -assert-count 1 t:$memwr
select -assert-count 1 t:$meminit
design -save orig
opt_clean
select -assert-none t:$memrd
select -assert-none t:$memwr
select -assert-none t:$meminit
design -load orig
expose top/rd1
opt_clean
select -assert-count 1 t:$memrd
select -assert-count 1 t:$memwr
select -assert-count 1 t:$meminit
design -load orig
expose top/rd1 top/rd2
opt_clean
select -assert-count 2 t:$memrd
select -assert-count 1 t:$memwr
select -assert-count 1 t:$meminit