From: Mikhail Glushenkov Date: Fri, 3 Oct 2008 21:26:27 +0000 (+0000) Subject: Rename llvmc2/core to llvmc2/driver. X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=3945b7cfce6cc58163e66c9524bc1d559df1d2d7;p=oota-llvm.git Rename llvmc2/core to llvmc2/driver. Makefiles try to remove 'core' by default, so it wasn't a very good name. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@57031 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/tools/llvmc2/Makefile b/tools/llvmc2/Makefile index 89a21bcb379..3012065e4ca 100644 --- a/tools/llvmc2/Makefile +++ b/tools/llvmc2/Makefile @@ -11,7 +11,7 @@ LEVEL = ../.. BUILTIN_PLUGINS = Base DRIVER_NAME = llvmc2 -DIRS = plugins core +DIRS = plugins driver export BUILTIN_PLUGINS export DRIVER_NAME diff --git a/tools/llvmc2/core/Action.cpp b/tools/llvmc2/core/Action.cpp deleted file mode 100644 index c0a1b849bcd..00000000000 --- a/tools/llvmc2/core/Action.cpp +++ /dev/null @@ -1,78 +0,0 @@ -//===--- 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/Support/CommandLine.h" -#include "llvm/System/Program.h" - -#include -#include - -using namespace llvm; -using namespace llvmc; - -extern cl::opt DryRun; -extern cl::opt VerboseMode; - -namespace { - int ExecuteProgram(const std::string& name, - const StrVector& args) { - sys::Path prog = sys::Program::FindProgramByName(name); - - if (prog.isEmpty()) - throw std::runtime_error("Can't find program '" + name + "'"); - if (!prog.canExecute()) - throw std::runtime_error("Program '" + name + "' is not executable."); - - // Build the command line vector and the redirects array. - const sys::Path* redirects[3] = {0,0,0}; - sys::Path stdout_redirect; - - std::vector 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. - return sys::Program::ExecuteAndWait(prog, &argv[0], 0, &redirects[0]); - } - - void print_string (const std::string& str) { - std::cerr << str << ' '; - } -} - -int llvmc::Action::Execute() const { - if (DryRun || VerboseMode) { - std::cerr << Command_ << " "; - std::for_each(Args_.begin(), Args_.end(), print_string); - std::cerr << '\n'; - } - if (DryRun) - return 0; - else - return ExecuteProgram(Command_, Args_); -} diff --git a/tools/llvmc2/core/CompilationGraph.cpp b/tools/llvmc2/core/CompilationGraph.cpp deleted file mode 100644 index 838b9405013..00000000000 --- a/tools/llvmc2/core/CompilationGraph.cpp +++ /dev/null @@ -1,442 +0,0 @@ -//===--- 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 "Error.h" -#include "llvm/CompilerDriver/CompilationGraph.h" - -#include "llvm/ADT/STLExtras.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/DOTGraphTraits.h" -#include "llvm/Support/GraphWriter.h" - -#include -#include -#include -#include -#include - -using namespace llvm; -using namespace llvmc; - -extern cl::list InputFilenames; -extern cl::opt OutputFilename; -extern cl::list Languages; - -namespace llvmc { - - const std::string& LanguageMap::GetLanguage(const sys::Path& File) const { - LanguageMap::const_iterator Lang = this->find(File.getSuffix()); - if (Lang == this->end()) - throw std::runtime_error("Unknown suffix: " + File.getSuffix()); - return Lang->second; - } -} - -namespace { - - /// 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* 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(); - unsigned EW = e->Weight(InLangs); - if (EW > MaxWeight) { - MaxEdge = e; - MaxWeight = EW; - SingleMax = true; - } else if (EW == MaxWeight) { - SingleMax = false; - } - } - - 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; - } - -} - -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 the 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 the graph!"); - 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()) - throw std::runtime_error("No tool corresponding to the language " - + LangName + " found"); - return I->second; -} - -void CompilationGraph::insertNode(Tool* V) { - if (NodesMap.count(V->Name()) == 0) { - Node N; - N.OwningGraph = this; - N.ToolPtr = V; - NodesMap[V->Name()] = N; - } -} - -void CompilationGraph::insertEdge(const std::string& A, Edge* Edg) { - Node& B = getNode(Edg->ToolName()); - if (A == "root") { - 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(Edg); - } - // Increase the inward edge counter. - B.IncrInEdges(); -} - -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 have to be placated with -f or something like that. - Out.makeUnique(true, NULL); - return Out; - } -} - -// Pass input file through the chain until we bump into a Join node or -// 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 LanguageMap& LangMap) const { - bool Last = false; - sys::Path In = InFile; - const Node* CurNode = StartNode; - - while(!Last) { - sys::Path Out; - Tool* CurTool = CurNode->ToolPtr.getPtr(); - - if (CurTool->IsJoin()) { - JoinTool& JT = dynamic_cast(*CurTool); - JT.AddToJoinList(In); - break; - } - - // Since toolchains do not have to end with a Join node, we should - // check if this Node is the last. - if (!CurNode->HasChildren() || CurTool->IsLast()) { - if (!OutputFilename.empty()) { - Out.set(OutputFilename); - } - else { - Out.set(In.getBasename()); - Out.appendSuffix(CurTool->OutputSuffix()); - } - Last = true; - } - else { - Out = MakeTempFile(TempDir, In.getBasename(), CurTool->OutputSuffix()); - } - - if (int ret = CurTool->GenerateAction(In, Out, InLangs, LangMap).Execute()) - throw error_code(ret); - - if (Last) - return; - - CurNode = &getNode(ChooseEdge(CurNode->OutEdges, - InLangs, - CurNode->Name())->ToolName()); - In = Out; Out.clear(); - } -} - -// 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& InLanguage = - ForceLanguage ? *ForceLanguage : LangMap.GetLanguage(In); - - // Add the current input language to the input language set. - InLangs.insert(InLanguage); - - // 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, InLangs)->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. -void CompilationGraph::BuildInitial (InputLanguagesSet& InLangs, - const sys::Path& TempDir, - const LanguageMap& LangMap) { - // This is related to -x option handling. - cl::list::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::const_iterator xNext = llvm::next(xIter); - xPosNext = (xNext == xEnd) ? std::numeric_limits::max() - : Languages.getPosition(xNext - xBegin); - xLanguage = (*xIter == "none") ? 0 : &(*xIter); - } - - // For each input file: - for (cl::list::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::const_iterator xNext = llvm::next(xIter); - if (xNext == xEnd) - xPosNext = std::numeric_limits::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); - // Pass file through the chain starting at head. - PassThroughGraph(In, N, InLangs, TempDir, LangMap); - } -} - -// 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, - const LanguageMap& LangMap) { - - InputLanguagesSet InLangs; - - // Traverse initial parts of the toolchains and fill in InLangs. - BuildInitial(InLangs, TempDir, LangMap); - - std::vector JTV; - TopologicalSortFilterJoinNodes(JTV); - - // For all join nodes in topological order: - for (std::vector::iterator B = JTV.begin(), E = JTV.end(); - B != E; ++B) { - - sys::Path Out; - const Node* CurNode = *B; - JoinTool* JT = &dynamic_cast(*CurNode->ToolPtr.getPtr()); - bool IsLast = false; - - // Are there any files in the join list? - if (JT->JoinListEmpty()) - continue; - - // 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"); - Out.appendSuffix(JT->OutputSuffix()); - } - else - Out.set(OutputFilename); - IsLast = true; - } - else { - Out = MakeTempFile(TempDir, "tmp", JT->OutputSuffix()); - } - - if (int ret = JT->GenerateAction(Out, InLangs, LangMap).Execute()) - throw error_code(ret); - - if (!IsLast) { - const Node* NextNode = - &getNode(ChooseEdge(CurNode->OutEdges, InLangs, - CurNode->Name())->ToolName()); - PassThroughGraph(Out, NextNode, InLangs, TempDir, LangMap); - } - } - - return 0; -} - -// Code related to graph visualization. - -namespace llvm { - template <> - struct DOTGraphTraits - : public DefaultDOTGraphTraits - { - - template - 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(": ") + N->ToolPtr->OutputLanguage() + ')'); - else - return N->Name(); - else - return "root"; - } - - template - static std::string getEdgeSourceLabel(const Node* N, EdgeIter I) { - if (N->ToolPtr) { - return N->ToolPtr->OutputLanguage(); - } - 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("compilation-graph.dot"); - - if (O.good()) { - llvm::WriteGraph(this, "compilation-graph"); - O.close(); - } - else { - throw std::runtime_error("Error opening file 'compilation-graph.dot'" - " for writing!"); - } -} - -void CompilationGraph::viewGraph() { - llvm::ViewGraph(this, "compilation-graph"); -} diff --git a/tools/llvmc2/core/Error.h b/tools/llvmc2/core/Error.h deleted file mode 100644 index c0aaff1a724..00000000000 --- a/tools/llvmc2/core/Error.h +++ /dev/null @@ -1,33 +0,0 @@ -//===--- Error.h - 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. -// -//===----------------------------------------------------------------------===// -// -// Exception classes for LLVMC. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVMC2_ERROR_H -#define LLVM_TOOLS_LLVMC2_ERROR_H - -#include - -namespace llvmc { - - class error_code: public std::runtime_error { - int Code_; - public: - error_code (int c) - : std::runtime_error("Tool returned error code"), Code_(c) - {} - - int code() const { return Code_; } - }; - -} - -#endif //LLVM_TOOLS_LLVMC2_ERROR_H diff --git a/tools/llvmc2/core/Makefile b/tools/llvmc2/core/Makefile deleted file mode 100644 index 7c04fe4aca4..00000000000 --- a/tools/llvmc2/core/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -##===- tools/llvmc2/src/Makefile ---------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open -# Source License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../.. -TOOLNAME = $(DRIVER_NAME) -LINK_COMPONENTS = support system -REQUIRES_EH := 1 - -ifneq ($(BUILTIN_PLUGINS),) -USEDLIBS = $(patsubst %,LLVMC%,$(BUILTIN_PLUGINS)) -endif - -include $(LEVEL)/Makefile.common diff --git a/tools/llvmc2/core/Plugin.cpp b/tools/llvmc2/core/Plugin.cpp deleted file mode 100644 index c9b3960c1e7..00000000000 --- a/tools/llvmc2/core/Plugin.cpp +++ /dev/null @@ -1,64 +0,0 @@ -//===--- Plugin.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. -// -//===----------------------------------------------------------------------===// -// -// Plugin support for llvmc2. -// -//===----------------------------------------------------------------------===// - -#include "llvm/CompilerDriver/Plugin.h" - -#include - -namespace { - - // Registry::Add<> does not do lifetime management (probably issues - // with static constructor/destructor ordering), so we have to - // implement it here. - // - // All this static registration/life-before-main model seems - // unnecessary convoluted to me. - - static bool pluginListInitialized = false; - typedef std::vector PluginList; - static PluginList Plugins; -} - -namespace llvmc { - - PluginLoader::PluginLoader() { - if (!pluginListInitialized) { - for (PluginRegistry::iterator B = PluginRegistry::begin(), - E = PluginRegistry::end(); B != E; ++B) - Plugins.push_back(B->instantiate()); - } - pluginListInitialized = true; - } - - PluginLoader::~PluginLoader() { - if (pluginListInitialized) { - for (PluginList::iterator B = Plugins.begin(), E = Plugins.end(); - B != E; ++B) - delete (*B); - } - pluginListInitialized = false; - } - - void PluginLoader::PopulateLanguageMap(LanguageMap& langMap) { - for (PluginList::iterator B = Plugins.begin(), E = Plugins.end(); - B != E; ++B) - (*B)->PopulateLanguageMap(langMap); - } - - void PluginLoader::PopulateCompilationGraph(CompilationGraph& graph) { - for (PluginList::iterator B = Plugins.begin(), E = Plugins.end(); - B != E; ++B) - (*B)->PopulateCompilationGraph(graph); - } - -} diff --git a/tools/llvmc2/core/llvmc.cpp b/tools/llvmc2/core/llvmc.cpp deleted file mode 100644 index f3a1e571926..00000000000 --- a/tools/llvmc2/core/llvmc.cpp +++ /dev/null @@ -1,119 +0,0 @@ -//===--- llvmc.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. -// -//===----------------------------------------------------------------------===// -// -// This tool provides a single point of access to the LLVM -// compilation tools. It has many options. To discover the options -// supported please refer to the tools' manual page or run the tool -// with the --help option. -// -//===----------------------------------------------------------------------===// - -#include "Error.h" - -#include "llvm/CompilerDriver/CompilationGraph.h" -#include "llvm/CompilerDriver/Plugin.h" - -#include "llvm/System/Path.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/PluginLoader.h" - -#include -#include -#include - -namespace cl = llvm::cl; -namespace sys = llvm::sys; -using namespace llvmc; - -// Built-in command-line options. -// External linkage here is intentional. - -cl::list InputFilenames(cl::Positional, cl::desc(""), - cl::ZeroOrMore); -cl::opt OutputFilename("o", cl::desc("Output file name"), - cl::value_desc("file")); -cl::list Languages("x", - cl::desc("Specify the language of the following input files"), - cl::ZeroOrMore); -cl::opt DryRun("dry-run", - cl::desc("Only pretend to run commands")); -cl::opt VerboseMode("v", - cl::desc("Enable verbose mode")); -cl::opt WriteGraph("write-graph", - cl::desc("Write compilation-graph.dot file"), - cl::Hidden); -cl::opt ViewGraph("view-graph", - cl::desc("Show compilation graph in GhostView"), - cl::Hidden); -cl::opt SaveTemps("save-temps", - cl::desc("Keep temporary files"), - cl::Hidden); - -namespace { - /// BuildTargets - A small wrapper for CompilationGraph::Build. - int BuildTargets(CompilationGraph& graph, const LanguageMap& langMap) { - int ret; - const sys::Path& tempDir = SaveTemps - ? sys::Path("") - : sys::Path(sys::Path::GetTemporaryDirectory()); - - try { - ret = graph.Build(tempDir, langMap); - } - catch(...) { - tempDir.eraseFromDisk(true); - throw; - } - - if (!SaveTemps) - tempDir.eraseFromDisk(true); - return ret; - } -} - -int main(int argc, char** argv) { - try { - LanguageMap langMap; - CompilationGraph graph; - - cl::ParseCommandLineOptions - (argc, argv, "LLVM Compiler Driver (Work In Progress)", true); - - PluginLoader Plugins; - Plugins.PopulateLanguageMap(langMap); - Plugins.PopulateCompilationGraph(graph); - - if (WriteGraph) { - graph.writeGraph(); - if (!ViewGraph) - return 0; - } - - if (ViewGraph) { - graph.viewGraph(); - return 0; - } - - if (InputFilenames.empty()) { - throw std::runtime_error("no input files"); - } - - return BuildTargets(graph, langMap); - } - catch(llvmc::error_code& ec) { - return ec.code(); - } - catch(const std::exception& ex) { - std::cerr << argv[0] << ": " << ex.what() << '\n'; - } - catch(...) { - std::cerr << argv[0] << ": unknown error!\n"; - } - return 1; -} diff --git a/tools/llvmc2/driver/Action.cpp b/tools/llvmc2/driver/Action.cpp new file mode 100644 index 00000000000..c0a1b849bcd --- /dev/null +++ b/tools/llvmc2/driver/Action.cpp @@ -0,0 +1,78 @@ +//===--- 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/Support/CommandLine.h" +#include "llvm/System/Program.h" + +#include +#include + +using namespace llvm; +using namespace llvmc; + +extern cl::opt DryRun; +extern cl::opt VerboseMode; + +namespace { + int ExecuteProgram(const std::string& name, + const StrVector& args) { + sys::Path prog = sys::Program::FindProgramByName(name); + + if (prog.isEmpty()) + throw std::runtime_error("Can't find program '" + name + "'"); + if (!prog.canExecute()) + throw std::runtime_error("Program '" + name + "' is not executable."); + + // Build the command line vector and the redirects array. + const sys::Path* redirects[3] = {0,0,0}; + sys::Path stdout_redirect; + + std::vector 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. + return sys::Program::ExecuteAndWait(prog, &argv[0], 0, &redirects[0]); + } + + void print_string (const std::string& str) { + std::cerr << str << ' '; + } +} + +int llvmc::Action::Execute() const { + if (DryRun || VerboseMode) { + std::cerr << Command_ << " "; + std::for_each(Args_.begin(), Args_.end(), print_string); + std::cerr << '\n'; + } + if (DryRun) + return 0; + else + return ExecuteProgram(Command_, Args_); +} diff --git a/tools/llvmc2/driver/CompilationGraph.cpp b/tools/llvmc2/driver/CompilationGraph.cpp new file mode 100644 index 00000000000..838b9405013 --- /dev/null +++ b/tools/llvmc2/driver/CompilationGraph.cpp @@ -0,0 +1,442 @@ +//===--- 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 "Error.h" +#include "llvm/CompilerDriver/CompilationGraph.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/DOTGraphTraits.h" +#include "llvm/Support/GraphWriter.h" + +#include +#include +#include +#include +#include + +using namespace llvm; +using namespace llvmc; + +extern cl::list InputFilenames; +extern cl::opt OutputFilename; +extern cl::list Languages; + +namespace llvmc { + + const std::string& LanguageMap::GetLanguage(const sys::Path& File) const { + LanguageMap::const_iterator Lang = this->find(File.getSuffix()); + if (Lang == this->end()) + throw std::runtime_error("Unknown suffix: " + File.getSuffix()); + return Lang->second; + } +} + +namespace { + + /// 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* 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(); + unsigned EW = e->Weight(InLangs); + if (EW > MaxWeight) { + MaxEdge = e; + MaxWeight = EW; + SingleMax = true; + } else if (EW == MaxWeight) { + SingleMax = false; + } + } + + 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; + } + +} + +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 the 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 the graph!"); + 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()) + throw std::runtime_error("No tool corresponding to the language " + + LangName + " found"); + return I->second; +} + +void CompilationGraph::insertNode(Tool* V) { + if (NodesMap.count(V->Name()) == 0) { + Node N; + N.OwningGraph = this; + N.ToolPtr = V; + NodesMap[V->Name()] = N; + } +} + +void CompilationGraph::insertEdge(const std::string& A, Edge* Edg) { + Node& B = getNode(Edg->ToolName()); + if (A == "root") { + 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(Edg); + } + // Increase the inward edge counter. + B.IncrInEdges(); +} + +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 have to be placated with -f or something like that. + Out.makeUnique(true, NULL); + return Out; + } +} + +// Pass input file through the chain until we bump into a Join node or +// 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 LanguageMap& LangMap) const { + bool Last = false; + sys::Path In = InFile; + const Node* CurNode = StartNode; + + while(!Last) { + sys::Path Out; + Tool* CurTool = CurNode->ToolPtr.getPtr(); + + if (CurTool->IsJoin()) { + JoinTool& JT = dynamic_cast(*CurTool); + JT.AddToJoinList(In); + break; + } + + // Since toolchains do not have to end with a Join node, we should + // check if this Node is the last. + if (!CurNode->HasChildren() || CurTool->IsLast()) { + if (!OutputFilename.empty()) { + Out.set(OutputFilename); + } + else { + Out.set(In.getBasename()); + Out.appendSuffix(CurTool->OutputSuffix()); + } + Last = true; + } + else { + Out = MakeTempFile(TempDir, In.getBasename(), CurTool->OutputSuffix()); + } + + if (int ret = CurTool->GenerateAction(In, Out, InLangs, LangMap).Execute()) + throw error_code(ret); + + if (Last) + return; + + CurNode = &getNode(ChooseEdge(CurNode->OutEdges, + InLangs, + CurNode->Name())->ToolName()); + In = Out; Out.clear(); + } +} + +// 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& InLanguage = + ForceLanguage ? *ForceLanguage : LangMap.GetLanguage(In); + + // Add the current input language to the input language set. + InLangs.insert(InLanguage); + + // 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, InLangs)->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. +void CompilationGraph::BuildInitial (InputLanguagesSet& InLangs, + const sys::Path& TempDir, + const LanguageMap& LangMap) { + // This is related to -x option handling. + cl::list::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::const_iterator xNext = llvm::next(xIter); + xPosNext = (xNext == xEnd) ? std::numeric_limits::max() + : Languages.getPosition(xNext - xBegin); + xLanguage = (*xIter == "none") ? 0 : &(*xIter); + } + + // For each input file: + for (cl::list::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::const_iterator xNext = llvm::next(xIter); + if (xNext == xEnd) + xPosNext = std::numeric_limits::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); + // Pass file through the chain starting at head. + PassThroughGraph(In, N, InLangs, TempDir, LangMap); + } +} + +// 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, + const LanguageMap& LangMap) { + + InputLanguagesSet InLangs; + + // Traverse initial parts of the toolchains and fill in InLangs. + BuildInitial(InLangs, TempDir, LangMap); + + std::vector JTV; + TopologicalSortFilterJoinNodes(JTV); + + // For all join nodes in topological order: + for (std::vector::iterator B = JTV.begin(), E = JTV.end(); + B != E; ++B) { + + sys::Path Out; + const Node* CurNode = *B; + JoinTool* JT = &dynamic_cast(*CurNode->ToolPtr.getPtr()); + bool IsLast = false; + + // Are there any files in the join list? + if (JT->JoinListEmpty()) + continue; + + // 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"); + Out.appendSuffix(JT->OutputSuffix()); + } + else + Out.set(OutputFilename); + IsLast = true; + } + else { + Out = MakeTempFile(TempDir, "tmp", JT->OutputSuffix()); + } + + if (int ret = JT->GenerateAction(Out, InLangs, LangMap).Execute()) + throw error_code(ret); + + if (!IsLast) { + const Node* NextNode = + &getNode(ChooseEdge(CurNode->OutEdges, InLangs, + CurNode->Name())->ToolName()); + PassThroughGraph(Out, NextNode, InLangs, TempDir, LangMap); + } + } + + return 0; +} + +// Code related to graph visualization. + +namespace llvm { + template <> + struct DOTGraphTraits + : public DefaultDOTGraphTraits + { + + template + 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(": ") + N->ToolPtr->OutputLanguage() + ')'); + else + return N->Name(); + else + return "root"; + } + + template + static std::string getEdgeSourceLabel(const Node* N, EdgeIter I) { + if (N->ToolPtr) { + return N->ToolPtr->OutputLanguage(); + } + 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("compilation-graph.dot"); + + if (O.good()) { + llvm::WriteGraph(this, "compilation-graph"); + O.close(); + } + else { + throw std::runtime_error("Error opening file 'compilation-graph.dot'" + " for writing!"); + } +} + +void CompilationGraph::viewGraph() { + llvm::ViewGraph(this, "compilation-graph"); +} diff --git a/tools/llvmc2/driver/Error.h b/tools/llvmc2/driver/Error.h new file mode 100644 index 00000000000..c0aaff1a724 --- /dev/null +++ b/tools/llvmc2/driver/Error.h @@ -0,0 +1,33 @@ +//===--- Error.h - 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. +// +//===----------------------------------------------------------------------===// +// +// Exception classes for LLVMC. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVMC2_ERROR_H +#define LLVM_TOOLS_LLVMC2_ERROR_H + +#include + +namespace llvmc { + + class error_code: public std::runtime_error { + int Code_; + public: + error_code (int c) + : std::runtime_error("Tool returned error code"), Code_(c) + {} + + int code() const { return Code_; } + }; + +} + +#endif //LLVM_TOOLS_LLVMC2_ERROR_H diff --git a/tools/llvmc2/driver/Makefile b/tools/llvmc2/driver/Makefile new file mode 100644 index 00000000000..7c04fe4aca4 --- /dev/null +++ b/tools/llvmc2/driver/Makefile @@ -0,0 +1,19 @@ +##===- tools/llvmc2/src/Makefile ---------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open +# Source License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +TOOLNAME = $(DRIVER_NAME) +LINK_COMPONENTS = support system +REQUIRES_EH := 1 + +ifneq ($(BUILTIN_PLUGINS),) +USEDLIBS = $(patsubst %,LLVMC%,$(BUILTIN_PLUGINS)) +endif + +include $(LEVEL)/Makefile.common diff --git a/tools/llvmc2/driver/Plugin.cpp b/tools/llvmc2/driver/Plugin.cpp new file mode 100644 index 00000000000..c9b3960c1e7 --- /dev/null +++ b/tools/llvmc2/driver/Plugin.cpp @@ -0,0 +1,64 @@ +//===--- Plugin.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. +// +//===----------------------------------------------------------------------===// +// +// Plugin support for llvmc2. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CompilerDriver/Plugin.h" + +#include + +namespace { + + // Registry::Add<> does not do lifetime management (probably issues + // with static constructor/destructor ordering), so we have to + // implement it here. + // + // All this static registration/life-before-main model seems + // unnecessary convoluted to me. + + static bool pluginListInitialized = false; + typedef std::vector PluginList; + static PluginList Plugins; +} + +namespace llvmc { + + PluginLoader::PluginLoader() { + if (!pluginListInitialized) { + for (PluginRegistry::iterator B = PluginRegistry::begin(), + E = PluginRegistry::end(); B != E; ++B) + Plugins.push_back(B->instantiate()); + } + pluginListInitialized = true; + } + + PluginLoader::~PluginLoader() { + if (pluginListInitialized) { + for (PluginList::iterator B = Plugins.begin(), E = Plugins.end(); + B != E; ++B) + delete (*B); + } + pluginListInitialized = false; + } + + void PluginLoader::PopulateLanguageMap(LanguageMap& langMap) { + for (PluginList::iterator B = Plugins.begin(), E = Plugins.end(); + B != E; ++B) + (*B)->PopulateLanguageMap(langMap); + } + + void PluginLoader::PopulateCompilationGraph(CompilationGraph& graph) { + for (PluginList::iterator B = Plugins.begin(), E = Plugins.end(); + B != E; ++B) + (*B)->PopulateCompilationGraph(graph); + } + +} diff --git a/tools/llvmc2/driver/llvmc.cpp b/tools/llvmc2/driver/llvmc.cpp new file mode 100644 index 00000000000..f3a1e571926 --- /dev/null +++ b/tools/llvmc2/driver/llvmc.cpp @@ -0,0 +1,119 @@ +//===--- llvmc.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. +// +//===----------------------------------------------------------------------===// +// +// This tool provides a single point of access to the LLVM +// compilation tools. It has many options. To discover the options +// supported please refer to the tools' manual page or run the tool +// with the --help option. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" + +#include "llvm/CompilerDriver/CompilationGraph.h" +#include "llvm/CompilerDriver/Plugin.h" + +#include "llvm/System/Path.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/PluginLoader.h" + +#include +#include +#include + +namespace cl = llvm::cl; +namespace sys = llvm::sys; +using namespace llvmc; + +// Built-in command-line options. +// External linkage here is intentional. + +cl::list InputFilenames(cl::Positional, cl::desc(""), + cl::ZeroOrMore); +cl::opt OutputFilename("o", cl::desc("Output file name"), + cl::value_desc("file")); +cl::list Languages("x", + cl::desc("Specify the language of the following input files"), + cl::ZeroOrMore); +cl::opt DryRun("dry-run", + cl::desc("Only pretend to run commands")); +cl::opt VerboseMode("v", + cl::desc("Enable verbose mode")); +cl::opt WriteGraph("write-graph", + cl::desc("Write compilation-graph.dot file"), + cl::Hidden); +cl::opt ViewGraph("view-graph", + cl::desc("Show compilation graph in GhostView"), + cl::Hidden); +cl::opt SaveTemps("save-temps", + cl::desc("Keep temporary files"), + cl::Hidden); + +namespace { + /// BuildTargets - A small wrapper for CompilationGraph::Build. + int BuildTargets(CompilationGraph& graph, const LanguageMap& langMap) { + int ret; + const sys::Path& tempDir = SaveTemps + ? sys::Path("") + : sys::Path(sys::Path::GetTemporaryDirectory()); + + try { + ret = graph.Build(tempDir, langMap); + } + catch(...) { + tempDir.eraseFromDisk(true); + throw; + } + + if (!SaveTemps) + tempDir.eraseFromDisk(true); + return ret; + } +} + +int main(int argc, char** argv) { + try { + LanguageMap langMap; + CompilationGraph graph; + + cl::ParseCommandLineOptions + (argc, argv, "LLVM Compiler Driver (Work In Progress)", true); + + PluginLoader Plugins; + Plugins.PopulateLanguageMap(langMap); + Plugins.PopulateCompilationGraph(graph); + + if (WriteGraph) { + graph.writeGraph(); + if (!ViewGraph) + return 0; + } + + if (ViewGraph) { + graph.viewGraph(); + return 0; + } + + if (InputFilenames.empty()) { + throw std::runtime_error("no input files"); + } + + return BuildTargets(graph, langMap); + } + catch(llvmc::error_code& ec) { + return ec.code(); + } + catch(const std::exception& ex) { + std::cerr << argv[0] << ": " << ex.what() << '\n'; + } + catch(...) { + std::cerr << argv[0] << ": unknown error!\n"; + } + return 1; +}