Add a layer of indirection to make plugins more flexible.
authorMikhail Glushenkov <foldr@codedgers.com>
Mon, 17 Nov 2008 17:29:18 +0000 (17:29 +0000)
committerMikhail Glushenkov <foldr@codedgers.com>
Mon, 17 Nov 2008 17:29:18 +0000 (17:29 +0000)
Use strings instead of TableGen defs in the compilation graph
definition. Makes it easier for the plugins to modify an existing graph.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@59447 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/CompilerDriver/Common.td
tools/llvmc2/doc/LLVMC-Reference.rst
tools/llvmc2/doc/LLVMC-Tutorial.rst
tools/llvmc2/plugins/Base/Base.td
tools/llvmc2/plugins/Clang/Clang.td
tools/llvmc2/plugins/Simple/Simple.td
utils/TableGen/LLVMCConfigurationEmitter.cpp

index 45518385e412f273385cec7012981cc4d54afeaa..e017326069ee92778d491068d90c676cb4e9d6b3 100644 (file)
@@ -15,10 +15,6 @@ class Tool<list<dag> l> {
       list<dag> 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<list<LangToSuffixes> lst> {
 
 // Compilation graph
 
-class EdgeBase<Tool t1, Tool t2, dag d> {
-      Tool a = t1;
-      Tool b = t2;
+class EdgeBase<string t1, string t2, dag d> {
+      string a = t1;
+      string b = t2;
       dag weight = d;
 }
 
-class Edge<Tool t1, Tool t2> : EdgeBase<t1, t2, (empty)>;
+class Edge<string t1, string t2> : EdgeBase<t1, t2, (empty)>;
 
 // Edge and SimpleEdge are synonyms.
-class SimpleEdge<Tool t1, Tool t2> : EdgeBase<t1, t2, (empty)>;
+class SimpleEdge<string t1, string t2> : EdgeBase<t1, t2, (empty)>;
 
 // Optionally enabled edge.
-class OptionalEdge<Tool t1, Tool t2, dag props> : EdgeBase<t1, t2, props>;
+class OptionalEdge<string t1, string t2, dag props> : EdgeBase<t1, t2, props>;
 
 class CompilationGraph<list<EdgeBase> lst> {
       list<EdgeBase> edges = lst;
index 62e2ef41a8bc338ba22fc2a2b50dd28547d3413f..2d7825729873bd7e4e66972baa84401a677ecd7d 100644 (file)
@@ -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<root, llvm_gcc_c>,
-        Edge<root, llvm_gcc_assembler>,
+        Edge<"root", "llvm_gcc_c">,
+        Edge<"root", "llvm_gcc_assembler">,
         ...
 
-        Edge<llvm_gcc_c, llc>,
-        Edge<llvm_gcc_cpp, llc>,
+        Edge<"llvm_gcc_c", "llc">,
+        Edge<"llvm_gcc_cpp", "llc">,
         ...
 
-        OptionalEdge<llvm_gcc_c, opt, [(switch_on "opt")]>,
-        OptionalEdge<llvm_gcc_cpp, opt, [(switch_on "opt")]>,
+        OptionalEdge<"llvm_gcc_c", "opt", [(switch_on "opt")]>,
+        OptionalEdge<"llvm_gcc_cpp", "opt", [(switch_on "opt")]>,
         ...
 
-        OptionalEdge<llvm_gcc_assembler, llvm_gcc_cpp_linker,
+        OptionalEdge<"llvm_gcc_assembler", "llvm_gcc_cpp_linker",
             (case (input_languages_contain "c++"), (inc_weight),
                   (or (parameter_equals "linker", "g++"),
                       (parameter_equals "linker", "c++")), (inc_weight))>,
@@ -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
index ffc1de903b8b2f4b833c1bd5b00d5ca9371c83d0..9c6741eba1db4809f7f0fe56058f1bd2c1b42fa2 100644 (file)
@@ -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<root, gcc>]>;
+    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.
index 158520c278ef01b2d99c4b29ba281ab88437d86c..85a37cb41a7c0a5eb25082ff736562f82b0933c0 100644 (file)
@@ -17,42 +17,42 @@ include "llvm/CompilerDriver/Tools.td"
 // Toolchains
 
 def CompilationGraph : CompilationGraph<[
-    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<llvm_gcc_c, llc>,
-    Edge<llvm_gcc_cpp, llc>,
-    Edge<llvm_gcc_m, llc>,
-    Edge<llvm_gcc_mxx, llc>,
-    Edge<llvm_as, llc>,
-
-    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<llc, llvm_gcc_assembler>,
-    Edge<llvm_gcc_assembler, llvm_gcc_linker>,
-    OptionalEdge<llvm_gcc_assembler, llvm_gcc_cpp_linker,
+    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<"llvm_gcc_c", "llc">,
+    Edge<"llvm_gcc_cpp", "llc">,
+    Edge<"llvm_gcc_m", "llc">,
+    Edge<"llvm_gcc_mxx", "llc">,
+    Edge<"llvm_as", "llc">,
+
+    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<"llc", "llvm_gcc_assembler">,
+    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<root, llvm_gcc_linker>,
-    OptionalEdge<root, llvm_gcc_cpp_linker,
+    Edge<"root", "llvm_gcc_linker">,
+    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))>
index d30bc978aa8b1d351a639f9472f7538199ffbd03..ee6987fa352fca874081526a3ea18f6fb0007427 100644 (file)
@@ -76,11 +76,11 @@ def LanguageMap : LanguageMap<
 // Compilation graph
 
 def CompilationGraph : CompilationGraph<[
-    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>
+    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">
     ]>;
 
index 2bc40119261aacb5626ed147d74c454c5d14bc14..b974cbc95eb69fc0393a6a9fe11762b417e018a5 100644 (file)
@@ -27,4 +27,4 @@ def gcc : Tool<
 
 def LanguageMap : LanguageMap<[LangToSuffixes<"c", ["c"]>]>;
 
-def CompilationGraph : CompilationGraph<[Edge<root, gcc>]>;
+def CompilationGraph : CompilationGraph<[Edge<"root", "gcc">]>;
index bacde538daab713c41acc3efb263057c1a959f41..f5a1cf8652ca098d8cbbd145c745b928930314bb 100644 (file)
@@ -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)
 {
+  // Generate code
+  O << "namespace {\n\n";
+  O << "void PopulateLanguageMapLocal(LanguageMap& langMap) {\n";
+
   // 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!");
+  // It is allowed for a plugin to have no language map.
+  if (LangMapRecord) {
 
-  // Generate code
-  O << "namespace {\n\n";
-  O << "void PopulateLanguageMapLocal(LanguageMap& langMap) {\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);
+    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");
+      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";
+      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<StringSet<> > 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<std::string>::iterator IA = ToolToOutLang.find(A->getName());
-    StringMap<StringSet<> >::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<std::string>::iterator IA = ToolToOutLang.find(A);
+    StringMap<StringSet<> >::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!");