blob: 4513d4a19ad403fa6d57e004216e022092584e69 [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 Glushenkov76b1b242008-05-06 18:15:12 +000023#include <iostream>
Mikhail Glushenkov87416b42008-05-06 18:10:53 +000024#include <limits>
Mikhail Glushenkov02606582008-05-06 18:07:14 +000025#include <queue>
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000026#include <stdexcept>
27
28using namespace llvm;
Mikhail Glushenkovbe9d9a12008-05-06 18:08:59 +000029using namespace llvmc;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000030
31extern cl::list<std::string> InputFilenames;
32extern cl::opt<std::string> OutputFilename;
Mikhail Glushenkov87416b42008-05-06 18:10:53 +000033extern cl::list<std::string> Languages;
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000034
Mikhail Glushenkov4f6e3a42008-05-06 17:28:03 +000035namespace {
36
Mikhail Glushenkovbb8b58d2008-05-06 18:14:24 +000037 // Return the edge with the maximum weight.
Mikhail Glushenkov4f6e3a42008-05-06 17:28:03 +000038 template <class C>
39 const Edge* ChooseEdge(const C& EdgesContainer,
Mikhail Glushenkov76b1b242008-05-06 18:15:12 +000040 const InputLanguagesSet& InLangs,
Mikhail Glushenkov4f6e3a42008-05-06 17:28:03 +000041 const std::string& NodeName = "root") {
Mikhail Glushenkovbb8b58d2008-05-06 18:14:24 +000042 const Edge* MaxEdge = 0;
43 unsigned MaxWeight = 0;
44 bool SingleMax = true;
Mikhail Glushenkov4f6e3a42008-05-06 17:28:03 +000045
46 for (typename C::const_iterator B = EdgesContainer.begin(),
47 E = EdgesContainer.end(); B != E; ++B) {
48 const Edge* E = B->getPtr();
Mikhail Glushenkov76b1b242008-05-06 18:15:12 +000049 unsigned EW = E->Weight(InLangs);
Mikhail Glushenkovbb8b58d2008-05-06 18:14:24 +000050 if (EW > MaxWeight) {
51 MaxEdge = E;
52 MaxWeight = EW;
53 SingleMax = true;
54 }
55 else if (EW == MaxWeight) {
56 SingleMax = false;
57 }
Mikhail Glushenkov4f6e3a42008-05-06 17:28:03 +000058 }
59
Mikhail Glushenkovbb8b58d2008-05-06 18:14:24 +000060 if (!SingleMax)
61 throw std::runtime_error("Node " + NodeName +
62 ": multiple maximal outward edges found!"
Mikhail Glushenkov87416b42008-05-06 18:10:53 +000063 " Most probably a specification error.");
Mikhail Glushenkovbb8b58d2008-05-06 18:14:24 +000064 if (!MaxEdge)
65 throw std::runtime_error("Node " + NodeName +
66 ": no maximal outward edge found!"
67 " Most probably a specification error.");
68 return MaxEdge;
Mikhail Glushenkov6591c892008-05-06 17:23:50 +000069 }
70
Mikhail Glushenkov6591c892008-05-06 17:23:50 +000071}
72
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +000073CompilationGraph::CompilationGraph() {
74 NodesMap["root"] = Node(this);
75}
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000076
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +000077Node& CompilationGraph::getNode(const std::string& ToolName) {
78 nodes_map_type::iterator I = NodesMap.find(ToolName);
79 if (I == NodesMap.end())
Mikhail Glushenkovd752c3f2008-05-06 16:36:50 +000080 throw std::runtime_error("Node " + ToolName + " is not in the graph");
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +000081 return I->second;
82}
83
84const Node& CompilationGraph::getNode(const std::string& ToolName) const {
85 nodes_map_type::const_iterator I = NodesMap.find(ToolName);
86 if (I == NodesMap.end())
Mikhail Glushenkovd752c3f2008-05-06 16:36:50 +000087 throw std::runtime_error("Node " + ToolName + " is not in the graph!");
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +000088 return I->second;
89}
90
91const std::string& CompilationGraph::getLanguage(const sys::Path& File) const {
92 LanguageMap::const_iterator Lang = ExtsToLangs.find(File.getSuffix());
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000093 if (Lang == ExtsToLangs.end())
Mikhail Glushenkov0d08db02008-05-06 16:35:25 +000094 throw std::runtime_error("Unknown suffix: " + File.getSuffix() + '!');
95 return Lang->second;
96}
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +000097
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 Glushenkov02606582008-05-06 18:07:14 +0000192// Sort the nodes in topological order.
193void CompilationGraph::TopologicalSort(std::vector<const Node*>& Out) {
194 std::queue<const Node*> Q;
195 Q.push(&getNode("root"));
196
197 while (!Q.empty()) {
198 const Node* A = Q.front();
199 Q.pop();
200 Out.push_back(A);
201 for (Node::const_iterator EB = A->EdgesBegin(), EE = A->EdgesEnd();
202 EB != EE; ++EB) {
203 Node* B = &getNode((*EB)->ToolName());
204 B->DecrInEdges();
205 if (B->HasNoInEdges())
206 Q.push(B);
207 }
208 }
209}
210
211namespace {
212 bool NotJoinNode(const Node* N) {
213 return N->ToolPtr ? !N->ToolPtr->IsJoin() : true;
214 }
215}
216
217// Call TopologicalSort and filter the resulting list to include
218// only Join nodes.
219void CompilationGraph::
220TopologicalSortFilterJoinNodes(std::vector<const Node*>& Out) {
221 std::vector<const Node*> TopSorted;
222 TopologicalSort(TopSorted);
223 std::remove_copy_if(TopSorted.begin(), TopSorted.end(),
224 std::back_inserter(Out), NotJoinNode);
225}
226
227// Find head of the toolchain corresponding to the given file.
Mikhail Glushenkov76b1b242008-05-06 18:15:12 +0000228// Also, insert an input language into InLangs.
Mikhail Glushenkov87416b42008-05-06 18:10:53 +0000229const Node* CompilationGraph::
Mikhail Glushenkov76b1b242008-05-06 18:15:12 +0000230FindToolChain(const sys::Path& In, const std::string* forceLanguage,
231 InputLanguagesSet& InLangs) const {
232
233 // Determine the input language.
Mikhail Glushenkov87416b42008-05-06 18:10:53 +0000234 const std::string& InLanguage =
235 forceLanguage ? *forceLanguage : getLanguage(In);
Mikhail Glushenkov76b1b242008-05-06 18:15:12 +0000236
237 // Add the current input language to the input language set.
238 InLangs.insert(InLanguage);
239
240 // Find the toolchain for the input language.
Mikhail Glushenkov02606582008-05-06 18:07:14 +0000241 const tools_vector_type& TV = getToolsVector(InLanguage);
242 if (TV.empty())
243 throw std::runtime_error("No toolchain corresponding to language"
244 + InLanguage + " found!");
Mikhail Glushenkov76b1b242008-05-06 18:15:12 +0000245 return &getNode(ChooseEdge(TV, InLangs)->ToolName());
Mikhail Glushenkov02606582008-05-06 18:07:14 +0000246}
247
Mikhail Glushenkov4c11a622008-05-06 18:15:35 +0000248// Helper function used by Build().
249// Traverses initial portions of the toolchains (up to the first Join node).
250// This function is also responsible for handling the -x option.
251void CompilationGraph::BuildInitial (InputLanguagesSet& InLangs,
252 const sys::Path& TempDir) {
Mikhail Glushenkov87416b42008-05-06 18:10:53 +0000253 // This is related to -x option handling.
254 cl::list<std::string>::const_iterator xIter = Languages.begin(),
255 xBegin = xIter, xEnd = Languages.end();
256 bool xEmpty = true;
257 const std::string* xLanguage = 0;
258 unsigned xPos = 0, xPosNext = 0, filePos = 0;
259
260 if (xIter != xEnd) {
261 xEmpty = false;
262 xPos = Languages.getPosition(xIter - xBegin);
263 cl::list<std::string>::const_iterator xNext = llvm::next(xIter);
264 xPosNext = (xNext == xEnd) ? std::numeric_limits<unsigned>::max()
265 : Languages.getPosition(xNext - xBegin);
266 xLanguage = (*xIter == "none") ? 0 : &(*xIter);
267 }
268
Mikhail Glushenkov4f6e3a42008-05-06 17:28:03 +0000269 // For each input file:
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000270 for (cl::list<std::string>::const_iterator B = InputFilenames.begin(),
Mikhail Glushenkov87416b42008-05-06 18:10:53 +0000271 CB = B, E = InputFilenames.end(); B != E; ++B) {
Mikhail Glushenkovbbbc9d42008-05-06 17:27:37 +0000272 sys::Path In = sys::Path(*B);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000273
Mikhail Glushenkov87416b42008-05-06 18:10:53 +0000274 // Code for handling the -x option.
275 // Output: std::string* xLanguage (can be NULL).
276 if (!xEmpty) {
277 filePos = InputFilenames.getPosition(B - CB);
278
279 if (xPos < filePos) {
280 if (filePos < xPosNext) {
281 xLanguage = (*xIter == "none") ? 0 : &(*xIter);
282 }
283 else { // filePos >= xPosNext
284 // Skip xIters while filePos > xPosNext
285 while (filePos > xPosNext) {
286 ++xIter;
287 xPos = xPosNext;
288
289 cl::list<std::string>::const_iterator xNext = llvm::next(xIter);
290 if (xNext == xEnd)
291 xPosNext = std::numeric_limits<unsigned>::max();
292 else
293 xPosNext = Languages.getPosition(xNext - xBegin);
294 xLanguage = (*xIter == "none") ? 0 : &(*xIter);
295 }
296 }
297 }
298 }
299
Mikhail Glushenkov02606582008-05-06 18:07:14 +0000300 // Find the toolchain corresponding to this file.
Mikhail Glushenkov76b1b242008-05-06 18:15:12 +0000301 const Node* N = FindToolChain(In, xLanguage, InLangs);
Mikhail Glushenkov02606582008-05-06 18:07:14 +0000302 // Pass file through the chain starting at head.
Mikhail Glushenkov76b1b242008-05-06 18:15:12 +0000303 PassThroughGraph(In, N, InLangs, TempDir);
Anton Korobeynikovac67b7e2008-03-23 08:57:20 +0000304 }
Mikhail Glushenkov4c11a622008-05-06 18:15:35 +0000305}
306
307// Build the targets. Command-line options are passed through
308// temporary variables.
309int 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 Glushenkov35a85e82008-05-06 18:10:20 +0000328 // Are there any files to be joined?
Mikhail Glushenkov3d688222008-05-06 18:07:48 +0000329 if (JT->JoinListEmpty())
330 continue;
331
Mikhail Glushenkov35a85e82008-05-06 18:10:20 +0000332 // Is this the last tool in the chain?
333 // NOTE: we can process several chains 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}