X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fllvmc2%2FCompilationGraph.cpp;h=acf391a29060f79ebf3ab9fbb59aa49a364e8130;hb=6fa1c051dc515b6fd1f9a26ac12fed985469bff5;hp=4b04d6f60b36451a6bce2ff51c7d0469a6c48325;hpb=87416b4cea4748a5d2c40c15b58e1a4a3310cd9f;p=oota-llvm.git diff --git a/tools/llvmc2/CompilationGraph.cpp b/tools/llvmc2/CompilationGraph.cpp index 4b04d6f60b3..acf391a2906 100644 --- a/tools/llvmc2/CompilationGraph.cpp +++ b/tools/llvmc2/CompilationGraph.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "Error.h" #include "CompilationGraph.h" #include "llvm/ADT/STLExtras.h" @@ -31,37 +32,52 @@ extern cl::list InputFilenames; extern cl::opt OutputFilename; extern cl::list Languages; +namespace llvmc { + /// ExtsToLangs - Map from file extensions to language names. + LanguageMap GlobalLanguageMap; + + /// GetLanguage - Find the language name corresponding to the given file. + const std::string& GetLanguage(const sys::Path& File) { + LanguageMap::const_iterator Lang = GlobalLanguageMap.find(File.getSuffix()); + if (Lang == GlobalLanguageMap.end()) + throw std::runtime_error("Unknown suffix: " + File.getSuffix()); + return Lang->second; + } +} + namespace { - // Go through the list C and find the edge that isEnabled(); if - // there is no such edge, return the default edge; if there is no - // default edge, throw an exception. + /// ChooseEdge - Return the edge with the maximum weight. template const Edge* ChooseEdge(const C& EdgesContainer, + const InputLanguagesSet& InLangs, const std::string& NodeName = "root") { - const Edge* DefaultEdge = 0; + const Edge* MaxEdge = 0; + unsigned MaxWeight = 0; + bool SingleMax = true; for (typename C::const_iterator B = EdgesContainer.begin(), E = EdgesContainer.end(); B != E; ++B) { const Edge* E = B->getPtr(); - - if (E->isDefault()) - if (!DefaultEdge) - DefaultEdge = E; - else - throw std::runtime_error("Node " + NodeName - + ": multiple default outward edges found!" - " Most probably a specification error."); - if (E->isEnabled()) - return E; + unsigned EW = E->Weight(InLangs); + if (EW > MaxWeight) { + MaxEdge = E; + MaxWeight = EW; + SingleMax = true; + } else if (EW == MaxWeight) { + SingleMax = false; + } } - if (DefaultEdge) - return DefaultEdge; - else - throw std::runtime_error("Node " + NodeName - + ": no default outward edge found!" + if (!SingleMax) + throw std::runtime_error("Node " + NodeName + + ": multiple maximal outward edges found!" " Most probably a specification error."); + if (!MaxEdge) + throw std::runtime_error("Node " + NodeName + + ": no maximal outward edge found!" + " Most probably a specification error."); + return MaxEdge; } } @@ -84,20 +100,14 @@ const Node& CompilationGraph::getNode(const std::string& ToolName) const { return I->second; } -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: " + File.getSuffix() + '!'); - return Lang->second; -} - +// Find the tools list corresponding to the given language name. 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 tool corresponding to the language " - + LangName + "found!"); + + LangName + " found"); return I->second; } @@ -110,16 +120,17 @@ void CompilationGraph::insertNode(Tool* V) { } } -void CompilationGraph::insertEdge(const std::string& A, Edge* E) { - Node& B = getNode(E->ToolName()); +void CompilationGraph::insertEdge(const std::string& A, Edge* Edg) { + Node& B = getNode(Edg->ToolName()); if (A == "root") { - const std::string& InputLanguage = B.ToolPtr->InputLanguage(); - ToolsMap[InputLanguage].push_back(IntrusiveRefCntPtr(E)); - NodesMap["root"].AddEdge(E); + const char** InLangs = B.ToolPtr->InputLanguages(); + for (;*InLangs; ++InLangs) + ToolsMap[*InLangs].push_back(IntrusiveRefCntPtr(Edg)); + NodesMap["root"].AddEdge(Edg); } else { Node& N = getNode(A); - N.AddEdge(E); + N.AddEdge(Edg); } // Increase the inward edge counter. B.IncrInEdges(); @@ -128,9 +139,22 @@ void CompilationGraph::insertEdge(const std::string& A, Edge* E) { namespace { sys::Path MakeTempFile(const sys::Path& TempDir, const std::string& BaseName, const std::string& Suffix) { - sys::Path Out = TempDir; - Out.appendComponent(BaseName); + sys::Path Out; + + // Make sure we don't end up with path names like '/file.o' if the + // TempDir is empty. + if (TempDir.empty()) { + Out.set(BaseName); + } + else { + Out = TempDir; + Out.appendComponent(BaseName); + } Out.appendSuffix(Suffix); + // NOTE: makeUnique always *creates* a unique temporary file, + // which is good, since there will be no races. However, some + // tools do not like it when the output file already exists, so + // they have to be placated with -f or something like that. Out.makeUnique(true, NULL); return Out; } @@ -140,6 +164,7 @@ namespace { // a node that says that it is the last. void CompilationGraph::PassThroughGraph (const sys::Path& InFile, const Node* StartNode, + const InputLanguagesSet& InLangs, const sys::Path& TempDir) const { bool Last = false; sys::Path In = InFile; @@ -171,69 +196,45 @@ void CompilationGraph::PassThroughGraph (const sys::Path& InFile, Out = MakeTempFile(TempDir, In.getBasename(), CurTool->OutputSuffix()); } - if (CurTool->GenerateAction(In, Out).Execute() != 0) - throw std::runtime_error("Tool returned error code!"); + if (int ret = CurTool->GenerateAction(In, Out, InLangs).Execute()) + throw error_code(ret); if (Last) return; CurNode = &getNode(ChooseEdge(CurNode->OutEdges, + InLangs, CurNode->Name())->ToolName()); In = Out; Out.clear(); } } -// Sort the nodes in topological order. -void CompilationGraph::TopologicalSort(std::vector& Out) { - std::queue Q; - Q.push(&getNode("root")); - - while (!Q.empty()) { - const Node* A = Q.front(); - Q.pop(); - Out.push_back(A); - for (Node::const_iterator EB = A->EdgesBegin(), EE = A->EdgesEnd(); - EB != EE; ++EB) { - Node* B = &getNode((*EB)->ToolName()); - B->DecrInEdges(); - if (B->HasNoInEdges()) - Q.push(B); - } - } -} +// Find the head of the toolchain corresponding to the given file. +// Also, insert an input language into InLangs. +const Node* CompilationGraph:: +FindToolChain(const sys::Path& In, const std::string* forceLanguage, + InputLanguagesSet& InLangs) const { -namespace { - bool NotJoinNode(const Node* N) { - return N->ToolPtr ? !N->ToolPtr->IsJoin() : true; - } -} + // Determine the input language. + const std::string& InLanguage = + forceLanguage ? *forceLanguage : GetLanguage(In); -// Call TopologicalSort and filter the resulting list to include -// only Join nodes. -void CompilationGraph:: -TopologicalSortFilterJoinNodes(std::vector& Out) { - std::vector TopSorted; - TopologicalSort(TopSorted); - std::remove_copy_if(TopSorted.begin(), TopSorted.end(), - std::back_inserter(Out), NotJoinNode); -} + // Add the current input language to the input language set. + InLangs.insert(InLanguage); -// Find head of the toolchain corresponding to the given file. -const Node* CompilationGraph:: -FindToolChain(const sys::Path& In, const std::string* forceLanguage) const { - const std::string& InLanguage = - forceLanguage ? *forceLanguage : getLanguage(In); + // Find the toolchain for the input language. const tools_vector_type& TV = getToolsVector(InLanguage); if (TV.empty()) - throw std::runtime_error("No toolchain corresponding to language" - + InLanguage + " found!"); - return &getNode(ChooseEdge(TV)->ToolName()); + throw std::runtime_error("No toolchain corresponding to language " + + InLanguage + " found"); + return &getNode(ChooseEdge(TV, InLangs)->ToolName()); } -// Build the targets. Command-line options are passed through -// temporary variables. -int CompilationGraph::Build (const sys::Path& TempDir) { - +// Helper function used by Build(). +// Traverses initial portions of the toolchains (up to the first Join node). +// This function is also responsible for handling the -x option. +void CompilationGraph::BuildInitial (InputLanguagesSet& InLangs, + const sys::Path& TempDir) { // This is related to -x option handling. cl::list::const_iterator xIter = Languages.begin(), xBegin = xIter, xEnd = Languages.end(); @@ -282,10 +283,53 @@ int CompilationGraph::Build (const sys::Path& TempDir) { } // Find the toolchain corresponding to this file. - const Node* N = FindToolChain(In, xLanguage); + const Node* N = FindToolChain(In, xLanguage, InLangs); // Pass file through the chain starting at head. - PassThroughGraph(In, N, TempDir); + PassThroughGraph(In, N, InLangs, TempDir); + } +} + +// Sort the nodes in topological order. +void CompilationGraph::TopologicalSort(std::vector& Out) { + std::queue Q; + Q.push(&getNode("root")); + + while (!Q.empty()) { + const Node* A = Q.front(); + Q.pop(); + Out.push_back(A); + for (Node::const_iterator EB = A->EdgesBegin(), EE = A->EdgesEnd(); + EB != EE; ++EB) { + Node* B = &getNode((*EB)->ToolName()); + B->DecrInEdges(); + if (B->HasNoInEdges()) + Q.push(B); + } } +} + +namespace { + bool NotJoinNode(const Node* N) { + return N->ToolPtr ? !N->ToolPtr->IsJoin() : true; + } +} + +// Call TopologicalSort and filter the resulting list to include +// only Join nodes. +void CompilationGraph:: +TopologicalSortFilterJoinNodes(std::vector& Out) { + std::vector TopSorted; + TopologicalSort(TopSorted); + std::remove_copy_if(TopSorted.begin(), TopSorted.end(), + std::back_inserter(Out), NotJoinNode); +} + +int CompilationGraph::Build (const sys::Path& TempDir) { + + InputLanguagesSet InLangs; + + // Traverse initial parts of the toolchains and fill in InLangs. + BuildInitial(InLangs, TempDir); std::vector JTV; TopologicalSortFilterJoinNodes(JTV); @@ -299,12 +343,12 @@ int CompilationGraph::Build (const sys::Path& TempDir) { JoinTool* JT = &dynamic_cast(*CurNode->ToolPtr.getPtr()); bool IsLast = false; - // Are there any files to be joined? + // Are there any files in the join list? if (JT->JoinListEmpty()) continue; - // Is this the last tool in the chain? - // NOTE: we can process several chains in parallel. + // Is this the last tool in the toolchain? + // NOTE: we can process several toolchains in parallel. if (!CurNode->HasChildren() || JT->IsLast()) { if (OutputFilename.empty()) { Out.set("a"); @@ -318,13 +362,14 @@ int CompilationGraph::Build (const sys::Path& TempDir) { Out = MakeTempFile(TempDir, "tmp", JT->OutputSuffix()); } - if (JT->GenerateAction(Out).Execute() != 0) - throw std::runtime_error("Tool returned error code!"); + if (int ret = JT->GenerateAction(Out, InLangs).Execute()) + throw error_code(ret); if (!IsLast) { - const Node* NextNode = &getNode(ChooseEdge(CurNode->OutEdges, - CurNode->Name())->ToolName()); - PassThroughGraph(Out, NextNode, TempDir); + const Node* NextNode = + &getNode(ChooseEdge(CurNode->OutEdges, InLangs, + CurNode->Name())->ToolName()); + PassThroughGraph(Out, NextNode, InLangs, TempDir); } } @@ -355,24 +400,40 @@ namespace llvm { template static std::string getEdgeSourceLabel(const Node* N, EdgeIter I) { - if (N->ToolPtr) + if (N->ToolPtr) { return N->ToolPtr->OutputLanguage(); - else - return I->ToolPtr->InputLanguage(); + } + else { + const char** InLangs = I->ToolPtr->InputLanguages(); + std::string ret; + + for (; *InLangs; ++InLangs) { + if (*(InLangs + 1)) { + ret += *InLangs; + ret += ", "; + } + else { + ret += *InLangs; + } + } + + return ret; + } } }; } void CompilationGraph::writeGraph() { - std::ofstream O("CompilationGraph.dot"); + std::ofstream O("compilation-graph.dot"); if (O.good()) { llvm::WriteGraph(this, "compilation-graph"); O.close(); } else { - throw std::runtime_error(""); + throw std::runtime_error("Error opening file 'compilation-graph.dot'" + " for writing!"); } }