opt_expr: WIP use patcher more

This commit is contained in:
Emil J. Tywoniak 2026-05-28 22:51:30 +02:00
parent b594196a48
commit dab9a386cc
4 changed files with 69 additions and 15 deletions

View File

@ -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) {

View File

@ -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> 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

View File

@ -6,7 +6,8 @@
YOSYS_NAMESPACE_BEGIN
struct RTLIL::Patch final : public CellAdderMixin<RTLIL::Patch>
// No virtual methods — subclasses cannot be dispatched through a Patch pointer.
struct RTLIL::Patch : public CellAdderMixin<RTLIL::Patch>
{
private:
void gc(Cell* old_cell);

View File

@ -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)) {