From dab9a386cc61b58e30f8b47010ae1c0fd50587ac Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Thu, 28 May 2026 22:51:30 +0200 Subject: [PATCH] opt_expr: WIP use patcher more --- kernel/rtlil_bufnorm.cc | 1 + kernel/unstable/patch.cc | 25 ++++++++++++++---- kernel/unstable/patch.h | 3 ++- passes/opt/opt_expr.cc | 55 +++++++++++++++++++++++++++++++++------- 4 files changed, 69 insertions(+), 15 deletions(-) diff --git a/kernel/rtlil_bufnorm.cc b/kernel/rtlil_bufnorm.cc index 3d5b86064..e2eaafdfb 100644 --- a/kernel/rtlil_bufnorm.cc +++ b/kernel/rtlil_bufnorm.cc @@ -1117,6 +1117,7 @@ void RTLIL::Cell::signorm_index_add(IdString portname, const SigSpec &new_signal { auto &index = *module->sig_norm_index; index.dirty.insert(this); + xlog("signorm_index_add cell %s port %s input %d signal %s\n", name, portname, is_input, log_signal(new_signal)); if (is_input) { int i = 0; for (auto bit : new_signal) { diff --git a/kernel/unstable/patch.cc b/kernel/unstable/patch.cc index bb6881136..a8dfc68ba 100644 --- a/kernel/unstable/patch.cc +++ b/kernel/unstable/patch.cc @@ -94,23 +94,29 @@ void Patch::gc(Cell* old_cell) { for (auto [port_name, sig] : old_cell->connections()) { auto dir = old_cell->port_dir(port_name); log_assert(dir != PD_UNKNOWN); + // TODO only running GC through whole connections? + log_debug("\tport %s\n", port_name); if (sig.size() && sig.is_wire()) { if (dir == PD_OUTPUT || dir == PD_INOUT) { for (auto bit : sig) { // Reject GC if used - if (!mod->fanout(bit).empty()) + if (!mod->fanout(bit).empty()) { + log_debug("\treject fanout\n"); return; + } else + log_debug("\tok\n"); } } if (dir == PD_INPUT || dir == PD_INOUT) { Wire* in_wire = sig.as_wire(); log_assert(in_wire); - log_debug("%s\n", in_wire->name); + log_debug("\twire %s\n", in_wire->name); if (in_wire->known_driver() && !leaves.count(in_wire)) inputs.push_back(in_wire->driverCell()); } } } + log_debug("\tremove %s\n", old_cell->name); old_cell->module->remove(old_cell); for (auto input : inputs) gc(input); @@ -134,7 +140,7 @@ Cell* Patch::commit_cell(std::unique_ptr cell) { void Patch::patch(Cell* old_cell, IdString old_port, SigSpec new_sig) { SigSpec old_sig = old_cell->getPort(old_port); log_assert(old_sig.size() == new_sig.size()); - log_debug("patching %s %s which is %s with %s:\n", old_cell->name, old_port, log_signal(old_sig), log_signal(new_sig)); + log("patching %s %s which is %s with %s:\n", old_cell->name, old_port, log_signal(old_sig), log_signal(new_sig)); SrcCollector collector; collector.collect_src(old_sig); @@ -147,12 +153,18 @@ void Patch::patch(Cell* old_cell, IdString old_port, SigSpec new_sig) { // Inefficient for (auto& cell : cells_) { + log_debug("cell %s\n", cell->name); for (auto& [port_name, sig] : cell->connections()) { + log_debug("port %s\n", port_name); auto dir = cell->port_dir(port_name); if (dir == PD_INPUT || dir == PD_INOUT) { - for (auto bit : sig) - if (bit.is_wire() && bit.wire->module) + for (auto bit : sig) { + log("bit %s\n", log_signal(bit)); + if (bit.is_wire() && bit.wire->module) { leaves.insert(bit.wire); + log_debug("leaf %s\n", bit.wire->name); + } + } } } } @@ -167,6 +179,9 @@ void Patch::patch(Cell* old_cell, IdString old_port, SigSpec new_sig) { commit_wire(std::move(wire)); gc(old_cell); + cells_.clear(); + wires_.clear(); + leaves.clear(); } YOSYS_NAMESPACE_END \ No newline at end of file diff --git a/kernel/unstable/patch.h b/kernel/unstable/patch.h index 46e5b59c4..ba38a4dcc 100644 --- a/kernel/unstable/patch.h +++ b/kernel/unstable/patch.h @@ -6,7 +6,8 @@ YOSYS_NAMESPACE_BEGIN -struct RTLIL::Patch final : public CellAdderMixin +// No virtual methods — subclasses cannot be dispatched through a Patch pointer. +struct RTLIL::Patch : public CellAdderMixin { private: void gc(Cell* old_cell); diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index 920e05490..60ce6a77f 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -18,6 +18,7 @@ */ #include "kernel/register.h" +#include "kernel/rtlil.h" #include "kernel/sigtools.h" #include "kernel/celltypes.h" #include "kernel/newcelltypes.h" @@ -118,15 +119,27 @@ void replace_undriven(RTLIL::Module *module, const NewCellTypes &ct) } } +void log_replace_sig(RTLIL::Module *module, RTLIL::Cell *cell, + const std::string &info, RTLIL::SigSpec old_sig, RTLIL::SigSpec new_sig) +{ + log_debug("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n", + cell->type.c_str(), cell->name.c_str(), info.c_str(), + module->name.c_str(), log_signal(old_sig), log_signal(new_sig)); +} + +void log_replace_port(RTLIL::Module *module, RTLIL::Cell *cell, + const std::string &info, RTLIL::IdString port, RTLIL::SigSpec new_sig) +{ + log_replace_sig(module, cell, info, cell->getPort(port), new_sig); +} + void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, const std::string &info, IdString out_port, RTLIL::SigSpec out_val) { RTLIL::SigSpec Y = cell->getPort(out_port); out_val.extend_u0(Y.size(), false); - log_debug("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n", - cell->type.c_str(), cell->name.c_str(), info.c_str(), - module->name.c_str(), log_signal(Y), log_signal(out_val)); + log_replace_sig(module, cell, info, Y, out_val); // log_cell(cell); assign_map.add(Y, out_val); module->connect(Y, out_val); @@ -134,6 +147,14 @@ void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, did_something = true; } +struct OptExprPatcher : public RTLIL::Patch { + using RTLIL::Patch::Patch; + void patch(Cell *old_cell, IdString old_port, SigSpec new_sig, const std::string &info) { + log_replace_port(mod, old_cell, info, old_port, new_sig); + RTLIL::Patch::patch(old_cell, old_port, new_sig); + } +}; + bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutative, SigMap &sigmap, bool keepdc) { IdString b_name = cell->hasPort(ID::B) ? ID::B : ID::A; @@ -621,18 +642,34 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (!sig_a.wire) std::swap(sig_a, sig_b); if (sig_b == State::S0 || sig_b == State::S1) { + OptExprPatcher patcher(module, &assign_map); + bool is_gate = cell->type.in(ID($_XOR_), ID($_XNOR_)); + int width = is_gate ? 1 : cell->getParam(ID::Y_WIDTH).as_int(); if (cell->type.in(ID($xor), ID($_XOR_))) { if (sig_b == State::S0) { - replace_cell(assign_map, module, cell, "xor_buffer", ID::Y, sig_a); - } else { - RTLIL::Patch patcher(module, &assign_map); - SigSpec sig_y = cell->type == ID($xor) ? patcher.Not(NEW_ID, sig_a) : (SigSpec)patcher.NotGate(NEW_ID, sig_a); - int width = cell->type == ID($xor) ? cell->getParam(ID::Y_WIDTH).as_int() : 1; + SigSpec sig_y = sig_a; sig_y.append(RTLIL::Const(State::S0, width-1)); - patcher.patch(cell, ID::Y, sig_y); + // replace_cell(assign_map, module, cell, "xor_buffer", ID::Y, sig_y); + patcher.patch(cell, ID::Y, sig_y, "xor_buffer"); + } else { + SigSpec sig_y = is_gate ? (SigSpec)patcher.NotGate(NEW_ID, sig_a) : patcher.Not(NEW_ID, sig_a); + sig_y.append(RTLIL::Const(State::S0, width-1)); + patcher.patch(cell, ID::Y, sig_y, "xor_buffer"); } goto next_cell; } + // if (cell->type.in(ID($xnor), ID($_XNOR_))) { + // if (sig_b == State::S1) { + // SigSpec sig_y = sig_a; + // sig_y.append(RTLIL::Const(State::S1, width-1)); + // patcher.patch(cell, ID::Y, sig_y, "xnor_buffer"); + // } else { + // SigSpec sig_y = is_gate ? (SigSpec)patcher.NotGate(NEW_ID, sig_a) : patcher.Not(NEW_ID, sig_a); + // sig_y.append(RTLIL::Const(State::S1, width-1)); + // patcher.patch(cell, ID::Y, sig_y, "xnor_buffer"); + // } + // goto next_cell; + // } if (cell->type.in(ID($xnor), ID($_XNOR_))) { SigSpec sig_y; if (cell->type == ID($xnor)) {