Jlm
Loading...
Searching...
No Matches
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
18namespace jlm::llvm
19{
20
21Argument::~Argument() noexcept = default;
22
23EntryNode::~EntryNode() noexcept = default;
24
25ExitNode::~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
135void
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
148}
149
150std::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
182std::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
194std::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
206std::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
236std::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
254std::unordered_map<ControlFlowGraphNode *, std::string>
255ControlFlowGraph::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
282std::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
313std::vector<ControlFlowGraphNode *>
315{
316 auto nodes = postorder(cfg);
317 std::reverse(nodes.begin(), nodes.end());
318 return nodes;
319}
320
321std::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
346size_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}
std::vector< rvsdg::Node * > nodes
~Argument() noexcept override
const ThreeAddressCodeList & tacs() const noexcept
size_t index() const noexcept
Definition cfg-node.hpp:66
ControlFlowGraphNode * source() const noexcept
Definition cfg-node.hpp:51
ControlFlowGraphNode * sink() const noexcept
Definition cfg-node.hpp:57
ControlFlowGraph & cfg() const noexcept
Definition cfg-node.hpp:106
ControlFlowGraphEdge * OutEdge(size_t n) const
Definition cfg-node.hpp:115
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
ExitNode * exit() const noexcept
Definition cfg.hpp:212
static ControlFlowGraph::iterator remove_node(ControlFlowGraph::iterator &it)
Definition cfg.cpp:36
ControlFlowGraph::iterator find_node(BasicBlock *bb)
Definition cfg.hpp:226
EntryNode * entry() const noexcept
Definition cfg.hpp:206
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
const llvm::Argument * argument(size_t index) const
Definition cfg.hpp:93
size_t narguments() const noexcept
Definition cfg.hpp:87
size_t nresults() const noexcept
Definition cfg.hpp:130
const Variable * result(size_t index) const
Definition cfg.hpp:136
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)
Edge & CreateDirectedEdge(Port &from, Port &to)
InOutNode & CreateInOutNode(size_t inputPorts, size_t outputPorts)
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