diff --git a/include/llvm/CompilerDriver/Common.td b/include/llvm/CompilerDriver/Common.td index 45518385e41..e017326069e 100644 --- a/include/llvm/CompilerDriver/Common.td +++ b/include/llvm/CompilerDriver/Common.td @@ -15,10 +15,6 @@ class Tool l> { list properties = l; } -// Special Tool instance - the root node of the compilation graph. - -def root : Tool<[]>; - // Possible Tool properties def in_language; @@ -87,19 +83,19 @@ class LanguageMap lst> { // Compilation graph -class EdgeBase { - Tool a = t1; - Tool b = t2; +class EdgeBase { + string a = t1; + string b = t2; dag weight = d; } -class Edge : EdgeBase; +class Edge : EdgeBase; // Edge and SimpleEdge are synonyms. -class SimpleEdge : EdgeBase; +class SimpleEdge : EdgeBase; // Optionally enabled edge. -class OptionalEdge : EdgeBase; +class OptionalEdge : EdgeBase; class CompilationGraph lst> { list edges = lst; diff --git a/tools/llvmc2/doc/LLVMC-Reference.rst b/tools/llvmc2/doc/LLVMC-Reference.rst index 62e2ef41a8b..2d782572987 100644 --- a/tools/llvmc2/doc/LLVMC-Reference.rst +++ b/tools/llvmc2/doc/LLVMC-Reference.rst @@ -158,7 +158,7 @@ definitions:: include "llvm/CompilerDriver/Common.td" // And optionally: // include "llvm/CompilerDriver/Tools.td" - // which contains tool definitions. + // which contains some useful tool definitions. Internally, LLVMC stores information about possible source transformations in form of a graph. Nodes in this graph represent @@ -171,19 +171,19 @@ The definition of the compilation graph (see file ``plugins/Base/Base.td`` for an example) is just a list of edges:: def CompilationGraph : CompilationGraph<[ - Edge, - Edge, + Edge<"root", "llvm_gcc_c">, + Edge<"root", "llvm_gcc_assembler">, ... - Edge, - Edge, + Edge<"llvm_gcc_c", "llc">, + Edge<"llvm_gcc_cpp", "llc">, ... - OptionalEdge, - OptionalEdge, + OptionalEdge<"llvm_gcc_c", "opt", [(switch_on "opt")]>, + OptionalEdge<"llvm_gcc_cpp", "opt", [(switch_on "opt")]>, ... - OptionalEdge, @@ -193,7 +193,10 @@ The definition of the compilation graph (see file As you can see, the edges can be either default or optional, where optional edges are differentiated by an additional ``case`` expression -used to calculate the weight of this edge. +used to calculate the weight of this edge. Notice also that we refer +to tools via their names (as strings). This allows us to add edges to +an existing compilation graph without having to include all tool +definitions that it uses. The default edges are assigned a weight of 1, and optional edges get a weight of 0 + 2*N where N is the number of tests that evaluated to diff --git a/tools/llvmc2/doc/LLVMC-Tutorial.rst b/tools/llvmc2/doc/LLVMC-Tutorial.rst index ffc1de903b8..9c6741eba1d 100644 --- a/tools/llvmc2/doc/LLVMC-Tutorial.rst +++ b/tools/llvmc2/doc/LLVMC-Tutorial.rst @@ -66,7 +66,7 @@ Contents of the file ``Simple.td`` look like this:: def LanguageMap : LanguageMap<[LangToSuffixes<"c", ["c"]>]>; // Compilation graph - def CompilationGraph : CompilationGraph<[Edge]>; + def CompilationGraph : CompilationGraph<[Edge<"root", "gcc">]>; As you can see, this file consists of three parts: tool descriptions, language map, and the compilation graph definition. diff --git a/tools/llvmc2/plugins/Base/Base.td b/tools/llvmc2/plugins/Base/Base.td index 158520c278e..85a37cb41a7 100644 --- a/tools/llvmc2/plugins/Base/Base.td +++ b/tools/llvmc2/plugins/Base/Base.td @@ -17,42 +17,42 @@ include "llvm/CompilerDriver/Tools.td" // Toolchains def CompilationGraph : CompilationGraph<[ - Edge, - Edge, - Edge, - Edge, - Edge, - Edge, + Edge<"root", "llvm_gcc_c">, + Edge<"root", "llvm_gcc_assembler">, + Edge<"root", "llvm_gcc_cpp">, + Edge<"root", "llvm_gcc_m">, + Edge<"root", "llvm_gcc_mxx">, + Edge<"root", "llvm_as">, - Edge, - Edge, - Edge, - Edge, - Edge, + Edge<"llvm_gcc_c", "llc">, + Edge<"llvm_gcc_cpp", "llc">, + Edge<"llvm_gcc_m", "llc">, + Edge<"llvm_gcc_mxx", "llc">, + Edge<"llvm_as", "llc">, - OptionalEdge, - OptionalEdge, - OptionalEdge, - OptionalEdge, - OptionalEdge, - Edge, + OptionalEdge<"llvm_gcc_c", "opt", (case (switch_on "opt"), (inc_weight))>, + OptionalEdge<"llvm_gcc_cpp", "opt", (case (switch_on "opt"), (inc_weight))>, + OptionalEdge<"llvm_gcc_m", "opt", (case (switch_on "opt"), (inc_weight))>, + OptionalEdge<"llvm_gcc_mxx", "opt", (case (switch_on "opt"), (inc_weight))>, + OptionalEdge<"llvm_as", "opt", (case (switch_on "opt"), (inc_weight))>, + Edge<"opt", "llc">, - Edge, - Edge, - OptionalEdge, + Edge<"llvm_gcc_assembler", "llvm_gcc_linker">, + OptionalEdge<"llvm_gcc_assembler", "llvm_gcc_cpp_linker", (case (or (input_languages_contain "c++"), - (input_languages_contain "objective-c++")), + (input_languages_contain "objective-c++")), (inc_weight), (or (parameter_equals "linker", "g++"), (parameter_equals "linker", "c++")), (inc_weight))>, - Edge, - OptionalEdge, + OptionalEdge<"root", "llvm_gcc_cpp_linker", (case (or (input_languages_contain "c++"), - (input_languages_contain "objective-c++")), + (input_languages_contain "objective-c++")), (inc_weight), (or (parameter_equals "linker", "g++"), (parameter_equals "linker", "c++")), (inc_weight))> diff --git a/tools/llvmc2/plugins/Clang/Clang.td b/tools/llvmc2/plugins/Clang/Clang.td index d30bc978aa8..ee6987fa352 100644 --- a/tools/llvmc2/plugins/Clang/Clang.td +++ b/tools/llvmc2/plugins/Clang/Clang.td @@ -76,11 +76,11 @@ def LanguageMap : LanguageMap< // Compilation graph def CompilationGraph : CompilationGraph<[ - Edge, - Edge, - Edge, - Edge, - Edge, - Edge + Edge<"root", "clang_c">, + Edge<"root", "clang_cpp">, + Edge<"root", "clang_objective_c">, + Edge<"clang_c", "llvm_ld">, + Edge<"clang_cpp", "llvm_ld">, + Edge<"clang_objective_c", "llvm_ld"> ]>; diff --git a/tools/llvmc2/plugins/Simple/Simple.td b/tools/llvmc2/plugins/Simple/Simple.td index 2bc40119261..b974cbc95eb 100644 --- a/tools/llvmc2/plugins/Simple/Simple.td +++ b/tools/llvmc2/plugins/Simple/Simple.td @@ -27,4 +27,4 @@ def gcc : Tool< def LanguageMap : LanguageMap<[LangToSuffixes<"c", ["c"]>]>; -def CompilationGraph : CompilationGraph<[Edge]>; +def CompilationGraph : CompilationGraph<[Edge<"root", "gcc">]>; diff --git a/utils/TableGen/LLVMCConfigurationEmitter.cpp b/utils/TableGen/LLVMCConfigurationEmitter.cpp index bacde538daa..f5a1cf8652c 100644 --- a/utils/TableGen/LLVMCConfigurationEmitter.cpp +++ b/utils/TableGen/LLVMCConfigurationEmitter.cpp @@ -764,11 +764,11 @@ void CollectToolProperties (RecordVector::const_iterator B, } -/// CollectPropertiesFromOptionList - Gather information about -/// *global* option properties from the OptionList. -void CollectPropertiesFromOptionList (RecordVector::const_iterator B, - RecordVector::const_iterator E, - GlobalOptionDescriptions& OptDescs) +/// CollectPropertiesFromOptionLists - Gather information about +/// *global* option properties from all OptionLists. +void CollectPropertiesFromOptionLists (RecordVector::const_iterator B, + RecordVector::const_iterator E, + GlobalOptionDescriptions& OptDescs) { // Iterate over a properties list of every Tool definition for (;B!=E;++B) { @@ -805,7 +805,7 @@ void CheckForSuperfluousOptions (const ToolPropertiesList& TPList, const GlobalOptionDescription& Val = B->second; if (!nonSuperfluousOptions.count(Val.Name) && Val.Type != OptionType::Alias) - cerr << "Warning: option '-" << Val.Name << "' has no effect! " + llvm::cerr << "Warning: option '-" << Val.Name << "' has no effect! " "Probable cause: this option is specified only in the OptionList.\n"; } } @@ -1448,29 +1448,31 @@ void EmitOptionDescriptions (const GlobalOptionDescriptions& descs, /// EmitPopulateLanguageMap - Emit the PopulateLanguageMap() function. void EmitPopulateLanguageMap (const RecordKeeper& Records, std::ostream& O) { - // Get the relevant field out of RecordKeeper - Record* LangMapRecord = Records.getDef("LanguageMap"); - if (!LangMapRecord) - throw std::string("Language map definition not found!"); - - ListInit* LangsToSuffixesList = LangMapRecord->getValueAsListInit("map"); - if (!LangsToSuffixesList) - throw std::string("Error in the language map definition!"); - // Generate code O << "namespace {\n\n"; O << "void PopulateLanguageMapLocal(LanguageMap& langMap) {\n"; - for (unsigned i = 0; i < LangsToSuffixesList->size(); ++i) { - Record* LangToSuffixes = LangsToSuffixesList->getElementAsRecord(i); + // Get the relevant field out of RecordKeeper + Record* LangMapRecord = Records.getDef("LanguageMap"); - const std::string& Lang = LangToSuffixes->getValueAsString("lang"); - const ListInit* Suffixes = LangToSuffixes->getValueAsListInit("suffixes"); + // It is allowed for a plugin to have no language map. + if (LangMapRecord) { - for (unsigned i = 0; i < Suffixes->size(); ++i) - O << Indent1 << "langMap[\"" - << InitPtrToString(Suffixes->getElement(i)) - << "\"] = \"" << Lang << "\";\n"; + ListInit* LangsToSuffixesList = LangMapRecord->getValueAsListInit("map"); + if (!LangsToSuffixesList) + throw std::string("Error in the language map definition!"); + + for (unsigned i = 0; i < LangsToSuffixesList->size(); ++i) { + Record* LangToSuffixes = LangsToSuffixesList->getElementAsRecord(i); + + const std::string& Lang = LangToSuffixes->getValueAsString("lang"); + const ListInit* Suffixes = LangToSuffixes->getValueAsListInit("suffixes"); + + for (unsigned i = 0; i < Suffixes->size(); ++i) + O << Indent1 << "langMap[\"" + << InitPtrToString(Suffixes->getElement(i)) + << "\"] = \"" << Lang << "\";\n"; + } } O << "}\n\n}\n\n"; @@ -1492,13 +1494,11 @@ void FillInToolToLang (const ToolPropertiesList& TPList, } /// TypecheckGraph - Check that names for output and input languages -/// on all edges do match. -// TOFIX: It would be nice if this function also checked for cycles -// and multiple default edges in the graph (better error -// reporting). Unfortunately, it is awkward to do right now because -// our intermediate representation is not sufficiently -// sophisticated. Algorithms like these require a real graph instead of -// an AST. +/// on all edges do match. This doesn't do much when the information +/// about the whole graph is not available (i.e. when compiling most +/// plugins). +// TODO: add a --check-graph switch to llvmc2. It would also make it +// possible to detect cycles and multiple default edges. void TypecheckGraph (Record* CompilationGraph, const ToolPropertiesList& TPList) { StringMap > ToolToInLang; @@ -1511,18 +1511,18 @@ void TypecheckGraph (Record* CompilationGraph, for (unsigned i = 0; i < edges->size(); ++i) { Record* Edge = edges->getElementAsRecord(i); - Record* A = Edge->getValueAsDef("a"); - Record* B = Edge->getValueAsDef("b"); - StringMap::iterator IA = ToolToOutLang.find(A->getName()); - StringMap >::iterator IB = ToolToInLang.find(B->getName()); - if (IA == IAE) - throw A->getName() + ": no such tool!"; - if (IB == IBE) - throw B->getName() + ": no such tool!"; - if (A->getName() != "root" && IB->second.count(IA->second) == 0) - throw "Edge " + A->getName() + "->" + B->getName() - + ": output->input language mismatch"; - if (B->getName() == "root") + const std::string& A = Edge->getValueAsString("a"); + const std::string& B = Edge->getValueAsString("b"); + StringMap::iterator IA = ToolToOutLang.find(A); + StringMap >::iterator IB = ToolToInLang.find(B); + + if (A != "root") { + if (IA != IAE && IB != IBE && IB->second.count(IA->second) == 0) + throw "Edge " + A + "->" + B + + ": output->input language mismatch"; + } + + if (B == "root") throw std::string("Edges back to the root are not allowed!"); } } @@ -1578,13 +1578,13 @@ void EmitEdgeClasses (Record* CompilationGraph, for (unsigned i = 0; i < edges->size(); ++i) { Record* Edge = edges->getElementAsRecord(i); - Record* B = Edge->getValueAsDef("b"); + const std::string& B = Edge->getValueAsString("b"); DagInit* Weight = Edge->getValueAsDag("weight"); if (isDagEmpty(Weight)) continue; - EmitEdgeClass(i, B->getName(), Weight, OptDescs, O); + EmitEdgeClass(i, B, Weight, OptDescs, O); } } @@ -1605,13 +1605,12 @@ void EmitPopulateCompilationGraph (Record* CompilationGraph, for (unsigned i = 0; i < edges->size(); ++i) { Record* Edge = edges->getElementAsRecord(i); - Record* A = Edge->getValueAsDef("a"); - Record* B = Edge->getValueAsDef("b"); + const std::string& A = Edge->getValueAsString("a"); + const std::string& B = Edge->getValueAsString("b"); - if (A->getName() != "root") - ToolsInGraph.insert(A->getName()); - if (B->getName() != "root") - ToolsInGraph.insert(B->getName()); + if (A != "root") + ToolsInGraph.insert(A); + ToolsInGraph.insert(B); } for (llvm::StringSet<>::iterator B = ToolsInGraph.begin(), @@ -1624,14 +1623,14 @@ void EmitPopulateCompilationGraph (Record* CompilationGraph, for (unsigned i = 0; i < edges->size(); ++i) { Record* Edge = edges->getElementAsRecord(i); - Record* A = Edge->getValueAsDef("a"); - Record* B = Edge->getValueAsDef("b"); + const std::string& A = Edge->getValueAsString("a"); + const std::string& B = Edge->getValueAsString("b"); DagInit* Weight = Edge->getValueAsDag("weight"); - O << Indent1 << "G.insertEdge(\"" << A->getName() << "\", "; + O << Indent1 << "G.insertEdge(\"" << A << "\", "; if (isDagEmpty(Weight)) - O << "new SimpleEdge(\"" << B->getName() << "\")"; + O << "new SimpleEdge(\"" << B << "\")"; else O << "new Edge" << i << "()"; @@ -1763,6 +1762,7 @@ void LLVMCConfigurationEmitter::run (std::ostream &O) { EmitIncludes(O); // Get a list of all defined Tools. + RecordVector Tools = Records.getAllDerivedDefinitions("Tool"); if (Tools.empty()) throw std::string("No tool definitions found!"); @@ -1773,8 +1773,8 @@ void LLVMCConfigurationEmitter::run (std::ostream &O) { CollectToolProperties(Tools.begin(), Tools.end(), tool_props, opt_descs); RecordVector OptionLists = Records.getAllDerivedDefinitions("OptionList"); - CollectPropertiesFromOptionList(OptionLists.begin(), OptionLists.end(), - opt_descs); + CollectPropertiesFromOptionLists(OptionLists.begin(), OptionLists.end(), + opt_descs); // Check that there are no options without side effects (specified // only in the OptionList). @@ -1795,6 +1795,9 @@ void LLVMCConfigurationEmitter::run (std::ostream &O) { E = tool_props.end(); B!=E; ++B) EmitToolClassDefinition(*(*B), opt_descs, O); + // TOTHINK: Nothing actually prevents us from having multiple + // compilation graphs in a single plugin; OTOH, I do not see how + // that could be useful. Record* CompilationGraphRecord = Records.getDef("CompilationGraph"); if (!CompilationGraphRecord) throw std::string("Compilation graph description not found!");