3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-03-02 03:36:56 +00:00

opt_clean: refactor

This commit is contained in:
Emil J. Tywoniak 2026-02-24 00:54:15 +01:00
parent 17d667eab0
commit ef536c4b1d

View file

@ -665,18 +665,18 @@ struct AnalysisContext {
AnalysisContext(RTLIL::Module* m, ParallelDispatchThreadPool::Subpool &p) : assign_map(m), mod(m), subpool(p) {} AnalysisContext(RTLIL::Module* m, ParallelDispatchThreadPool::Subpool &p) : assign_map(m), mod(m), subpool(p) {}
}; };
struct SigAnalysis { /**
// `registers` and `connected` will help us decide later on * What kinds of things are signals connected to?
// on picking representatives out of groups of connected signals * Helps pick representatives out of groups of connected signals */
struct SigConnKinds {
// Wire bits driven by registers (with clk2fflogic exception) // Wire bits driven by registers (with clk2fflogic exception)
ShardedSigPool registers; ShardedSigPool registers;
// Wire bits connected to any cell port // Wire bits connected to any cell port
ShardedSigPool connected; ShardedSigPool cells;
// construct a pool of wires which are directly driven by a known celltype, // construct a pool of wires which are directly driven by a known celltype,
// this will influence our choice of representatives // this will influence our choice of representatives
ShardedSigSpecPool direct; ShardedSigSpecPool direct;
SigAnalysis(bool purge_mode, const AnalysisContext& actx) { SigConnKinds(bool purge_mode, const AnalysisContext& actx) {
ShardedSigPool::Builder register_signals_builder(actx.subpool); ShardedSigPool::Builder register_signals_builder(actx.subpool);
ShardedSigPool::Builder connected_signals_builder(actx.subpool); ShardedSigPool::Builder connected_signals_builder(actx.subpool);
ShardedSigSpecPool::Builder direct_sigs_builder(actx.subpool); ShardedSigSpecPool::Builder direct_sigs_builder(actx.subpool);
@ -712,17 +712,17 @@ struct SigAnalysis {
direct_sigs_builder.process(ctx); direct_sigs_builder.process(ctx);
}); });
registers = register_signals_builder; registers = register_signals_builder;
connected = connected_signals_builder; cells = connected_signals_builder;
direct = direct_sigs_builder; direct = direct_sigs_builder;
} }
void clear(const ParallelDispatchThreadPool::RunCtx &ctx) { void clear(const ParallelDispatchThreadPool::RunCtx &ctx) {
registers.clear(ctx); registers.clear(ctx);
connected.clear(ctx); cells.clear(ctx);
direct.clear(ctx); direct.clear(ctx);
} }
}; };
ShardedVector<RTLIL::SigBit> build_candidates(DirectWires& direct_wires, const SigAnalysis& sig_analysis, const AnalysisContext& actx) { ShardedVector<RTLIL::SigBit> build_candidates(DirectWires& direct_wires, const SigConnKinds& sig_analysis, const AnalysisContext& actx) {
ShardedVector<RTLIL::SigBit> sigmap_canonical_candidates(actx.subpool); ShardedVector<RTLIL::SigBit> sigmap_canonical_candidates(actx.subpool);
actx.subpool.run([&actx, &sig_analysis, &sigmap_canonical_candidates, &direct_wires](const ParallelDispatchThreadPool::RunCtx &ctx) { actx.subpool.run([&actx, &sig_analysis, &sigmap_canonical_candidates, &direct_wires](const ParallelDispatchThreadPool::RunCtx &ctx) {
std::optional<DirectWires> local_direct_wires; std::optional<DirectWires> local_direct_wires;
@ -738,7 +738,7 @@ ShardedVector<RTLIL::SigBit> build_candidates(DirectWires& direct_wires, const S
for (int j = 0; j < wire->width; ++j) { for (int j = 0; j < wire->width; ++j) {
RTLIL::SigBit s1(wire, j); RTLIL::SigBit s1(wire, j);
RTLIL::SigBit s2 = actx.assign_map(s1); RTLIL::SigBit s2 = actx.assign_map(s1);
if (compare_signals(s2, s1, sig_analysis.registers, sig_analysis.connected, *this_thread_direct_wires)) if (compare_signals(s2, s1, sig_analysis.registers, sig_analysis.cells, *this_thread_direct_wires))
sigmap_canonical_candidates.insert(ctx, s1); sigmap_canonical_candidates.insert(ctx, s1);
} }
} }
@ -746,30 +746,43 @@ ShardedVector<RTLIL::SigBit> build_candidates(DirectWires& direct_wires, const S
return sigmap_canonical_candidates; return sigmap_canonical_candidates;
} }
bool update_assign_map(ShardedVector<RTLIL::SigBit>& sigmap_canonical_candidates, DirectWires& direct_wires, const SigAnalysis& sig_analysis, SigMap& assign_map) { void update_assign_map(ShardedVector<RTLIL::SigBit>& sigmap_canonical_candidates, DirectWires& direct_wires, const SigConnKinds& sig_analysis, SigMap& assign_map) {
for (RTLIL::SigBit candidate : sigmap_canonical_candidates) { for (RTLIL::SigBit candidate : sigmap_canonical_candidates) {
RTLIL::SigBit current_canonical = assign_map(candidate); RTLIL::SigBit current_canonical = assign_map(candidate);
if (compare_signals(current_canonical, candidate, sig_analysis.registers, sig_analysis.connected, direct_wires)) if (compare_signals(current_canonical, candidate, sig_analysis.registers, sig_analysis.cells, direct_wires))
assign_map.add(candidate); assign_map.add(candidate);
} }
} }
struct UsedSigAnalysis {
struct DeferredUpdates {
// Deferred updates to the assign_map
ShardedVector<UpdateConnection> update_connections;
// Wires we should remove init from
ShardedVector<RTLIL::Wire*> initialized_wires;
DeferredUpdates(ParallelDispatchThreadPool::Subpool &subpool) : update_connections(subpool), initialized_wires(subpool) {}
};
struct UsedSignals {
// here, "used" means "driven or driving something" // here, "used" means "driven or driving something"
// meanwhile, "unused" means "driving nothing" // meanwhile, "unused" means "driving nothing"
// TODO ... // TODO ...
// used signals sigmapped // used signals sigmapped
ShardedSigPool used; ShardedSigPool connected;
// used signals pre-sigmapped // used signals pre-sigmapped
ShardedSigPool raw_used; ShardedSigPool raw_connected;
// used signals sigmapped, ignoring drivers (we keep track of this to set `unused_bits`) // used signals sigmapped, ignoring drivers (we keep track of this to set `unused_bits`)
ShardedSigPool used_nodrivers; ShardedSigPool used;
// Deferred updates to the assign_map void clear(ParallelDispatchThreadPool::Subpool &subpool) {
ShardedVector<UpdateConnection> update_connections; subpool.run([this](const ParallelDispatchThreadPool::RunCtx &ctx) {
ShardedVector<RTLIL::Wire*> initialized_wires; connected.clear(ctx);
raw_connected.clear(ctx);
used.clear(ctx);
});
}
};
UsedSigAnalysis(SigAnalysis& sig_analysis, const AnalysisContext& actx) : update_connections(actx.subpool), initialized_wires(actx.subpool) { std::tuple<DeferredUpdates, UsedSignals> analyse_connectivity(SigConnKinds& sig_analysis, const AnalysisContext& actx) {
DeferredUpdates deferred(actx.subpool);
ShardedSigPool::Builder used_builder(actx.subpool); ShardedSigPool::Builder used_builder(actx.subpool);
ShardedSigPool::Builder raw_used_builder(actx.subpool); ShardedSigPool::Builder raw_used_builder(actx.subpool);
ShardedSigPool::Builder used_nodrivers_builder(actx.subpool); ShardedSigPool::Builder used_nodrivers_builder(actx.subpool);
@ -777,7 +790,7 @@ struct UsedSigAnalysis {
// gather the usage information for cells and update cell connections with the altered sigmap // gather the usage information for cells and update cell connections with the altered sigmap
// also gather the usage information for ports, wires with `keep` // also gather the usage information for ports, wires with `keep`
// also gather init bits // also gather init bits
actx.subpool.run([&actx, &sig_analysis, &used_builder, &raw_used_builder, &used_nodrivers_builder, this](const ParallelDispatchThreadPool::RunCtx &ctx) { actx.subpool.run([&deferred, &used_builder, &raw_used_builder, &used_nodrivers_builder, &sig_analysis, &actx](const ParallelDispatchThreadPool::RunCtx &ctx) {
// Parallel destruction of these sharded structures // Parallel destruction of these sharded structures
sig_analysis.clear(ctx); sig_analysis.clear(ctx);
@ -786,7 +799,7 @@ struct UsedSigAnalysis {
for (const auto &[port, sig] : cell->connections_) { for (const auto &[port, sig] : cell->connections_) {
SigSpec spec = actx.assign_map(sig); SigSpec spec = actx.assign_map(sig);
if (spec != sig) if (spec != sig)
update_connections.insert(ctx, {cell, port, spec}); deferred.update_connections.insert(ctx, {cell, port, spec});
add_spec(raw_used_builder, ctx, spec); add_spec(raw_used_builder, ctx, spec);
add_spec(used_builder, ctx, spec); add_spec(used_builder, ctx, spec);
if (!ct_all.cell_output(cell->type, port)) if (!ct_all.cell_output(cell->type, port))
@ -810,7 +823,7 @@ struct UsedSigAnalysis {
} }
auto it = wire->attributes.find(ID::init); auto it = wire->attributes.find(ID::init);
if (it != wire->attributes.end()) if (it != wire->attributes.end())
initialized_wires.insert(ctx, wire); deferred.initialized_wires.insert(ctx, wire);
} }
}); });
actx.subpool.run([&used_builder, &raw_used_builder, &used_nodrivers_builder](const ParallelDispatchThreadPool::RunCtx &ctx) { actx.subpool.run([&used_builder, &raw_used_builder, &used_nodrivers_builder](const ParallelDispatchThreadPool::RunCtx &ctx) {
@ -818,16 +831,9 @@ struct UsedSigAnalysis {
raw_used_builder.process(ctx); raw_used_builder.process(ctx);
used_nodrivers_builder.process(ctx); used_nodrivers_builder.process(ctx);
}); });
ShardedSigPool used_signals(used_builder); UsedSignals used {used_builder, raw_used_builder, used_nodrivers_builder};
ShardedSigPool raw_used_signals(raw_used_builder); return {std::move(deferred), std::move(used)};
ShardedSigPool used_signals_nodrivers(used_nodrivers_builder);
} }
void clear(const ParallelDispatchThreadPool::RunCtx &ctx) {
used.clear(ctx);
raw_used.clear(ctx);
used_nodrivers.clear(ctx);
}
};
struct WireDeleter { struct WireDeleter {
pool<RTLIL::Wire*> del_wires_queue; pool<RTLIL::Wire*> del_wires_queue;
@ -836,7 +842,7 @@ struct WireDeleter {
ShardedVector<RTLIL::SigSig> new_connections; ShardedVector<RTLIL::SigSig> new_connections;
ShardedVector<RTLIL::Wire*> remove_unused_bits; ShardedVector<RTLIL::Wire*> remove_unused_bits;
ShardedVector<std::pair<RTLIL::Wire*, RTLIL::Const>> set_unused_bits; ShardedVector<std::pair<RTLIL::Wire*, RTLIL::Const>> set_unused_bits;
WireDeleter(UsedSigAnalysis& used_sig_analysis, bool purge_mode, const AnalysisContext& actx) : WireDeleter(UsedSignals& used_sig_analysis, bool purge_mode, const AnalysisContext& actx) :
remove_init(actx.subpool), remove_init(actx.subpool),
set_init(actx.subpool), set_init(actx.subpool),
new_connections(actx.subpool), new_connections(actx.subpool),
@ -867,10 +873,10 @@ struct WireDeleter {
if (wire->port_id != 0 || wire->get_bool_attribute(ID::keep) || !initval.is_fully_undef()) { if (wire->port_id != 0 || wire->get_bool_attribute(ID::keep) || !initval.is_fully_undef()) {
// do not delete anything with "keep" or module ports or initialized wires // do not delete anything with "keep" or module ports or initialized wires
} else } else
if (!purge_mode && check_public_name(wire->name) && (check_any(used_sig_analysis.raw_used, s1) || check_any(used_sig_analysis.used, s2) || s1 != s2)) { if (!purge_mode && check_public_name(wire->name) && (check_any(used_sig_analysis.raw_connected, s1) || check_any(used_sig_analysis.connected, s2) || s1 != s2)) {
// do not get rid of public names unless in purge mode or if the wire is entirely unused, not even aliased // do not get rid of public names unless in purge mode or if the wire is entirely unused, not even aliased
} else } else
if (!check_any(used_sig_analysis.raw_used, s1)) { if (!check_any(used_sig_analysis.raw_connected, s1)) {
// delete wires that aren't used by anything directly // delete wires that aren't used by anything directly
goto delete_this_wire; goto delete_this_wire;
} }
@ -903,12 +909,12 @@ struct WireDeleter {
set_init.insert(ctx, {wire, std::move(initval)}); set_init.insert(ctx, {wire, std::move(initval)});
std::string unused_bits; std::string unused_bits;
if (!check_all(used_sig_analysis.used_nodrivers, s2)) { if (!check_all(used_sig_analysis.used, s2)) {
for (int i = 0; i < GetSize(s2); i++) { for (int i = 0; i < GetSize(s2); i++) {
if (s2[i].wire == NULL) if (s2[i].wire == NULL)
continue; continue;
SigBit b = s2[i]; SigBit b = s2[i];
if (used_sig_analysis.used_nodrivers.find({b, b.hash_top().yield()}) == nullptr) { if (used_sig_analysis.used.find({b, b.hash_top().yield()}) == nullptr) {
if (!unused_bits.empty()) if (!unused_bits.empty())
unused_bits += " "; unused_bits += " ";
unused_bits += stringf("%d", i); unused_bits += stringf("%d", i);
@ -962,32 +968,31 @@ struct WireDeleter {
bool rmunused_module_signals(RTLIL::Module *module, ParallelDispatchThreadPool::Subpool &subpool, bool purge_mode, bool verbose, RmStats &stats) bool rmunused_module_signals(RTLIL::Module *module, ParallelDispatchThreadPool::Subpool &subpool, bool purge_mode, bool verbose, RmStats &stats)
{ {
AnalysisContext actx(module, subpool); AnalysisContext actx(module, subpool);
SigAnalysis sig_analysis(purge_mode, actx); SigConnKinds conn_kinds(purge_mode, actx);
// Main thread's cached direct wires are retained and used later: // Main thread's cached direct wires are retained and used later:
DirectWires direct_wires(sig_analysis.direct, actx.assign_map); DirectWires direct_wires(conn_kinds.direct, actx.assign_map);
// Other threads' caches get discarded when threads finish in build_candidates // Other threads' caches get discarded when threads finish in build_candidates
// but the per-thread results are collected into sigmap_canonical_candidates // but the per-thread results are collected into sigmap_canonical_candidates
ShardedVector<RTLIL::SigBit> sigmap_canonical_candidates = build_candidates(direct_wires, sig_analysis, actx); ShardedVector<RTLIL::SigBit> sigmap_canonical_candidates = build_candidates(direct_wires, conn_kinds, actx);
// Cache all the direct_wires results that we might possible need. This avoids the results // Cache all the direct_wires results that we might possible need. This avoids the results
// changing when we update `assign_map` below. // changing when we update `assign_map` below.
direct_wires.cache_all(sigmap_canonical_candidates); direct_wires.cache_all(sigmap_canonical_candidates);
// Modify assign_map to reflect the connectivity we want, not the one we have // Modify assign_map to reflect the connectivity we want, not the one we have
update_assign_map(sigmap_canonical_candidates, direct_wires, sig_analysis, actx.assign_map); update_assign_map(sigmap_canonical_candidates, direct_wires, conn_kinds, actx.assign_map);
// Remove all wire-wire connections // Remove all wire-wire connections
module->connections_.clear(); module->connections_.clear();
UsedSigAnalysis used_sig_analysis(sig_analysis, actx); // UsedSigConnKinds used_sig_analysis(sig_analysis, actx);
fixup_update_ports(used_sig_analysis.update_connections); auto [deferred, used] = analyse_connectivity(conn_kinds, actx);
consume_inits(used_sig_analysis.initialized_wires, actx.assign_map).apply_normalised_inits(); fixup_update_ports(deferred.update_connections);
consume_inits(deferred.initialized_wires, actx.assign_map).apply_normalised_inits();
WireDeleter deleter(used_sig_analysis, purge_mode, actx); WireDeleter deleter(used, purge_mode, actx);
subpool.run([&used_sig_analysis](const ParallelDispatchThreadPool::RunCtx &ctx) { used.clear(subpool);
used_sig_analysis.clear(ctx);
});
deleter.commit_changes(module); deleter.commit_changes(module);
int deleted_and_unreported = deleter.delete_wires(module, verbose); int deleted_and_unreported = deleter.delete_wires(module, verbose);