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
|
||||
// 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 <iostream>
|
||||
|
|
|
@ -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 <iostream>
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <queue>
|
||||
#include <stdexcept>
|
||||
|
@ -36,6 +37,7 @@ namespace {
|
|||
// Return the edge with the maximum weight.
|
||||
template <class C>
|
||||
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<const Node*>& 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<std::string>::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<const Node*> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 <set>
|
||||
#include <string>
|
||||
|
||||
namespace llvmc {
|
||||
|
||||
typedef std::set<std::string> InputLanguagesSet;
|
||||
|
||||
// An edge of the compilation graph.
|
||||
class Edge : public llvm::RefCountedBaseVPTR<Edge> {
|
||||
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<const Node*>& Out);
|
||||
|
|
|
@ -34,12 +34,14 @@ def CompilationGraph : CompilationGraph<[
|
|||
Edge<llc, llvm_gcc_assembler>,
|
||||
Edge<llvm_gcc_assembler, llvm_gcc_linker>,
|
||||
OptionalEdge<llvm_gcc_assembler, llvm_gcc_cpp_linker,
|
||||
[(parameter_equals "linker", "g++"),
|
||||
(parameter_equals "linker", "c++")]>,
|
||||
[(if_input_languages_contain "c++"),
|
||||
(or (parameter_equals "linker", "g++"),
|
||||
(parameter_equals "linker", "c++"))]>,
|
||||
|
||||
|
||||
Edge<root, llvm_gcc_linker>,
|
||||
OptionalEdge<root, llvm_gcc_cpp_linker,
|
||||
[(parameter_equals "linker", "g++"),
|
||||
(parameter_equals "linker", "c++")]>
|
||||
[(if_input_languages_contain "c++"),
|
||||
(or (parameter_equals "linker", "g++"),
|
||||
(parameter_equals "linker", "c++"))]>
|
||||
]>;
|
||||
|
|
|
@ -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<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.
|
||||
|
@ -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<DagInit&>(*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)
|
||||
|
|
Loading…
Reference in New Issue