forked from OSchip/llvm-project
Use edge weights to choose the right linker based on input language names.
llvm-svn: 50759
This commit is contained in:
parent
6a70e2019b
commit
a02084cff7
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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++"))]>
|
||||||
]>;
|
]>;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue