Use edge weights to choose the right linker based on input language names.

llvm-svn: 50759
This commit is contained in:
Mikhail Glushenkov 2008-05-06 18:15:12 +00:00
parent 6a70e2019b
commit a02084cff7
7 changed files with 94 additions and 42 deletions

View File

@ -1,5 +1,5 @@
// Test that we can compile .c files as C++ and vice versa // 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 // RUN: ./%t | grep hello
#include <iostream> #include <iostream>

View File

@ -1,5 +1,5 @@
// Test that we can compile C++ code. // Test that we can compile C++ code.
// RUN: llvmc2 --linker=c++ %s -o %t // RUN: llvmc2 %s -o %t
// RUN: ./%t | grep hello // RUN: ./%t | grep hello
#include <iostream> #include <iostream>

View File

@ -50,7 +50,11 @@ def required;
def switch_on; def switch_on;
def parameter_equals; def parameter_equals;
def element_in_list; def element_in_list;
def if_input_languages_contain;
// Edge property combinators.
def and; def and;
def or;
// Map from suffixes to language names // Map from suffixes to language names

View File

@ -20,6 +20,7 @@
#include <algorithm> #include <algorithm>
#include <iterator> #include <iterator>
#include <iostream>
#include <limits> #include <limits>
#include <queue> #include <queue>
#include <stdexcept> #include <stdexcept>
@ -36,6 +37,7 @@ namespace {
// Return the edge with the maximum weight. // Return the edge with the maximum weight.
template <class C> template <class C>
const Edge* ChooseEdge(const C& EdgesContainer, const Edge* ChooseEdge(const C& EdgesContainer,
const InputLanguagesSet& InLangs,
const std::string& NodeName = "root") { const std::string& NodeName = "root") {
const Edge* MaxEdge = 0; const Edge* MaxEdge = 0;
unsigned MaxWeight = 0; unsigned MaxWeight = 0;
@ -44,7 +46,7 @@ namespace {
for (typename C::const_iterator B = EdgesContainer.begin(), for (typename C::const_iterator B = EdgesContainer.begin(),
E = EdgesContainer.end(); B != E; ++B) { E = EdgesContainer.end(); B != E; ++B) {
const Edge* E = B->getPtr(); const Edge* E = B->getPtr();
unsigned EW = E->Weight(); unsigned EW = E->Weight(InLangs);
if (EW > MaxWeight) { if (EW > MaxWeight) {
MaxEdge = E; MaxEdge = E;
MaxWeight = EW; MaxWeight = EW;
@ -142,6 +144,7 @@ namespace {
// a node that says that it is the last. // a node that says that it is the last.
void CompilationGraph::PassThroughGraph (const sys::Path& InFile, void CompilationGraph::PassThroughGraph (const sys::Path& InFile,
const Node* StartNode, const Node* StartNode,
const InputLanguagesSet& InLangs,
const sys::Path& TempDir) const { const sys::Path& TempDir) const {
bool Last = false; bool Last = false;
sys::Path In = InFile; sys::Path In = InFile;
@ -180,6 +183,7 @@ void CompilationGraph::PassThroughGraph (const sys::Path& InFile,
return; return;
CurNode = &getNode(ChooseEdge(CurNode->OutEdges, CurNode = &getNode(ChooseEdge(CurNode->OutEdges,
InLangs,
CurNode->Name())->ToolName()); CurNode->Name())->ToolName());
In = Out; Out.clear(); In = Out; Out.clear();
} }
@ -221,21 +225,32 @@ TopologicalSortFilterJoinNodes(std::vector<const Node*>& Out) {
} }
// Find head of the toolchain corresponding to the given file. // Find head of the toolchain corresponding to the given file.
// Also, insert an input language into InLangs.
const Node* CompilationGraph:: 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 = const std::string& InLanguage =
forceLanguage ? *forceLanguage : getLanguage(In); 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); const tools_vector_type& TV = getToolsVector(InLanguage);
if (TV.empty()) if (TV.empty())
throw std::runtime_error("No toolchain corresponding to language" throw std::runtime_error("No toolchain corresponding to language"
+ InLanguage + " found!"); + InLanguage + " found!");
return &getNode(ChooseEdge(TV)->ToolName()); return &getNode(ChooseEdge(TV, InLangs)->ToolName());
} }
// Build the targets. Command-line options are passed through // Build the targets. Command-line options are passed through
// temporary variables. // temporary variables.
int CompilationGraph::Build (const sys::Path& TempDir) { int CompilationGraph::Build (const sys::Path& TempDir) {
InputLanguagesSet InLangs;
// This is related to -x option handling. // This is related to -x option handling.
cl::list<std::string>::const_iterator xIter = Languages.begin(), cl::list<std::string>::const_iterator xIter = Languages.begin(),
xBegin = xIter, xEnd = Languages.end(); xBegin = xIter, xEnd = Languages.end();
@ -284,9 +299,9 @@ int CompilationGraph::Build (const sys::Path& TempDir) {
} }
// Find the toolchain corresponding to this file. // 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. // Pass file through the chain starting at head.
PassThroughGraph(In, N, TempDir); PassThroughGraph(In, N, InLangs, TempDir);
} }
std::vector<const Node*> JTV; std::vector<const Node*> JTV;
@ -324,9 +339,10 @@ int CompilationGraph::Build (const sys::Path& TempDir) {
throw std::runtime_error("Tool returned error code!"); throw std::runtime_error("Tool returned error code!");
if (!IsLast) { if (!IsLast) {
const Node* NextNode = &getNode(ChooseEdge(CurNode->OutEdges, const Node* NextNode =
CurNode->Name())->ToolName()); &getNode(ChooseEdge(CurNode->OutEdges, InLangs,
PassThroughGraph(Out, NextNode, TempDir); CurNode->Name())->ToolName());
PassThroughGraph(Out, NextNode, InLangs, TempDir);
} }
} }

View File

@ -20,14 +20,18 @@
#include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/GraphTraits.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/iterator" #include "llvm/ADT/iterator"
//#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringMap.h"
#include "llvm/System/Path.h" #include "llvm/System/Path.h"
#include <set>
#include <string> #include <string>
namespace llvmc { namespace llvmc {
typedef std::set<std::string> InputLanguagesSet;
// An edge of the compilation graph. // An edge of the compilation graph.
class Edge : public llvm::RefCountedBaseVPTR<Edge> { class Edge : public llvm::RefCountedBaseVPTR<Edge> {
public: public:
@ -35,7 +39,7 @@ namespace llvmc {
virtual ~Edge() {}; virtual ~Edge() {};
const std::string& ToolName() const { return ToolName_; } const std::string& ToolName() const { return ToolName_; }
virtual unsigned Weight() const = 0; virtual unsigned Weight(const InputLanguagesSet& InLangs) const = 0;
private: private:
std::string ToolName_; std::string ToolName_;
}; };
@ -44,7 +48,7 @@ namespace llvmc {
class SimpleEdge : public Edge { class SimpleEdge : public Edge {
public: public:
SimpleEdge(const std::string& T) : Edge(T) {} 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. // A node of the compilation graph.
@ -160,11 +164,13 @@ namespace llvmc {
// Pass the input file through the toolchain. // Pass the input file through the toolchain.
void PassThroughGraph (const llvm::sys::Path& In, const Node* StartNode, void PassThroughGraph (const llvm::sys::Path& In, const Node* StartNode,
const InputLanguagesSet& InLangs,
const llvm::sys::Path& TempDir) const; const llvm::sys::Path& TempDir) const;
// Find head of the toolchain corresponding to the given file. // Find head of the toolchain corresponding to the given file.
const Node* FindToolChain(const llvm::sys::Path& In, 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. // Sort the nodes in topological order.
void TopologicalSort(std::vector<const Node*>& Out); void TopologicalSort(std::vector<const Node*>& Out);

View File

@ -34,12 +34,14 @@ def CompilationGraph : CompilationGraph<[
Edge<llc, llvm_gcc_assembler>, Edge<llc, llvm_gcc_assembler>,
Edge<llvm_gcc_assembler, llvm_gcc_linker>, Edge<llvm_gcc_assembler, llvm_gcc_linker>,
OptionalEdge<llvm_gcc_assembler, llvm_gcc_cpp_linker, OptionalEdge<llvm_gcc_assembler, llvm_gcc_cpp_linker,
[(parameter_equals "linker", "g++"), [(if_input_languages_contain "c++"),
(parameter_equals "linker", "c++")]>, (or (parameter_equals "linker", "g++"),
(parameter_equals "linker", "c++"))]>,
Edge<root, llvm_gcc_linker>, Edge<root, llvm_gcc_linker>,
OptionalEdge<root, llvm_gcc_cpp_linker, OptionalEdge<root, llvm_gcc_cpp_linker,
[(parameter_equals "linker", "g++"), [(if_input_languages_contain "c++"),
(parameter_equals "linker", "c++")]> (or (parameter_equals "linker", "g++"),
(parameter_equals "linker", "c++"))]>
]>; ]>;

View File

@ -911,19 +911,29 @@ void TypecheckGraph (Record* CompilationGraph,
} }
// Helper function used by EmitEdgePropertyTest. // Helper function used by EmitEdgePropertyTest.
void EmitEdgePropertyTest1Arg(const DagInit& Prop, bool EmitEdgePropertyTest1Arg(const std::string& PropName,
const DagInit& Prop,
const GlobalOptionDescriptions& OptDescs, const GlobalOptionDescriptions& OptDescs,
std::ostream& O) { std::ostream& O) {
checkNumberOfArguments(&Prop, 1); checkNumberOfArguments(&Prop, 1);
const std::string& OptName = InitPtrToString(Prop.getArg(0)); const std::string& OptName = InitPtrToString(Prop.getArg(0));
const GlobalOptionDescription& OptDesc = OptDescs.FindOption(OptName); if (PropName == "switch_on") {
if (OptDesc.Type != OptionType::Switch) const GlobalOptionDescription& OptDesc = OptDescs.FindOption(OptName);
throw OptName + ": incorrect option type!"; if (OptDesc.Type != OptionType::Switch)
O << OptDesc.GenVariableName(); 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. // Helper function used by EmitEdgePropertyTest.
void EmitEdgePropertyTest2Args(const std::string& PropName, bool EmitEdgePropertyTest2Args(const std::string& PropName,
const DagInit& Prop, const DagInit& Prop,
const GlobalOptionDescriptions& OptDescs, const GlobalOptionDescriptions& OptDescs,
std::ostream& O) { std::ostream& O) {
@ -937,6 +947,7 @@ void EmitEdgePropertyTest2Args(const std::string& PropName,
&& OptDesc.Type != OptionType::Prefix) && OptDesc.Type != OptionType::Prefix)
throw OptName + ": incorrect option type!"; throw OptName + ": incorrect option type!";
O << OptDesc.GenVariableName() << " == \"" << OptArg << "\""; O << OptDesc.GenVariableName() << " == \"" << OptArg << "\"";
return true;
} }
else if (PropName == "element_in_list") { else if (PropName == "element_in_list") {
if (OptDesc.Type != OptionType::ParameterList if (OptDesc.Type != OptionType::ParameterList
@ -946,9 +957,10 @@ void EmitEdgePropertyTest2Args(const std::string& PropName,
O << "std::find(" << VarName << ".begin(),\n" O << "std::find(" << VarName << ".begin(),\n"
<< Indent3 << VarName << ".end(), \"" << Indent3 << VarName << ".end(), \""
<< OptArg << "\") != " << VarName << ".end()"; << OptArg << "\") != " << VarName << ".end()";
return true;
} }
else
throw PropName + ": unknown edge property!"; return false;
} }
// Helper function used by EmitEdgeClass. // Helper function used by EmitEdgeClass.
@ -956,10 +968,29 @@ void EmitEdgePropertyTest(const std::string& PropName,
const DagInit& Prop, const DagInit& Prop,
const GlobalOptionDescriptions& OptDescs, const GlobalOptionDescriptions& OptDescs,
std::ostream& O) { std::ostream& O) {
if (PropName == "switch_on") if (EmitEdgePropertyTest1Arg(PropName, Prop, OptDescs, O))
EmitEdgePropertyTest1Arg(Prop, OptDescs, O); return;
else if (EmitEdgePropertyTest2Args(PropName, Prop, OptDescs, O))
return;
else 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<DagInit&>(*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. // Emit a single Edge* class.
@ -975,7 +1006,7 @@ void EmitEdgeClass(unsigned N, const std::string& Target,
<< "\") {}\n\n" << "\") {}\n\n"
// Function Weight(). // Function Weight().
<< Indent1 << "unsigned Weight() const {\n" << Indent1 << "unsigned Weight(const InputLanguagesSet& InLangs) const {\n"
<< Indent2 << "unsigned ret = 0;\n"; << Indent2 << "unsigned ret = 0;\n";
for (size_t i = 0, PropsSize = Props->size(); i < PropsSize; ++i) { 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") if (PropName == "default")
IsDefault = true; IsDefault = true;
O << Indent2 << "if (("; O << Indent2 << "if (";
if (PropName == "and") { if (PropName == "and") {
O << '('; EmitLogicalOperationTest(Prop, "&&", OptDescs, O);
for (unsigned j = 0, NumArgs = Prop.getNumArgs(); j < NumArgs; ++j) { }
const DagInit& InnerProp = dynamic_cast<DagInit&>(*Prop.getArg(j)); else if (PropName == "or") {
const std::string& InnerPropName = EmitLogicalOperationTest(Prop, "||", OptDescs, O);
InnerProp.getOperator()->getAsString();
EmitEdgePropertyTest(InnerPropName, InnerProp, OptDescs, O);
if (j != NumArgs - 1)
O << ")\n" << Indent3 << " && (";
else
O << ')';
}
} }
else { else {
EmitEdgePropertyTest(PropName, Prop, OptDescs, O); EmitEdgePropertyTest(PropName, Prop, OptDescs, O);
} }
O << "))\n" << Indent3 << "ret += 2;\n"; O << ")\n" << Indent3 << "ret += 2;\n";
} }
if (IsDefault) if (IsDefault)