mirror of https://github.com/YosysHQ/yosys.git
functional backend: topological sort starts with the output and next states nodes, other nodes get deleted
This commit is contained in:
parent
7ac0e92d35
commit
8c0f625c3a
|
@ -129,14 +129,13 @@ struct FunctionalTestGeneric : public Pass
|
||||||
|
|
||||||
size_t argidx = 1;
|
size_t argidx = 1;
|
||||||
extra_args(args, argidx, design);
|
extra_args(args, argidx, design);
|
||||||
|
/*
|
||||||
MemContentsTest test(8, 16);
|
MemContentsTest test(8, 16);
|
||||||
|
|
||||||
std::random_device seed_dev;
|
std::random_device seed_dev;
|
||||||
std::mt19937 rnd(23); //seed_dev());
|
std::mt19937 rnd(23); //seed_dev());
|
||||||
test.run(rnd, 1000);
|
test.run(rnd, 1000);
|
||||||
|
*/
|
||||||
/*
|
|
||||||
|
|
||||||
for (auto module : design->selected_modules()) {
|
for (auto module : design->selected_modules()) {
|
||||||
log("Dumping module `%s'.\n", module->name.c_str());
|
log("Dumping module `%s'.\n", module->name.c_str());
|
||||||
|
@ -144,11 +143,10 @@ struct FunctionalTestGeneric : public Pass
|
||||||
for(auto node : fir)
|
for(auto node : fir)
|
||||||
std::cout << RTLIL::unescape_id(node.name()) << " = " << node.to_string([](auto n) { return RTLIL::unescape_id(n.name()); }) << "\n";
|
std::cout << RTLIL::unescape_id(node.name()) << " = " << node.to_string([](auto n) { return RTLIL::unescape_id(n.name()); }) << "\n";
|
||||||
for(auto [name, sort] : fir.outputs())
|
for(auto [name, sort] : fir.outputs())
|
||||||
std::cout << RTLIL::unescape_id(name) << " = " << RTLIL::unescape_id(fir.get_output_node(name).name()) << "\n";
|
std::cout << "output " << RTLIL::unescape_id(name) << " = " << RTLIL::unescape_id(fir.get_output_node(name).name()) << "\n";
|
||||||
for(auto [name, sort] : fir.state())
|
for(auto [name, sort] : fir.state())
|
||||||
std::cout << RTLIL::unescape_id(name) << " = " << RTLIL::unescape_id(fir.get_state_next_node(name).name()) << "\n";
|
std::cout << "state " << RTLIL::unescape_id(name) << " = " << RTLIL::unescape_id(fir.get_state_next_node(name).name()) << "\n";
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
} FunctionalCxxBackend;
|
} FunctionalCxxBackend;
|
||||||
|
|
||||||
|
|
|
@ -268,6 +268,19 @@ public:
|
||||||
return added;
|
return added;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void compact_args()
|
||||||
|
{
|
||||||
|
std::vector<int> new_args;
|
||||||
|
for (auto &node : nodes)
|
||||||
|
{
|
||||||
|
int new_offset = GetSize(new_args);
|
||||||
|
for (int i = 0; i < node.arg_count; i++)
|
||||||
|
new_args.push_back(args[node.arg_offset + i]);
|
||||||
|
node.arg_offset = new_offset;
|
||||||
|
}
|
||||||
|
std::swap(args, new_args);
|
||||||
|
}
|
||||||
|
|
||||||
void permute(std::vector<int> const &perm)
|
void permute(std::vector<int> const &perm)
|
||||||
{
|
{
|
||||||
log_assert(perm.size() <= nodes.size());
|
log_assert(perm.size() <= nodes.size());
|
||||||
|
@ -276,7 +289,7 @@ public:
|
||||||
for (int i = 0; i < GetSize(perm); ++i)
|
for (int i = 0; i < GetSize(perm); ++i)
|
||||||
{
|
{
|
||||||
int j = perm[i];
|
int j = perm[i];
|
||||||
log_assert(j >= 0 && j < GetSize(perm));
|
log_assert(j >= 0 && j < GetSize(nodes));
|
||||||
log_assert(inv_perm[j] == -1);
|
log_assert(inv_perm[j] == -1);
|
||||||
inv_perm[j] = i;
|
inv_perm[j] = i;
|
||||||
}
|
}
|
||||||
|
@ -301,15 +314,18 @@ public:
|
||||||
std::swap(nodes, new_nodes);
|
std::swap(nodes, new_nodes);
|
||||||
std::swap(sparse_attrs, new_sparse_attrs);
|
std::swap(sparse_attrs, new_sparse_attrs);
|
||||||
|
|
||||||
|
compact_args();
|
||||||
for (int &arg : args)
|
for (int &arg : args)
|
||||||
{
|
{
|
||||||
log_assert(arg < GetSize(inv_perm));
|
log_assert(arg < GetSize(inv_perm));
|
||||||
|
log_assert(inv_perm[arg] >= 0);
|
||||||
arg = inv_perm[arg];
|
arg = inv_perm[arg];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &key : keys_)
|
for (auto &key : keys_)
|
||||||
{
|
{
|
||||||
log_assert(key.second < GetSize(inv_perm));
|
log_assert(key.second < GetSize(inv_perm));
|
||||||
|
log_assert(inv_perm[key.second] >= 0);
|
||||||
key.second = inv_perm[key.second];
|
key.second = inv_perm[key.second];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -657,19 +657,27 @@ void FunctionalIR::topological_sort() {
|
||||||
Graph::SccAdaptor compute_graph_scc(_graph);
|
Graph::SccAdaptor compute_graph_scc(_graph);
|
||||||
bool scc = false;
|
bool scc = false;
|
||||||
std::vector<int> perm;
|
std::vector<int> perm;
|
||||||
topo_sorted_sccs(compute_graph_scc, [&](int *begin, int *end) {
|
TopoSortedSccs toposort(compute_graph_scc, [&](int *begin, int *end) {
|
||||||
perm.insert(perm.end(), begin, end);
|
perm.insert(perm.end(), begin, end);
|
||||||
if (end > begin + 1)
|
if (end > begin + 1)
|
||||||
{
|
{
|
||||||
log_warning("SCC:");
|
log_warning("Combinational loop:\n");
|
||||||
for (int *i = begin; i != end; ++i)
|
for (int *i = begin; i != end; ++i) {
|
||||||
log(" %d", *i);
|
Node node(_graph[*i]);
|
||||||
|
log("- %s = %s\n", RTLIL::unescape_id(node.name()).c_str(), node.to_string().c_str());
|
||||||
|
}
|
||||||
log("\n");
|
log("\n");
|
||||||
scc = true;
|
scc = true;
|
||||||
}
|
}
|
||||||
}, /* sources_first */ true);
|
});
|
||||||
|
for(const auto &[name, sort]: _state_sorts)
|
||||||
|
toposort.process(get_state_next_node(name).id());
|
||||||
|
for(const auto &[name, sort]: _output_sorts)
|
||||||
|
toposort.process(get_output_node(name).id());
|
||||||
|
// any nodes untouched by this point are dead code and will be removed by permute
|
||||||
_graph.permute(perm);
|
_graph.permute(perm);
|
||||||
if(scc) log_error("combinational loops, aborting\n");
|
if(scc) log_error("The design contains combinational loops. This is not supported by the functional backend. "
|
||||||
|
"Try `scc -select; simplemap; select -clear` to avoid this error.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static IdString merge_name(IdString a, IdString b) {
|
static IdString merge_name(IdString a, IdString b) {
|
||||||
|
|
|
@ -194,7 +194,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename G, typename ComponentCallback>
|
template<typename G, typename ComponentCallback>
|
||||||
void topo_sorted_sccs(G &graph, ComponentCallback component, bool sources_first = false)
|
class TopoSortedSccs
|
||||||
{
|
{
|
||||||
typedef typename G::node_enumerator node_enumerator;
|
typedef typename G::node_enumerator node_enumerator;
|
||||||
typedef typename G::successor_enumerator successor_enumerator;
|
typedef typename G::successor_enumerator successor_enumerator;
|
||||||
|
@ -210,14 +210,20 @@ void topo_sorted_sccs(G &graph, ComponentCallback component, bool sources_first
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
G &graph;
|
||||||
|
ComponentCallback component;
|
||||||
|
|
||||||
std::vector<dfs_entry> dfs_stack;
|
std::vector<dfs_entry> dfs_stack;
|
||||||
std::vector<node_type> component_stack;
|
std::vector<node_type> component_stack;
|
||||||
int next_index = 0;
|
int next_index = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TopoSortedSccs(G &graph, ComponentCallback component)
|
||||||
|
: graph(graph), component(component) {}
|
||||||
|
|
||||||
node_enumerator nodes = graph.enumerate_nodes();
|
// process all sources (nodes without a successor)
|
||||||
|
TopoSortedSccs &process_sources() {
|
||||||
if (sources_first) {
|
node_enumerator nodes = graph.enumerate_nodes();
|
||||||
while (!nodes.finished()) {
|
while (!nodes.finished()) {
|
||||||
node_type node = nodes.next();
|
node_type node = nodes.next();
|
||||||
successor_enumerator successors = graph.enumerate_successors(node);
|
successor_enumerator successors = graph.enumerate_successors(node);
|
||||||
|
@ -231,16 +237,23 @@ void topo_sorted_sccs(G &graph, ComponentCallback component, bool sources_first
|
||||||
graph.dfs_index(node) = INT_MAX;
|
graph.dfs_index(node) = INT_MAX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nodes = graph.enumerate_nodes();
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// iterate over all nodes to ensure we process the whole graph
|
// process all remaining nodes in the graph
|
||||||
while (!nodes.finished()) {
|
TopoSortedSccs &process_all() {
|
||||||
node_type node = nodes.next();
|
node_enumerator nodes = graph.enumerate_nodes();
|
||||||
|
// iterate over all nodes to ensure we process the whole graph
|
||||||
|
while (!nodes.finished())
|
||||||
|
process(nodes.next());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// process all nodes that are reachable from a given start node
|
||||||
|
TopoSortedSccs &process(node_type node) {
|
||||||
// only start a new search if the node wasn't visited yet
|
// only start a new search if the node wasn't visited yet
|
||||||
if (graph.dfs_index(node) >= 0)
|
if (graph.dfs_index(node) >= 0)
|
||||||
continue;
|
return *this;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// at this point we're visiting the node for the first time during
|
// at this point we're visiting the node for the first time during
|
||||||
// the DFS search
|
// the DFS search
|
||||||
|
@ -299,7 +312,7 @@ void topo_sorted_sccs(G &graph, ComponentCallback component, bool sources_first
|
||||||
// continues the search at the parent node or returns to
|
// continues the search at the parent node or returns to
|
||||||
// the outer loop if we already are at the root node.
|
// the outer loop if we already are at the root node.
|
||||||
if (dfs_stack.empty())
|
if (dfs_stack.empty())
|
||||||
goto next_search;
|
return *this;
|
||||||
auto &dfs_top = dfs_stack.back();
|
auto &dfs_top = dfs_stack.back();
|
||||||
|
|
||||||
node = dfs_top.node;
|
node = dfs_top.node;
|
||||||
|
@ -336,9 +349,8 @@ void topo_sorted_sccs(G &graph, ComponentCallback component, bool sources_first
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
next_search:;
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
YOSYS_NAMESPACE_END
|
YOSYS_NAMESPACE_END
|
||||||
|
|
||||||
|
|
|
@ -183,7 +183,7 @@ struct ExampleDtPass : public Pass
|
||||||
|
|
||||||
|
|
||||||
std::vector<int> perm;
|
std::vector<int> perm;
|
||||||
topo_sorted_sccs(compute_graph_scc, [&](int *begin, int *end) {
|
TopoSortedSccs(compute_graph_scc, [&](int *begin, int *end) {
|
||||||
perm.insert(perm.end(), begin, end);
|
perm.insert(perm.end(), begin, end);
|
||||||
if (end > begin + 1)
|
if (end > begin + 1)
|
||||||
{
|
{
|
||||||
|
@ -192,7 +192,7 @@ struct ExampleDtPass : public Pass
|
||||||
log(" %d", *i);
|
log(" %d", *i);
|
||||||
log("\n");
|
log("\n");
|
||||||
}
|
}
|
||||||
}, /* sources_first */ true);
|
}).process_sources().process_all();
|
||||||
compute_graph.permute(perm);
|
compute_graph.permute(perm);
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue