diff options
Diffstat (limited to 'tools/llvmc2/CompilationGraph.cpp')
-rw-r--r-- | tools/llvmc2/CompilationGraph.cpp | 163 |
1 files changed, 135 insertions, 28 deletions
diff --git a/tools/llvmc2/CompilationGraph.cpp b/tools/llvmc2/CompilationGraph.cpp index 36e5fc7c0a..bff1aa5627 100644 --- a/tools/llvmc2/CompilationGraph.cpp +++ b/tools/llvmc2/CompilationGraph.cpp @@ -14,46 +14,120 @@ #include "CompilationGraph.h" #include "llvm/Support/CommandLine.h" -#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/DOTGraphTraits.h" +#include "llvm/Support/GraphWriter.h" #include <stdexcept> using namespace llvm; +using namespace llvmcc; extern cl::list<std::string> InputFilenames; extern cl::opt<std::string> OutputFilename; -int llvmcc::CompilationGraph::Build (const sys::Path& tempDir) const { - sys::Path In(InputFilenames.at(0)), Out; +CompilationGraph::CompilationGraph() { + NodesMap["root"] = Node(this); +} + +Node& CompilationGraph::getNode(const std::string& ToolName) { + nodes_map_type::iterator I = NodesMap.find(ToolName); + if (I == NodesMap.end()) + throw std::runtime_error("Node " + ToolName + " is not in graph"); + return I->second; +} + +const Node& CompilationGraph::getNode(const std::string& ToolName) const { + nodes_map_type::const_iterator I = NodesMap.find(ToolName); + if (I == NodesMap.end()) + throw std::runtime_error("Node " + ToolName + " is not in graph!"); + return I->second; +} - // Find out which language corresponds to the suffix of the first input file - LanguageMap::const_iterator Lang = ExtsToLangs.find(In.getSuffix()); +const std::string& CompilationGraph::getLanguage(const sys::Path& File) const { + LanguageMap::const_iterator Lang = ExtsToLangs.find(File.getSuffix()); if (Lang == ExtsToLangs.end()) - throw std::runtime_error("Unknown suffix!"); + throw std::runtime_error("Unknown suffix: " + File.getSuffix() + '!'); + return Lang->second; +} + +const CompilationGraph::tools_vector_type& +CompilationGraph::getToolsVector(const std::string& LangName) const +{ + tools_map_type::const_iterator I = ToolsMap.find(LangName); + if (I == ToolsMap.end()) + throw std::runtime_error("No tools corresponding to " + LangName + + " found!"); + return I->second; +} + +void CompilationGraph::insertVertex(const IntrusiveRefCntPtr<Tool> V) { + if (!NodesMap.count(V->Name())) { + Node N; + N.OwningGraph = this; + N.ToolPtr = V; + NodesMap[V->Name()] = N; + } +} + +void CompilationGraph::insertEdge(const std::string& A, + const std::string& B) { + // TOTHINK: check this at compile-time? + if (B == "root") + throw std::runtime_error("Edges back to the root are not allowed!" + "Compilation graph should be acyclic!"); - // Find the toolchain corresponding to this language - ToolChainMap::const_iterator ToolsIt = ToolChains.find(Lang->second); - if (ToolsIt == ToolChains.end()) - throw std::runtime_error("Unknown language!"); - ToolChain Tools = ToolsIt->second; + if (A == "root") { + const Node& N = getNode(B); + const std::string& InputLanguage = N.ToolPtr->InputLanguage(); + ToolsMap[InputLanguage].push_back(B); + // Needed to support iteration via GraphTraits. + NodesMap["root"].Children.push_back(B); + } + else { + Node& NA = getNode(A); + // Check that there is a node at B. + getNode(B); + NA.Children.push_back(B); + } +} + +// TOFIX: extend, add an ability to choose between different +// toolchains, support more interesting graph topologies. +int CompilationGraph::Build (const sys::Path& tempDir) const { PathVector JoinList; + const Tool* JoinTool = 0; + sys::Path In, Out; + // For each input file for (cl::list<std::string>::const_iterator B = InputFilenames.begin(), E = InputFilenames.end(); B != E; ++B) { In = sys::Path(*B); - // Pass input file through the toolchain - for (ToolChain::const_iterator B = Tools.begin(), E = Tools.end(); - B != E; ++B) { + // Get to the head of the toolchain. + const tools_vector_type& TV = getToolsVector(getLanguage(In)); + if(TV.empty()) + throw std::runtime_error("Tool names vector is empty!"); + const Node* N = &getNode(*TV.begin()); - const Tool* CurTool = B->getPtr(); + // Pass it through the chain until we bump into a Join node or a + // node that says that it is the last. + bool Last = false; + while(!Last) { + const Tool* CurTool = N->ToolPtr.getPtr(); - // Is this the last step in the chain? - if (llvm::next(B) == E || CurTool->IsLast()) { + if(CurTool->IsJoin()) { JoinList.push_back(In); + JoinTool = CurTool; break; } + + // Is this the last tool? + if (N->Children.empty() || CurTool->IsLast()) { + Out.appendComponent(In.getBasename()); + Out.appendSuffix(CurTool->OutputSuffix()); + Last = true; + } else { Out = tempDir; Out.appendComponent(In.getBasename()); @@ -65,24 +139,57 @@ int llvmcc::CompilationGraph::Build (const sys::Path& tempDir) const { if (CurTool->GenerateAction(In, Out).Execute() != 0) throw std::runtime_error("Tool returned error code!"); + N = &getNode(*N->Children.begin()); In = Out; Out.clear(); } } - // Pass .o files to linker - const Tool* JoinNode = (--Tools.end())->getPtr(); + if(JoinTool) { + // If the final output name is empty, set it to "a.out" + if (!OutputFilename.empty()) { + Out = sys::Path(OutputFilename); + } + else { + Out = sys::Path("a"); + Out.appendSuffix(JoinTool->OutputSuffix()); + } - // If the final output name is empty, set it to "a.out" - if (!OutputFilename.empty()) { - Out = sys::Path(OutputFilename); + if (JoinTool->GenerateAction(JoinList, Out).Execute() != 0) + throw std::runtime_error("Tool returned error code!"); } - else { - Out = sys::Path("a"); - Out.appendSuffix(JoinNode->OutputSuffix()); + + return 0; +} + +namespace llvm { + template <> + struct DOTGraphTraits<llvmcc::CompilationGraph*> + : public DefaultDOTGraphTraits + { + + template<typename GraphType> + static std::string getNodeLabel(const Node* N, const GraphType&) { + if (N->ToolPtr) + return N->ToolPtr->Name(); + else + return "root"; } - if (JoinNode->GenerateAction(JoinList, Out).Execute() != 0) - throw std::runtime_error("Tool returned error code!"); + }; +} - return 0; +void CompilationGraph::writeGraph() { + std::ofstream O("CompilationGraph.dot"); + + if(O.good()) { + llvm::WriteGraph(this, "CompilationGraph"); + O.close(); + } + else { + throw std::runtime_error(""); + } +} + +void CompilationGraph::viewGraph() { + llvm::ViewGraph(this, "CompilationGraph"); } |