From 5ba566abf185f3599170c0b1080f9a626d2fe635 Mon Sep 17 00:00:00 2001 From: Emily Schmidt Date: Thu, 25 Jul 2024 10:35:32 +0100 Subject: [PATCH] functional backend: topological sort starts with the output and next states nodes, other nodes get deleted --- backends/functional/test_generic.cc | 10 +++----- kernel/functional.h | 18 +++++++++++++- kernel/functionalir.cc | 20 ++++++++++----- kernel/topo_scc.h | 38 +++++++++++++++++++---------- passes/cmds/example_dt.cc | 4 +-- 5 files changed, 62 insertions(+), 28 deletions(-) diff --git a/backends/functional/test_generic.cc b/backends/functional/test_generic.cc index ba713b36c32..5d93492767f 100644 --- a/backends/functional/test_generic.cc +++ b/backends/functional/test_generic.cc @@ -129,14 +129,13 @@ struct FunctionalTestGeneric : public Pass size_t argidx = 1; extra_args(args, argidx, design); - +/* MemContentsTest test(8, 16); std::random_device seed_dev; std::mt19937 rnd(23); //seed_dev()); test.run(rnd, 1000); - -/* +*/ for (auto module : design->selected_modules()) { log("Dumping module `%s'.\n", module->name.c_str()); @@ -144,11 +143,10 @@ struct FunctionalTestGeneric : public Pass for(auto node : fir) 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()) - 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()) - 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; diff --git a/kernel/functional.h b/kernel/functional.h index 09f66c9813b..77e965f6474 100644 --- a/kernel/functional.h +++ b/kernel/functional.h @@ -268,6 +268,19 @@ struct ComputeGraph return added; } + void compact_args() + { + std::vector 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 const &perm) { log_assert(perm.size() <= nodes.size()); @@ -276,7 +289,7 @@ struct ComputeGraph for (int i = 0; i < GetSize(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); inv_perm[j] = i; } @@ -301,15 +314,18 @@ struct ComputeGraph std::swap(nodes, new_nodes); std::swap(sparse_attrs, new_sparse_attrs); + compact_args(); for (int &arg : args) { log_assert(arg < GetSize(inv_perm)); + log_assert(inv_perm[arg] >= 0); arg = inv_perm[arg]; } for (auto &key : keys_) { log_assert(key.second < GetSize(inv_perm)); + log_assert(inv_perm[key.second] >= 0); key.second = inv_perm[key.second]; } } diff --git a/kernel/functionalir.cc b/kernel/functionalir.cc index 195e47b12ac..223fdaa913e 100644 --- a/kernel/functionalir.cc +++ b/kernel/functionalir.cc @@ -657,19 +657,27 @@ void FunctionalIR::topological_sort() { Graph::SccAdaptor compute_graph_scc(_graph); bool scc = false; std::vector 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); if (end > begin + 1) { - log_warning("SCC:"); - for (int *i = begin; i != end; ++i) - log(" %d", *i); + log_warning("Combinational loop:\n"); + for (int *i = begin; i != end; ++i) { + Node node(_graph[*i]); + log("- %s = %s\n", RTLIL::unescape_id(node.name()).c_str(), node.to_string().c_str()); + } log("\n"); 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); - 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) { diff --git a/kernel/topo_scc.h b/kernel/topo_scc.h index 89df8928aa2..7e730bb27dc 100644 --- a/kernel/topo_scc.h +++ b/kernel/topo_scc.h @@ -194,7 +194,7 @@ class IntGraph { }; template -void topo_sorted_sccs(G &graph, ComponentCallback component, bool sources_first = false) +class TopoSortedSccs { typedef typename G::node_enumerator node_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_stack; std::vector component_stack; int next_index = 0; +public: + TopoSortedSccs(G &graph, ComponentCallback component) + : graph(graph), component(component) {} - node_enumerator nodes = graph.enumerate_nodes(); - - if (sources_first) { + // process all sources (nodes without a successor) + TopoSortedSccs &process_sources() { + node_enumerator nodes = graph.enumerate_nodes(); while (!nodes.finished()) { node_type node = nodes.next(); 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; } } - nodes = graph.enumerate_nodes(); + return *this; } - // iterate over all nodes to ensure we process the whole graph - while (!nodes.finished()) { - node_type node = nodes.next(); + // process all remaining nodes in the graph + TopoSortedSccs &process_all() { + 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 if (graph.dfs_index(node) >= 0) - continue; - + return *this; while (true) { // at this point we're visiting the node for the first time during // 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 // the outer loop if we already are at the root node. if (dfs_stack.empty()) - goto next_search; + return *this; auto &dfs_top = dfs_stack.back(); node = dfs_top.node; @@ -336,9 +349,8 @@ void topo_sorted_sccs(G &graph, ComponentCallback component, bool sources_first } } } - next_search:; } -} +}; YOSYS_NAMESPACE_END diff --git a/passes/cmds/example_dt.cc b/passes/cmds/example_dt.cc index 859b0b7ba4b..4b836d75b88 100644 --- a/passes/cmds/example_dt.cc +++ b/passes/cmds/example_dt.cc @@ -183,7 +183,7 @@ struct ExampleDtPass : public Pass std::vector 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); if (end > begin + 1) { @@ -192,7 +192,7 @@ struct ExampleDtPass : public Pass log(" %d", *i); log("\n"); } - }, /* sources_first */ true); + }).process_sources().process_all(); compute_graph.permute(perm);