Make it possible to have multiple input languages for a single tool.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@51742 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/utils/TableGen/LLVMCConfigurationEmitter.cpp b/utils/TableGen/LLVMCConfigurationEmitter.cpp
index d3ad22c..68548d6 100644
--- a/utils/TableGen/LLVMCConfigurationEmitter.cpp
+++ b/utils/TableGen/LLVMCConfigurationEmitter.cpp
@@ -18,6 +18,7 @@
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringSet.h"
 #include "llvm/Support/Streams.h"
 
 #include <algorithm>
@@ -53,17 +54,22 @@
 //===----------------------------------------------------------------------===//
 /// Helper functions
 
-const std::string& InitPtrToString(const Init* ptr) {
-  const StringInit& val = dynamic_cast<const StringInit&>(*ptr);
-  return val.getValue();
-}
-
 int InitPtrToInt(const Init* ptr) {
   const IntInit& val = dynamic_cast<const IntInit&>(*ptr);
   return val.getValue();
 }
 
-const DagInit& InitPtrToDagInitRef(const Init* ptr) {
+const std::string& InitPtrToString(const Init* ptr) {
+  const StringInit& val = dynamic_cast<const StringInit&>(*ptr);
+  return val.getValue();
+}
+
+const ListInit& InitPtrToList(const Init* ptr) {
+  const ListInit& val = dynamic_cast<const ListInit&>(*ptr);
+  return val;
+}
+
+const DagInit& InitPtrToDag(const Init* ptr) {
   const DagInit& val = dynamic_cast<const DagInit&>(*ptr);
   return val;
 }
@@ -308,7 +314,7 @@
 struct ToolProperties : public RefCountedBase<ToolProperties> {
   std::string Name;
   Init* CmdLine;
-  std::string InLanguage;
+  StrVector InLanguage;
   std::string OutLanguage;
   std::string OutputSuffix;
   unsigned Flags;
@@ -412,7 +418,7 @@
   /// operator() - Gets called for every tool property; Just forwards
   /// to the corresponding property handler.
   void operator() (Init* i) {
-    const DagInit& d = InitPtrToDagInitRef(i);
+    const DagInit& d = InitPtrToDag(i);
     const std::string& property_name = d.getOperator()->getAsString();
     PropertyHandlerMap::iterator method
       = propertyHandlers_.find(property_name);
@@ -439,7 +445,29 @@
 
   void onInLanguage (const DagInit* d) {
     checkNumberOfArguments(d, 1);
-    toolProps_.InLanguage = InitPtrToString(d->getArg(0));
+    Init* arg = d->getArg(0);
+
+    // Find out the argument's type.
+    if (typeid(*arg) == typeid(StringInit)) {
+      // It's a string.
+      toolProps_.InLanguage.push_back(InitPtrToString(arg));
+    }
+    else {
+      // It's a list.
+      const ListInit& lst = InitPtrToList(arg);
+      StrVector& out = toolProps_.InLanguage;
+
+      // Copy strings to the output vector.
+      for (ListInit::const_iterator B = lst.begin(), E = lst.end();
+           B != E; ++B) {
+        out.push_back(InitPtrToString(*B));
+      }
+
+      // Remove duplicates.
+      std::sort(out.begin(), out.end());
+      StrVector::iterator newE = std::unique(out.begin(), out.end());
+      out.erase(newE, out.end());
+    }
   }
 
   void onJoin (const DagInit* d) {
@@ -573,7 +601,7 @@
 
     for (unsigned B = 1, E = d->getNumArgs(); B!=E; ++B) {
       const DagInit& option_property
-        = InitPtrToDagInitRef(d->getArg(B));
+        = InitPtrToDag(d->getArg(B));
       const std::string& option_property_name
         = option_property.getOperator()->getAsString();
       OptionPropertyHandlerMap::iterator method
@@ -691,7 +719,7 @@
                               std::ostream& O) {
   O << '(';
   for (unsigned j = 0, NumArgs = d.getNumArgs(); j < NumArgs; ++j) {
-    const DagInit& InnerTest = InitPtrToDagInitRef(d.getArg(j));
+    const DagInit& InnerTest = InitPtrToDag(d.getArg(j));
     EmitCaseTest(InnerTest, IndentLevel, OptDescs, O);
     if (j != NumArgs - 1)
       O << ")\n" << IndentLevel << Indent1 << ' ' << LogicOp << " (";
@@ -736,7 +764,7 @@
       + d->getAsString();
 
   for (unsigned i = 0; i != numArgs; ++i) {
-    const DagInit& Test = InitPtrToDagInitRef(d->getArg(i));
+    const DagInit& Test = InitPtrToDag(d->getArg(i));
 
     // Emit the test.
     if (Test.getOperator()->getAsString() == "default") {
@@ -996,7 +1024,7 @@
   if (typeid(*P.CmdLine) == typeid(StringInit))
     EmitCmdLineVecFill(P.CmdLine, P.Name, Version, Indent2, O);
   else
-    EmitCaseConstructHandler(&InitPtrToDagInitRef(P.CmdLine), Indent2,
+    EmitCaseConstructHandler(&InitPtrToDag(P.CmdLine), Indent2,
                              EmitCmdLineVecFillCallback(Version, P.Name),
                              true, OptDescs, O);
 
@@ -1061,8 +1089,15 @@
 /// EmitInOutLanguageMethods - Emit the [Input,Output]Language()
 /// methods for a given Tool class.
 void EmitInOutLanguageMethods (const ToolProperties& P, std::ostream& O) {
-  O << Indent1 << "const char* InputLanguage() const {\n"
-    << Indent2 << "return \"" << P.InLanguage << "\";\n"
+  O << Indent1 << "StrVector InputLanguages() const {\n"
+    << Indent2 << "StrVector ret;\n";
+
+  for (StrVector::const_iterator B = P.InLanguage.begin(),
+         E = P.InLanguage.end(); B != E; ++B) {
+    O << Indent2 << "ret.push_back(\"" << *B << "\");\n";
+  }
+
+  O << Indent2 << "return ret;\n"
     << Indent1 << "}\n\n";
 
   O << Indent1 << "const char* OutputLanguage() const {\n"
@@ -1207,41 +1242,47 @@
 /// FillInToolToLang - Fills in two tables that map tool names to
 /// (input, output) languages.  Used by the typechecker.
 void FillInToolToLang (const ToolPropertiesList& TPList,
-                       StringMap<std::string>& ToolToInLang,
+                       StringMap<StringSet<> >& ToolToInLang,
                        StringMap<std::string>& ToolToOutLang) {
   for (ToolPropertiesList::const_iterator B = TPList.begin(), E = TPList.end();
        B != E; ++B) {
     const ToolProperties& P = *(*B);
-    ToolToInLang[P.Name] = P.InLanguage;
+    for (StrVector::const_iterator B = P.InLanguage.begin(),
+           E = P.InLanguage.end(); B != E; ++B)
+      ToolToInLang[P.Name].insert(*B);
     ToolToOutLang[P.Name] = P.OutLanguage;
   }
 }
 
 /// TypecheckGraph - Check that names for output and input languages
 /// on all edges do match.
-// TOFIX: check for cycles.
-// TOFIX: check for multiple default edges.
+// 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
+// sofisticated. Algorithms like these should be run on a real graph
+// instead of AST.
 void TypecheckGraph (Record* CompilationGraph,
                      const ToolPropertiesList& TPList) {
-  StringMap<std::string> ToolToInLang;
+  StringMap<StringSet<> > ToolToInLang;
   StringMap<std::string> ToolToOutLang;
 
   FillInToolToLang(TPList, ToolToInLang, ToolToOutLang);
   ListInit* edges = CompilationGraph->getValueAsListInit("edges");
-  StringMap<std::string>::iterator IAE = ToolToInLang.end();
-  StringMap<std::string>::iterator IBE = ToolToOutLang.end();
+  StringMap<std::string>::iterator IAE = ToolToOutLang.end();
+  StringMap<StringSet<> >::iterator IBE = ToolToInLang.end();
 
   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<std::string>::iterator IB = ToolToInLang.find(B->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" && IA->second != IB->second)
+    if (A->getName() != "root" && IB->second.count(IA->second) == 0)
       throw "Edge " + A->getName() + "->" + B->getName()
         + ": output->input language mismatch";
     if (B->getName() == "root")
@@ -1253,7 +1294,7 @@
 /// by EmitEdgeClass().
 void IncDecWeight (const Init* i, const char* IndentLevel,
                    std::ostream& O) {
-  const DagInit& d = InitPtrToDagInitRef(i);
+  const DagInit& d = InitPtrToDag(i);
   const std::string& OpName = d.getOperator()->getAsString();
 
   if (OpName == "inc_weight")
@@ -1389,7 +1430,7 @@
     }
     else {
       // This is a 'case' construct.
-      const DagInit& d = InitPtrToDagInitRef(P.CmdLine);
+      const DagInit& d = InitPtrToDag(P.CmdLine);
       bool even = false;
       for (DagInit::const_arg_iterator B = d.arg_begin(), E = d.arg_end();
            B != E; ++B) {