diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 359c76d42..3b059e0e5 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -55,6 +55,7 @@ struct WreduceWorker ModIndex mi; std::set> work_queue_cells; + std::set> work_queue_wires; std::set work_queue_bits; pool 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 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 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 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(); } } }; diff --git a/tests/opt/wreduce_traversal.ys b/tests/opt/wreduce_traversal.ys new file mode 100644 index 000000000..ab4bd2b44 --- /dev/null +++ b/tests/opt/wreduce_traversal.ys @@ -0,0 +1,34 @@ +# Ensure wreduce propagates width reductions across dependent cells. +read_verilog <