Jlm
view.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2024 David Metz <david.c.metz@ntnu.no>
3  * See COPYING for terms of redistribution.
4  */
5 
6 #include <jlm/hls/ir/hls.hpp>
7 #include <jlm/hls/util/view.hpp>
8 #include <jlm/rvsdg/gamma.hpp>
9 #include <jlm/rvsdg/region.hpp>
12 #include <jlm/rvsdg/theta.hpp>
13 #include <jlm/rvsdg/traverser.hpp>
14 #include <jlm/rvsdg/view.hpp>
15 
16 #include <algorithm>
17 
18 namespace jlm::hls
19 {
20 
21 std::string
23 {
24  switch (color)
25  {
26  case NONE:
27  return "";
28  break;
29 
30  case BLACK:
31  return "black";
32  break;
33 
34  case RED:
35  return "red";
36  break;
37 
38  default:
39  JLM_UNREACHABLE("HLS view color not defined");
40  break;
41  }
42 }
43 
44 static inline std::string
45 hex(size_t i)
46 {
47  std::stringstream stream;
48  stream << std::hex << i;
49  return stream.str();
50 }
51 
52 std::string
54 {
55  return util::strfmt("n", hex((intptr_t)node));
56 }
57 
58 std::string
60 {
61  if (dynamic_cast<rvsdg::RegionArgument *>(output))
62  {
63  return util::strfmt("a", hex((intptr_t)output), ":", "default");
64  }
65 
66  if (auto simpleNode = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*output))
67  {
68  return util::strfmt(GetDotName(simpleNode), ":", "o", hex((intptr_t)output));
69  }
70  else if (dynamic_cast<rvsdg::StructuralOutput *>(output))
71  {
72  return util::strfmt("so", hex((intptr_t)output), ":", "default");
73  }
74  JLM_UNREACHABLE("not implemented");
75 }
76 
77 template<class T>
79 GetDefaultColor(std::unordered_map<T *, ViewColors> & map, T * elem, ViewColors def = BLACK)
80 {
81  auto f = map.find(elem);
82  if (f == map.end())
83  {
84  return def;
85  }
86  return f->second;
87 }
88 
89 template<class T>
91 GetDefaultLabel(std::unordered_map<T *, ViewColors> & map, T * elem, ViewColors def = NONE)
92 {
93  auto f = map.find(elem);
94  if (f == map.end())
95  {
96  return def;
97  }
98  return f->second;
99 }
100 
101 std::string
103 {
104  if (dynamic_cast<rvsdg::RegionResult *>(input))
105  {
106  return util::strfmt("r", hex((intptr_t)input), ":", "default");
107  }
108  if (auto simpleNode = rvsdg::TryGetOwnerNode<rvsdg::SimpleNode>(*input))
109  {
110  return util::strfmt(GetDotName(simpleNode), ":", "i", hex((intptr_t)input));
111  }
112  else if (dynamic_cast<rvsdg::StructuralInput *>(input))
113  {
114  return util::strfmt("si", hex((intptr_t)input), ":", "default");
115  }
116  JLM_UNREACHABLE("not implemented");
117 }
118 
119 std::string
120 PortToDot(const std::string & display_name, const std::string & dot_name, const ViewColors & color)
121 {
122  auto dot =
123  dot_name
124  + " [shape=plaintext label=<\n"
125  " <TABLE BORDER=\"0\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">\n"
126  " <TR>\n"
127  " <TD PORT=\"default\" BORDER=\"1\" CELLPADDING=\"1\"><FONT "
128  "POINT-SIZE=\"10\">"
129  + display_name
130  + "</FONT></TD>\n"
131  " </TR>\n"
132  " </TABLE>\n"
133  "> tooltip=\""
134  + dot_name + "\" color=" + ViewcolorToString(color) + " fontcolor=" + ViewcolorToString(color)
135  + "];\n";
136  return dot;
137 }
138 
139 std::string
141 {
142  auto display_name = util::strfmt("a", argument->index());
143  auto dot_name = util::strfmt("a", hex((intptr_t)argument));
144  return PortToDot(display_name, dot_name, color);
145 }
146 
147 std::string
149 {
150  auto display_name = util::strfmt("r", result->index());
151  auto dot_name = util::strfmt("r", hex((intptr_t)result));
152  return PortToDot(display_name, dot_name, color);
153 }
154 
155 std::string
156 StructuralInputToDot(rvsdg::StructuralInput * structuralInput, const ViewColors & color)
157 {
158  auto display_name = util::strfmt("si", structuralInput->index());
159  auto dot_name = util::strfmt("si", hex((intptr_t)structuralInput));
160  return PortToDot(display_name, dot_name, color);
161 }
162 
163 std::string
164 StructuralOutputToDot(rvsdg::StructuralOutput * structuralOutput, const ViewColors & color)
165 {
166  auto display_name = util::strfmt("so", structuralOutput->index());
167  auto dot_name = util::strfmt("so", hex((intptr_t)structuralOutput));
168  return PortToDot(display_name, dot_name, color);
169 }
170 
171 std::string
173  jlm::rvsdg::Output * output,
174  jlm::rvsdg::Input * input,
175  std::unordered_map<rvsdg::Output *, ViewColors> & tailLabel,
176  bool back_edge = false)
177 {
178  auto color = "black";
179  auto tailLabelColor = GetDefaultLabel(tailLabel, output);
180  if (!back_edge)
181  {
182  return GetDotName(output) + " -> " + GetDotName(input)
183  + " [style=\"\", arrowhead=\"normal\", color=" + color
184  + ", headlabel=<>, fontsize=15, labelangle=45, labeldistance=2.0, labelfontcolor=blue, "
185  "tooltip=\""
186  + output->Type()->debug_string() + "\", taillabel=\"" + ViewcolorToString(tailLabelColor)
187  + "\"];\n";
188  }
189  return GetDotName(input) + " -> " + GetDotName(output)
190  + " [style=\"\", arrowhead=\"normal\", color=" + color
191  + ", headlabel=<>, fontsize=15, labelangle=45, labeldistance=2.0, labelfontcolor=blue, "
192  "constraint=false, tooltip=\""
193  + output->Type()->debug_string() + "\", taillabel=\"" + ViewcolorToString(tailLabelColor)
194  + "\"];\n";
195 }
196 
197 std::string
199 {
200  auto color = "black";
201  return GetDotName(output) + " -> " + GetDotName(input)
202  + " [style=\"\", arrowhead=\"normal\", color=" + color
203  + ", headlabel=<>, fontsize=10, labelangle=45, labeldistance=2.0, labelfontcolor=black, "
204  "tooltip=\""
205  + output->Type()->debug_string() + "\"];\n";
206 }
207 
208 static bool
209 isForbiddenChar(char c)
210 {
211  if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || ('0' <= c && c <= '9') || '_' == c)
212  {
213  return false;
214  }
215  return true;
216 }
217 
218 std::string
220  rvsdg::StructuralNode * structuralNode,
221  std::unordered_map<rvsdg::Output *, ViewColors> & outputColor,
222  std::unordered_map<rvsdg::Input *, ViewColors> & inputColor,
223  std::unordered_map<rvsdg::Output *, ViewColors> & tailLabel)
224 {
225 
226  std::ostringstream dot;
227  dot << "subgraph cluster_sn" << hex((intptr_t)structuralNode) << " {\n";
228  dot << "color=\"#ff8080\"\n";
229  dot << "penwidth=6\n";
230  dot << "label=\"" << structuralNode->DebugString() << "\"\n";
231  dot << "labeljust=l\n";
232 
233  // input nodes
234  for (size_t i = 0; i < structuralNode->ninputs(); ++i)
235  {
236  dot << StructuralInputToDot(
237  structuralNode->input(i),
238  GetDefaultColor<rvsdg::Input>(inputColor, structuralNode->input(i)));
239  }
240 
241  for (size_t i = 0; i < structuralNode->nsubregions(); ++i)
242  {
243  dot << RegionToDot(structuralNode->subregion(i), outputColor, inputColor, tailLabel);
244  }
245 
246  for (size_t i = 0; i < structuralNode->ninputs(); ++i)
247  {
248  for (auto & argument : structuralNode->input(i)->arguments)
249  {
250  dot << SymbolicEdge(structuralNode->input(i), &argument);
251  }
252  }
253 
254  // output nodes
255  for (size_t i = 0; i < structuralNode->noutputs(); ++i)
256  {
257  dot << StructuralOutputToDot(
258  structuralNode->output(i),
259  GetDefaultColor<rvsdg::Output>(outputColor, structuralNode->output(i)));
260  for (auto & result : structuralNode->output(i)->results)
261  {
262  dot << SymbolicEdge(&result, structuralNode->output(i));
263  }
264  }
265 
266  dot << "}\n";
267 
268  return dot.str();
269 }
270 
271 std::string
273  rvsdg::SimpleNode * simpleNode,
274  std::unordered_map<rvsdg::Output *, ViewColors> & outputColor,
275  std::unordered_map<rvsdg::Input *, ViewColors> & inputColor)
276 {
277  auto SPACER = " <TD WIDTH=\"10\"></TD>\n";
278  auto name = GetDotName(simpleNode);
279  auto opname = simpleNode->DebugString();
280  std::replace_if(opname.begin(), opname.end(), isForbiddenChar, '_');
281 
282  std::ostringstream inputs;
283  // inputs
284  for (size_t i = 0; i < simpleNode->ninputs(); ++i)
285  {
286  auto color = GetDefaultColor<rvsdg::Input>(inputColor, simpleNode->input(i));
287  if (i != 0)
288  {
289  inputs << SPACER;
290  }
291  inputs << " <TD PORT=\"i" << hex((intptr_t)simpleNode->input(i))
292  << "\" BORDER=\"1\" CELLPADDING=\"1\" COLOR=\"" << color
293  << "\"><FONT POINT-SIZE=\"10\" COLOR=\"" << color << "\"> i" << i << "</FONT></TD>\n";
294  }
295 
296  std::ostringstream outputs;
297  // outputs
298  for (size_t i = 0; i < simpleNode->noutputs(); ++i)
299  {
300  auto color = GetDefaultColor<rvsdg::Output>(outputColor, simpleNode->output(i));
301  if (i != 0)
302  {
303  outputs << SPACER;
304  }
305  outputs << " <TD PORT=\"o" << hex((intptr_t)simpleNode->output(i))
306  << "\" BORDER=\"1\" CELLPADDING=\"1\" COLOR=\"" << color
307  << "\"><FONT POINT-SIZE=\"10\" COLOR=\"" << color << "\"> o" << i << "</FONT></TD>\n";
308  }
309 
310  std::string color = "black";
311  auto dot =
312  name
313  + " [shape=plaintext label=<\n"
314  "<TABLE BORDER=\"0\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">\n"
315  // inputs
316  " <TR>\n"
317  " <TD BORDER=\"0\">\n"
318  " <TABLE BORDER=\"0\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">\n"
319  " <TR>\n"
320  " <TD WIDTH=\"20\"></TD>\n"
321  + inputs.str()
322  + " <TD WIDTH=\"20\"></TD>\n"
323  " </TR>\n"
324  " </TABLE>\n"
325  " </TD>\n"
326  " </TR>\n"
327  " <TR>\n"
328  " <TD BORDER=\"3\" STYLE=\"ROUNDED\" CELLPADDING=\"4\">"
329  + opname + "<BR/><FONT POINT-SIZE=\"10\">" + name
330  + "</FONT></TD>\n"
331  " </TR>\n"
332  " <TR>\n"
333  " <TD BORDER=\"0\">\n"
334  " <TABLE BORDER=\"0\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">\n"
335  " <TR>\n"
336  " <TD WIDTH=\"20\"></TD>\n"
337  + outputs.str()
338  + " <TD WIDTH=\"20\"></TD>\n"
339  " </TR>\n"
340  " </TABLE>\n"
341  " </TD>\n"
342  " </TR>\n"
343  "</TABLE>\n"
344  "> fontcolor="
345  + color + " color=" + color + "];\n";
346  return dot;
347 }
348 
349 std::string
351  rvsdg::Region * region,
352  std::unordered_map<rvsdg::Output *, ViewColors> & outputColor,
353  std::unordered_map<rvsdg::Input *, ViewColors> & inputColor,
354  std::unordered_map<rvsdg::Output *, ViewColors> & tailLabel)
355 {
356  std::ostringstream dot;
357  dot << "subgraph cluster_reg" << hex((intptr_t)region) << " {\n";
358  dot << "color=\"#80b3ff\"\n";
359  dot << "penwidth=6\n";
360  dot << "label=\"" << region->index() << " - " << hex((intptr_t)region) << "\"\n";
361 
362  // argument nodes
363  dot << "{rank=source; ";
364  for (size_t i = 0; i < region->narguments(); ++i)
365  {
366  dot << ArgumentToDot(
367  region->argument(i),
368  GetDefaultColor<rvsdg::Output>(outputColor, region->argument(i)));
369  }
370  dot << "}\n";
371 
372  // nodes
373  for (auto node : rvsdg::TopDownTraverser(region))
374  {
375  if (auto simpleNode = dynamic_cast<rvsdg::SimpleNode *>(node))
376  {
377  auto node_dot = SimpleNodeToDot(simpleNode, outputColor, inputColor);
378  dot << node_dot;
379  }
380  else if (auto structuralNode = dynamic_cast<rvsdg::StructuralNode *>(node))
381  {
382  auto node_dot = StructuralNodeToDot(structuralNode, outputColor, inputColor, tailLabel);
383  dot << node_dot;
384  }
385 
386  for (size_t i = 0; i < node->ninputs(); ++i)
387  {
388  dot << Edge(node->input(i)->origin(), node->input(i), tailLabel);
389  }
390  }
391 
392  // result nodes
393  dot << "{rank=sink; ";
394  for (size_t i = 0; i < region->nresults(); ++i)
395  {
396  dot << ResultToDot(
397  region->result(i),
398  GetDefaultColor<rvsdg::Input>(inputColor, region->result(i)));
399  }
400  dot << "}\n";
401  for (size_t i = 0; i < region->nresults(); ++i)
402  {
403  dot << Edge(region->result(i)->origin(), region->result(i), tailLabel);
404  if (auto be = dynamic_cast<BackEdgeResult *>(region->result(i)))
405  {
406  dot << Edge(be->argument(), be, tailLabel, true);
407  }
408  else if (
409  region->result(i)->output()
410  && rvsdg::TryGetOwnerNode<rvsdg::ThetaNode>(*region->result(i)->output()))
411  {
412  auto theta = rvsdg::TryGetOwnerNode<rvsdg::ThetaNode>(*region->result(i)->output());
413  auto loopvar = theta->MapOutputLoopVar(*region->result(i)->output());
414  dot << Edge(loopvar.pre, loopvar.post, tailLabel, true);
415  }
416  }
417 
418  dot << "}\n";
419 
420  return dot.str();
421 }
422 
423 std::string
425  rvsdg::Region * region,
426  std::unordered_map<rvsdg::Output *, ViewColors> & outputColor,
427  std::unordered_map<rvsdg::Input *, ViewColors> & inputColor,
428  std::unordered_map<rvsdg::Output *, ViewColors> & tailLabel)
429 {
430  std::ostringstream dot;
431  dot << "digraph G {\n";
432  dot << RegionToDot(region, outputColor, inputColor, tailLabel);
433  dot << "}\n";
434  return dot.str();
435 }
436 
437 void
439  rvsdg::Region * region,
440  FILE * out,
441  std::unordered_map<rvsdg::Output *, ViewColors> & outputColor,
442  std::unordered_map<rvsdg::Input *, ViewColors> & inputColor,
443  std::unordered_map<rvsdg::Output *, ViewColors> & tailLabel)
444 {
445  fputs(ToDot(region, outputColor, inputColor, tailLabel).c_str(), out);
446  fflush(out);
447 }
448 
449 void
450 ViewDot(rvsdg::Region * region, FILE * out)
451 {
452  std::unordered_map<rvsdg::Output *, ViewColors> outputColor;
453  std::unordered_map<rvsdg::Input *, ViewColors> inputColor;
454  std::unordered_map<rvsdg::Output *, ViewColors> tailLabel;
455  ViewDot(region, out, outputColor, inputColor, tailLabel);
456 }
457 
458 void
459 DumpDot(llvm::LlvmRvsdgModule & rvsdgModule, const std::string & file_name)
460 {
461  DumpDot(&rvsdgModule.Rvsdg().GetRootRegion(), file_name);
462 }
463 
464 void
466  llvm::LlvmRvsdgModule & rvsdgModule,
467  const std::string & file_name,
468  std::unordered_map<rvsdg::Output *, ViewColors> outputColor,
469  std::unordered_map<rvsdg::Input *, ViewColors> inputColor,
470  std::unordered_map<rvsdg::Output *, ViewColors> tailLabel)
471 {
472  DumpDot(&rvsdgModule.Rvsdg().GetRootRegion(), file_name, outputColor, inputColor, tailLabel);
473 }
474 
475 void
476 DumpDot(rvsdg::Region * region, const std::string & file_name)
477 {
478  auto dot_file = fopen(file_name.c_str(), "w");
479  ViewDot(region, dot_file);
480  fclose(dot_file);
481 }
482 
483 void
485  rvsdg::Region * region,
486  const std::string & file_name,
487  std::unordered_map<rvsdg::Output *, ViewColors> outputColor,
488  std::unordered_map<rvsdg::Input *, ViewColors> inputColor,
489  std::unordered_map<rvsdg::Output *, ViewColors> tailLabel)
490 {
491  auto dot_file = fopen(file_name.c_str(), "w");
492  ViewDot(region, dot_file, outputColor, inputColor, tailLabel);
493  fclose(dot_file);
494 }
495 
496 void
497 DotToSvg(const std::string & file_name)
498 {
499  auto cmd = "dot -Tsvg -O " + file_name;
500  if (system(cmd.c_str()))
501  exit(EXIT_FAILURE);
502 }
503 
505 
508 {}
509 
510 void
512  rvsdg::RvsdgModule & rvsdgModule,
513  util::StatisticsCollector & statisticsCollector)
514 {
515  const auto file = statisticsCollector.createOutputFile("rvsdg-graph.dot", true);
516  DumpDot(&rvsdgModule.Rvsdg().GetRootRegion(), file.path().to_str());
517 }
518 
519 } // namespace jlm::hls
~DumpDotTransformation() noexcept override
void Run(rvsdg::RvsdgModule &rvsdgModule, util::StatisticsCollector &statisticsCollector) override
Definition: view.cpp:511
Region & GetRootRegion() const noexcept
Definition: graph.hpp:99
Output * origin() const noexcept
Definition: node.hpp:58
size_t index() const noexcept
Definition: node.hpp:52
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition: node.hpp:67
size_t ninputs() const noexcept
Definition: node.hpp:609
size_t noutputs() const noexcept
Definition: node.hpp:644
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition: node.hpp:366
size_t index() const noexcept
Definition: node.hpp:274
Represents the argument of a region.
Definition: region.hpp:41
Represents the result of a region.
Definition: region.hpp:120
StructuralOutput * output() const noexcept
Definition: region.hpp:149
Represent acyclic RVSDG subgraphs.
Definition: region.hpp:213
RegionResult * result(size_t index) const noexcept
Definition: region.hpp:471
size_t nresults() const noexcept
Definition: region.hpp:465
size_t index() const noexcept
Definition: region.hpp:375
RegionArgument * argument(size_t index) const noexcept
Definition: region.hpp:437
size_t narguments() const noexcept
Definition: region.hpp:431
Graph & Rvsdg() noexcept
Definition: RvsdgModule.hpp:57
std::string DebugString() const override
Definition: simple-node.cpp:79
NodeInput * input(size_t index) const noexcept
Definition: simple-node.hpp:82
NodeOutput * output(size_t index) const noexcept
Definition: simple-node.hpp:88
std::string DebugString() const override
size_t nsubregions() const noexcept
StructuralOutput * output(size_t index) const noexcept
StructuralInput * input(size_t index) const noexcept
rvsdg::Region * subregion(size_t index) const noexcept
Represents an RVSDG transformation.
File createOutputFile(std::string fileNameSuffix, bool includeCount=false)
Definition: Statistics.cpp:179
#define JLM_UNREACHABLE(msg)
Definition: common.hpp:43
std::string GetDotName(rvsdg::Node *node)
Definition: view.cpp:53
ViewColors GetDefaultLabel(std::unordered_map< T *, ViewColors > &map, T *elem, ViewColors def=NONE)
Definition: view.cpp:91
std::string SymbolicEdge(rvsdg::Input *output, rvsdg::Output *input)
Definition: view.cpp:198
void DumpDot(llvm::LlvmRvsdgModule &rvsdgModule, const std::string &file_name)
Definition: view.cpp:459
std::string RegionToDot(rvsdg::Region *region, std::unordered_map< rvsdg::Output *, ViewColors > &outputColor, std::unordered_map< rvsdg::Input *, ViewColors > &inputColor, std::unordered_map< rvsdg::Output *, ViewColors > &tailLabel)
Definition: view.cpp:350
ViewColors
Definition: view.hpp:19
@ BLACK
Definition: view.hpp:21
@ NONE
Definition: view.hpp:20
@ RED
Definition: view.hpp:22
std::string ResultToDot(rvsdg::RegionResult *result, const ViewColors &color)
Definition: view.cpp:148
std::string PortToDot(const std::string &display_name, const std::string &dot_name, const ViewColors &color)
Definition: view.cpp:120
void DotToSvg(const std::string &file_name)
Definition: view.cpp:497
void ViewDot(rvsdg::Region *region, FILE *out, std::unordered_map< rvsdg::Output *, ViewColors > &outputColor, std::unordered_map< rvsdg::Input *, ViewColors > &inputColor, std::unordered_map< rvsdg::Output *, ViewColors > &tailLabel)
Definition: view.cpp:438
std::string Edge(jlm::rvsdg::Output *output, jlm::rvsdg::Input *input, std::unordered_map< rvsdg::Output *, ViewColors > &tailLabel, bool back_edge=false)
Definition: view.cpp:172
std::string StructuralOutputToDot(rvsdg::StructuralOutput *structuralOutput, const ViewColors &color)
Definition: view.cpp:164
ViewColors GetDefaultColor(std::unordered_map< T *, ViewColors > &map, T *elem, ViewColors def=BLACK)
Definition: view.cpp:79
std::string ToDot(rvsdg::Region *region, std::unordered_map< rvsdg::Output *, ViewColors > &outputColor, std::unordered_map< rvsdg::Input *, ViewColors > &inputColor, std::unordered_map< rvsdg::Output *, ViewColors > &tailLabel)
Definition: view.cpp:424
static std::string hex(size_t i)
Definition: view.cpp:45
std::string ArgumentToDot(rvsdg::RegionArgument *argument, const ViewColors &color)
Definition: view.cpp:140
std::string StructuralNodeToDot(rvsdg::StructuralNode *structuralNode, std::unordered_map< rvsdg::Output *, ViewColors > &outputColor, std::unordered_map< rvsdg::Input *, ViewColors > &inputColor, std::unordered_map< rvsdg::Output *, ViewColors > &tailLabel)
Definition: view.cpp:219
std::string StructuralInputToDot(rvsdg::StructuralInput *structuralInput, const ViewColors &color)
Definition: view.cpp:156
std::string ViewcolorToString(const ViewColors &color)
Definition: view.cpp:22
bool isForbiddenChar(char c)
Definition: base-hls.cpp:16
std::string SimpleNodeToDot(rvsdg::SimpleNode *simpleNode, std::unordered_map< rvsdg::Output *, ViewColors > &outputColor, std::unordered_map< rvsdg::Input *, ViewColors > &inputColor)
Definition: view.cpp:272
static std::vector< jlm::rvsdg::Output * > outputs(const Node *node)
Definition: node.hpp:1058
static std::string strfmt(Args... args)
Definition: strfmt.hpp:35