Jlm
cfg.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2014 Helge Bahmann <hcb@chaoticmind.net>
3  * Copyright 2013 2014 2015 Nico Reißmann <nico.reissmann@gmail.com>
4  * See COPYING for terms of redistribution.
5  */
6 
11 #include <jlm/util/Program.hpp>
12 
13 #include <algorithm>
14 #include <deque>
15 #include <fstream>
16 #include <unordered_map>
17 
18 namespace jlm::llvm
19 {
20 
21 Argument::~Argument() noexcept = default;
22 
23 EntryNode::~EntryNode() noexcept = default;
24 
25 ExitNode::~ExitNode() noexcept = default;
26 
28  : module_(im)
29 {
30  entry_ = std::make_unique<EntryNode>(*this);
31  exit_ = std::make_unique<ExitNode>(*this);
32  entry_->add_outedge(exit_.get());
33 }
34 
37 {
38  auto & cfg = nodeit->cfg();
39 
40  for (auto & inedge : nodeit->InEdges())
41  {
42  if (inedge.source() != &*nodeit)
43  throw util::Error("cannot remove node. It has still incoming edges.");
44  }
45 
46  nodeit->remove_outedges();
47  std::unique_ptr<BasicBlock> tmp(&*nodeit);
48  auto rit = iterator(std::next(cfg.nodes_.find(tmp)));
49  cfg.nodes_.erase(tmp);
50  tmp.release();
51  return rit;
52 }
53 
56 {
57  auto & cfg = bb->cfg();
58 
59  auto it = cfg.find_node(bb);
60  return remove_node(it);
61 }
62 
65 {
66  util::graph::Graph & dotGraph = writer.CreateGraph();
67  dotGraph.SetProgramObject(controlFlowGraph);
68 
69  // Handle entry node
70  const auto entryNode = controlFlowGraph.entry();
71  auto & dotEntryNode = dotGraph.CreateInOutNode(0, entryNode->NumOutEdges());
72  dotEntryNode.SetProgramObject(*entryNode);
73 
74  std::string label = "Entry\n";
75  for (const auto argument : entryNode->arguments())
76  {
77  label += argument->name() + " <" + argument->type().debug_string() + ">\n";
78  }
79  dotEntryNode.SetLabel(label);
80 
81  // Handle exit node
82  const auto exitNode = controlFlowGraph.exit();
83  auto & dotExitNode = dotGraph.CreateInOutNode(exitNode->NumInEdges(), 0);
84  dotExitNode.SetProgramObject(*exitNode);
85 
86  label = "Exit\n";
87  for (const auto result : exitNode->results())
88  {
89  label += result->name() + " <" + result->type().debug_string() + ">\n";
90  }
91  dotExitNode.SetLabel(label);
92 
93  // Handle basic blocks
94  for (auto & basicBlock : controlFlowGraph)
95  {
96  auto & dotBasicBlock =
97  dotGraph.CreateInOutNode(basicBlock.NumInEdges(), basicBlock.NumOutEdges());
98  dotBasicBlock.SetProgramObject(basicBlock);
99 
100  label = util::strfmt("BasicBlock ", &basicBlock, "\n");
101  for (const auto & tac : basicBlock.tacs())
102  label += ThreeAddressCode::ToAscii(*tac) + "\n";
103  dotBasicBlock.SetLabel(label);
104  }
105 
106  // Handle edges
107  auto createEdge = [&dotGraph](const ControlFlowGraphEdge & edge, const size_t index)
108  {
109  auto & dotSourceNode = dotGraph.GetFromProgramObject<util::graph::InOutNode>(*edge.source());
110  auto & dotSinkNode = dotGraph.GetFromProgramObject<util::graph::InOutNode>(*edge.sink());
111  auto & sourcePort = dotSourceNode.GetOutputPort(edge.index());
112  sourcePort.SetLabel(util::strfmt(edge.index()));
113  auto & sinkPort = dotSinkNode.GetInputPort(index);
114  dotGraph.CreateDirectedEdge(sourcePort, sinkPort);
115  };
116 
117  auto createEdges = [&createEdge](const ControlFlowGraphNode & node)
118  {
119  size_t index = 0;
120  for (auto & edge : node.InEdges())
121  {
122  createEdge(edge, index++);
123  }
124  };
125 
126  for (auto & basicBlock : controlFlowGraph)
127  {
128  createEdges(basicBlock);
129  }
130  createEdges(*exitNode);
131 
132  return dotGraph;
133 }
134 
135 void
137 {
138  util::graph::Writer graphWriter;
139  toDot(graphWriter, *this);
140 
141  const util::FilePath outputFilePath =
143 
144  std::ofstream outputFile(outputFilePath.to_str());
145  graphWriter.outputAllGraphs(outputFile, util::graph::OutputFormat::Dot);
146 
147  util::executeProgramAndWait(util::getDotViewer(), { outputFilePath.to_str() });
148 }
149 
150 std::string
152 {
153  std::string str;
154  auto nodes = breadth_first(controlFlowGraph);
155  auto labels = CreateLabels(nodes);
156  for (const auto & node : nodes)
157  {
158  str += labels.at(node) + ":";
159  str += (is<BasicBlock>(node) ? "\n" : " ");
160 
161  if (const auto entryNode = dynamic_cast<const EntryNode *>(node))
162  {
163  str += ToAscii(*entryNode);
164  }
165  else if (const auto exitNode = dynamic_cast<const ExitNode *>(node))
166  {
167  str += ToAscii(*exitNode);
168  }
169  else if (auto basicBlock = dynamic_cast<const BasicBlock *>(node))
170  {
171  str += ToAscii(*basicBlock, labels);
172  }
173  else
174  {
175  JLM_UNREACHABLE("Unhandled control flow graph node type!");
176  }
177  }
178 
179  return str;
180 }
181 
182 std::string
184 {
185  std::string str;
186  for (size_t n = 0; n < entryNode.narguments(); n++)
187  {
188  str += entryNode.argument(n)->debug_string() + " ";
189  }
190 
191  return str + "\n";
192 }
193 
194 std::string
196 {
197  std::string str;
198  for (size_t n = 0; n < exitNode.nresults(); n++)
199  {
200  str += exitNode.result(n)->debug_string() + " ";
201  }
202 
203  return str;
204 }
205 
206 std::string
208  const BasicBlock & basicBlock,
209  const std::unordered_map<ControlFlowGraphNode *, std::string> & labels)
210 {
211  auto & threeAddressCodes = basicBlock.tacs();
212 
213  std::string str;
214  for (const auto & tac : threeAddressCodes)
215  {
216  str += "\t" + ThreeAddressCode::ToAscii(*tac);
217  if (tac != threeAddressCodes.last())
218  str += "\n";
219  }
220 
221  if (threeAddressCodes.last())
222  {
223  if (is<BranchOperation>(threeAddressCodes.last()->operation()))
224  str += " " + CreateTargets(basicBlock, labels);
225  else
226  str += "\n\t" + CreateTargets(basicBlock, labels);
227  }
228  else
229  {
230  str += "\t" + CreateTargets(basicBlock, labels);
231  }
232 
233  return str + "\n";
234 }
235 
236 std::string
238  const ControlFlowGraphNode & node,
239  const std::unordered_map<ControlFlowGraphNode *, std::string> & labels)
240 {
241  size_t n = 0;
242  std::string str("[");
243  for (auto & outedge : node.OutEdges())
244  {
245  str += labels.at(outedge.sink());
246  if (n != node.NumOutEdges() - 1)
247  str += ", ";
248  }
249  str += "]";
250 
251  return str;
252 }
253 
254 std::unordered_map<ControlFlowGraphNode *, std::string>
255 ControlFlowGraph::CreateLabels(const std::vector<ControlFlowGraphNode *> & nodes)
256 {
257  std::unordered_map<ControlFlowGraphNode *, std::string> map;
258  for (size_t n = 0; n < nodes.size(); n++)
259  {
260  auto node = nodes[n];
261  if (is<EntryNode>(node))
262  {
263  map[node] = "entry";
264  }
265  else if (is<ExitNode>(node))
266  {
267  map[node] = "exit";
268  }
269  else if (is<BasicBlock>(node))
270  {
271  map[node] = util::strfmt("bb", n);
272  }
273  else
274  {
275  JLM_UNREACHABLE("Unhandled control flow graph node type!");
276  }
277  }
278 
279  return map;
280 }
281 
282 std::vector<ControlFlowGraphNode *>
284 {
285  JLM_ASSERT(is_closed(cfg));
286 
287  std::function<void(
289  std::unordered_set<ControlFlowGraphNode *> &,
290  std::vector<ControlFlowGraphNode *> &)>
291  traverse = [&](ControlFlowGraphNode * node,
292  std::unordered_set<ControlFlowGraphNode *> & visited,
293  std::vector<ControlFlowGraphNode *> & nodes)
294  {
295  visited.insert(node);
296  for (size_t n = 0; n < node->NumOutEdges(); n++)
297  {
298  auto edge = node->OutEdge(n);
299  if (visited.find(edge->sink()) == visited.end())
300  traverse(edge->sink(), visited, nodes);
301  }
302 
303  nodes.push_back(node);
304  };
305 
306  std::vector<ControlFlowGraphNode *> nodes;
307  std::unordered_set<ControlFlowGraphNode *> visited;
308  traverse(cfg.entry(), visited, nodes);
309 
310  return nodes;
311 }
312 
313 std::vector<ControlFlowGraphNode *>
315 {
316  auto nodes = postorder(cfg);
317  std::reverse(nodes.begin(), nodes.end());
318  return nodes;
319 }
320 
321 std::vector<ControlFlowGraphNode *>
323 {
324  std::deque<ControlFlowGraphNode *> next({ cfg.entry() });
325  std::vector<ControlFlowGraphNode *> nodes({ cfg.entry() });
326  std::unordered_set<ControlFlowGraphNode *> visited({ cfg.entry() });
327  while (!next.empty())
328  {
329  auto node = next.front();
330  next.pop_front();
331 
332  for (auto & outedge : node->OutEdges())
333  {
334  if (visited.find(outedge.sink()) == visited.end())
335  {
336  visited.insert(outedge.sink());
337  next.push_back(outedge.sink());
338  nodes.push_back(outedge.sink());
339  }
340  }
341  }
342 
343  return nodes;
344 }
345 
346 size_t
348 {
349  size_t ntacs = 0;
350  for (auto & node : cfg)
351  {
352  if (auto bb = dynamic_cast<const BasicBlock *>(&node))
353  ntacs += bb->ntacs();
354  }
355 
356  return ntacs;
357 }
358 
359 }
~Argument() noexcept override
const ThreeAddressCodeList & tacs() const noexcept
Definition: basic-block.hpp:38
size_t index() const noexcept
Definition: cfg-node.hpp:66
ControlFlowGraphNode * sink() const noexcept
Definition: cfg-node.hpp:57
ControlFlowGraphNode * source() const noexcept
Definition: cfg-node.hpp:51
ControlFlowGraphEdge * OutEdge(size_t n) const
Definition: cfg-node.hpp:115
ControlFlowGraph & cfg() const noexcept
Definition: cfg-node.hpp:106
outedge_iterator_range OutEdges() const
Definition: cfg-node.hpp:122
size_t NumOutEdges() const noexcept
Definition: cfg-node.cpp:46
static std::string ToAscii(const ControlFlowGraph &controlFlowGraph)
Definition: cfg.cpp:151
EntryNode * entry() const noexcept
Definition: cfg.hpp:206
static ControlFlowGraph::iterator remove_node(ControlFlowGraph::iterator &it)
Definition: cfg.cpp:36
ControlFlowGraph::iterator find_node(BasicBlock *bb)
Definition: cfg.hpp:226
ExitNode * exit() const noexcept
Definition: cfg.hpp:212
static std::unordered_map< ControlFlowGraphNode *, std::string > CreateLabels(const std::vector< ControlFlowGraphNode * > &nodes)
Definition: cfg.cpp:255
static std::string CreateTargets(const ControlFlowGraphNode &node, const std::unordered_map< ControlFlowGraphNode *, std::string > &labels)
Definition: cfg.cpp:237
static util::graph::Graph & toDot(util::graph::Writer &writer, const ControlFlowGraph &controlFlowGraph)
Definition: cfg.cpp:64
util::PtrIterator< BasicBlock, std::unordered_set< std::unique_ptr< BasicBlock > >::iterator > iterator
Definition: cfg.hpp:161
size_t narguments() const noexcept
Definition: cfg.hpp:87
const llvm::Argument * argument(size_t index) const
Definition: cfg.hpp:93
const Variable * result(size_t index) const
Definition: cfg.hpp:136
size_t nresults() const noexcept
Definition: cfg.hpp:130
static std::string ToAscii(const ThreeAddressCode &threeAddressCode)
Definition: tac.cpp:120
virtual std::string debug_string() const
Definition: variable.cpp:14
static FilePath createUniqueFileName(const FilePath &directory, const std::string &fileNamePrefix, const std::string &fileNameSuffix)
Generates a unique file in a given directory with a prefix and suffix.
Definition: file.hpp:301
static FilePath TempDirectoryPath()
Definition: file.hpp:317
const std::string & to_str() const noexcept
Definition: file.hpp:275
void SetProgramObject(const T &object)
void SetLabel(std::string label)
InOutNode & CreateInOutNode(size_t inputPorts, size_t outputPorts)
Edge & CreateDirectedEdge(Port &from, Port &to)
Element & GetFromProgramObject(const ProgramObject &object) const
OutputPort & GetOutputPort(size_t index)
InputPort & GetInputPort(size_t index)
void outputAllGraphs(std::ostream &out, OutputFormat format)
#define JLM_ASSERT(x)
Definition: common.hpp:16
#define JLM_UNREACHABLE(msg)
Definition: common.hpp:43
Global memory state passed between functions.
std::vector< ControlFlowGraphNode * > breadth_first(const ControlFlowGraph &cfg)
Definition: cfg.cpp:322
std::vector< ControlFlowGraphNode * > postorder(const ControlFlowGraph &cfg)
Definition: cfg.cpp:283
size_t ntacs(const AggregationNode &root)
bool is_closed(const ControlFlowGraph &cfg)
std::vector< ControlFlowGraphNode * > reverse_postorder(const ControlFlowGraph &cfg)
Definition: cfg.cpp:314
std::string getDotViewer()
Definition: Program.cpp:42
static std::string strfmt(Args... args)
Definition: strfmt.hpp:35
int executeProgramAndWait(const std::string &programName, const std::vector< std::string > &programArguments)
Definition: Program.cpp:18