mirror of
https://github.com/YosysHQ/yosys
synced 2026-03-02 03:36:56 +00:00
opt_clean: refactor
This commit is contained in:
parent
17d667eab0
commit
ef536c4b1d
1 changed files with 98 additions and 93 deletions
|
|
@ -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);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue