CGRA-ME
MRRGProcedures.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  * The software programs comprising "CGRA-ME" and the documentation provided
3  * with them are copyright by its authors and the University of Toronto. Only
4  * non-commercial, not-for-profit use of this software is permitted without ex-
5  * plicit permission. This software is provided "as is" with no warranties or
6  * guarantees of support. See the LICENCE for more details. You should have re-
7  * ceived a copy of the full licence along with this software. If not, see
8  * <http://cgra-me.ece.utoronto.ca/license/>.
9  ******************************************************************************/
10 
11 #include <CGRA/MRRGProcedures.h>
12 
13 #include <CGRA/GraphAlgorithms.h>
14 
15 #include <queue>
16 
17 namespace {
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";
23  });
24  }
25  }
26 } // end anon namespace
27 
29  auto neigh_search_result = neighbours.find(src);
30  if (neigh_search_result == neighbours.end()) {
31  return false;
32  } else {
33  auto& neighs = neigh_search_result->second;
34  return neighs.end() != neighs.find(dest);
35  }
36 }
37 
38 std::ostream& operator<<(std::ostream& os, const FunctionalUnitNeighbours& fu_neighbours) {
39  os << "{\n";
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';
44  }
45  os << '\n';
46  }
47  os << '}';
48  return os;
49 }
50 
51 void InterMRRGMap::addAllByMatchingProperties(const MRRG& src_mrrg, const MRRG& transformed_mrrg) {
52  for (const auto& nodes_for_cycle : src_mrrg.allNodesByCycle()) {
53  for (const auto& name_and_nodeUPtr : nodes_for_cycle) {
54  const auto& ndesc = name_and_nodeUPtr.second.get();
55  const auto ndesc_in_transformed_graph = transformed_mrrg.getNodeByPropertiesOf(src_mrrg.getNodeRef(ndesc));
56  if (ndesc_in_transformed_graph) {
57  addMapping(ndesc, ndesc_in_transformed_graph);
58  }
59  }
60  }
61 
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();
65  const auto ndesc_in_src_graph = src_mrrg.getNodeByPropertiesOf(transformed_mrrg.getNodeRef(ndesc));
66  if (ndesc_in_src_graph) {
67  addMapping(ndesc_in_src_graph, ndesc);
68  }
69  }
70  }
71 }
72 
74  for (auto& map_ptr : {&forward_map, &reverse_map}) {
75  auto& map = *map_ptr;
76 
77  // rename references to `from`
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);
83  set.insert(into);
84  }
85  }
86 
87  // merge/create sets that map from `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)));
94  }
95  }
96 }
97 
98 std::ostream& operator<<(std::ostream& os, const InterMRRGMap& imm) {
99  const auto mapping_printer = [=](auto&& s, auto&& mapping_set) {
100  print_container(s, mapping_set);
101  };
102  os << "}\n forward_map = ";
103  print_assoc_container(os, imm.forward_map, mapping_printer);
104  os << "\n reverse_map = ";
105  print_assoc_container(os, imm.reverse_map, mapping_printer);
106  os << '}';
107  return os;
108 }
109 
111 public:
113  struct Paths {
114  std::vector<std::vector<MRRGNDesc>> paths = {};
115  bool all_paths_found = false;
116  };
117 
118  std::unordered_map<MRRGNDesc, std::unordered_map<MRRGNDesc, std::map<OperandTag,
119  Paths
120  >>> shortest_paths = {};
121 };
122 
127 
130 
132  if (not impl_ptr) {
133  impl_ptr = std::make_shared<MRRGProcedureCache>();
134  }
135  return *impl_ptr;
136 }
137 
140 
141  int i = 0;
142  for (const auto& nodes_for_cycle : mrrg.allNodesByCycle())
143  {
144  std::vector<MRRG::NodeDescriptor> func_nodes;
145  std::vector<MRRG::NodeDescriptor> rout_nodes;
146  for (const auto& node : nodes_for_cycle)
147  {
148  if(node.second->type == MRRG_NODE_FUNCTION)
149  func_nodes.push_back(node.second.get());
150  else if(node.second->type == MRRG_NODE_ROUTING)
151  rout_nodes.push_back(node.second.get());
152  else if(node.second->type == MRRG_NODE_ROUTING_FUNCTION){
153  rout_nodes.push_back(node.second.get());
154  func_nodes.push_back(node.second.get());
155  }
156  else
157  make_and_throw<cgrame_error>([&](auto&& s) {
158  s << "unhanded MRRG node type " << node.second->type;
159  });
160  }
161 
162  result.function_nodes.push_back(func_nodes);
163  result.routing_nodes.push_back(rout_nodes);
164  }
165 
166  return result;
167 }
168 
170  MRRGNodeClassLists result;
171 
172  for (const auto& nodes_for_cycle : mrrg.allNodesByCycle())
173  {
174  for (const auto& node : nodes_for_cycle)
175  {
176  if(node.second->type == MRRG_NODE_FUNCTION)
177  result.function_nodes.push_back(node.second.get());
178  else if(node.second->type == MRRG_NODE_ROUTING)
179  result.routing_nodes.push_back(node.second.get());
180  else if(node.second->type == MRRG_NODE_ROUTING_FUNCTION){
181  result.routing_nodes.push_back(node.second.get());
182  result.function_nodes.push_back(node.second.get());
183  }
184  else
185  make_and_throw<cgrame_error>([&](auto&& s) {
186  s << "unhanded MRRG node type " << node.second->type;
187  });
188  }
189  }
190 
191  return result;
192 }
193 
194 FunctionalUnitNeighbours::NodeInfoList findNeighbourFUs(const MRRG& mrrg, MRRG::NodeDescriptor source, int min_neighbours_to_find) {
195  const auto g_algos = GraphAlgorithms<MRRG::NodeDescriptor>();
196 
197  // start at the fanout of source, so we don't immediately "find it" (only want paths with length > 1)
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;
200 
201  FindNeighbourFUsVisitor visitor;
202 
203  const auto should_stop_searching = [&](auto& discovered_node) {
204  (void)discovered_node;
205  if (min_neighbours_to_find < 0) {
206  return false;
207  } else {
208  std::ptrdiff_t num_found = visitor.discovered_fu_nodes.size();
209  if (visitor.discovered_fu_nodes.find(source) != visitor.discovered_fu_nodes.end()) {
210  num_found -= 1;
211  }
212  return num_found >= min_neighbours_to_find;
213  }
214  };
215 
216  const auto vertex_data = g_algos.wavedBreadthFirstVisit(mrrg, source_fanout_set, should_stop_searching, visitor);
217 
219 
220  for (auto& sink : visitor.discovered_fu_nodes) {
221  auto path_and_success = g_algos.singleTraceback(source_fanout_set, sink, vertex_data);
222  if (path_and_success.success) {
223  result.emplace(sink, FunctionalUnitNeighbours::NodeInfo{ sink, (int)path_and_success.path.size() + path_length_adjustment});
224  }
225  }
226 
227  return result;
228 }
229 
230 std::unordered_map<OpGraph::OpDescriptor, std::vector<MRRG::NodeDescriptor>> findAllCompatibleFUs(const OpGraph& opgraph, const MRRG& base_mrrg) {
231  std::unordered_map<OpGraph::OpDescriptor, std::vector<MRRG::NodeDescriptor>> compatible_fu_nodes;
232 
233  for (auto& op : opgraph.opNodes()) {
234  compatible_fu_nodes.emplace(op, decltype(compatible_fu_nodes)::mapped_type{});
235  for (int cycle = 0; cycle < base_mrrg.initiationInterval(); ++cycle) {
236  for (auto& name_and_node : base_mrrg.allNodesByCycle().at(cycle)) {
237  auto ndesc = name_and_node.second.get();
238  if (base_mrrg.getNodeRef(ndesc).canMapOp(op)) {
239  compatible_fu_nodes[op].emplace_back(ndesc);
240  }
241  }
242  }
243  }
244 
245  return compatible_fu_nodes;
246 }
247 
248 std::vector<std::vector<MRRG::NodeDescriptor>> findNRoutingPathsBetween(
249  int num_paths, const MRRG& mrrg, MRRG::NodeDescriptor source, MRRG::NodeDescriptor sink,
250  std::pair<int,int> cycle_trip_count_min_max, const OperandTag& operand_tag,
251  MRRGProcedureCacheHandle* cache_handle
252 ) {
253  if (cache_handle) {
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()))};
258  }
259  }
260 
261  const auto g_algos = GraphAlgorithms<MRRG::NodeDescriptor>();
262 
263  struct V : DoNothingGraphVisitor<MRRG::NodeDescriptor> {
264  const MRRG* mrrg;
265  MRRG::NodeDescriptor sink, source;
266  const OperandTag* operand_tag;
267 
268  V(const MRRG* mrrg, MRRG::NodeDescriptor sink, MRRG::NodeDescriptor source, const OperandTag* operand_tag)
269  : mrrg(mrrg), sink(sink), source(source), operand_tag(operand_tag) { }
270 
272  if (not nodeIsCompatibleWithOperand(*mrrg, v, *operand_tag)) return true;
273  return v != sink && v != source && (mrrg->getNodeRef(v).type == MRRG_NODE_FUNCTION);
274  }
275  } visitor { &mrrg, sink, source, &operand_tag };
276 
277  // find the paths, ignoring some loops
278  auto result = g_algos.findNShortestPaths(num_paths, mrrg, {source}, findSingleVertex(sink), visitor,
279  [&](const auto& path) {
280  // if it's not a loop, then anything is fine
281  if (source != sink) { return true; }
282  // else only allow trip_count in the interval specified
283  const auto tc = tripCountOfWalk(mrrg, path);
284  return cycle_trip_count_min_max.first <= tc && tc <= cycle_trip_count_min_max.second;
285  }
286  );
287 
288  if (cache_handle) {
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;
292  }
293  return result;
294 }
295 
296 std::vector<std::vector<MRRG::NodeDescriptor>> mergeMRRGWalks(const MRRG& mrrg, const std::vector<MrrgNodeSpan>& walks) {
297  const auto g_algos = GraphAlgorithms<MRRG::NodeDescriptor>();
298  struct Graph {
299  std::map<MRRG::NodeDescriptor, std::set<MRRG::NodeDescriptor>> edges;
300  auto fanout(const MRRG::NodeDescriptor& v) const { return edges.at(v); }
301  } g;
302  std::set<MRRG::NodeDescriptor> sources;
303  std::set<MRRG::NodeDescriptor> sinks;
304 
305  // construct graph, and source & sink sets
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);
312  }
313  g.edges[*prev]; // just make sure it exists
314  }
315 
316  // keep searching until we find all the sinks, and remember their order
317  struct SinkRecordingVisitor : DoNothingGraphVisitor<MRRG::NodeDescriptor> {
318  const std::set<MRRG::NodeDescriptor>* sinks;
319  std::set<MRRG::NodeDescriptor> found_sinks = {};
320  std::vector<MRRG::NodeDescriptor> sink_order = {};
321 
322  SinkRecordingVisitor(const std::set<MRRG::NodeDescriptor>* sinks) : sinks(sinks) { }
323 
324  void onExamine(const MRRG::NodeDescriptor& v) {
325  if (sinks->find(v) == sinks->end()) { return; }
326  if (not found_sinks.insert(v).second) { return; }
327  sink_order.push_back(v);
328  }
329  } sink_recorder {&sinks};
330 
331  // if this is changed to Dijkstra and all costs are positive, then this function will return the optimal merge
332  auto search_tree = g_algos.wavedBreadthFirstVisit(g, sources, visitAllVertices(), sink_recorder);
333 
334  std::vector<std::vector<MRRG::NodeDescriptor>> result;
335 
336  std::set<MRRG::NodeDescriptor> sources_not_found = sources;
337  std::set<MRRG::NodeDescriptor> nodes_in_result = sources;
338 
339  const auto trace_back_and_add = [&](const auto& search_set, const auto& tb_start, const auto& fanin_map) {
340  auto path_and_success = [&]() { // (immediately invoked)
341  if (search_set.find(tb_start) == search_set.end()) {
342  // not a loop, do a normal trace-back
343  return g_algos.singleTraceback(search_set, tb_start, fanin_map);
344  } else {
345  // is a loop, try tracing back from each fanin, because there are no loops in a search *tree*
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); // remember, we started at the fanin
351  return std::move(result);
352  }
353  }
354  throw std::logic_error("loop trace-back failed");
355  }
356  }();
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));
361  };
362 
363  for (const auto& sink : sink_recorder.sink_order) {
364  trace_back_and_add(nodes_in_result, sink, search_tree);
365  }
366 
367  for (const auto& walk : walks) {
368  const auto source = walk.front();
369  if (not sources_not_found.erase(source)) { continue; }
370  MRRG::NodeDescriptor the_node_found;
371  auto fixup_search_tree = g_algos.wavedBreadthFirstVisit(g, singleItemSet(source), findVertexInSet(nodes_in_result, the_node_found));
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);
374  }
375 
376  return result;
377 }
378 
379 int tripCountOfWalk(const MRRG& mrrg, const std::vector<MRRG::NodeDescriptor>& walk) {
380  if (walk.empty()) { return 0; }
381  assertWalkLength(mrrg, walk);
382 
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();
386  // trip count is how many IIs in the future that the output's cycle would be
387  return sum + hypothetical_cycle/mrrg.initiationInterval();
388  });
389 }
390 
391 bool nodeIsCompatibleWithOperand(const MRRG& mrrg, MRRG::NodeDescriptor node, const OperandTag& operand_tag) {
392  const auto& supported_ops = mrrg.getNodeRef(node).supported_operand_tags;
393  return operand_tag.empty() || supported_ops.empty() || supported_ops.find(operand_tag) != supported_ops.end();
394 }
395 
396 bool walkIsCompatibleWithOperand(const MRRG& mrrg, const std::vector<MRRG::NodeDescriptor>& walk, const OperandTag& operand_tag) {
397  if (walk.empty()) { return true; }
398  if (operand_tag.empty()) return true;
399  assertWalkLength(mrrg, walk);
400 
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);
403 }
404 
405 static void recordNodeMerge(
406  const MRRG& src_mrrg, MRRGTransformationResult& transformation_result,
407  MRRG::NodeDescriptor into_ndesc, MRRG::NodeDescriptor from_ndesc
408 ) {
409  auto& new_mrrg = transformation_result.transformed_mrrg;
410  auto& from = new_mrrg.getNodeRef(from_ndesc);
411 
412  // add it to the mappings
413  transformation_result.mapping.mergeDescriptors(from_ndesc, into_ndesc);
414  transformation_result.mapping.addMapping(src_mrrg.getNodeByPropertiesOf(from), into_ndesc);
415 
416  // erase the node, remove all links
417  new_mrrg.erase(from_ndesc);
418 }
419 
421 {
422  MRRGTransformationResult result{src_mrrg};
423  auto& new_mrrg = result.transformed_mrrg;
424  (void)flags;
425 
426  const auto& node_classes = computeNodeClassLists(new_mrrg);
427  std::unordered_set<MRRG::NodeDescriptor> removed_nodes;
428 
429  // remove routing nodes that have exactly one fanin where that fanin only fans-out to this node
430  for (auto& ndesc : node_classes.routing_nodes)
431  {
432  // make sure we haven't already deleted this node
433  if (removed_nodes.find(ndesc) != end(removed_nodes)) { continue; }
434 
435  const auto& node = src_mrrg.getNodeRef(ndesc);
436 
437  // Remove nodes that have an exclusive fanin and are a exclusive fanout of that fanin
438  if (node.fanin.size() == 1) {
439  const auto the_fanin_ndesc = new_mrrg.getNodeRef(ndesc).fanin.at(0); // if statement guarantees there is only one
440  auto& the_fanin_node = new_mrrg.getNodeRef(the_fanin_ndesc);
441  if (
442  (the_fanin_node.type == MRRG_NODE_ROUTING)
443  && the_fanin_node.fanout.size() == 1
444  ) {
445  // std::cout << "reduceLosslessly merging: " << node << " into " << the_fanin_node << '\n';
446  mergeNodePropertiesOfExclusiveFanoutToExclusiveFanin(new_mrrg, the_fanin_ndesc, ndesc);
447  recordNodeMerge(src_mrrg, result, the_fanin_ndesc, ndesc);
448  removed_nodes.emplace(ndesc);
449  }
450  }
451  }
452 
453  result.mapping.addAllByMatchingProperties(src_mrrg, new_mrrg);
454 
455  return result;
456 }
457 
459  MRRGTransformationResult result {src_mrrg};
460  auto& new_mrrg = result.transformed_mrrg;
461 
462  std::vector<std::pair<MRRG::NodeDescriptor, MRRG::NodeDescriptor>> insertionEdges;
463  for (const auto & nodesForCycle: src_mrrg.allNodesByCycle()) {
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);
473  }
474  }
475  }
476  }
477  }
478 
479  // Insert the dummy nodes
480  int i = 0;
481  for (auto & edge: insertionEdges) {
482  const auto & firstNode = src_mrrg.getNodeRef(edge.first);
483  const auto & secondNode = src_mrrg.getNodeRef(edge.second);
484 
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;
487 
488  new_mrrg.link(newNode, new_mrrg.getNodeByPropertiesOf(secondNode));
489  }
490  result.mapping.addAllByMatchingProperties(src_mrrg, new_mrrg);
491 
492  return result;
493 }
494 
495 bool isNodeFanoutOf(const MRRG& mrrg, MRRG::NodeDescriptor driver_ndesc, MRRG::NodeDescriptor test_ndesc) {
496  const auto& driver = mrrg.getNodeRef(driver_ndesc);
497  const auto& test = mrrg.getNodeRef(test_ndesc);
498 
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);
501 
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";
505  });
506  }
507 
508  return found_test_in_fanout_of_driver;
509 }
510 
511 bool isNodeFaninOf(const MRRG& mrrg, MRRG::NodeDescriptor driven_ndesc, MRRG::NodeDescriptor test_ndesc) {
512  const auto& driver = mrrg.getNodeRef(driven_ndesc);
513  const auto& test = mrrg.getNodeRef(test_ndesc);
514 
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);
517 
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";
521  });
522  }
523 
524  return found_test_in_fanin_of_driver;
525 }
526 
527 void assertNodeIsFanoutOf(const MRRG& mrrg, MRRG::NodeDescriptor driver_ndesc, MRRG::NodeDescriptor test_ndesc, const char* action_name) {
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";
530  });}
531 }
532 
533 void assertNodeIsFaninOf(const MRRG& mrrg, MRRG::NodeDescriptor driven_ndesc, MRRG::NodeDescriptor test_ndesc, const char* action_name) {
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";
536  });}
537 }
538 
539 void assertNodeIsExcusiveFanout(const MRRG& mrrg, MRRG::NodeDescriptor driver_ndesc, MRRG::NodeDescriptor test_ndesc, const char* action_name) {
540  assertNodeIsFanoutOf(mrrg, driver_ndesc, test_ndesc, action_name);
541 
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";
544  });}
545 }
546 
547 void assertNodeIsExcusiveFanin(const MRRG& mrrg, MRRG::NodeDescriptor driven_ndesc, MRRG::NodeDescriptor test_ndesc, const char* action_name) {
548  assertNodeIsFaninOf(mrrg, driven_ndesc, test_ndesc, action_name);
549 
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";
552  });}
553 }
554 
555 void assertHasNoOps(const MRRGNode& n, const char* action_name) {
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";
558  });}
559 }
560 
561 void assertHasSingleFanout(const MRRGNode& n, const char* action_name) {
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";
564  });}
565 }
566 
568  auto& from = mrrg.getNodeRef(from_ndesc);
569 
570  for(auto& fanout_ndesc : from.fanout) {
571  if (fanout_ndesc != into_ndesc) {
572  mrrg.link(into_ndesc, fanout_ndesc);
573  }
574  }
575 
576  for(auto& fanin_ndesc : from.fanin) {
577  if (fanin_ndesc != into_ndesc) {
578  mrrg.link(into_ndesc, fanin_ndesc);
579  }
580  }
581 }
582 
584  auto& into = mrrg.getNodeRef(into_ndesc);
585  const auto& from = mrrg.getNodeRef(from_ndesc);
586 
587  assertNodeIsExcusiveFanout(mrrg, into_ndesc, from_ndesc, "merge");
588  assertNodeIsExcusiveFanin(mrrg, from_ndesc, into_ndesc, "merge");
589  assertHasNoOps(from, "merge");
590 
591  mergeNodeConnections(mrrg, into_ndesc, from_ndesc);
592 
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;
597  }
598  else {
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";
602  });
603  }
604  }
605 }
606 
607 Mapping transformToOriginalMRRG(const Mapping & map, const MRRGTransformationResult & transformation) {
608  Mapping reversedMap(map);
609  reversedMap.clear(); // Start with an empty mapping
610  reversedMap.setStatus(map.getStatus());
612 
618  for (auto & opToMRRG : map.getMapping()) {
619  for (auto & node_trans : opToMRRG.second) {
620  // Get the nodes that were transformed from the original MRRG
621  for (auto & node_orig: transformation.mapping.oldNodesForNewNode(node_trans)) {
622  reversedMap.mapMRRGNode(opToMRRG.first, node_orig);
623  }
624  }
625  }
626 
627  return reversedMap;
628 }
findAllCompatibleFUs
std::unordered_map< OpGraph::OpDescriptor, std::vector< MRRG::NodeDescriptor > > findAllCompatibleFUs(const OpGraph &opgraph, const MRRG &base_mrrg)
Definition: MRRGProcedures.cpp:230
MRRG::link
void link(MRRG::NodeDescriptor driver, MRRG::NodeDescriptor fanout)
Definition: MRRG.cpp:849
assertNodeIsFanoutOf
void assertNodeIsFanoutOf(const MRRG &mrrg, MRRG::NodeDescriptor driver_ndesc, MRRG::NodeDescriptor test_ndesc, const char *action_name)
Definition: MRRGProcedures.cpp:527
MRRG_NODE_ROUTING_FUNCTION
@ MRRG_NODE_ROUTING_FUNCTION
Definition: MRRG.h:47
MRRGNodeClassLists::function_nodes
std::vector< MRRG::NodeDescriptor > function_nodes
Definition: MRRGProcedures.h:39
recordNodeMerge
static void recordNodeMerge(const MRRG &src_mrrg, MRRGTransformationResult &transformation_result, MRRG::NodeDescriptor into_ndesc, MRRG::NodeDescriptor from_ndesc)
Definition: MRRGProcedures.cpp:405
MRRGTransformationResult::mapping
InterMRRGMap mapping
Definition: MRRGProcedures.h:280
OperandTag
std::string OperandTag
Definition: OpGraph.h:81
MRRGProcedureCacheHandle::~MRRGProcedureCacheHandle
~MRRGProcedureCacheHandle()
findNRoutingPathsBetween
std::vector< std::vector< MRRG::NodeDescriptor > > findNRoutingPathsBetween(int num_paths, const MRRG &mrrg, MRRG::NodeDescriptor source, MRRG::NodeDescriptor sink, std::pair< int, int > cycle_trip_count_min_max, const OperandTag &operand_tag, MRRGProcedureCacheHandle *cache_handle)
Definition: MRRGProcedures.cpp:248
MRRG::allNodesByCycle
const auto & allNodesByCycle() const
Definition: MRRG.h:357
InterMRRGMap
Definition: MRRGProcedures.h:246
GraphAlgorithms
Definition: GraphAlgorithms.h:72
MRRG
Definition: MRRG.h:216
MRRG::NodeDescriptor
const MRRGNode * NodeDescriptor
Definition: MRRG.h:219
GraphAlgorithms.h
MRRGNode::type
MRRGNode_Type type
Definition: MRRG.h:107
Mapping::getMapping
std::map< OpGraph::NodeDescriptor, std::vector< MRRG::NodeDescriptor > > & getMapping()
Definition: Mapping.h:47
InterMRRGMap::forward_map
std::unordered_map< MRRG::NodeDescriptor, NodeSet > forward_map
Definition: MRRGProcedures.h:275
assertNodeIsExcusiveFanin
void assertNodeIsExcusiveFanin(const MRRG &mrrg, MRRG::NodeDescriptor driven_ndesc, MRRG::NodeDescriptor test_ndesc, const char *action_name)
Definition: MRRGProcedures.cpp:547
MRRGNodeClassListsByCycle::routing_nodes
std::vector< std::vector< MRRG::NodeDescriptor > > routing_nodes
Definition: MRRGProcedures.h:45
nodeIsCompatibleWithOperand
bool nodeIsCompatibleWithOperand(const MRRG &mrrg, MRRG::NodeDescriptor node, const OperandTag &operand_tag)
Definition: MRRGProcedures.cpp:391
begin
auto begin(const SingleItemImmutableSet< VertexID > &siis)
Definition: Collections.h:137
FindNeighbourFUsVisitor::discovered_fu_nodes
std::unordered_set< MRRG::NodeDescriptor > discovered_fu_nodes
Definition: MRRGProcedures.h:284
MRRGProcedureCache::Paths::all_paths_found
bool all_paths_found
Definition: MRRGProcedures.cpp:115
Mapping::solve_time_in_seconds
double solve_time_in_seconds
Definition: Mapping.h:110
MRRGProcedureCacheHandle::MRRGProcedureCacheHandle
MRRGProcedureCacheHandle()
Definition: MRRGProcedures.cpp:123
FindNeighbourFUsVisitor
Definition: MRRGProcedures.h:283
isNodeFanoutOf
bool isNodeFanoutOf(const MRRG &mrrg, MRRG::NodeDescriptor driver_ndesc, MRRG::NodeDescriptor test_ndesc)
Definition: MRRGProcedures.cpp:495
DoNothingGraphVisitor::shouldIgnore
bool shouldIgnore(const VertexID &)
Definition: GraphAlgorithmHelpers.h:65
visitAllVertices
auto visitAllVertices()
Definition: GraphAlgorithmHelpers.h:38
Mapping::getStatus
MappingStatus getStatus() const
Definition: Mapping.h:39
computeNodeClassListsByCycle
MRRGNodeClassListsByCycle computeNodeClassListsByCycle(const MRRG &mrrg)
Definition: MRRGProcedures.cpp:138
MRRGTransformationResult::transformed_mrrg
MRRG transformed_mrrg
Definition: MRRGProcedures.h:279
DoNothingGraphVisitor::onExamine
void onExamine(const VertexID &)
Definition: GraphAlgorithmHelpers.h:55
mergeNodePropertiesOfExclusiveFanoutToExclusiveFanin
void mergeNodePropertiesOfExclusiveFanoutToExclusiveFanin(MRRG &mrrg, MRRG::NodeDescriptor into_ndesc, MRRG::NodeDescriptor from_ndesc)
Definition: MRRGProcedures.cpp:583
isNodeFaninOf
bool isNodeFaninOf(const MRRG &mrrg, MRRG::NodeDescriptor driven_ndesc, MRRG::NodeDescriptor test_ndesc)
Definition: MRRGProcedures.cpp:511
to_string
const std::string & to_string(const OpGraphOpCode &opcode)
Definition: OpGraph.cpp:111
set
dot tab cc set(dot_y_cc ${gen_dir}/dot.y.cc) if(BISON_FOUND) bison_target(dotparser_parser dot.y $
Definition: CMakeLists.txt:8
Mapping::mapMRRGNode
void mapMRRGNode(OpGraph::NodeDescriptor, MRRG::NodeDescriptor node)
Definition: Mapping.cpp:58
findSingleVertex
auto findSingleVertex(VertexID v)
Definition: GraphAlgorithmHelpers.h:22
MRRG::getNodeByPropertiesOf
NodeDescriptor getNodeByPropertiesOf(const MRRGNode &node) const
Definition: MRRG.h:266
print_assoc_container
void print_assoc_container(OSTREAM &&os, const ASSOC_CONTAINER &c, const T1 &element_separator, const T2 &key_value_separator, const T3 &element_prefix, const T4 &element_suffix, const T5 &container_prefix, const T6 &container_suffix, KEY_PRINTER &&value_printer=KEY_PRINTER{}, VALUE_PRINTER &&key_printer=VALUE_PRINTER{})
Definition: Collections.h:488
Mapping
Definition: Mapping.h:31
findNeighbourFUs
FunctionalUnitNeighbours::NodeInfoList findNeighbourFUs(const MRRG &mrrg, MRRG::NodeDescriptor source, int min_neighbours_to_find)
Definition: MRRGProcedures.cpp:194
MRRGProcedureCache::shortest_paths
std::unordered_map< MRRGNDesc, std::unordered_map< MRRGNDesc, std::map< OperandTag, Paths > > > shortest_paths
Definition: MRRGProcedures.cpp:120
muxExNodeInsertion
MRRGTransformationResult muxExNodeInsertion(const MRRG &src_mrrg)
Definition: MRRGProcedures.cpp:458
MRRG::fanout
auto & fanout(NodeDescriptor ndesc) const
Definition: MRRG.h:288
MRRGNode::canMapOp
bool canMapOp(OpGraphOp const *op) const
Definition: MRRG.cpp:581
MRRG::getNodeRef
MRRGNode & getNodeRef(NodeDescriptor ndesc)
Definition: MRRG.h:273
MRRGNode::fanin
std::vector< MRRGNode * > fanin
Definition: MRRG.h:114
OpGraph::opNodes
auto & opNodes() const
Definition: OpGraph.h:313
InterMRRGMap::oldNodesForNewNode
const NodeSet & oldNodesForNewNode(MRRG::NodeDescriptor n) const
Definition: MRRGProcedures.h:255
MRRG_NODE_FUNCTION
@ MRRG_NODE_FUNCTION
Definition: MRRG.h:46
MRRGProcedureCache
Definition: MRRGProcedures.cpp:110
InterMRRGMap::addMapping
void addMapping(MRRG::NodeDescriptor old_node, MRRG::NodeDescriptor new_node)
Definition: MRRGProcedures.h:257
FunctionalUnitNeighbours
Definition: MRRGProcedures.h:48
assertHasSingleFanout
void assertHasSingleFanout(const MRRGNode &n, const char *action_name)
Definition: MRRGProcedures.cpp:561
MRRG_NODE_ROUTING
@ MRRG_NODE_ROUTING
Definition: MRRG.h:45
FunctionalUnitNeighbours::isReachableFrom
bool isReachableFrom(MRRG::NodeDescriptor src, MRRG::NodeDescriptor dest) const
Definition: MRRGProcedures.cpp:28
MRRGNode::supported_ops
std::vector< OpGraphOpCode > supported_ops
Definition: MRRG.h:111
operator<<
std::ostream & operator<<(std::ostream &os, const FunctionalUnitNeighbours &fu_neighbours)
Definition: MRRGProcedures.cpp:38
assertNodeIsExcusiveFanout
void assertNodeIsExcusiveFanout(const MRRG &mrrg, MRRG::NodeDescriptor driver_ndesc, MRRG::NodeDescriptor test_ndesc, const char *action_name)
Definition: MRRGProcedures.cpp:539
MRRGProcedureCache::Paths
Definition: MRRGProcedures.cpp:113
transformToOriginalMRRG
Mapping transformToOriginalMRRG(const Mapping &map, const MRRGTransformationResult &transformation)
Definition: MRRGProcedures.cpp:607
InterMRRGMap::addAllByMatchingProperties
void addAllByMatchingProperties(const MRRG &src_mrrg, const MRRG &transformed_mrrg)
Definition: MRRGProcedures.cpp:51
DoNothingGraphVisitor
Definition: GraphAlgorithmHelpers.h:49
end
auto end(const SingleItemImmutableSet< VertexID > &siis)
Definition: Collections.h:138
InterMRRGMap::reverse_map
std::unordered_map< MRRG::NodeDescriptor, NodeSet > reverse_map
Definition: MRRGProcedures.h:276
MRRGNodeClassLists::routing_nodes
std::vector< MRRG::NodeDescriptor > routing_nodes
Definition: MRRGProcedures.h:40
print_container
void print_container(OSTREAM &&os, const CONTAINER &c, const T1 &element_separator, const T2 &container_prefix, const T3 &container_suffix, PRINTER &&element_printer=PRINTER{})
Definition: Collections.h:435
MRRGNode
Definition: MRRG.h:60
reduceLosslessly
MRRGTransformationResult reduceLosslessly(const MRRG &src_mrrg, const MRRGTransformFlags &flags)
Definition: MRRGProcedures.cpp:420
Mapping::clear
void clear()
Definition: Mapping.cpp:95
MRRGNode::fanout
std::vector< MRRGNode * > fanout
Definition: MRRG.h:113
MRRGProcedureCacheHandle::impl_ptr
std::shared_ptr< MRRGProcedureCache > impl_ptr
Definition: MRRGProcedureCache.h:38
mergeNodeConnections
void mergeNodeConnections(MRRG &mrrg, MRRG::NodeDescriptor into_ndesc, MRRG::NodeDescriptor from_ndesc)
Definition: MRRGProcedures.cpp:567
MRRGNodeClassListsByCycle::function_nodes
std::vector< std::vector< MRRG::NodeDescriptor > > function_nodes
Definition: MRRGProcedures.h:44
InterMRRGMap::mergeDescriptors
void mergeDescriptors(MRRG::NodeDescriptor from, MRRG::NodeDescriptor into)
Definition: MRRGProcedures.cpp:73
MRRGProcedureCache::Paths::paths
std::vector< std::vector< MRRGNDesc > > paths
Definition: MRRGProcedures.cpp:114
FunctionalUnitNeighbours::NodeInfoList
std::unordered_map< MRRG::NodeDescriptor, NodeInfo > NodeInfoList
Definition: MRRGProcedures.h:56
FunctionalUnitNeighbours::neighbours
std::unordered_map< MRRG::NodeDescriptor, NodeInfoList > neighbours
Definition: MRRGProcedures.h:62
MRRGNode::supported_operand_tags
SupportedOpTags supported_operand_tags
Definition: MRRG.h:117
MRRG::initiationInterval
int initiationInterval() const
Definition: MRRG.h:346
MRRGProcedures.h
singleItemSet
SingleItemImmutableSet< VertexID > singleItemSet(VertexID v)
Definition: Collections.h:143
findVertexInSet
auto findVertexInSet(const VertexSet &v_set, VertexID &vertex_found)
Definition: GraphAlgorithmHelpers.h:27
MRRGProcedureCacheHandle
Definition: MRRGProcedureCache.h:20
MRRGProcedureCache::MRRGNDesc
MRRG::NodeDescriptor MRRGNDesc
Definition: MRRGProcedures.cpp:112
mergeMRRGWalks
std::vector< std::vector< MRRG::NodeDescriptor > > mergeMRRGWalks(const MRRG &mrrg, const std::vector< MrrgNodeSpan > &walks)
Definition: MRRGProcedures.cpp:296
MRRGNodeClassLists
Definition: MRRGProcedures.h:38
MRRGNode::make_routing
static MRRGNode make_routing(Module *parent, int bitwidth, int cycle, STR &&name, int latency=0, int max_cap=1)
Definition: MRRG.h:151
MRRGNodeClassListsByCycle
Definition: MRRGProcedures.h:43
MRRGTransformFlags
Definition: MRRGProcedures.h:70
tripCountOfWalk
int tripCountOfWalk(const MRRG &mrrg, const std::vector< MRRG::NodeDescriptor > &walk)
Definition: MRRGProcedures.cpp:379
walkIsCompatibleWithOperand
bool walkIsCompatibleWithOperand(const MRRG &mrrg, const std::vector< MRRG::NodeDescriptor > &walk, const OperandTag &operand_tag)
Definition: MRRGProcedures.cpp:396
OpGraph
Definition: OpGraph.h:215
assertHasNoOps
void assertHasNoOps(const MRRGNode &n, const char *action_name)
Definition: MRRGProcedures.cpp:555
assertNodeIsFaninOf
void assertNodeIsFaninOf(const MRRG &mrrg, MRRG::NodeDescriptor driven_ndesc, MRRG::NodeDescriptor test_ndesc, const char *action_name)
Definition: MRRGProcedures.cpp:533
FunctionalUnitNeighbours::NodeInfo
Definition: MRRGProcedures.h:49
Mapping::setStatus
void setStatus(MappingStatus new_status)
Definition: Mapping.h:40
computeNodeClassLists
MRRGNodeClassLists computeNodeClassLists(const MRRG &mrrg)
Definition: MRRGProcedures.cpp:169
MRRGProcedureCacheHandle::getOrCreate
MRRGProcedureCache & getOrCreate()
Definition: MRRGProcedures.cpp:131
MRRGProcedureCacheHandle::operator=
MRRGProcedureCacheHandle & operator=(const MRRGProcedureCacheHandle &)
MRRGTransformationResult
Definition: MRRGProcedures.h:278