Jlm
ipgraph.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2013 2014 2015 Nico Reißmann <nico.reissmann@gmail.com>
3  * See COPYING for terms of redistribution.
4  */
5 
7 #include <jlm/util/file.hpp>
8 #include <jlm/util/Program.hpp>
9 
10 #include <algorithm>
11 #include <fstream>
12 
13 /* Tarjan's SCC algorithm */
14 
15 static void
18  std::unordered_map<const jlm::llvm::InterProceduralGraphNode *, std::pair<size_t, size_t>> &
19  map,
20  std::vector<const jlm::llvm::InterProceduralGraphNode *> & node_stack,
21  size_t & index,
22  std::vector<std::unordered_set<const jlm::llvm::InterProceduralGraphNode *>> & sccs)
23 {
24  map.emplace(node, std::make_pair(index, index));
25  node_stack.push_back(node);
26  index++;
27 
28  for (auto callee : *node)
29  {
30  if (map.find(callee) == map.end())
31  {
32  /* successor has not been visited yet; recurse on it */
33  strongconnect(callee, map, node_stack, index, sccs);
34  map[node].second = std::min(map[node].second, map[callee].second);
35  }
36  else if (std::find(node_stack.begin(), node_stack.end(), callee) != node_stack.end())
37  {
38  /* successor is in stack and hence in the current SCC */
39  map[node].second = std::min(map[node].second, map[callee].first);
40  }
41  }
42 
43  if (map[node].second == map[node].first)
44  {
45  std::unordered_set<const jlm::llvm::InterProceduralGraphNode *> scc;
46  const jlm::llvm::InterProceduralGraphNode * w = nullptr;
47  do
48  {
49  w = node_stack.back();
50  node_stack.pop_back();
51  scc.insert(w);
52  } while (w != node);
53 
54  sccs.push_back(scc);
55  }
56 }
57 
58 namespace jlm::llvm
59 {
60 
61 void
62 InterProceduralGraph::add_node(std::unique_ptr<InterProceduralGraphNode> node)
63 {
64  nodes_.push_back(std::move(node));
65 }
66 
67 std::vector<std::unordered_set<const InterProceduralGraphNode *>>
69 {
70  std::vector<std::unordered_set<const InterProceduralGraphNode *>> sccs;
71 
72  std::unordered_map<const InterProceduralGraphNode *, std::pair<size_t, size_t>> map;
73  std::vector<const InterProceduralGraphNode *> node_stack;
74  size_t index = 0;
75 
76  for (auto & node : *this)
77  {
78  if (map.find(&node) == map.end())
79  strongconnect(&node, map, node_stack, index, sccs);
80  }
81 
82  return sccs;
83 }
84 
86 InterProceduralGraph::find(const std::string & name) const noexcept
87 {
88  for (auto & node : nodes_)
89  {
90  if (node->name() == name)
91  return node.get();
92  }
93 
94  return nullptr;
95 }
96 
98 
99 util::graph::Graph &
101  util::graph::Writer & writer,
102  const InterProceduralGraph & interProceduralGraph)
103 {
104  util::graph::Graph & dotGraph = writer.CreateGraph();
105  dotGraph.SetProgramObject(interProceduralGraph);
106 
107  // Create nodes
108  for (auto & node : interProceduralGraph)
109  {
110  auto & dotNode = dotGraph.CreateInOutNode(0, 0);
111  dotNode.SetProgramObject(node);
112  dotNode.SetLabel(node.name());
113  }
114 
115  // Create edges
116  for (auto & node : interProceduralGraph)
117  {
118  auto & dotNode = dotGraph.GetFromProgramObject<util::graph::InOutNode>(node);
119  for (auto & depNode : node)
120  {
121  auto & dotDepNode = dotGraph.GetFromProgramObject<util::graph::InOutNode>(*depNode);
122  auto & outputPort = dotDepNode.CreateOutputPort();
123  auto & inputPort = dotNode.CreateInputPort();
124  dotGraph.CreateEdge(inputPort, outputPort, false);
125  }
126  }
127 
128  return dotGraph;
129 }
130 
131 void
133 {
134  util::graph::Writer graphWriter;
135  toDot(graphWriter, *this);
136 
137  const util::FilePath outputFilePath =
139 
140  std::ofstream outputFile(outputFilePath.to_str());
141  graphWriter.outputAllGraphs(outputFile, util::graph::OutputFormat::Dot);
142 
143  util::executeProgramAndWait(util::getDotViewer(), { outputFilePath.to_str() });
144 }
145 
146 FunctionNode::~FunctionNode() noexcept = default;
147 
148 const std::string &
149 FunctionNode::name() const noexcept
150 {
151  return name_;
152 }
153 
154 const jlm::rvsdg::Type &
155 FunctionNode::type() const noexcept
156 {
157  return *FunctionType_;
158 }
159 
160 std::shared_ptr<const jlm::rvsdg::Type>
162 {
163  return FunctionType_;
164 }
165 
166 const llvm::Linkage &
167 FunctionNode::linkage() const noexcept
168 {
169  return linkage_;
170 }
171 
172 bool
173 FunctionNode::hasBody() const noexcept
174 {
175  return cfg() != nullptr;
176 }
177 
178 void
179 FunctionNode::add_cfg(std::unique_ptr<ControlFlowGraph> cfg)
180 {
181  if (cfg->fcttype() != fcttype())
182  throw util::Error("CFG does not match the function node's type.");
183 
184  cfg_ = std::move(cfg);
185 }
186 
187 FunctionVariable::~FunctionVariable() noexcept = default;
188 
189 DataNode::~DataNode() noexcept = default;
190 
191 const std::string &
192 DataNode::name() const noexcept
193 {
194  return name_;
195 }
196 
197 const PointerType &
198 DataNode::type() const noexcept
199 {
200  static PointerType pointerType;
201  return pointerType;
202 }
203 
204 std::shared_ptr<const rvsdg::Type>
206 {
207  return PointerType::Create();
208 }
209 
210 const llvm::Linkage &
211 DataNode::linkage() const noexcept
212 {
213  return linkage_;
214 }
215 
216 bool
217 DataNode::hasBody() const noexcept
218 {
219  return initialization() != nullptr;
220 }
221 
222 }
rvsdg::FunctionType fcttype() const
Definition: cfg.hpp:253
llvm::Linkage linkage_
Definition: ipgraph.hpp:457
std::shared_ptr< const jlm::rvsdg::Type > Type() const override
Definition: ipgraph.cpp:205
const llvm::Linkage & linkage() const noexcept override
Definition: ipgraph.cpp:211
const DataNodeInit * initialization() const noexcept
Definition: ipgraph.hpp:413
const PointerType & type() const noexcept override
Definition: ipgraph.cpp:198
bool hasBody() const noexcept override
Definition: ipgraph.cpp:217
const jlm::rvsdg::Type & type() const noexcept override
Definition: ipgraph.cpp:155
const rvsdg::FunctionType & fcttype() const noexcept
Definition: ipgraph.hpp:202
std::shared_ptr< const rvsdg::FunctionType > FunctionType_
Definition: ipgraph.hpp:271
void add_cfg(std::unique_ptr< ControlFlowGraph > cfg)
Adds cfg to the function node. If the function node already has a CFG, then it is replaced with cfg.
Definition: ipgraph.cpp:179
std::unique_ptr< ControlFlowGraph > cfg_
Definition: ipgraph.hpp:276
llvm::Linkage linkage_
Definition: ipgraph.hpp:273
bool hasBody() const noexcept override
Definition: ipgraph.cpp:173
const llvm::Linkage & linkage() const noexcept override
Definition: ipgraph.cpp:167
~FunctionNode() noexcept override
llvm::ControlFlowGraph * cfg() const noexcept
Definition: ipgraph.hpp:190
std::shared_ptr< const jlm::rvsdg::Type > Type() const override
Definition: ipgraph.cpp:161
~FunctionVariable() noexcept override
virtual ~InterProceduralGraphNode() noexcept
std::vector< std::unordered_set< const InterProceduralGraphNode * > > find_sccs() const
Definition: ipgraph.cpp:68
const InterProceduralGraphNode * find(const std::string &name) const noexcept
Definition: ipgraph.cpp:86
std::vector< std::unique_ptr< InterProceduralGraphNode > > nodes_
Definition: ipgraph.hpp:90
void add_node(std::unique_ptr< InterProceduralGraphNode > node)
Definition: ipgraph.cpp:62
static util::graph::Graph & toDot(util::graph::Writer &writer, const InterProceduralGraph &interProceduralGraph)
Definition: ipgraph.cpp:100
PointerType class.
Definition: types.hpp:25
static std::shared_ptr< const PointerType > Create()
Definition: types.cpp:45
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)
InOutNode & CreateInOutNode(size_t inputPorts, size_t outputPorts)
Element & GetFromProgramObject(const ProgramObject &object) const
Edge & CreateEdge(Port &from, Port &to, bool directed)
OutputPort & CreateOutputPort()
void outputAllGraphs(std::ostream &out, OutputFormat format)
static void strongconnect(const jlm::llvm::InterProceduralGraphNode *node, std::unordered_map< const jlm::llvm::InterProceduralGraphNode *, std::pair< size_t, size_t >> &map, std::vector< const jlm::llvm::InterProceduralGraphNode * > &node_stack, size_t &index, std::vector< std::unordered_set< const jlm::llvm::InterProceduralGraphNode * >> &sccs)
Definition: ipgraph.cpp:16
Global memory state passed between functions.
static void strongconnect(ControlFlowGraphNode *node, ControlFlowGraphNode *exit, std::unordered_map< ControlFlowGraphNode *, std::pair< size_t, size_t >> &map, std::vector< ControlFlowGraphNode * > &node_stack, size_t &index, std::vector< StronglyConnectedComponent > &sccs)
std::string getDotViewer()
Definition: Program.cpp:42
int executeProgramAndWait(const std::string &programName, const std::vector< std::string > &programArguments)
Definition: Program.cpp:18