diff options
Diffstat (limited to 'contrib/llvm/lib/CompilerDriver')
-rw-r--r-- | contrib/llvm/lib/CompilerDriver/Action.cpp | 134 | ||||
-rw-r--r-- | contrib/llvm/lib/CompilerDriver/BuiltinOptions.cpp | 61 | ||||
-rw-r--r-- | contrib/llvm/lib/CompilerDriver/CompilationGraph.cpp | 655 | ||||
-rw-r--r-- | contrib/llvm/lib/CompilerDriver/Main.cpp | 146 | ||||
-rw-r--r-- | contrib/llvm/lib/CompilerDriver/Tool.cpp | 95 |
5 files changed, 1091 insertions, 0 deletions
diff --git a/contrib/llvm/lib/CompilerDriver/Action.cpp b/contrib/llvm/lib/CompilerDriver/Action.cpp new file mode 100644 index 0000000..a8d625c --- /dev/null +++ b/contrib/llvm/lib/CompilerDriver/Action.cpp @@ -0,0 +1,134 @@ +//===--- Action.cpp - The LLVM Compiler Driver ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open +// Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Action class - implementation and auxiliary functions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CompilerDriver/Action.h" +#include "llvm/CompilerDriver/BuiltinOptions.h" +#include "llvm/CompilerDriver/Error.h" +#include "llvm/CompilerDriver/Main.h" + +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/SystemUtils.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/TimeValue.h" + +#include <stdexcept> +#include <string> + +using namespace llvm; +using namespace llvmc; + +namespace llvmc { + +extern const char* ProgramName; + +} + +namespace { + + void PrintString (const std::string& str) { + errs() << str << ' '; + } + + void PrintCommand (const std::string& Cmd, const StrVector& Args) { + errs() << Cmd << ' '; + std::for_each(Args.begin(), Args.end(), &PrintString); + errs() << '\n'; + } + + bool IsSegmentationFault (int returnCode) { +#ifdef LLVM_ON_WIN32 + return (returnCode >= 0xc0000000UL) +#else + return (returnCode < 0); +#endif + } + + int ExecuteProgram (const std::string& name, const StrVector& args) { + sys::Path prog(name); + + if (sys::path::is_relative(prog.str())) { + prog = PrependMainExecutablePath(name, ProgramName, + (void *)(intptr_t)&Main); + + if (!prog.canExecute()) { + prog = sys::Program::FindProgramByName(name); + if (prog.isEmpty()) { + PrintError("Can't find program '" + name + "'"); + return -1; + } + } + } + if (!prog.canExecute()) { + PrintError("Program '" + name + "' is not executable."); + return -1; + } + + // Build the command line vector and the redirects array. + const sys::Path* redirects[3] = {0,0,0}; + sys::Path stdout_redirect; + + std::vector<const char*> argv; + argv.reserve((args.size()+2)); + argv.push_back(name.c_str()); + + for (StrVector::const_iterator B = args.begin(), E = args.end(); + B!=E; ++B) { + if (*B == ">") { + ++B; + stdout_redirect.set(*B); + redirects[1] = &stdout_redirect; + } + else { + argv.push_back((*B).c_str()); + } + } + argv.push_back(0); // null terminate list. + + // Invoke the program. + int ret = sys::Program::ExecuteAndWait(prog, &argv[0], 0, &redirects[0]); + + if (IsSegmentationFault(ret)) { + errs() << "Segmentation fault: "; + PrintCommand(name, args); + } + + return ret; + } +} + +namespace llvmc { + void AppendToGlobalTimeLog (const std::string& cmd, double time); +} + +int llvmc::Action::Execute () const { + if (DryRun || VerboseMode) + PrintCommand(Command_, Args_); + + if (!DryRun) { + if (Time) { + sys::TimeValue now = sys::TimeValue::now(); + int ret = ExecuteProgram(Command_, Args_); + sys::TimeValue now2 = sys::TimeValue::now(); + now2 -= now; + double elapsed = now2.seconds() + now2.microseconds() / 1000000.0; + AppendToGlobalTimeLog(Command_, elapsed); + + return ret; + } + else { + return ExecuteProgram(Command_, Args_); + } + } + + return 0; +} diff --git a/contrib/llvm/lib/CompilerDriver/BuiltinOptions.cpp b/contrib/llvm/lib/CompilerDriver/BuiltinOptions.cpp new file mode 100644 index 0000000..3844203 --- /dev/null +++ b/contrib/llvm/lib/CompilerDriver/BuiltinOptions.cpp @@ -0,0 +1,61 @@ +//===--- BuiltinOptions.cpp - The LLVM Compiler Driver ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open +// Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Definitions of all global command-line option variables. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CompilerDriver/BuiltinOptions.h" + +#ifdef ENABLE_LLVMC_DYNAMIC_PLUGINS +#include "llvm/Support/PluginLoader.h" +#endif + +namespace cl = llvm::cl; + +namespace llvmc { + +cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<input file>"), + cl::ZeroOrMore); +cl::opt<std::string> OutputFilename("o", cl::desc("Output file name"), + cl::value_desc("file"), cl::Prefix); +cl::opt<std::string> TempDirname("temp-dir", cl::desc("Temp dir name"), + cl::value_desc("<directory>"), cl::Prefix); +cl::list<std::string> Languages("x", + cl::desc("Specify the language of the following input files"), + cl::ZeroOrMore); + +cl::opt<bool> DryRun("dry-run", + cl::desc("Only pretend to run commands")); +cl::opt<bool> Time("time", cl::desc("Time individual commands")); +cl::opt<bool> VerboseMode("v", + cl::desc("Enable verbose mode")); + +cl::opt<bool> CheckGraph("check-graph", + cl::desc("Check the compilation graph for errors"), + cl::Hidden); +cl::opt<bool> WriteGraph("write-graph", + cl::desc("Write compilation-graph.dot file"), + cl::Hidden); +cl::opt<bool> ViewGraph("view-graph", + cl::desc("Show compilation graph in GhostView"), + cl::Hidden); + +cl::opt<SaveTempsEnum::Values> SaveTemps +("save-temps", cl::desc("Keep temporary files"), + cl::init(SaveTempsEnum::Unset), + cl::values(clEnumValN(SaveTempsEnum::Obj, "obj", + "Save files in the directory specified with -o"), + clEnumValN(SaveTempsEnum::Cwd, "cwd", + "Use current working directory"), + clEnumValN(SaveTempsEnum::Obj, "", "Same as 'cwd'"), + clEnumValEnd), + cl::ValueOptional); + +} // End namespace llvmc. diff --git a/contrib/llvm/lib/CompilerDriver/CompilationGraph.cpp b/contrib/llvm/lib/CompilerDriver/CompilationGraph.cpp new file mode 100644 index 0000000..33c6566 --- /dev/null +++ b/contrib/llvm/lib/CompilerDriver/CompilationGraph.cpp @@ -0,0 +1,655 @@ +//===--- CompilationGraph.cpp - The LLVM Compiler Driver --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open +// Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Compilation graph - implementation. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CompilerDriver/BuiltinOptions.h" +#include "llvm/CompilerDriver/CompilationGraph.h" +#include "llvm/CompilerDriver/Error.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/DOTGraphTraits.h" +#include "llvm/Support/GraphWriter.h" +#include "llvm/Support/raw_ostream.h" + +#include <algorithm> +#include <cstring> +#include <iterator> +#include <limits> +#include <queue> + +using namespace llvm; +using namespace llvmc; + +namespace llvmc { + + const std::string* LanguageMap::GetLanguage(const sys::Path& File) const { + // Remove the '.'. + StringRef suf = sys::path::extension(File.str()).substr(1); + LanguageMap::const_iterator Lang = + this->find(suf.empty() ? "*empty*" : suf); + if (Lang == this->end()) { + PrintError("File '" + File.str() + "' has unknown suffix '" + + suf.str() + '\''); + return 0; + } + return &Lang->second; + } +} + +namespace { + + /// ChooseEdge - Return the edge with the maximum weight. Returns 0 on error. + template <class C> + const Edge* ChooseEdge(const C& EdgesContainer, + const InputLanguagesSet& InLangs, + const std::string& NodeName = "root") { + const Edge* MaxEdge = 0; + int MaxWeight = 0; + bool SingleMax = true; + + // TODO: fix calculation of SingleMax. + for (typename C::const_iterator B = EdgesContainer.begin(), + E = EdgesContainer.end(); B != E; ++B) { + const Edge* e = B->getPtr(); + int EW = e->Weight(InLangs); + if (EW < 0) { + // (error) invocation in TableGen -> we don't need to print an error + // message. + return 0; + } + if (EW > MaxWeight) { + MaxEdge = e; + MaxWeight = EW; + SingleMax = true; + } else if (EW == MaxWeight) { + SingleMax = false; + } + } + + if (!SingleMax) { + PrintError("Node " + NodeName + ": multiple maximal outward edges found!" + " Most probably a specification error."); + return 0; + } + if (!MaxEdge) { + PrintError("Node " + NodeName + ": no maximal outward edge found!" + " Most probably a specification error."); + return 0; + } + return MaxEdge; + } + +} + +void Node::AddEdge(Edge* Edg) { + // If there already was an edge between two nodes, modify it instead + // of adding a new edge. + const std::string& ToolName = Edg->ToolName(); + for (container_type::iterator B = OutEdges.begin(), E = OutEdges.end(); + B != E; ++B) { + if ((*B)->ToolName() == ToolName) { + llvm::IntrusiveRefCntPtr<Edge>(Edg).swap(*B); + return; + } + } + OutEdges.push_back(llvm::IntrusiveRefCntPtr<Edge>(Edg)); +} + +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()) { + PrintError("Node " + ToolName + " is not in the graph"); + return 0; + } + 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()) { + PrintError("Node " + ToolName + " is not in the graph!"); + return 0; + } + return &I->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()) { + PrintError("No tool corresponding to the language " + LangName + " found"); + return 0; + } + return &I->second; +} + +void CompilationGraph::insertNode(Tool* V) { + if (NodesMap.count(V->Name()) == 0) + NodesMap[V->Name()] = Node(this, V); +} + +int CompilationGraph::insertEdge(const std::string& A, Edge* Edg) { + Node* B = getNode(Edg->ToolName()); + if (B == 0) + return 1; + + if (A == "root") { + const char** InLangs = B->ToolPtr->InputLanguages(); + for (;*InLangs; ++InLangs) + ToolsMap[*InLangs].push_back(IntrusiveRefCntPtr<Edge>(Edg)); + NodesMap["root"].AddEdge(Edg); + } + else { + Node* N = getNode(A); + if (N == 0) + return 1; + + N->AddEdge(Edg); + } + // Increase the inward edge counter. + B->IncrInEdges(); + + return 0; +} + +// Pass input file through the chain until we bump into a Join node or +// a node that says that it is the last. +int CompilationGraph::PassThroughGraph (const sys::Path& InFile, + const Node* StartNode, + const InputLanguagesSet& InLangs, + const sys::Path& TempDir, + const LanguageMap& LangMap) const { + sys::Path In = InFile; + const Node* CurNode = StartNode; + + while(true) { + Tool* CurTool = CurNode->ToolPtr.getPtr(); + + if (CurTool->IsJoin()) { + JoinTool& JT = static_cast<JoinTool&>(*CurTool); + JT.AddToJoinList(In); + break; + } + + Action CurAction; + if (int ret = CurTool->GenerateAction(CurAction, In, CurNode->HasChildren(), + TempDir, InLangs, LangMap)) { + return ret; + } + + if (int ret = CurAction.Execute()) + return ret; + + if (CurAction.StopCompilation()) + return 0; + + const Edge* Edg = ChooseEdge(CurNode->OutEdges, InLangs, CurNode->Name()); + if (Edg == 0) + return 1; + + CurNode = getNode(Edg->ToolName()); + if (CurNode == 0) + return 1; + + In = CurAction.OutFile(); + } + + return 0; +} + +// 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 LanguageMap& LangMap) const { + + // Determine the input language. + const std::string* InLang = (ForceLanguage ? ForceLanguage + : LangMap.GetLanguage(In)); + if (InLang == 0) + return 0; + const std::string& InLanguage = *InLang; + + // Add the current input language to the input language set. + InLangs.insert(InLanguage); + + // Find the toolchain for the input language. + const tools_vector_type* pTV = getToolsVector(InLanguage); + if (pTV == 0) + return 0; + + const tools_vector_type& TV = *pTV; + if (TV.empty()) { + PrintError("No toolchain corresponding to language " + + InLanguage + " found"); + return 0; + } + + const Edge* Edg = ChooseEdge(TV, InLangs); + if (Edg == 0) + return 0; + + return getNode(Edg->ToolName()); +} + +// 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. +int CompilationGraph::BuildInitial (InputLanguagesSet& InLangs, + const sys::Path& TempDir, + const LanguageMap& LangMap) { + // This is related to -x option handling. + cl::list<std::string>::const_iterator xIter = Languages.begin(), + xBegin = xIter, xEnd = Languages.end(); + bool xEmpty = true; + const std::string* xLanguage = 0; + unsigned xPos = 0, xPosNext = 0, filePos = 0; + + if (xIter != xEnd) { + xEmpty = false; + xPos = Languages.getPosition(xIter - xBegin); + cl::list<std::string>::const_iterator xNext = llvm::next(xIter); + xPosNext = (xNext == xEnd) ? std::numeric_limits<unsigned>::max() + : Languages.getPosition(xNext - xBegin); + xLanguage = (*xIter == "none") ? 0 : &(*xIter); + } + + // For each input file: + for (cl::list<std::string>::const_iterator B = InputFilenames.begin(), + CB = B, E = InputFilenames.end(); B != E; ++B) { + sys::Path In = sys::Path(*B); + + // Code for handling the -x option. + // Output: std::string* xLanguage (can be NULL). + if (!xEmpty) { + filePos = InputFilenames.getPosition(B - CB); + + if (xPos < filePos) { + if (filePos < xPosNext) { + xLanguage = (*xIter == "none") ? 0 : &(*xIter); + } + else { // filePos >= xPosNext + // Skip xIters while filePos > xPosNext + while (filePos > xPosNext) { + ++xIter; + xPos = xPosNext; + + cl::list<std::string>::const_iterator xNext = llvm::next(xIter); + if (xNext == xEnd) + xPosNext = std::numeric_limits<unsigned>::max(); + else + xPosNext = Languages.getPosition(xNext - xBegin); + xLanguage = (*xIter == "none") ? 0 : &(*xIter); + } + } + } + } + + // Find the toolchain corresponding to this file. + const Node* N = FindToolChain(In, xLanguage, InLangs, LangMap); + if (N == 0) + return 1; + // Pass file through the chain starting at head. + if (int ret = PassThroughGraph(In, N, InLangs, TempDir, LangMap)) + return ret; + } + + return 0; +} + +// Sort the nodes in topological order. +int CompilationGraph::TopologicalSort(std::vector<const Node*>& Out) { + std::queue<const Node*> Q; + + Node* Root = getNode("root"); + if (Root == 0) + return 1; + + Q.push(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()); + if (B == 0) + return 1; + + B->DecrInEdges(); + if (B->HasNoInEdges()) + Q.push(B); + } + } + + return 0; +} + +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. +int CompilationGraph:: +TopologicalSortFilterJoinNodes(std::vector<const Node*>& Out) { + std::vector<const Node*> TopSorted; + if (int ret = TopologicalSort(TopSorted)) + return ret; + std::remove_copy_if(TopSorted.begin(), TopSorted.end(), + std::back_inserter(Out), NotJoinNode); + + return 0; +} + +int CompilationGraph::Build (const sys::Path& TempDir, + const LanguageMap& LangMap) { + InputLanguagesSet InLangs; + bool WasSomeActionGenerated = !InputFilenames.empty(); + + // Traverse initial parts of the toolchains and fill in InLangs. + if (int ret = BuildInitial(InLangs, TempDir, LangMap)) + return ret; + + std::vector<const Node*> JTV; + if (int ret = TopologicalSortFilterJoinNodes(JTV)) + return ret; + + // For all join nodes in topological order: + for (std::vector<const Node*>::iterator B = JTV.begin(), E = JTV.end(); + B != E; ++B) { + + const Node* CurNode = *B; + JoinTool* JT = &static_cast<JoinTool&>(*CurNode->ToolPtr.getPtr()); + + // Are there any files in the join list? + if (JT->JoinListEmpty() && !(JT->WorksOnEmpty() && InputFilenames.empty())) + continue; + + WasSomeActionGenerated = true; + Action CurAction; + if (int ret = JT->GenerateAction(CurAction, CurNode->HasChildren(), + TempDir, InLangs, LangMap)) { + return ret; + } + + if (int ret = CurAction.Execute()) + return ret; + + if (CurAction.StopCompilation()) + return 0; + + const Edge* Edg = ChooseEdge(CurNode->OutEdges, InLangs, CurNode->Name()); + if (Edg == 0) + return 1; + + const Node* NextNode = getNode(Edg->ToolName()); + if (NextNode == 0) + return 1; + + if (int ret = PassThroughGraph(sys::Path(CurAction.OutFile()), NextNode, + InLangs, TempDir, LangMap)) { + return ret; + } + } + + if (!WasSomeActionGenerated) { + PrintError("no input files"); + return 1; + } + + return 0; +} + +int CompilationGraph::CheckLanguageNames() const { + int ret = 0; + + // Check that names for output and input languages on all edges do match. + for (const_nodes_iterator B = this->NodesMap.begin(), + E = this->NodesMap.end(); B != E; ++B) { + + const Node & N1 = B->second; + if (N1.ToolPtr) { + for (Node::const_iterator EB = N1.EdgesBegin(), EE = N1.EdgesEnd(); + EB != EE; ++EB) { + const Node* N2 = this->getNode((*EB)->ToolName()); + if (N2 == 0) + return 1; + + if (!N2->ToolPtr) { + ++ret; + errs() << "Error: there is an edge from '" << N1.ToolPtr->Name() + << "' back to the root!\n\n"; + continue; + } + + const char** OutLangs = N1.ToolPtr->OutputLanguages(); + const char** InLangs = N2->ToolPtr->InputLanguages(); + bool eq = false; + const char* OutLang = 0; + for (;*OutLangs; ++OutLangs) { + OutLang = *OutLangs; + for (;*InLangs; ++InLangs) { + if (std::strcmp(OutLang, *InLangs) == 0) { + eq = true; + break; + } + } + } + + if (!eq) { + ++ret; + errs() << "Error: Output->input language mismatch in the edge '" + << N1.ToolPtr->Name() << "' -> '" << N2->ToolPtr->Name() + << "'!\n" + << "Expected one of { "; + + InLangs = N2->ToolPtr->InputLanguages(); + for (;*InLangs; ++InLangs) { + errs() << '\'' << *InLangs << (*(InLangs+1) ? "', " : "'"); + } + + errs() << " }, but got '" << OutLang << "'!\n\n"; + } + + } + } + } + + return ret; +} + +int CompilationGraph::CheckMultipleDefaultEdges() const { + int ret = 0; + InputLanguagesSet Dummy; + + // For all nodes, just iterate over the outgoing edges and check if there is + // more than one edge with maximum weight. + for (const_nodes_iterator B = this->NodesMap.begin(), + E = this->NodesMap.end(); B != E; ++B) { + const Node& N = B->second; + int MaxWeight = -1024; + + // Ignore the root node. + if (!N.ToolPtr) + continue; + + for (Node::const_iterator EB = N.EdgesBegin(), EE = N.EdgesEnd(); + EB != EE; ++EB) { + int EdgeWeight = (*EB)->Weight(Dummy); + if (EdgeWeight > MaxWeight) { + MaxWeight = EdgeWeight; + } + else if (EdgeWeight == MaxWeight) { + ++ret; + errs() << "Error: there are multiple maximal edges stemming from the '" + << N.ToolPtr->Name() << "' node!\n\n"; + break; + } + } + } + + return ret; +} + +int CompilationGraph::CheckCycles() { + unsigned deleted = 0; + std::queue<Node*> Q; + + Node* Root = getNode("root"); + if (Root == 0) + return 1; + + Q.push(Root); + + // Try to delete all nodes that have no ingoing edges, starting from the + // root. If there are any nodes left after this operation, then we have a + // cycle. This relies on '--check-graph' not performing the topological sort. + while (!Q.empty()) { + Node* A = Q.front(); + Q.pop(); + ++deleted; + + for (Node::iterator EB = A->EdgesBegin(), EE = A->EdgesEnd(); + EB != EE; ++EB) { + Node* B = getNode((*EB)->ToolName()); + if (B == 0) + return 1; + + B->DecrInEdges(); + if (B->HasNoInEdges()) + Q.push(B); + } + } + + if (deleted != NodesMap.size()) { + errs() << "Error: there are cycles in the compilation graph!\n" + << "Try inspecting the diagram produced by " + << "'llvmc --view-graph'.\n\n"; + return 1; + } + + return 0; +} + +int CompilationGraph::Check () { + // We try to catch as many errors as we can in one go. + int errs = 0; + int ret = 0; + + // Check that output/input language names match. + ret = this->CheckLanguageNames(); + if (ret < 0) + return 1; + errs += ret; + + // Check for multiple default edges. + ret = this->CheckMultipleDefaultEdges(); + if (ret < 0) + return 1; + errs += ret; + + // Check for cycles. + ret = this->CheckCycles(); + if (ret < 0) + return 1; + errs += ret; + + return errs; +} + +// Code related to graph visualization. + +namespace { + +std::string SquashStrArray (const char** StrArr) { + std::string ret; + + for (; *StrArr; ++StrArr) { + if (*(StrArr + 1)) { + ret += *StrArr; + ret += ", "; + } + else { + ret += *StrArr; + } + } + + return ret; +} + +} // End anonymous namespace. + +namespace llvm { + template <> + struct DOTGraphTraits<llvmc::CompilationGraph*> + : public DefaultDOTGraphTraits + { + DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} + + template<typename GraphType> + static std::string getNodeLabel(const Node* N, const GraphType&) + { + if (N->ToolPtr) + if (N->ToolPtr->IsJoin()) + return N->Name() + "\n (join" + + (N->HasChildren() ? ")" + : std::string(": ") + + SquashStrArray(N->ToolPtr->OutputLanguages()) + ')'); + else + return N->Name(); + else + return "root"; + } + + template<typename EdgeIter> + static std::string getEdgeSourceLabel(const Node* N, EdgeIter I) { + if (N->ToolPtr) { + return SquashStrArray(N->ToolPtr->OutputLanguages()); + } + else { + return SquashStrArray(I->ToolPtr->InputLanguages()); + } + } + }; + +} // End namespace llvm + +int CompilationGraph::writeGraph(const std::string& OutputFilename) { + std::string ErrorInfo; + raw_fd_ostream O(OutputFilename.c_str(), ErrorInfo); + + if (ErrorInfo.empty()) { + errs() << "Writing '"<< OutputFilename << "' file..."; + llvm::WriteGraph(O, this); + errs() << "done.\n"; + } + else { + PrintError("Error opening file '" + OutputFilename + "' for writing!"); + return 1; + } + + return 0; +} + +void CompilationGraph::viewGraph() { + llvm::ViewGraph(this, "compilation-graph"); +} diff --git a/contrib/llvm/lib/CompilerDriver/Main.cpp b/contrib/llvm/lib/CompilerDriver/Main.cpp new file mode 100644 index 0000000..7120027 --- /dev/null +++ b/contrib/llvm/lib/CompilerDriver/Main.cpp @@ -0,0 +1,146 @@ +//===--- Main.cpp - The LLVM Compiler Driver --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open +// Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// llvmc::Main function - driver entry point. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CompilerDriver/AutoGenerated.h" +#include "llvm/CompilerDriver/BuiltinOptions.h" +#include "llvm/CompilerDriver/CompilationGraph.h" +#include "llvm/CompilerDriver/Error.h" + +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Path.h" + +#include <sstream> +#include <string> + +namespace cl = llvm::cl; +namespace sys = llvm::sys; +using namespace llvmc; + +namespace { + + std::stringstream* GlobalTimeLog; + + /// GetTempDir - Get the temporary directory location. Returns non-zero value + /// on error. + int GetTempDir(sys::Path& tempDir) { + // The --temp-dir option. + if (!TempDirname.empty()) { + tempDir = TempDirname; + } + // GCC 4.5-style -save-temps handling. + else if (SaveTemps == SaveTempsEnum::Unset) { + tempDir = sys::Path::GetTemporaryDirectory(); + return 0; + } + else if (SaveTemps == SaveTempsEnum::Obj && !OutputFilename.empty()) { + tempDir = sys::path::parent_path(OutputFilename); + } + else { + // SaveTemps == Cwd --> use current dir (leave tempDir empty). + return 0; + } + + bool Exists; + if (llvm::sys::fs::exists(tempDir.str(), Exists) || !Exists) { + std::string ErrMsg; + if (tempDir.createDirectoryOnDisk(true, &ErrMsg)) { + PrintError(ErrMsg); + return 1; + } + } + + return 0; + } + + /// BuildTargets - A small wrapper for CompilationGraph::Build. Returns + /// non-zero value in case of error. + int BuildTargets(CompilationGraph& graph, const LanguageMap& langMap) { + int ret; + sys::Path tempDir; + bool toDelete = (SaveTemps == SaveTempsEnum::Unset); + + if (int ret = GetTempDir(tempDir)) + return ret; + + ret = graph.Build(tempDir, langMap); + + if (toDelete) + tempDir.eraseFromDisk(true); + + return ret; + } +} + +namespace llvmc { + +// Used to implement -time option. External linkage is intentional. +void AppendToGlobalTimeLog(const std::string& cmd, double time) { + *GlobalTimeLog << "# " << cmd << ' ' << time << '\n'; +} + +// Sometimes user code wants to access the argv[0] value. +const char* ProgramName; + +int Main(int argc, char** argv) { + int ret = 0; + LanguageMap langMap; + CompilationGraph graph; + + ProgramName = argv[0]; + + cl::ParseCommandLineOptions + (argc, argv, + /* Overview = */ "LLVM Compiler Driver (Work In Progress)", + /* ReadResponseFiles = */ false); + + if (int ret = autogenerated::RunInitialization(langMap, graph)) + return ret; + + if (CheckGraph) { + ret = graph.Check(); + if (!ret) + llvm::errs() << "check-graph: no errors found.\n"; + + return ret; + } + + if (ViewGraph) { + graph.viewGraph(); + if (!WriteGraph) + return 0; + } + + if (WriteGraph) { + const std::string& Out = (OutputFilename.empty() + ? std::string("compilation-graph.dot") + : OutputFilename); + return graph.writeGraph(Out); + } + + if (Time) { + GlobalTimeLog = new std::stringstream; + GlobalTimeLog->precision(2); + } + + ret = BuildTargets(graph, langMap); + + if (Time) { + llvm::errs() << GlobalTimeLog->str(); + delete GlobalTimeLog; + } + + return ret; +} + +} // end namespace llvmc diff --git a/contrib/llvm/lib/CompilerDriver/Tool.cpp b/contrib/llvm/lib/CompilerDriver/Tool.cpp new file mode 100644 index 0000000..876759a --- /dev/null +++ b/contrib/llvm/lib/CompilerDriver/Tool.cpp @@ -0,0 +1,95 @@ +//===--- Tool.cpp - The LLVM Compiler Driver --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open +// Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Tool base class - implementation details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CompilerDriver/BuiltinOptions.h" +#include "llvm/CompilerDriver/Tool.h" + +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Path.h" + +#include <algorithm> + +using namespace llvm; +using namespace llvmc; + +namespace { + sys::Path MakeTempFile(const sys::Path& TempDir, const std::string& BaseName, + const std::string& Suffix) { + 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 need to be placated with -f or something like that. + Out.makeUnique(true, NULL); + return Out; + } +} + +sys::Path Tool::OutFilename(const sys::Path& In, + const sys::Path& TempDir, + bool StopCompilation, + const char* OutputSuffix) const { + sys::Path Out; + + if (StopCompilation) { + if (!OutputFilename.empty()) { + Out.set(OutputFilename); + } + else if (IsJoin()) { + Out.set("a"); + Out.appendSuffix(OutputSuffix); + } + else { + Out.set(sys::path::stem(In.str())); + Out.appendSuffix(OutputSuffix); + } + } + else { + if (IsJoin()) + Out = MakeTempFile(TempDir, "tmp", OutputSuffix); + else + Out = MakeTempFile(TempDir, sys::path::stem(In.str()), OutputSuffix); + } + return Out; +} + +namespace { + template <class A, class B> + bool CompareFirst (std::pair<A,B> p1, std::pair<A,B> p2) { + return std::less<A>()(p1.first, p2.first); + } +} + +StrVector Tool::SortArgs(ArgsVector& Args) const { + StrVector Out; + + // HACK: this won't be needed when we'll migrate away from CommandLine. + std::stable_sort(Args.begin(), Args.end(), + &CompareFirst<unsigned, std::string>); + for (ArgsVector::iterator B = Args.begin(), E = Args.end(); B != E; ++B) { + Out.push_back(B->second); + } + + return Out; +} |