Jlm
DotWriter.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2025 Nico Reißmann <nico.reissmann@gmail.com>
3  * See COPYING for terms of redistribution.
4  */
5 
9 #include <jlm/util/strfmt.hpp>
10 
11 namespace jlm::rvsdg
12 {
13 
14 DotWriter::~DotWriter() noexcept = default;
15 
16 void
17 DotWriter::AnnotateTypeGraphNode(const Type & type, util::graph::Node & node)
18 {}
19 
20 void
22  const Node & rvsdgNode,
23  util::graph::Node & node,
24  util::graph::Graph * typeGraph)
25 {}
26 
27 void
28 DotWriter::AnnotateEdge(const Input & rvsdgInput, util::graph::Edge & edge)
29 {}
30 
31 void
33  const RegionArgument & regionArgument,
34  util::graph::Node & node,
35  util::graph::Graph * typeGraph)
36 {}
37 
44 {
45  // If the type already has a corresponding node, return it
46  if (auto * graphElement = typeGraph.GetElementFromProgramObject(type))
47  {
48  auto * node = reinterpret_cast<util::graph::Node *>(graphElement);
49  JLM_ASSERT(node);
50  return *node;
51  }
52 
53  auto & node = typeGraph.CreateNode();
54  node.SetProgramObject(type);
55  node.SetLabel(type.debug_string());
56 
58 
59  return node;
60 }
61 
68 void
70 {
71  auto & graph = inputPort.GetGraph();
72  inputPort.SetProgramObject(rvsdgInput);
73  inputPort.SetLabel(util::strfmt(rvsdgInput.index()));
74 
75  // nodes are visited in topological order, so if the origin is an output, it will already exist
76  if (auto originPort = reinterpret_cast<util::graph::Port *>(
77  graph.GetElementFromProgramObject(*rvsdgInput.origin())))
78  {
79  auto & edge = graph.CreateDirectedEdge(*originPort, inputPort);
80  AnnotateEdge(rvsdgInput, edge);
81  }
82 }
83 
91 void
93  util::graph::Port & outputPort,
94  const rvsdg::Output & rvsdgOutput,
95  util::graph::Graph * typeGraph)
96 {
97  outputPort.SetProgramObject(rvsdgOutput);
98  outputPort.SetLabel(util::strfmt(rvsdgOutput.index()));
99 
100  if (typeGraph)
101  outputPort.SetAttributeGraphElement(
102  "type",
103  GetOrCreateTypeGraphNode(*rvsdgOutput.Type(), *typeGraph));
104 }
105 
111 void
113  util::graph::Graph & graph,
114  const Region & region,
115  util::graph::Graph * typeGraph,
116  const bool traverseRecursively)
117 {
118  graph.SetProgramObject(region);
119 
120  // Start by creating nodes for all the region arguments, and attaching them to the RVSDG outputs.
121  for (size_t n = 0; n < region.narguments(); n++)
122  {
123  auto & node = graph.CreateArgumentNode();
124  auto & argument = *region.argument(n);
125  AttachNodeOutput(node, argument, typeGraph);
126 
127  // Include the index among the region's attributes
128  node.SetAttribute("index", std::to_string(n));
129 
130  // Use the debug string as the label
131  node.SetLabel(argument.debug_string());
132 
133  // If this argument corresponds to one of the structural node's inputs, reference it
134  if (argument.input())
135  {
136  node.SetAttributeObject("input", *argument.input());
137  // Include the local index of the node's input in the label
138  node.AppendToLabel(util::strfmt("<- ", argument.input()->debug_string()), " ");
139  }
140 
141  AnnotateRegionArgument(argument, node, typeGraph);
142  }
143 
144  // Create a node for each node in the region in topological order.
145  // Inputs expect the node representing their origin to exist before being visited.
146  TopDownConstTraverser traverser(&region);
147  for (const auto rvsdgNode : traverser)
148  {
149  auto & node = graph.CreateInOutNode(rvsdgNode->ninputs(), rvsdgNode->noutputs());
150  node.SetLabel(rvsdgNode->DebugString());
151  node.SetProgramObject(*rvsdgNode);
152 
153  for (size_t i = 0; i < rvsdgNode->ninputs(); i++)
154  AttachNodeInput(node.GetInputPort(i), *rvsdgNode->input(i));
155 
156  for (size_t i = 0; i < rvsdgNode->noutputs(); i++)
157  AttachNodeOutput(node.GetOutputPort(i), *rvsdgNode->output(i), typeGraph);
158 
159  // Structural nodes also have subgraphs
160  const auto structuralNode = dynamic_cast<const StructuralNode *>(rvsdgNode);
161  if (structuralNode && traverseRecursively)
162  {
163  for (auto & subregion : structuralNode->Subregions())
164  {
165  auto & subGraph = node.CreateSubgraph();
166  subGraph.SetLabel(util::strfmt("RegionID: ", subregion.getRegionId()));
167  CreateGraphNodes(subGraph, subregion, typeGraph, traverseRecursively);
168  }
169  }
170 
171  AnnotateGraphNode(*rvsdgNode, node, typeGraph);
172  }
173 
174  // Create result nodes for the region's results, and attach them to their origins
175  for (size_t n = 0; n < region.nresults(); n++)
176  {
177  auto & node = graph.CreateResultNode();
178  auto & result = *region.result(n);
179  AttachNodeInput(node, result);
180 
181  // Include the index among the region's results
182  node.SetAttribute("index", std::to_string(n));
183 
184  // Use the debug string as the label
185  node.SetLabel(result.debug_string());
186 
187  // If this result corresponds to one of the structural node's outputs, reference it
188  if (result.output())
189  {
190  node.SetAttributeObject("output", *result.output());
191  // Include the local index of the node's output in the label
192  node.AppendToLabel(util::strfmt("-> ", result.output()->debug_string()), " ");
193  }
194  }
195 }
196 
199  util::graph::Writer & writer,
200  const Region & region,
201  const bool emitTypeGraph)
202 {
203  util::graph::Graph * typeGraph = nullptr;
204  if (emitTypeGraph)
205  {
206  typeGraph = &writer.CreateGraph();
207  typeGraph->SetLabel("Type graph");
208  }
209  util::graph::Graph & rootGraph = writer.CreateGraph();
210  rootGraph.SetLabel(util::strfmt("RegionID: ", region.getRegionId()));
211  CreateGraphNodes(rootGraph, region, typeGraph, true);
212 
213  return rootGraph;
214 }
215 
218 {
219  util::graph::Graph & graph = writer.CreateGraph();
220  CreateGraphNodes(graph, region, nullptr, false);
221  return graph;
222 }
223 
224 }
void AttachNodeOutput(util::graph::Port &outputPort, const Output &rvsdgOutput, util::graph::Graph *typeGraph)
Definition: DotWriter.cpp:92
virtual void AnnotateGraphNode(const Node &rvsdgNode, util::graph::Node &node, util::graph::Graph *typeGraph)
Definition: DotWriter.cpp:21
virtual ~DotWriter() noexcept
virtual void AnnotateTypeGraphNode(const Type &type, util::graph::Node &node)
Definition: DotWriter.cpp:17
util::graph::Graph & WriteGraphs(util::graph::Writer &writer, const Region &region, bool emitTypeGraph)
Definition: DotWriter.cpp:198
util::graph::Graph & WriteGraph(util::graph::Writer &writer, const Region &region)
Definition: DotWriter.cpp:217
void AttachNodeInput(util::graph::Port &inputPort, const Input &rvsdgInput)
Definition: DotWriter.cpp:69
virtual void AnnotateRegionArgument(const RegionArgument &regionArgument, util::graph::Node &node, util::graph::Graph *typeGraph)
Definition: DotWriter.cpp:32
virtual void AnnotateEdge(const Input &rvsdgInput, util::graph::Edge &edge)
Definition: DotWriter.cpp:28
void CreateGraphNodes(util::graph::Graph &graph, const Region &region, util::graph::Graph *typeGraph, bool traverseRecursively)
Definition: DotWriter.cpp:112
util::graph::Node & GetOrCreateTypeGraphNode(const Type &type, util::graph::Graph &typeGraph)
Definition: DotWriter.cpp:43
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:366
size_t index() const noexcept
Definition: node.hpp:274
Represents the argument of a region.
Definition: region.hpp:41
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
Id getRegionId() const noexcept
Definition: region.hpp:263
RegionArgument * argument(size_t index) const noexcept
Definition: region.hpp:437
size_t narguments() const noexcept
Definition: region.hpp:431
void SetProgramObject(const T &object)
void SetLabel(std::string label)
void SetAttributeGraphElement(const std::string &attribute, const GraphElement &element)
ArgumentNode & CreateArgumentNode()
GraphElement * GetElementFromProgramObject(uintptr_t object) const
ResultNode & CreateResultNode()
InOutNode & CreateInOutNode(size_t inputPorts, size_t outputPorts)
Graph & GetGraph() override
#define JLM_ASSERT(x)
Definition: common.hpp:16
static std::string type(const Node *n)
Definition: view.cpp:255
static std::string strfmt(Args... args)
Definition: strfmt.hpp:35