18 template<
typename WALK_TYPE>
19 void assertWalkLength(
const MRRG&,
const WALK_TYPE& walk) {
20 if (std::next(walk.begin()) == walk.end() ) {
21 throw make_from_stream<std::logic_error>([&,f=__func__](
auto&& s) {
22 s << f <<
" called with a walk that has fewer than 2 vertices";
29 auto neigh_search_result =
neighbours.find(src);
33 auto& neighs = neigh_search_result->second;
34 return neighs.end() != neighs.find(dest);
40 for (
auto& node_and_infos : fu_neighbours.
neighbours) {
41 os <<
'\t' << node_and_infos.first <<
" -> \n";
42 for (
auto& node_info : node_and_infos.second) {
43 os <<
"\t\t" << node_info.second.node <<
'@' << node_info.second.distance <<
'\n';
53 for (
const auto& name_and_nodeUPtr : nodes_for_cycle) {
54 const auto& ndesc = name_and_nodeUPtr.second.get();
56 if (ndesc_in_transformed_graph) {
62 for (
const auto& nodes_for_cycle : transformed_mrrg.
allNodesByCycle()) {
63 for (
const auto& name_and_nodeUPtr : nodes_for_cycle) {
64 const auto& ndesc = name_and_nodeUPtr.second.get();
66 if (ndesc_in_src_graph) {
78 for (
auto& node_and_set : map) {
79 auto&
set = node_and_set.second;
80 const auto search_for_from =
set.find(from);
81 if (search_for_from !=
end(
set)) {
82 set.erase(search_for_from);
88 const auto search_for_from = map.find(from);
89 if (search_for_from !=
end(map)) {
90 auto src = std::move(search_for_from->second);
91 map.erase(search_for_from);
92 auto& dest = map[into];
93 std::move(
begin(src),
end(src), std::inserter(dest,
end(dest)));
99 const auto mapping_printer = [=](
auto&& s,
auto&& mapping_set) {
102 os <<
"}\n forward_map = ";
104 os <<
"\n reverse_map = ";
114 std::vector<std::vector<MRRGNDesc>>
paths = {};
133 impl_ptr = std::make_shared<MRRGProcedureCache>();
144 std::vector<MRRG::NodeDescriptor> func_nodes;
145 std::vector<MRRG::NodeDescriptor> rout_nodes;
146 for (
const auto& node : nodes_for_cycle)
149 func_nodes.push_back(node.second.get());
151 rout_nodes.push_back(node.second.get());
153 rout_nodes.push_back(node.second.get());
154 func_nodes.push_back(node.second.get());
157 make_and_throw<cgrame_error>([&](
auto&& s) {
158 s <<
"unhanded MRRG node type " << node.second->type;
174 for (
const auto& node : nodes_for_cycle)
185 make_and_throw<cgrame_error>([&](
auto&& s) {
186 s <<
"unhanded MRRG node type " << node.second->type;
198 const std::unordered_set<MRRG::NodeDescriptor> source_fanout_set(mrrg.
fanout(source).begin(), mrrg.
fanout(source).end());
199 const int path_length_adjustment = 1;
203 const auto should_stop_searching = [&](
auto& discovered_node) {
204 (void)discovered_node;
205 if (min_neighbours_to_find < 0) {
212 return num_found >= min_neighbours_to_find;
216 const auto vertex_data = g_algos.wavedBreadthFirstVisit(mrrg, source_fanout_set, should_stop_searching, visitor);
221 auto path_and_success = g_algos.singleTraceback(source_fanout_set, sink, vertex_data);
222 if (path_and_success.success) {
231 std::unordered_map<OpGraph::OpDescriptor, std::vector<MRRG::NodeDescriptor>> compatible_fu_nodes;
233 for (
auto& op : opgraph.
opNodes()) {
234 compatible_fu_nodes.emplace(op, decltype(compatible_fu_nodes)::mapped_type{});
237 auto ndesc = name_and_node.second.get();
239 compatible_fu_nodes[op].emplace_back(ndesc);
245 return compatible_fu_nodes;
250 std::pair<int,int> cycle_trip_count_min_max,
const OperandTag& operand_tag,
254 auto& datum = cache_handle->getOrCreate().
shortest_paths[source][sink][operand_tag];
255 auto& existing_paths = datum.paths;
256 if ((std::ptrdiff_t)existing_paths.size() >= num_paths || datum.all_paths_found) {
257 return {existing_paths.begin(), std::next(existing_paths.begin(), std::min(num_paths, (
int)existing_paths.size()))};
269 : mrrg(mrrg), sink(sink), source(source), operand_tag(operand_tag) { }
275 } visitor { &mrrg, sink, source, &operand_tag };
278 auto result = g_algos.findNShortestPaths(num_paths, mrrg, {source},
findSingleVertex(sink), visitor,
279 [&](
const auto& path) {
281 if (source != sink) {
return true; }
284 return cycle_trip_count_min_max.first <= tc && tc <= cycle_trip_count_min_max.second;
289 auto& datum = cache_handle->getOrCreate().
shortest_paths[source][sink][operand_tag];
290 datum.paths = result;
291 datum.all_paths_found = (std::ptrdiff_t)result.size() < num_paths;
296 std::vector<std::vector<MRRG::NodeDescriptor>>
mergeMRRGWalks(
const MRRG& mrrg,
const std::vector<MrrgNodeSpan>& walks) {
299 std::map<MRRG::NodeDescriptor, std::set<MRRG::NodeDescriptor>> edges;
302 std::set<MRRG::NodeDescriptor> sources;
303 std::set<MRRG::NodeDescriptor> sinks;
306 for (
const auto& walk : walks) {
307 sources.insert(walk.front());
308 sinks.insert(walk.back());
309 auto prev = walk.begin();
310 for (
auto curr = std::next(prev); curr != walk.end(); prev=curr,++curr) {
311 g.edges[*prev].insert(*curr);
318 const std::set<MRRG::NodeDescriptor>* sinks;
319 std::set<MRRG::NodeDescriptor> found_sinks = {};
320 std::vector<MRRG::NodeDescriptor> sink_order = {};
322 SinkRecordingVisitor(
const std::set<MRRG::NodeDescriptor>* sinks) : sinks(sinks) { }
325 if (sinks->find(v) == sinks->end()) {
return; }
326 if (not found_sinks.insert(v).second) {
return; }
327 sink_order.push_back(v);
329 } sink_recorder {&sinks};
332 auto search_tree = g_algos.wavedBreadthFirstVisit(g, sources,
visitAllVertices(), sink_recorder);
334 std::vector<std::vector<MRRG::NodeDescriptor>> result;
336 std::set<MRRG::NodeDescriptor> sources_not_found = sources;
337 std::set<MRRG::NodeDescriptor> nodes_in_result = sources;
339 const auto trace_back_and_add = [&](
const auto& search_set,
const auto& tb_start,
const auto& fanin_map) {
340 auto path_and_success = [&]() {
341 if (search_set.find(tb_start) == search_set.end()) {
343 return g_algos.singleTraceback(search_set, tb_start, fanin_map);
346 for (
const auto& src_and_fanout_set : g.edges) {
347 if (src_and_fanout_set.second.find(tb_start) == src_and_fanout_set.second.end()) {
continue; }
348 auto result = g_algos.singleTraceback(search_set, src_and_fanout_set.first, fanin_map);
349 if (result.success) {
350 result.path.push_back(tb_start);
351 return std::move(result);
354 throw std::logic_error(
"loop trace-back failed");
357 if (not path_and_success.success) {
throw std::logic_error(
"trace-back failed"); }
358 sources_not_found.erase(path_and_success.path.front());
359 std::copy(path_and_success.path.begin(), path_and_success.path.end(), std::inserter(nodes_in_result, nodes_in_result.end()));
360 result.emplace_back(std::move(path_and_success.path));
363 for (
const auto& sink : sink_recorder.sink_order) {
364 trace_back_and_add(nodes_in_result, sink, search_tree);
367 for (
const auto& walk : walks) {
368 const auto source = walk.front();
369 if (not sources_not_found.erase(source)) {
continue; }
372 if (not the_node_found) {
throw std::logic_error(
"fix-up search failed"); }
373 trace_back_and_add(
singleItemSet(source), the_node_found, fixup_search_tree);
380 if (walk.empty()) {
return 0; }
381 assertWalkLength(mrrg, walk);
383 return std::accumulate(walk.begin(), std::prev(walk.end()), 0, [&](
auto sum,
const auto& ndesc) {
384 const auto& node = mrrg.getNodeRef(ndesc);
385 const auto hypothetical_cycle = node.getContextNum() + node.getLatency();
387 return sum + hypothetical_cycle/mrrg.initiationInterval();
393 return operand_tag.empty() || supported_ops.empty() || supported_ops.find(operand_tag) != supported_ops.end();
397 if (walk.empty()) {
return true; }
398 if (operand_tag.empty())
return true;
399 assertWalkLength(mrrg, walk);
401 const auto node_allows_tag = [&mrrg,&operand_tag](
const auto& node) {
return nodeIsCompatibleWithOperand(mrrg, node, operand_tag); };
402 return std::all_of(walk.begin(), std::prev(walk.end()), node_allows_tag);
417 new_mrrg.erase(from_ndesc);
423 auto& new_mrrg = result.transformed_mrrg;
427 std::unordered_set<MRRG::NodeDescriptor> removed_nodes;
430 for (
auto& ndesc : node_classes.routing_nodes)
433 if (removed_nodes.find(ndesc) !=
end(removed_nodes)) {
continue; }
435 const auto& node = src_mrrg.
getNodeRef(ndesc);
438 if (node.fanin.size() == 1) {
439 const auto the_fanin_ndesc = new_mrrg.getNodeRef(ndesc).
fanin.at(0);
440 auto& the_fanin_node = new_mrrg.getNodeRef(the_fanin_ndesc);
443 && the_fanin_node.fanout.size() == 1
448 removed_nodes.emplace(ndesc);
453 result.mapping.addAllByMatchingProperties(src_mrrg, new_mrrg);
460 auto& new_mrrg = result.transformed_mrrg;
462 std::vector<std::pair<MRRG::NodeDescriptor, MRRG::NodeDescriptor>> insertionEdges;
464 for (
const auto & node: nodesForCycle) {
469 if (node.second->fanout.size() > 1) {
470 for (
const auto & fanout: node.second->fanout) {
471 if (fanout->fanin.size() > 1) {
472 insertionEdges.emplace_back(node.second.get(), fanout);
481 for (
auto & edge: insertionEdges) {
482 const auto & firstNode = src_mrrg.
getNodeRef(edge.first);
483 const auto & secondNode = src_mrrg.
getNodeRef(edge.second);
485 new_mrrg.unlink(new_mrrg.getNodeByPropertiesOf(firstNode), new_mrrg.getNodeByPropertiesOf(secondNode));
486 auto newNode = new_mrrg.insert(new_mrrg.getNodeByPropertiesOf(firstNode),
MRRGNode::make_routing(new_mrrg.getNodeByPropertiesOf(firstNode)->parent, firstNode.bitwidth, (firstNode.cycle + firstNode.latency) % new_mrrg.initiationInterval(),
"mux_ex_insert_" +
std::to_string(i++), 0)).first;
488 new_mrrg.link(newNode, new_mrrg.getNodeByPropertiesOf(secondNode));
490 result.mapping.addAllByMatchingProperties(src_mrrg, new_mrrg);
496 const auto& driver = mrrg.
getNodeRef(driver_ndesc);
497 const auto& test = mrrg.
getNodeRef(test_ndesc);
499 const bool found_test_in_fanout_of_driver =
end(driver.fanout) != std::find(
begin(driver.fanout),
end(driver.fanout), test_ndesc);
500 const bool found_driver_in_fanin_of_test =
end(test.fanin) != std::find(
begin(test.fanin),
end(test.fanin), driver_ndesc);
502 if (found_driver_in_fanin_of_test != found_test_in_fanout_of_driver) {
503 make_and_throw<cgrame_error>([&](
auto&& s) {
504 s <<
"non-reflective MRRG link discovered";
508 return found_test_in_fanout_of_driver;
512 const auto& driver = mrrg.
getNodeRef(driven_ndesc);
513 const auto& test = mrrg.
getNodeRef(test_ndesc);
515 const bool found_test_in_fanin_of_driver =
end(driver.fanin) != std::find(
begin(driver.fanin),
end(driver.fanin), test_ndesc);
516 const bool found_driver_in_fanout_of_test =
end(test.fanout) != std::find(
begin(test.fanout),
end(test.fanout), driven_ndesc);
518 if (found_driver_in_fanout_of_test != found_test_in_fanin_of_driver) {
519 make_and_throw<cgrame_error>([&](
auto&& s) {
520 s <<
"non-reflective MRRG link discovered";
524 return found_test_in_fanin_of_driver;
528 if (not
isNodeFanoutOf(mrrg, driver_ndesc, test_ndesc)) { make_and_throw<cgrame_error>([&](
auto&& s) {
529 s <<
"attempted to " << action_name <<
" a non-fanout node";
534 if (not
isNodeFaninOf(mrrg, driven_ndesc, test_ndesc)) { make_and_throw<cgrame_error>([&](
auto&& s) {
535 s <<
"attempted to " << action_name <<
" a non-fanin node";
542 if (mrrg.
getNodeRef(driver_ndesc).
fanout.size() != 1) { make_and_throw<cgrame_error>([&](
auto&& s) {
543 s <<
"attempted to " << action_name <<
" a non-exclusive-fanout node";
550 if (mrrg.
getNodeRef(driven_ndesc).
fanin.size() != 1) { make_and_throw<cgrame_error>([&](
auto&& s) {
551 s <<
"attempted to " << action_name <<
" a non-exclusive-fanin node";
556 if (not n.
supported_ops.empty()) { make_and_throw<cgrame_error>([&](
auto&& s) {
557 s <<
"attempted to " << action_name <<
" in a node that supports ops";
562 if (n.
fanout.size() != 1) { make_and_throw<cgrame_error>([&](
auto&& s) {
563 s <<
"attempted to " << action_name <<
" in a node that has multiple fanouts";
570 for(
auto& fanout_ndesc : from.fanout) {
571 if (fanout_ndesc != into_ndesc) {
572 mrrg.
link(into_ndesc, fanout_ndesc);
576 for(
auto& fanin_ndesc : from.fanin) {
577 if (fanin_ndesc != into_ndesc) {
578 mrrg.
link(into_ndesc, fanin_ndesc);
585 const auto& from = mrrg.
getNodeRef(from_ndesc);
593 into.latency += from.latency;
594 into.delay += from.delay;
595 if (into.supported_operand_tags.empty()) {
596 into.supported_operand_tags = from.supported_operand_tags;
599 if (into.supported_operand_tags != from.supported_operand_tags) {
600 make_and_throw<cgrame_error>([&](
auto&& s) {
601 s <<
"Attempting to merge nodes that support different operands";
619 for (
auto & node_trans : opToMRRG.second) {
622 reversedMap.
mapMRRGNode(opToMRRG.first, node_orig);