From 76b1b24dc805c7a3adb4517443241ed3ecd0ba74 Mon Sep 17 00:00:00 2001 From: Mikhail Glushenkov Date: Tue, 6 May 2008 18:15:12 +0000 Subject: [PATCH] Use edge weights to choose the right linker based on input language names. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@50759 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/LLVMC/false.c | 2 +- test/LLVMC/hello.cpp | 2 +- tools/llvmc2/Common.td | 4 ++ tools/llvmc2/CompilationGraph.cpp | 32 ++++++--- tools/llvmc2/CompilationGraph.h | 12 +++- tools/llvmc2/Example.td | 10 +-- utils/TableGen/LLVMCConfigurationEmitter.cpp | 74 +++++++++++++------- 7 files changed, 94 insertions(+), 42 deletions(-) diff --git a/test/LLVMC/false.c b/test/LLVMC/false.c index 8319036c363..69b400c59b0 100644 --- a/test/LLVMC/false.c +++ b/test/LLVMC/false.c @@ -1,5 +1,5 @@ // Test that we can compile .c files as C++ and vice versa -// RUN: llvmc2 --linker=c++ -x c++ %s -x c %p/false.cpp -x lisp -x whatnot -x none %p/false2.cpp -o %t +// RUN: llvmc2 -x c++ %s -x c %p/false.cpp -x lisp -x whatnot -x none %p/false2.cpp -o %t // RUN: ./%t | grep hello #include diff --git a/test/LLVMC/hello.cpp b/test/LLVMC/hello.cpp index 4b45ea945e0..a3148c3c164 100644 --- a/test/LLVMC/hello.cpp +++ b/test/LLVMC/hello.cpp @@ -1,5 +1,5 @@ // Test that we can compile C++ code. -// RUN: llvmc2 --linker=c++ %s -o %t +// RUN: llvmc2 %s -o %t // RUN: ./%t | grep hello #include diff --git a/tools/llvmc2/Common.td b/tools/llvmc2/Common.td index 5e25dcf2f99..db28841afb9 100644 --- a/tools/llvmc2/Common.td +++ b/tools/llvmc2/Common.td @@ -50,7 +50,11 @@ def required; def switch_on; def parameter_equals; def element_in_list; +def if_input_languages_contain; + +// Edge property combinators. def and; +def or; // Map from suffixes to language names diff --git a/tools/llvmc2/CompilationGraph.cpp b/tools/llvmc2/CompilationGraph.cpp index 310413b9f0a..f5cefbf0a90 100644 --- a/tools/llvmc2/CompilationGraph.cpp +++ b/tools/llvmc2/CompilationGraph.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -36,6 +37,7 @@ namespace { // 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; @@ -44,7 +46,7 @@ namespace { for (typename C::const_iterator B = EdgesContainer.begin(), E = EdgesContainer.end(); B != E; ++B) { const Edge* E = B->getPtr(); - unsigned EW = E->Weight(); + unsigned EW = E->Weight(InLangs); if (EW > MaxWeight) { MaxEdge = E; MaxWeight = EW; @@ -142,6 +144,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; @@ -180,6 +183,7 @@ void CompilationGraph::PassThroughGraph (const sys::Path& InFile, return; CurNode = &getNode(ChooseEdge(CurNode->OutEdges, + InLangs, CurNode->Name())->ToolName()); In = Out; Out.clear(); } @@ -221,21 +225,32 @@ TopologicalSortFilterJoinNodes(std::vector& Out) { } // Find 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) const { +FindToolChain(const sys::Path& In, const std::string* forceLanguage, + InputLanguagesSet& InLangs) const { + + // Determine the input language. const std::string& InLanguage = forceLanguage ? *forceLanguage : 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)->ToolName()); + return &getNode(ChooseEdge(TV, InLangs)->ToolName()); } // Build the targets. Command-line options are passed through // temporary variables. int CompilationGraph::Build (const sys::Path& TempDir) { + InputLanguagesSet InLangs; + // This is related to -x option handling. cl::list::const_iterator xIter = Languages.begin(), xBegin = xIter, xEnd = Languages.end(); @@ -284,9 +299,9 @@ 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); } std::vector JTV; @@ -324,9 +339,10 @@ int CompilationGraph::Build (const sys::Path& TempDir) { throw std::runtime_error("Tool returned error code!"); 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); } } diff --git a/tools/llvmc2/CompilationGraph.h b/tools/llvmc2/CompilationGraph.h index 3dc8bc06232..1158d8df1d8 100644 --- a/tools/llvmc2/CompilationGraph.h +++ b/tools/llvmc2/CompilationGraph.h @@ -20,14 +20,18 @@ #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/iterator" +//#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/System/Path.h" +#include #include namespace llvmc { + typedef std::set InputLanguagesSet; + // An edge of the compilation graph. class Edge : public llvm::RefCountedBaseVPTR { public: @@ -35,7 +39,7 @@ namespace llvmc { virtual ~Edge() {}; const std::string& ToolName() const { return ToolName_; } - virtual unsigned Weight() const = 0; + virtual unsigned Weight(const InputLanguagesSet& InLangs) const = 0; private: std::string ToolName_; }; @@ -44,7 +48,7 @@ namespace llvmc { class SimpleEdge : public Edge { public: SimpleEdge(const std::string& T) : Edge(T) {} - unsigned Weight() const { return 1; } + unsigned Weight(const InputLanguagesSet&) const { return 1; } }; // A node of the compilation graph. @@ -160,11 +164,13 @@ namespace llvmc { // Pass the input file through the toolchain. void PassThroughGraph (const llvm::sys::Path& In, const Node* StartNode, + const InputLanguagesSet& InLangs, const llvm::sys::Path& TempDir) const; // Find head of the toolchain corresponding to the given file. const Node* FindToolChain(const llvm::sys::Path& In, - const std::string* forceLanguage) const; + const std::string* forceLanguage, + InputLanguagesSet& InLangs) const; // Sort the nodes in topological order. void TopologicalSort(std::vector& Out); diff --git a/tools/llvmc2/Example.td b/tools/llvmc2/Example.td index 227090258a9..6fb998b28b2 100644 --- a/tools/llvmc2/Example.td +++ b/tools/llvmc2/Example.td @@ -34,12 +34,14 @@ def CompilationGraph : CompilationGraph<[ Edge, Edge, OptionalEdge, + [(if_input_languages_contain "c++"), + (or (parameter_equals "linker", "g++"), + (parameter_equals "linker", "c++"))]>, Edge, OptionalEdge + [(if_input_languages_contain "c++"), + (or (parameter_equals "linker", "g++"), + (parameter_equals "linker", "c++"))]> ]>; diff --git a/utils/TableGen/LLVMCConfigurationEmitter.cpp b/utils/TableGen/LLVMCConfigurationEmitter.cpp index 3db91763962..101dd951175 100644 --- a/utils/TableGen/LLVMCConfigurationEmitter.cpp +++ b/utils/TableGen/LLVMCConfigurationEmitter.cpp @@ -911,19 +911,29 @@ void TypecheckGraph (Record* CompilationGraph, } // Helper function used by EmitEdgePropertyTest. -void EmitEdgePropertyTest1Arg(const DagInit& Prop, +bool EmitEdgePropertyTest1Arg(const std::string& PropName, + const DagInit& Prop, const GlobalOptionDescriptions& OptDescs, std::ostream& O) { checkNumberOfArguments(&Prop, 1); const std::string& OptName = InitPtrToString(Prop.getArg(0)); - const GlobalOptionDescription& OptDesc = OptDescs.FindOption(OptName); - if (OptDesc.Type != OptionType::Switch) - throw OptName + ": incorrect option type!"; - O << OptDesc.GenVariableName(); + if (PropName == "switch_on") { + const GlobalOptionDescription& OptDesc = OptDescs.FindOption(OptName); + if (OptDesc.Type != OptionType::Switch) + throw OptName + ": incorrect option type!"; + O << OptDesc.GenVariableName(); + return true; + } + else if (PropName == "if_input_languages_contain") { + O << "InLangs.count(\"" << OptName << "\") != 0"; + return true; + } + + return false; } // Helper function used by EmitEdgePropertyTest. -void EmitEdgePropertyTest2Args(const std::string& PropName, +bool EmitEdgePropertyTest2Args(const std::string& PropName, const DagInit& Prop, const GlobalOptionDescriptions& OptDescs, std::ostream& O) { @@ -937,6 +947,7 @@ void EmitEdgePropertyTest2Args(const std::string& PropName, && OptDesc.Type != OptionType::Prefix) throw OptName + ": incorrect option type!"; O << OptDesc.GenVariableName() << " == \"" << OptArg << "\""; + return true; } else if (PropName == "element_in_list") { if (OptDesc.Type != OptionType::ParameterList @@ -946,9 +957,10 @@ void EmitEdgePropertyTest2Args(const std::string& PropName, O << "std::find(" << VarName << ".begin(),\n" << Indent3 << VarName << ".end(), \"" << OptArg << "\") != " << VarName << ".end()"; + return true; } - else - throw PropName + ": unknown edge property!"; + + return false; } // Helper function used by EmitEdgeClass. @@ -956,10 +968,29 @@ void EmitEdgePropertyTest(const std::string& PropName, const DagInit& Prop, const GlobalOptionDescriptions& OptDescs, std::ostream& O) { - if (PropName == "switch_on") - EmitEdgePropertyTest1Arg(Prop, OptDescs, O); + if (EmitEdgePropertyTest1Arg(PropName, Prop, OptDescs, O)) + return; + else if (EmitEdgePropertyTest2Args(PropName, Prop, OptDescs, O)) + return; else - EmitEdgePropertyTest2Args(PropName, Prop, OptDescs, O); + throw PropName + ": unknown edge property!"; +} + +// Helper function used by EmitEdgeClass. +void EmitLogicalOperationTest(const DagInit& Prop, const char* LogicOp, + const GlobalOptionDescriptions& OptDescs, + std::ostream& O) { + O << '('; + for (unsigned j = 0, NumArgs = Prop.getNumArgs(); j < NumArgs; ++j) { + const DagInit& InnerProp = dynamic_cast(*Prop.getArg(j)); + const std::string& InnerPropName = + InnerProp.getOperator()->getAsString(); + EmitEdgePropertyTest(InnerPropName, InnerProp, OptDescs, O); + if (j != NumArgs - 1) + O << ")\n" << Indent3 << ' ' << LogicOp << " ("; + else + O << ')'; + } } // Emit a single Edge* class. @@ -975,7 +1006,7 @@ void EmitEdgeClass(unsigned N, const std::string& Target, << "\") {}\n\n" // Function Weight(). - << Indent1 << "unsigned Weight() const {\n" + << Indent1 << "unsigned Weight(const InputLanguagesSet& InLangs) const {\n" << Indent2 << "unsigned ret = 0;\n"; for (size_t i = 0, PropsSize = Props->size(); i < PropsSize; ++i) { @@ -985,24 +1016,17 @@ void EmitEdgeClass(unsigned N, const std::string& Target, if (PropName == "default") IsDefault = true; - O << Indent2 << "if (("; + O << Indent2 << "if ("; if (PropName == "and") { - O << '('; - for (unsigned j = 0, NumArgs = Prop.getNumArgs(); j < NumArgs; ++j) { - const DagInit& InnerProp = dynamic_cast(*Prop.getArg(j)); - const std::string& InnerPropName = - InnerProp.getOperator()->getAsString(); - EmitEdgePropertyTest(InnerPropName, InnerProp, OptDescs, O); - if (j != NumArgs - 1) - O << ")\n" << Indent3 << " && ("; - else - O << ')'; - } + EmitLogicalOperationTest(Prop, "&&", OptDescs, O); + } + else if (PropName == "or") { + EmitLogicalOperationTest(Prop, "||", OptDescs, O); } else { EmitEdgePropertyTest(PropName, Prop, OptDescs, O); } - O << "))\n" << Indent3 << "ret += 2;\n"; + O << ")\n" << Indent3 << "ret += 2;\n"; } if (IsDefault)