blob: 1b507114874196f5aa4f8669d5fc22db07dbca6e [file] [log] [blame]
Mikhail Glushenkovb90cd832008-05-06 16:34:12 +00001//===--- CompilationGraph.cpp - The LLVM Compiler Driver --------*- C++ -*-===//
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open
6// Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
Mikhail Glushenkovb90cd832008-05-06 16:34:12 +000010// Compilation graph - implementation.
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000011//
12//===----------------------------------------------------------------------===//
13
Mikhail Glushenkovb90cd832008-05-06 16:34:12 +000014#include "CompilationGraph.h"
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000015
Mikhail Glushenkov87416b42008-05-06 18:10:53 +000016#include "llvm/ADT/STLExtras.h"
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000017#include "llvm/Support/CommandLine.h"
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +000018#include "llvm/Support/DOTGraphTraits.h"
19#include "llvm/Support/GraphWriter.h"
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000020
Mikhail Glushenkov02606582008-05-06 18:07:14 +000021#include <algorithm>
Mikhail Glushenkov02606582008-05-06 18:07:14 +000022#include <iterator>
Mikhail Glushenkov87416b42008-05-06 18:10:53 +000023#include <limits>
Mikhail Glushenkov02606582008-05-06 18:07:14 +000024#include <queue>
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000025#include <stdexcept>
26
27using namespace llvm;
Mikhail Glushenkovbe9d9a12008-05-06 18:08:59 +000028using namespace llvmc;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000029
30extern cl::list<std::string> InputFilenames;
31extern cl::opt<std::string> OutputFilename;
Mikhail Glushenkov87416b42008-05-06 18:10:53 +000032extern cl::list<std::string> Languages;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000033
Mikhail Glushenkov4f6e3a42008-05-06 17:28:03 +000034namespace {
35
Mikhail Glushenkovbb8b58d2008-05-06 18:14:24 +000036 // Return the edge with the maximum weight.
Mikhail Glushenkov4f6e3a42008-05-06 17:28:03 +000037 template <class C>
38 const Edge* ChooseEdge(const C& EdgesContainer,
Mikhail Glushenkov76b1b242008-05-06 18:15:12 +000039 const InputLanguagesSet& InLangs,
Mikhail Glushenkov4f6e3a42008-05-06 17:28:03 +000040 const std::string& NodeName = "root") {
Mikhail Glushenkovbb8b58d2008-05-06 18:14:24 +000041 const Edge* MaxEdge = 0;
42 unsigned MaxWeight = 0;
43 bool SingleMax = true;
Mikhail Glushenkov4f6e3a42008-05-06 17:28:03 +000044
45 for (typename C::const_iterator B = EdgesContainer.begin(),
46 E = EdgesContainer.end(); B != E; ++B) {
47 const Edge* E = B->getPtr();
Mikhail Glushenkov76b1b242008-05-06 18:15:12 +000048 unsigned EW = E->Weight(InLangs);
Mikhail Glushenkovbb8b58d2008-05-06 18:14:24 +000049 if (EW > MaxWeight) {
50 MaxEdge = E;
51 MaxWeight = EW;
52 SingleMax = true;
Mikhail Glushenkove0ff9ae2008-05-06 18:18:58 +000053 } else if (EW == MaxWeight) {
Mikhail Glushenkovbb8b58d2008-05-06 18:14:24 +000054 SingleMax = false;
55 }
Mikhail Glushenkov4f6e3a42008-05-06 17:28:03 +000056 }
57
Mikhail Glushenkovbb8b58d2008-05-06 18:14:24 +000058 if (!SingleMax)
59 throw std::runtime_error("Node " + NodeName +
60 ": multiple maximal outward edges found!"
Mikhail Glushenkov87416b42008-05-06 18:10:53 +000061 " Most probably a specification error.");
Mikhail Glushenkovbb8b58d2008-05-06 18:14:24 +000062 if (!MaxEdge)
63 throw std::runtime_error("Node " + NodeName +
64 ": no maximal outward edge found!"
65 " Most probably a specification error.");
66 return MaxEdge;
Mikhail Glushenkov6591c892008-05-06 17:23:50 +000067 }
68
Mikhail Glushenkov6591c892008-05-06 17:23:50 +000069}
70
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +000071CompilationGraph::CompilationGraph() {
72 NodesMap["root"] = Node(this);
73}
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000074
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +000075Node& CompilationGraph::getNode(const std::string& ToolName) {
76 nodes_map_type::iterator I = NodesMap.find(ToolName);
77 if (I == NodesMap.end())
Mikhail Glushenkovd752c3f2008-05-06 16:36:50 +000078 throw std::runtime_error("Node " + ToolName + " is not in the graph");
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +000079 return I->second;
80}
81
82const Node& CompilationGraph::getNode(const std::string& ToolName) const {
83 nodes_map_type::const_iterator I = NodesMap.find(ToolName);
84 if (I == NodesMap.end())
Mikhail Glushenkovd752c3f2008-05-06 16:36:50 +000085 throw std::runtime_error("Node " + ToolName + " is not in the graph!");
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +000086 return I->second;
87}
88
Mikhail Glushenkovbe867122008-05-06 18:16:52 +000089// Find the language name corresponding to the given file.
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +000090const std::string& CompilationGraph::getLanguage(const sys::Path& File) const {
91 LanguageMap::const_iterator Lang = ExtsToLangs.find(File.getSuffix());
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000092 if (Lang == ExtsToLangs.end())
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +000093 throw std::runtime_error("Unknown suffix: " + File.getSuffix() + '!');
94 return Lang->second;
95}
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000096
Mikhail Glushenkovbe867122008-05-06 18:16:52 +000097// Find the tools list corresponding to the given language name.
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +000098const CompilationGraph::tools_vector_type&
99CompilationGraph::getToolsVector(const std::string& LangName) const
100{
101 tools_map_type::const_iterator I = ToolsMap.find(LangName);
102 if (I == ToolsMap.end())
Mikhail Glushenkov87416b42008-05-06 18:10:53 +0000103 throw std::runtime_error("No tool corresponding to the language "
104 + LangName + "found!");
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +0000105 return I->second;
106}
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000107
Mikhail Glushenkov0a174932008-05-06 16:36:06 +0000108void CompilationGraph::insertNode(Tool* V) {
Mikhail Glushenkovc74bfc92008-05-06 17:26:53 +0000109 if (NodesMap.count(V->Name()) == 0) {
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +0000110 Node N;
111 N.OwningGraph = this;
112 N.ToolPtr = V;
113 NodesMap[V->Name()] = N;
114 }
115}
116
Mikhail Glushenkovd752c3f2008-05-06 16:36:50 +0000117void CompilationGraph::insertEdge(const std::string& A, Edge* E) {
Mikhail Glushenkovc74bfc92008-05-06 17:26:53 +0000118 Node& B = getNode(E->ToolName());
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +0000119 if (A == "root") {
Mikhail Glushenkovc74bfc92008-05-06 17:26:53 +0000120 const std::string& InputLanguage = B.ToolPtr->InputLanguage();
Mikhail Glushenkov4f6e3a42008-05-06 17:28:03 +0000121 ToolsMap[InputLanguage].push_back(IntrusiveRefCntPtr<Edge>(E));
Mikhail Glushenkovd752c3f2008-05-06 16:36:50 +0000122 NodesMap["root"].AddEdge(E);
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +0000123 }
124 else {
Mikhail Glushenkov0a174932008-05-06 16:36:06 +0000125 Node& N = getNode(A);
Mikhail Glushenkovd752c3f2008-05-06 16:36:50 +0000126 N.AddEdge(E);
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +0000127 }
Mikhail Glushenkovc74bfc92008-05-06 17:26:53 +0000128 // Increase the inward edge counter.
129 B.IncrInEdges();
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +0000130}
131
Mikhail Glushenkov87416b42008-05-06 18:10:53 +0000132namespace {
133 sys::Path MakeTempFile(const sys::Path& TempDir, const std::string& BaseName,
134 const std::string& Suffix) {
135 sys::Path Out = TempDir;
136 Out.appendComponent(BaseName);
137 Out.appendSuffix(Suffix);
138 Out.makeUnique(true, NULL);
139 return Out;
140 }
Mikhail Glushenkov35a85e82008-05-06 18:10:20 +0000141}
142
Mikhail Glushenkov2ba4c5a2008-05-06 17:25:51 +0000143// Pass input file through the chain until we bump into a Join node or
144// a node that says that it is the last.
Mikhail Glushenkov35a85e82008-05-06 18:10:20 +0000145void CompilationGraph::PassThroughGraph (const sys::Path& InFile,
146 const Node* StartNode,
Mikhail Glushenkov76b1b242008-05-06 18:15:12 +0000147 const InputLanguagesSet& InLangs,
Mikhail Glushenkov35a85e82008-05-06 18:10:20 +0000148 const sys::Path& TempDir) const {
Mikhail Glushenkov2ba4c5a2008-05-06 17:25:51 +0000149 bool Last = false;
Mikhail Glushenkov35a85e82008-05-06 18:10:20 +0000150 sys::Path In = InFile;
Mikhail Glushenkov4f6e3a42008-05-06 17:28:03 +0000151 const Node* CurNode = StartNode;
Mikhail Glushenkov2ba4c5a2008-05-06 17:25:51 +0000152
Mikhail Glushenkov2ba4c5a2008-05-06 17:25:51 +0000153 while(!Last) {
Mikhail Glushenkovbbbc9d42008-05-06 17:27:37 +0000154 sys::Path Out;
Mikhail Glushenkov4f6e3a42008-05-06 17:28:03 +0000155 Tool* CurTool = CurNode->ToolPtr.getPtr();
Mikhail Glushenkov2ba4c5a2008-05-06 17:25:51 +0000156
157 if (CurTool->IsJoin()) {
Mikhail Glushenkov35a85e82008-05-06 18:10:20 +0000158 JoinTool& JT = dynamic_cast<JoinTool&>(*CurTool);
159 JT.AddToJoinList(In);
Mikhail Glushenkov2ba4c5a2008-05-06 17:25:51 +0000160 break;
161 }
162
Mikhail Glushenkov35a85e82008-05-06 18:10:20 +0000163 // Since toolchains do not have to end with a Join node, we should
164 // check if this Node is the last.
Mikhail Glushenkov4f6e3a42008-05-06 17:28:03 +0000165 if (!CurNode->HasChildren() || CurTool->IsLast()) {
Mikhail Glushenkov35a85e82008-05-06 18:10:20 +0000166 if (!OutputFilename.empty()) {
167 Out.set(OutputFilename);
168 }
169 else {
Mikhail Glushenkov2ba4c5a2008-05-06 17:25:51 +0000170 Out.set(In.getBasename());
Mikhail Glushenkov35a85e82008-05-06 18:10:20 +0000171 Out.appendSuffix(CurTool->OutputSuffix());
172 }
Mikhail Glushenkov2ba4c5a2008-05-06 17:25:51 +0000173 Last = true;
174 }
175 else {
Mikhail Glushenkov35a85e82008-05-06 18:10:20 +0000176 Out = MakeTempFile(TempDir, In.getBasename(), CurTool->OutputSuffix());
Mikhail Glushenkov2ba4c5a2008-05-06 17:25:51 +0000177 }
178
179 if (CurTool->GenerateAction(In, Out).Execute() != 0)
180 throw std::runtime_error("Tool returned error code!");
181
Mikhail Glushenkov87416b42008-05-06 18:10:53 +0000182 if (Last)
183 return;
184
Mikhail Glushenkov4f6e3a42008-05-06 17:28:03 +0000185 CurNode = &getNode(ChooseEdge(CurNode->OutEdges,
Mikhail Glushenkov76b1b242008-05-06 18:15:12 +0000186 InLangs,
Mikhail Glushenkov4f6e3a42008-05-06 17:28:03 +0000187 CurNode->Name())->ToolName());
Mikhail Glushenkov2ba4c5a2008-05-06 17:25:51 +0000188 In = Out; Out.clear();
189 }
Mikhail Glushenkov2ba4c5a2008-05-06 17:25:51 +0000190}
191
Mikhail Glushenkovbe867122008-05-06 18:16:52 +0000192// Find the head of the toolchain corresponding to the given file.
Mikhail Glushenkov76b1b242008-05-06 18:15:12 +0000193// Also, insert an input language into InLangs.
Mikhail Glushenkov87416b42008-05-06 18:10:53 +0000194const Node* CompilationGraph::
Mikhail Glushenkov76b1b242008-05-06 18:15:12 +0000195FindToolChain(const sys::Path& In, const std::string* forceLanguage,
196 InputLanguagesSet& InLangs) const {
197
198 // Determine the input language.
Mikhail Glushenkov87416b42008-05-06 18:10:53 +0000199 const std::string& InLanguage =
200 forceLanguage ? *forceLanguage : getLanguage(In);
Mikhail Glushenkov76b1b242008-05-06 18:15:12 +0000201
202 // Add the current input language to the input language set.
203 InLangs.insert(InLanguage);
204
205 // Find the toolchain for the input language.
Mikhail Glushenkov02606582008-05-06 18:07:14 +0000206 const tools_vector_type& TV = getToolsVector(InLanguage);
207 if (TV.empty())
208 throw std::runtime_error("No toolchain corresponding to language"
209 + InLanguage + " found!");
Mikhail Glushenkov76b1b242008-05-06 18:15:12 +0000210 return &getNode(ChooseEdge(TV, InLangs)->ToolName());
Mikhail Glushenkov02606582008-05-06 18:07:14 +0000211}
212
Mikhail Glushenkov4c11a622008-05-06 18:15:35 +0000213// Helper function used by Build().
214// Traverses initial portions of the toolchains (up to the first Join node).
215// This function is also responsible for handling the -x option.
216void CompilationGraph::BuildInitial (InputLanguagesSet& InLangs,
217 const sys::Path& TempDir) {
Mikhail Glushenkov87416b42008-05-06 18:10:53 +0000218 // This is related to -x option handling.
219 cl::list<std::string>::const_iterator xIter = Languages.begin(),
220 xBegin = xIter, xEnd = Languages.end();
221 bool xEmpty = true;
222 const std::string* xLanguage = 0;
223 unsigned xPos = 0, xPosNext = 0, filePos = 0;
224
225 if (xIter != xEnd) {
226 xEmpty = false;
227 xPos = Languages.getPosition(xIter - xBegin);
228 cl::list<std::string>::const_iterator xNext = llvm::next(xIter);
229 xPosNext = (xNext == xEnd) ? std::numeric_limits<unsigned>::max()
230 : Languages.getPosition(xNext - xBegin);
231 xLanguage = (*xIter == "none") ? 0 : &(*xIter);
232 }
233
Mikhail Glushenkov4f6e3a42008-05-06 17:28:03 +0000234 // For each input file:
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000235 for (cl::list<std::string>::const_iterator B = InputFilenames.begin(),
Mikhail Glushenkov87416b42008-05-06 18:10:53 +0000236 CB = B, E = InputFilenames.end(); B != E; ++B) {
Mikhail Glushenkovbbbc9d42008-05-06 17:27:37 +0000237 sys::Path In = sys::Path(*B);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000238
Mikhail Glushenkov87416b42008-05-06 18:10:53 +0000239 // Code for handling the -x option.
240 // Output: std::string* xLanguage (can be NULL).
241 if (!xEmpty) {
242 filePos = InputFilenames.getPosition(B - CB);
243
244 if (xPos < filePos) {
245 if (filePos < xPosNext) {
246 xLanguage = (*xIter == "none") ? 0 : &(*xIter);
247 }
248 else { // filePos >= xPosNext
249 // Skip xIters while filePos > xPosNext
250 while (filePos > xPosNext) {
251 ++xIter;
252 xPos = xPosNext;
253
254 cl::list<std::string>::const_iterator xNext = llvm::next(xIter);
255 if (xNext == xEnd)
256 xPosNext = std::numeric_limits<unsigned>::max();
257 else
258 xPosNext = Languages.getPosition(xNext - xBegin);
259 xLanguage = (*xIter == "none") ? 0 : &(*xIter);
260 }
261 }
262 }
263 }
264
Mikhail Glushenkov02606582008-05-06 18:07:14 +0000265 // Find the toolchain corresponding to this file.
Mikhail Glushenkov76b1b242008-05-06 18:15:12 +0000266 const Node* N = FindToolChain(In, xLanguage, InLangs);
Mikhail Glushenkov02606582008-05-06 18:07:14 +0000267 // Pass file through the chain starting at head.
Mikhail Glushenkov76b1b242008-05-06 18:15:12 +0000268 PassThroughGraph(In, N, InLangs, TempDir);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000269 }
Mikhail Glushenkov4c11a622008-05-06 18:15:35 +0000270}
271
Mikhail Glushenkovbe867122008-05-06 18:16:52 +0000272// Sort the nodes in topological order.
273void CompilationGraph::TopologicalSort(std::vector<const Node*>& Out) {
274 std::queue<const Node*> Q;
275 Q.push(&getNode("root"));
276
277 while (!Q.empty()) {
278 const Node* A = Q.front();
279 Q.pop();
280 Out.push_back(A);
281 for (Node::const_iterator EB = A->EdgesBegin(), EE = A->EdgesEnd();
282 EB != EE; ++EB) {
283 Node* B = &getNode((*EB)->ToolName());
284 B->DecrInEdges();
285 if (B->HasNoInEdges())
286 Q.push(B);
287 }
288 }
289}
290
291namespace {
292 bool NotJoinNode(const Node* N) {
293 return N->ToolPtr ? !N->ToolPtr->IsJoin() : true;
294 }
295}
296
297// Call TopologicalSort and filter the resulting list to include
298// only Join nodes.
299void CompilationGraph::
300TopologicalSortFilterJoinNodes(std::vector<const Node*>& Out) {
301 std::vector<const Node*> TopSorted;
302 TopologicalSort(TopSorted);
303 std::remove_copy_if(TopSorted.begin(), TopSorted.end(),
304 std::back_inserter(Out), NotJoinNode);
305}
306
307// Build the targets. Command-line options are accessed through global
308// variables.
Mikhail Glushenkov4c11a622008-05-06 18:15:35 +0000309int CompilationGraph::Build (const sys::Path& TempDir) {
310
311 InputLanguagesSet InLangs;
312
313 // Traverse initial parts of the toolchains and fill in InLangs.
314 BuildInitial(InLangs, TempDir);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000315
Mikhail Glushenkov02606582008-05-06 18:07:14 +0000316 std::vector<const Node*> JTV;
317 TopologicalSortFilterJoinNodes(JTV);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000318
Mikhail Glushenkov02606582008-05-06 18:07:14 +0000319 // For all join nodes in topological order:
320 for (std::vector<const Node*>::iterator B = JTV.begin(), E = JTV.end();
321 B != E; ++B) {
Mikhail Glushenkovbe9d9a12008-05-06 18:08:59 +0000322
Mikhail Glushenkov3d688222008-05-06 18:07:48 +0000323 sys::Path Out;
324 const Node* CurNode = *B;
325 JoinTool* JT = &dynamic_cast<JoinTool&>(*CurNode->ToolPtr.getPtr());
326 bool IsLast = false;
327
Mikhail Glushenkovbe867122008-05-06 18:16:52 +0000328 // Are there any files in the join list?
Mikhail Glushenkov3d688222008-05-06 18:07:48 +0000329 if (JT->JoinListEmpty())
330 continue;
331
Mikhail Glushenkovbe867122008-05-06 18:16:52 +0000332 // Is this the last tool in the toolchain?
333 // NOTE: we can process several toolchains in parallel.
Mikhail Glushenkov3d688222008-05-06 18:07:48 +0000334 if (!CurNode->HasChildren() || JT->IsLast()) {
335 if (OutputFilename.empty()) {
336 Out.set("a");
337 Out.appendSuffix(JT->OutputSuffix());
338 }
339 else
340 Out.set(OutputFilename);
341 IsLast = true;
342 }
343 else {
Mikhail Glushenkov35a85e82008-05-06 18:10:20 +0000344 Out = MakeTempFile(TempDir, "tmp", JT->OutputSuffix());
Mikhail Glushenkov3d688222008-05-06 18:07:48 +0000345 }
346
347 if (JT->GenerateAction(Out).Execute() != 0)
348 throw std::runtime_error("Tool returned error code!");
349
350 if (!IsLast) {
Mikhail Glushenkov76b1b242008-05-06 18:15:12 +0000351 const Node* NextNode =
352 &getNode(ChooseEdge(CurNode->OutEdges, InLangs,
353 CurNode->Name())->ToolName());
354 PassThroughGraph(Out, NextNode, InLangs, TempDir);
Mikhail Glushenkov3d688222008-05-06 18:07:48 +0000355 }
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000356 }
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000357
358 return 0;
359}
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +0000360
Mikhail Glushenkovbbbc9d42008-05-06 17:27:37 +0000361// Code related to graph visualization.
362
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +0000363namespace llvm {
364 template <>
Mikhail Glushenkovbe9d9a12008-05-06 18:08:59 +0000365 struct DOTGraphTraits<llvmc::CompilationGraph*>
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +0000366 : public DefaultDOTGraphTraits
367 {
368
Mikhail Glushenkov97fda6d2008-05-06 17:26:14 +0000369 template<typename GraphType>
370 static std::string getNodeLabel(const Node* N, const GraphType&)
371 {
372 if (N->ToolPtr)
373 if (N->ToolPtr->IsJoin())
374 return N->Name() + "\n (join" +
375 (N->HasChildren() ? ")"
376 : std::string(": ") + N->ToolPtr->OutputLanguage() + ')');
377 else
378 return N->Name();
379 else
380 return "root";
381 }
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +0000382
Mikhail Glushenkov97fda6d2008-05-06 17:26:14 +0000383 template<typename EdgeIter>
384 static std::string getEdgeSourceLabel(const Node* N, EdgeIter I) {
385 if (N->ToolPtr)
386 return N->ToolPtr->OutputLanguage();
387 else
388 return I->ToolPtr->InputLanguage();
389 }
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +0000390 };
Mikhail Glushenkov97fda6d2008-05-06 17:26:14 +0000391
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +0000392}
393
394void CompilationGraph::writeGraph() {
395 std::ofstream O("CompilationGraph.dot");
396
Mikhail Glushenkova4db8c02008-05-06 16:37:33 +0000397 if (O.good()) {
Mikhail Glushenkov3d688222008-05-06 18:07:48 +0000398 llvm::WriteGraph(this, "compilation-graph");
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +0000399 O.close();
400 }
401 else {
402 throw std::runtime_error("");
403 }
404}
405
406void CompilationGraph::viewGraph() {
Mikhail Glushenkovd752c3f2008-05-06 16:36:50 +0000407 llvm::ViewGraph(this, "compilation-graph");
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +0000408}