mirror of
https://github.com/YosysHQ/yosys
synced 2026-01-18 16:28:57 +00:00
wreduce: queue traversal and add regression test
Implement iterative queue-based traversal in wreduce pass to propagate width reductions across dependent cells and wires. Previously, wreduce would process all cells once, then all wires once. This meant that reductions couldn't propagate through chains of operations. The new algorithm maintains work queues for both cells and wires, processing them iteratively until no more reductions are possible. When a cell or wire is reduced, dependent cells and wires are added back to the queues for reprocessing. Add regression test to verify that width reductions propagate through a chain of operations: (a + b)[3:0] + c, ensuring the first addition is reduced from 9 bits to 4 bits.
This commit is contained in:
parent
71feb2a2a1
commit
d25171806b
2 changed files with 97 additions and 34 deletions
|
|
@ -55,6 +55,7 @@ struct WreduceWorker
|
|||
ModIndex mi;
|
||||
|
||||
std::set<Cell*, IdString::compare_ptr_by_name<Cell>> work_queue_cells;
|
||||
std::set<Wire*, IdString::compare_ptr_by_name<Wire>> work_queue_wires;
|
||||
std::set<SigBit> work_queue_bits;
|
||||
pool<SigBit> keep_bits;
|
||||
FfInitVals initvals;
|
||||
|
|
@ -78,6 +79,8 @@ struct WreduceWorker
|
|||
for (int i = GetSize(sig_y)-1; i >= 0; i--)
|
||||
{
|
||||
auto info = mi.query(sig_y[i]);
|
||||
if (info == nullptr)
|
||||
return;
|
||||
if (!info->is_output && GetSize(info->ports) <= 1 && !keep_bits.count(mi.sigmap(sig_y[i]))) {
|
||||
bits_removed.push_back(State::Sx);
|
||||
continue;
|
||||
|
|
@ -393,6 +396,8 @@ struct WreduceWorker
|
|||
break;
|
||||
|
||||
auto info = mi.query(bit);
|
||||
if (info == nullptr)
|
||||
return;
|
||||
if (info->is_output || GetSize(info->ports) > 1)
|
||||
break;
|
||||
|
||||
|
|
@ -457,63 +462,87 @@ struct WreduceWorker
|
|||
return count;
|
||||
}
|
||||
|
||||
void run_wire(Wire *w, pool<SigSpec> complete_wires)
|
||||
{
|
||||
int unused_top_bits = 0;
|
||||
|
||||
if (w->port_id > 0 || count_nontrivial_wire_attrs(w) > 0)
|
||||
return;
|
||||
|
||||
for (int i = GetSize(w)-1; i >= 0; i--) {
|
||||
SigBit bit(w, i);
|
||||
auto info = mi.query(bit);
|
||||
if (info == nullptr)
|
||||
return;
|
||||
if (info && (info->is_input || info->is_output || GetSize(info->ports) > 0))
|
||||
break;
|
||||
unused_top_bits++;
|
||||
}
|
||||
|
||||
if (unused_top_bits == 0 || unused_top_bits == GetSize(w))
|
||||
return;
|
||||
|
||||
if (complete_wires[mi.sigmap(w).extract(0, GetSize(w) - unused_top_bits)])
|
||||
return;
|
||||
|
||||
log("Removed top %d bits (of %d) from wire %s.%s.\n", unused_top_bits, GetSize(w), log_id(module), log_id(w));
|
||||
Wire *nw = module->addWire(module->uniquify(IdString(w->name.str() + "_wreduce")), GetSize(w) - unused_top_bits);
|
||||
module->connect(nw, SigSpec(w).extract(0, GetSize(nw)));
|
||||
module->swap_names(w, nw);
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
// create a copy as mi.sigmap will be updated as we process the module
|
||||
// Create a copy as mi.sigmap will be updated as we process the module
|
||||
SigMap init_attr_sigmap = mi.sigmap;
|
||||
initvals.set(&init_attr_sigmap, module);
|
||||
|
||||
// Initialize cell work queue
|
||||
for (auto c : module->selected_cells())
|
||||
work_queue_cells.insert(c);
|
||||
|
||||
// Initialize wire work queue
|
||||
for (auto w : module->selected_wires())
|
||||
work_queue_wires.insert(w);
|
||||
|
||||
// Initialize keep bits
|
||||
for (auto w : module->wires()) {
|
||||
if (w->get_bool_attribute(ID::keep))
|
||||
for (auto bit : mi.sigmap(w))
|
||||
keep_bits.insert(bit);
|
||||
}
|
||||
|
||||
for (auto c : module->selected_cells())
|
||||
work_queue_cells.insert(c);
|
||||
|
||||
while (!work_queue_cells.empty())
|
||||
while (!work_queue_cells.empty() || !work_queue_wires.empty())
|
||||
{
|
||||
// Initialize complete wires
|
||||
pool<SigSpec> complete_wires;
|
||||
for (auto w : module->wires())
|
||||
complete_wires.insert(mi.sigmap(w));
|
||||
|
||||
// Run cells
|
||||
work_queue_bits.clear();
|
||||
for (auto c : work_queue_cells)
|
||||
run_cell(c);
|
||||
|
||||
// Run wires
|
||||
for (auto w : work_queue_wires)
|
||||
run_wire(w, complete_wires);
|
||||
|
||||
// Get next batch of cells to process
|
||||
work_queue_cells.clear();
|
||||
for (auto bit : work_queue_bits)
|
||||
for (auto port : mi.query_ports(bit))
|
||||
if (module->selected(port.cell))
|
||||
work_queue_cells.insert(port.cell);
|
||||
}
|
||||
|
||||
pool<SigSpec> complete_wires;
|
||||
for (auto w : module->wires())
|
||||
complete_wires.insert(mi.sigmap(w));
|
||||
// Get next batch of wires to process
|
||||
work_queue_wires.clear();
|
||||
for (auto bit : work_queue_bits)
|
||||
if (bit.wire != NULL && module->selected(bit.wire))
|
||||
work_queue_wires.insert(bit.wire);
|
||||
|
||||
for (auto w : module->selected_wires())
|
||||
{
|
||||
int unused_top_bits = 0;
|
||||
|
||||
if (w->port_id > 0 || count_nontrivial_wire_attrs(w) > 0)
|
||||
continue;
|
||||
|
||||
for (int i = GetSize(w)-1; i >= 0; i--) {
|
||||
SigBit bit(w, i);
|
||||
auto info = mi.query(bit);
|
||||
if (info && (info->is_input || info->is_output || GetSize(info->ports) > 0))
|
||||
break;
|
||||
unused_top_bits++;
|
||||
}
|
||||
|
||||
if (unused_top_bits == 0 || unused_top_bits == GetSize(w))
|
||||
continue;
|
||||
|
||||
if (complete_wires[mi.sigmap(w).extract(0, GetSize(w) - unused_top_bits)])
|
||||
continue;
|
||||
|
||||
log("Removed top %d bits (of %d) from wire %s.%s.\n", unused_top_bits, GetSize(w), log_id(module), log_id(w));
|
||||
Wire *nw = module->addWire(NEW_ID, GetSize(w) - unused_top_bits);
|
||||
module->connect(nw, SigSpec(w).extract(0, GetSize(nw)));
|
||||
module->swap_names(w, nw);
|
||||
// Reload module
|
||||
mi.reload_module();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
34
tests/opt/wreduce_traversal.ys
Normal file
34
tests/opt/wreduce_traversal.ys
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Ensure wreduce propagates width reductions across dependent cells.
|
||||
read_verilog <<EOT
|
||||
module top(input [7:0] a, input [7:0] b, input [3:0] c, output [3:0] y);
|
||||
wire [8:0] sum_full;
|
||||
wire [3:0] sum_trunc;
|
||||
|
||||
assign sum_full = a + b;
|
||||
assign sum_trunc = sum_full[3:0];
|
||||
assign y = sum_trunc + c;
|
||||
endmodule
|
||||
EOT
|
||||
|
||||
hierarchy -auto-top
|
||||
proc
|
||||
opt_expr
|
||||
opt_clean
|
||||
|
||||
design -save gold
|
||||
|
||||
wreduce
|
||||
opt_clean
|
||||
|
||||
# After wreduce, the first add should be reduced from 9 bits to 4 bits
|
||||
select -assert-count 2 t:$add
|
||||
select -assert-count 0 t:$add r:Y_WIDTH=9 %i
|
||||
select -assert-count 2 t:$add r:Y_WIDTH=4 %i
|
||||
|
||||
design -stash reduced
|
||||
|
||||
design -import gold -as gold
|
||||
design -import reduced -as reduced
|
||||
|
||||
miter -equiv -flatten -make_assert -make_outputs gold reduced miter
|
||||
sat -verify -prove-asserts -show-ports miter
|
||||
Loading…
Add table
Add a link
Reference in a new issue