Use toposort.

This commit is contained in:
nella 2026-08-06 10:51:49 +02:00
parent 7bbb69872c
commit c5d47334f4
1 changed files with 27 additions and 39 deletions

View File

@ -21,6 +21,7 @@
#include "kernel/yosys.h" #include "kernel/yosys.h"
#include "kernel/sigtools.h" #include "kernel/sigtools.h"
#include "kernel/utils.h"
#include <deque> #include <deque>
USING_YOSYS_NAMESPACE USING_YOSYS_NAMESPACE
@ -69,41 +70,36 @@ struct OptBalanceTreeWorker {
return y_width >= natural_width; return y_width >= natural_width;
} }
// Get the driver of a cell input port if it continues the chain, else nullptr
Cell *chain_driver(Cell *cell, IdString port, IdString cell_type) {
auto sig = sigmap(cell->getPort(port));
Cell *drv = sig_to_driver[sig];
if (!drv || !is_right_type(drv, cell_type))
return nullptr;
for (auto bit : sig)
if (input_port_sigs.count(bit) && !consumed_cells.count(drv))
return nullptr;
return drv;
}
// Check if the driver graph reachable from head contains a cycle, // Check if the driver graph reachable from head contains a cycle,
// following the same edges as the backward chain traversal // following the same edges as the backward chain traversal
bool has_cycle(Cell *head, IdString cell_type) { bool has_cycle(Cell *head, IdString cell_type) {
pool<Cell*> on_path, done; TopoSort<Cell*, IdString::compare_ptr_by_name<Cell>> toposort;
vector<std::pair<Cell*, bool>> stack = {{head, false}}; toposort.analyze_loops = false;
while (!stack.empty()) vector<Cell*> queue = {head};
while (!queue.empty())
{ {
auto [c, leave] = stack.back(); Cell *c = queue.back();
stack.pop_back(); queue.pop_back();
if (leave) { for (IdString port: {ID::A, ID::B})
on_path.erase(c); if (Cell *drv = chain_driver(c, port, cell_type)) {
done.insert(c); if (!toposort.has_node(drv))
continue; queue.push_back(drv);
} toposort.edge(drv, c);
if (done.count(c))
continue;
if (on_path.count(c))
return true;
on_path.insert(c);
stack.push_back({c, true});
for (IdString port: {ID::A, ID::B}) {
auto sig = sigmap(c->getPort(port));
Cell *drv = sig_to_driver[sig];
bool drv_ok = drv && is_right_type(drv, cell_type);
for (auto bit : sig) {
if (input_port_sigs.count(bit) && !consumed_cells.count(drv)) {
drv_ok = false;
break;
}
} }
if (drv_ok)
stack.push_back({drv, false});
}
} }
return false; return !toposort.sort();
} }
// Create a balanced binary tree from a vector of source signals // Create a balanced binary tree from a vector of source signals
@ -308,19 +304,11 @@ struct OptBalanceTreeWorker {
bfs_queue.pop_front(); bfs_queue.pop_front();
for (IdString port: {ID::A, ID::B}) { for (IdString port: {ID::A, ID::B}) {
auto sig = sigmap(x->getPort(port)); if (Cell *drv = chain_driver(x, port, cell_type)) {
Cell* drv = sig_to_driver[sig];
bool drv_ok = drv && is_right_type(drv, cell_type);
for (auto bit : sig) {
if (input_port_sigs.count(bit) && !consumed_cells.count(drv)) {
drv_ok = false;
break;
}
}
if (drv_ok) {
inner_cells++; inner_cells++;
bfs_queue.push_back(drv); bfs_queue.push_back(drv);
} else { } else {
auto sig = sigmap(x->getPort(port));
sources[sig]++; sources[sig]++;
signeds[sig] = x->getParam(port == ID::A ? ID::A_SIGNED : ID::B_SIGNED).as_bool(); signeds[sig] = x->getParam(port == ID::A ? ID::A_SIGNED : ID::B_SIGNED).as_bool();
} }