llvm.org GIT mirror llvm / 76b1b24
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 Mikhail Glushenkov 11 years ago
7 changed file(s) with 95 addition(s) and 43 deletion(s). Raw diff Collapse all Expand all
0 // Test that we can compile .c files as C++ and vice versa
1 // RUN: llvmc2 --linker=c++ -x c++ %s -x c %p/false.cpp -x lisp -x whatnot -x none %p/false2.cpp -o %t
1 // RUN: llvmc2 -x c++ %s -x c %p/false.cpp -x lisp -x whatnot -x none %p/false2.cpp -o %t
22 // RUN: ./%t | grep hello
33
44 #include
0 // Test that we can compile C++ code.
1 // RUN: llvmc2 --linker=c++ %s -o %t
1 // RUN: llvmc2 %s -o %t
22 // RUN: ./%t | grep hello
33 #include
44
4949 def switch_on;
5050 def parameter_equals;
5151 def element_in_list;
52 def if_input_languages_contain;
53
54 // Edge property combinators.
5255 def and;
56 def or;
5357
5458 // Map from suffixes to language names
5559
1919
2020 #include
2121 #include
22 #include
2223 #include
2324 #include
2425 #include
3536 // Return the edge with the maximum weight.
3637 template
3738 const Edge* ChooseEdge(const C& EdgesContainer,
39 const InputLanguagesSet& InLangs,
3840 const std::string& NodeName = "root") {
3941 const Edge* MaxEdge = 0;
4042 unsigned MaxWeight = 0;
4345 for (typename C::const_iterator B = EdgesContainer.begin(),
4446 E = EdgesContainer.end(); B != E; ++B) {
4547 const Edge* E = B->getPtr();
46 unsigned EW = E->Weight();
48 unsigned EW = E->Weight(InLangs);
4749 if (EW > MaxWeight) {
4850 MaxEdge = E;
4951 MaxWeight = EW;
141143 // a node that says that it is the last.
142144 void CompilationGraph::PassThroughGraph (const sys::Path& InFile,
143145 const Node* StartNode,
146 const InputLanguagesSet& InLangs,
144147 const sys::Path& TempDir) const {
145148 bool Last = false;
146149 sys::Path In = InFile;
179182 return;
180183
181184 CurNode = &getNode(ChooseEdge(CurNode->OutEdges,
185 InLangs,
182186 CurNode->Name())->ToolName());
183187 In = Out; Out.clear();
184188 }
220224 }
221225
222226 // Find head of the toolchain corresponding to the given file.
227 // Also, insert an input language into InLangs.
223228 const Node* CompilationGraph::
224 FindToolChain(const sys::Path& In, const std::string* forceLanguage) const {
229 FindToolChain(const sys::Path& In, const std::string* forceLanguage,
230 InputLanguagesSet& InLangs) const {
231
232 // Determine the input language.
225233 const std::string& InLanguage =
226234 forceLanguage ? *forceLanguage : getLanguage(In);
235
236 // Add the current input language to the input language set.
237 InLangs.insert(InLanguage);
238
239 // Find the toolchain for the input language.
227240 const tools_vector_type& TV = getToolsVector(InLanguage);
228241 if (TV.empty())
229242 throw std::runtime_error("No toolchain corresponding to language"
230243 + InLanguage + " found!");
231 return &getNode(ChooseEdge(TV)->ToolName());
244 return &getNode(ChooseEdge(TV, InLangs)->ToolName());
232245 }
233246
234247 // Build the targets. Command-line options are passed through
235248 // temporary variables.
236249 int CompilationGraph::Build (const sys::Path& TempDir) {
250
251 InputLanguagesSet InLangs;
237252
238253 // This is related to -x option handling.
239254 cl::list::const_iterator xIter = Languages.begin(),
283298 }
284299
285300 // Find the toolchain corresponding to this file.
286 const Node* N = FindToolChain(In, xLanguage);
301 const Node* N = FindToolChain(In, xLanguage, InLangs);
287302 // Pass file through the chain starting at head.
288 PassThroughGraph(In, N, TempDir);
303 PassThroughGraph(In, N, InLangs, TempDir);
289304 }
290305
291306 std::vector JTV;
323338 throw std::runtime_error("Tool returned error code!");
324339
325340 if (!IsLast) {
326 const Node* NextNode = &getNode(ChooseEdge(CurNode->OutEdges,
327 CurNode->Name())->ToolName());
328 PassThroughGraph(Out, NextNode, TempDir);
341 const Node* NextNode =
342 &getNode(ChooseEdge(CurNode->OutEdges, InLangs,
343 CurNode->Name())->ToolName());
344 PassThroughGraph(Out, NextNode, InLangs, TempDir);
329345 }
330346 }
331347
1919 #include "llvm/ADT/GraphTraits.h"
2020 #include "llvm/ADT/IntrusiveRefCntPtr.h"
2121 #include "llvm/ADT/iterator"
22 //#include "llvm/ADT/SmallSet.h"
2223 #include "llvm/ADT/SmallVector.h"
2324 #include "llvm/ADT/StringMap.h"
2425 #include "llvm/System/Path.h"
2526
27 #include
2628 #include
2729
2830 namespace llvmc {
31
32 typedef std::set InputLanguagesSet;
2933
3034 // An edge of the compilation graph.
3135 class Edge : public llvm::RefCountedBaseVPTR {
3438 virtual ~Edge() {};
3539
3640 const std::string& ToolName() const { return ToolName_; }
37 virtual unsigned Weight() const = 0;
41 virtual unsigned Weight(const InputLanguagesSet& InLangs) const = 0;
3842 private:
3943 std::string ToolName_;
4044 };
4347 class SimpleEdge : public Edge {
4448 public:
4549 SimpleEdge(const std::string& T) : Edge(T) {}
46 unsigned Weight() const { return 1; }
50 unsigned Weight(const InputLanguagesSet&) const { return 1; }
4751 };
4852
4953 // A node of the compilation graph.
159163
160164 // Pass the input file through the toolchain.
161165 void PassThroughGraph (const llvm::sys::Path& In, const Node* StartNode,
166 const InputLanguagesSet& InLangs,
162167 const llvm::sys::Path& TempDir) const;
163168
164169 // Find head of the toolchain corresponding to the given file.
165170 const Node* FindToolChain(const llvm::sys::Path& In,
166 const std::string* forceLanguage) const;
171 const std::string* forceLanguage,
172 InputLanguagesSet& InLangs) const;
167173
168174 // Sort the nodes in topological order.
169175 void TopologicalSort(std::vector& Out);
3333 Edge,
3434 Edge,
3535 OptionalEdge
36 [(parameter_equals "linker", "g++"),
37 (parameter_equals "linker", "c++")]>,
36 [(if_input_languages_contain "c++"),
37 (or (parameter_equals "linker", "g++"),
38 (parameter_equals "linker", "c++"))]>,
3839
3940
4041 Edge,
4142 OptionalEdge
42 [(parameter_equals "linker", "g++"),
43 (parameter_equals "linker", "c++")]>
43 [(if_input_languages_contain "c++"),
44 (or (parameter_equals "linker", "g++"),
45 (parameter_equals "linker", "c++"))]>
4446 ]>;
910910 }
911911
912912 // Helper function used by EmitEdgePropertyTest.
913 void EmitEdgePropertyTest1Arg(const DagInit& Prop,
913 bool EmitEdgePropertyTest1Arg(const std::string& PropName,
914 const DagInit& Prop,
914915 const GlobalOptionDescriptions& OptDescs,
915916 std::ostream& O) {
916917 checkNumberOfArguments(&Prop, 1);
917918 const std::string& OptName = InitPtrToString(Prop.getArg(0));
918 const GlobalOptionDescription& OptDesc = OptDescs.FindOption(OptName);
919 if (OptDesc.Type != OptionType::Switch)
920 throw OptName + ": incorrect option type!";
921 O << OptDesc.GenVariableName();
919 if (PropName == "switch_on") {
920 const GlobalOptionDescription& OptDesc = OptDescs.FindOption(OptName);
921 if (OptDesc.Type != OptionType::Switch)
922 throw OptName + ": incorrect option type!";
923 O << OptDesc.GenVariableName();
924 return true;
925 }
926 else if (PropName == "if_input_languages_contain") {
927 O << "InLangs.count(\"" << OptName << "\") != 0";
928 return true;
929 }
930
931 return false;
922932 }
923933
924934 // Helper function used by EmitEdgePropertyTest.
925 void EmitEdgePropertyTest2Args(const std::string& PropName,
935 bool EmitEdgePropertyTest2Args(const std::string& PropName,
926936 const DagInit& Prop,
927937 const GlobalOptionDescriptions& OptDescs,
928938 std::ostream& O) {
936946 && OptDesc.Type != OptionType::Prefix)
937947 throw OptName + ": incorrect option type!";
938948 O << OptDesc.GenVariableName() << " == \"" << OptArg << "\"";
949 return true;
939950 }
940951 else if (PropName == "element_in_list") {
941952 if (OptDesc.Type != OptionType::ParameterList
945956 O << "std::find(" << VarName << ".begin(),\n"
946957 << Indent3 << VarName << ".end(), \""
947958 << OptArg << "\") != " << VarName << ".end()";
948 }
949 else
950 throw PropName + ": unknown edge property!";
959 return true;
960 }
961
962 return false;
951963 }
952964
953965 // Helper function used by EmitEdgeClass.
955967 const DagInit& Prop,
956968 const GlobalOptionDescriptions& OptDescs,
957969 std::ostream& O) {
958 if (PropName == "switch_on")
959 EmitEdgePropertyTest1Arg(Prop, OptDescs, O);
970 if (EmitEdgePropertyTest1Arg(PropName, Prop, OptDescs, O))
971 return;
972 else if (EmitEdgePropertyTest2Args(PropName, Prop, OptDescs, O))
973 return;
960974 else
961 EmitEdgePropertyTest2Args(PropName, Prop, OptDescs, O);
975 throw PropName + ": unknown edge property!";
976 }
977
978 // Helper function used by EmitEdgeClass.
979 void EmitLogicalOperationTest(const DagInit& Prop, const char* LogicOp,
980 const GlobalOptionDescriptions& OptDescs,
981 std::ostream& O) {
982 O << '(';
983 for (unsigned j = 0, NumArgs = Prop.getNumArgs(); j < NumArgs; ++j) {
984 const DagInit& InnerProp = dynamic_cast(*Prop.getArg(j));
985 const std::string& InnerPropName =
986 InnerProp.getOperator()->getAsString();
987 EmitEdgePropertyTest(InnerPropName, InnerProp, OptDescs, O);
988 if (j != NumArgs - 1)
989 O << ")\n" << Indent3 << ' ' << LogicOp << " (";
990 else
991 O << ')';
992 }
962993 }
963994
964995 // Emit a single Edge* class.
9741005 << "\") {}\n\n"
9751006
9761007 // Function Weight().
977 << Indent1 << "unsigned Weight() const {\n"
1008 << Indent1 << "unsigned Weight(const InputLanguagesSet& InLangs) const {\n"
9781009 << Indent2 << "unsigned ret = 0;\n";
9791010
9801011 for (size_t i = 0, PropsSize = Props->size(); i < PropsSize; ++i) {
9841015 if (PropName == "default")
9851016 IsDefault = true;
9861017
987 O << Indent2 << "if ((";
1018 O << Indent2 << "if (";
9881019 if (PropName == "and") {
989 O << '(';
990 for (unsigned j = 0, NumArgs = Prop.getNumArgs(); j < NumArgs; ++j) {
991 const DagInit& InnerProp = dynamic_cast(*Prop.getArg(j));
992 const std::string& InnerPropName =
993 InnerProp.getOperator()->getAsString();
994 EmitEdgePropertyTest(InnerPropName, InnerProp, OptDescs, O);
995 if (j != NumArgs - 1)
996 O << ")\n" << Indent3 << " && (";
997 else
998 O << ')';
999 }
1020 EmitLogicalOperationTest(Prop, "&&", OptDescs, O);
1021 }
1022 else if (PropName == "or") {
1023 EmitLogicalOperationTest(Prop, "||", OptDescs, O);
10001024 }
10011025 else {
10021026 EmitEdgePropertyTest(PropName, Prop, OptDescs, O);
10031027 }
1004 O << "))\n" << Indent3 << "ret += 2;\n";
1028 O << ")\n" << Indent3 << "ret += 2;\n";
10051029 }
10061030
10071031 if (IsDefault)