Add a generalised 'case' construct.

Besides assigning edge weights, it will also be used by the cmd_line tool property.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@51727 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/utils/TableGen/LLVMCConfigurationEmitter.cpp b/utils/TableGen/LLVMCConfigurationEmitter.cpp
index 8e4d870..1224244 100644
--- a/utils/TableGen/LLVMCConfigurationEmitter.cpp
+++ b/utils/TableGen/LLVMCConfigurationEmitter.cpp
@@ -68,15 +68,18 @@
   return val;
 }
 
-
 // checkNumberOfArguments - Ensure that the number of args in d is
-// less than or equal to min_arguments, otherwise throw an exception .
+// less than or equal to min_arguments, otherwise throw an exception.
 void checkNumberOfArguments (const DagInit* d, unsigned min_arguments) {
   if (d->getNumArgs() < min_arguments)
     throw "Property " + d->getOperator()->getAsString()
       + " has too few arguments!";
 }
 
+// isDagEmpty - is this DAG marked with an empty marker?
+bool isDagEmpty (const DagInit* d) {
+  return d->getOperator()->getAsString() == "empty";
+}
 
 //===----------------------------------------------------------------------===//
 /// Back-end specific code
@@ -974,21 +977,21 @@
   }
 }
 
-/// EmitEdgePropertyTest1Arg - Helper function used by
-/// EmitEdgePropertyTest.
-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));
-  if (PropName == "switch_on") {
+/// EmitCaseTest1Arg - Helper function used by
+/// EmitCaseConstructHandler.
+bool EmitCaseTest1Arg(const std::string& TestName,
+                      const DagInit& d,
+                      const GlobalOptionDescriptions& OptDescs,
+                      std::ostream& O) {
+  checkNumberOfArguments(&d, 1);
+  const std::string& OptName = InitPtrToString(d.getArg(0));
+  if (TestName == "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") {
+  } else if (TestName == "input_languages_contain") {
     O << "InLangs.count(\"" << OptName << "\") != 0";
     return true;
   }
@@ -996,31 +999,32 @@
   return false;
 }
 
-/// EmitEdgePropertyTest2Args - Helper function used by
-/// EmitEdgePropertyTest.
-bool EmitEdgePropertyTest2Args(const std::string& PropName,
-                               const DagInit& Prop,
-                               const GlobalOptionDescriptions& OptDescs,
-                               std::ostream& O) {
-  checkNumberOfArguments(&Prop, 2);
-  const std::string& OptName = InitPtrToString(Prop.getArg(0));
-  const std::string& OptArg = InitPtrToString(Prop.getArg(1));
+/// EmitCaseTest2Args - Helper function used by
+/// EmitCaseConstructHandler.
+bool EmitCaseTest2Args(const std::string& TestName,
+                       const DagInit& d,
+                       const char* IndentLevel,
+                       const GlobalOptionDescriptions& OptDescs,
+                       std::ostream& O) {
+  checkNumberOfArguments(&d, 2);
+  const std::string& OptName = InitPtrToString(d.getArg(0));
+  const std::string& OptArg = InitPtrToString(d.getArg(1));
   const GlobalOptionDescription& OptDesc = OptDescs.FindOption(OptName);
 
-  if (PropName == "parameter_equals") {
+  if (TestName == "parameter_equals") {
     if (OptDesc.Type != OptionType::Parameter
         && OptDesc.Type != OptionType::Prefix)
       throw OptName + ": incorrect option type!";
     O << OptDesc.GenVariableName() << " == \"" << OptArg << "\"";
     return true;
   }
-  else if (PropName == "element_in_list") {
+  else if (TestName == "element_in_list") {
     if (OptDesc.Type != OptionType::ParameterList
         && OptDesc.Type != OptionType::PrefixList)
       throw OptName + ": incorrect option type!";
     const std::string& VarName = OptDesc.GenVariableName();
     O << "std::find(" << VarName << ".begin(),\n"
-      << Indent3 << VarName << ".end(), \""
+      << IndentLevel << Indent1 << VarName << ".end(), \""
       << OptArg << "\") != " << VarName << ".end()";
     return true;
   }
@@ -1029,47 +1033,95 @@
 }
 
 // Forward declaration.
-void EmitEdgePropertyTest(const DagInit& Prop,
-                          const GlobalOptionDescriptions& OptDescs,
-                          std::ostream& O);
+// EmitLogicalOperationTest and EmitCaseTest are mutually recursive.
+void EmitCaseTest(const DagInit& d, const char* IndentLevel,
+                  const GlobalOptionDescriptions& OptDescs,
+                  std::ostream& O);
 
 /// EmitLogicalOperationTest - Helper function used by
-/// EmitEdgePropertyTest.
-void EmitLogicalOperationTest(const DagInit& Prop, const char* LogicOp,
+/// EmitCaseConstructHandler.
+void EmitLogicalOperationTest(const DagInit& d, const char* LogicOp,
+                              const char* IndentLevel,
                               const GlobalOptionDescriptions& OptDescs,
                               std::ostream& O) {
   O << '(';
-  for (unsigned j = 0, NumArgs = Prop.getNumArgs(); j < NumArgs; ++j) {
-    const DagInit& InnerProp = InitPtrToDagInitRef(Prop.getArg(j));
-    EmitEdgePropertyTest(InnerProp, OptDescs, O);
+  for (unsigned j = 0, NumArgs = d.getNumArgs(); j < NumArgs; ++j) {
+    const DagInit& InnerTest = InitPtrToDagInitRef(d.getArg(j));
+    EmitCaseTest(InnerTest, IndentLevel, OptDescs, O);
     if (j != NumArgs - 1)
-      O << ")\n" << Indent3 << ' ' << LogicOp << " (";
+      O << ")\n" << IndentLevel << Indent1 << ' ' << LogicOp << " (";
     else
       O << ')';
   }
 }
 
-/// EmitEdgePropertyTest - Helper function used by EmitEdgeClass.
-void EmitEdgePropertyTest(const DagInit& Prop,
-                          const GlobalOptionDescriptions& OptDescs,
-                          std::ostream& O) {
-  const std::string& PropName = Prop.getOperator()->getAsString();
+/// EmitCaseTest - Helper function used by EmitCaseConstructHandler.
+void EmitCaseTest(const DagInit& d, const char* IndentLevel,
+                  const GlobalOptionDescriptions& OptDescs,
+                  std::ostream& O) {
+  const std::string& TestName = d.getOperator()->getAsString();
 
-  if (PropName == "and")
-    EmitLogicalOperationTest(Prop, "&&", OptDescs, O);
-  else if (PropName == "or")
-    EmitLogicalOperationTest(Prop, "||", OptDescs, O);
-  else if (EmitEdgePropertyTest1Arg(PropName, Prop, OptDescs, O))
+  if (TestName == "and")
+    EmitLogicalOperationTest(d, "&&", IndentLevel, OptDescs, O);
+  else if (TestName == "or")
+    EmitLogicalOperationTest(d, "||", IndentLevel, OptDescs, O);
+  else if (EmitCaseTest1Arg(TestName, d, OptDescs, O))
     return;
-  else if (EmitEdgePropertyTest2Args(PropName, Prop, OptDescs, O))
+  else if (EmitCaseTest2Args(TestName, d, IndentLevel, OptDescs, O))
     return;
   else
-    throw PropName + ": unknown edge property!";
+    throw TestName + ": unknown edge property!";
+}
+
+// Emit code that handles the 'case' construct.
+// Takes a function object that should emit code for every case clause.
+template <typename F>
+void EmitCaseConstructHandler(DagInit* d, const char* IndentLevel,
+                              const F& Callback,
+                              const GlobalOptionDescriptions& OptDescs,
+                              std::ostream& O) {
+  assert(d->getOperator()->getAsString() == "case");
+
+  for (DagInit::arg_iterator B = d->arg_begin(), E = d->arg_end();
+       B != E; ++B) {
+    const DagInit& Test = InitPtrToDagInitRef(*B);
+    O << IndentLevel << "if (";
+    EmitCaseTest(Test, IndentLevel, OptDescs, O);
+    O << ") {\n";
+
+    ++B;
+    if (B == E)
+      throw "Case construct handler: no corresponding action "
+        "found for the test " + Test.getAsString() + '!';
+
+    const DagInit& Action = InitPtrToDagInitRef(*B);
+    Callback(IndentLevel, Action, O);
+    O << IndentLevel << "}\n";
+  }
+}
+
+// Helper function passed to EmitCaseConstructHandler by EmitEdgeClass.
+void IncDecWeight(const char* IndentLevel,
+                  const DagInit& d, std::ostream& O) {
+  const std::string& OpName = d.getOperator()->getAsString();
+
+  if (OpName == "inc_weight")
+    O << IndentLevel << Indent1 << "ret += ";
+  else if (OpName == "dec_weight")
+    O << IndentLevel << Indent1 << "ret -= ";
+  else
+    throw "Unknown operator in edge properties list: " + OpName + '!';
+
+  if (d.getNumArgs() > 0)
+    O << InitPtrToInt(d.getArg(0)) << ";\n";
+  else
+    O << "2;\n";
+
 }
 
 /// EmitEdgeClass - Emit a single Edge# class.
 void EmitEdgeClass(unsigned N, const std::string& Target,
-                   ListInit* Props, const GlobalOptionDescriptions& OptDescs,
+                   DagInit* Case, const GlobalOptionDescriptions& OptDescs,
                    std::ostream& O) {
 
   // Class constructor.
@@ -1082,26 +1134,8 @@
     << Indent1 << "unsigned Weight(const InputLanguagesSet& InLangs) const {\n"
     << Indent2 << "unsigned ret = 0;\n";
 
-  // Emit tests for every edge property.
-  for (size_t i = 0, PropsSize = Props->size(); i < PropsSize; ++i) {
-    const DagInit& Prop = InitPtrToDagInitRef(Props->getElement(i));
-    const std::string& PropName = Prop.getOperator()->getAsString();
-    unsigned N = 2;
-
-    O << Indent2 << "if (";
-
-    if (PropName == "weight") {
-      checkNumberOfArguments(&Prop, 2);
-      N = InitPtrToInt(Prop.getArg(0));
-      const DagInit& InnerProp = InitPtrToDagInitRef(Prop.getArg(1));
-      EmitEdgePropertyTest(InnerProp, OptDescs, O);
-    }
-    else {
-      EmitEdgePropertyTest(Prop, OptDescs, O);
-    }
-
-    O << ")\n" << Indent3 << "ret += " << N << ";\n";
-  }
+  // Handle the 'case' construct.
+  EmitCaseConstructHandler(Case, Indent2, IncDecWeight, OptDescs, O);
 
   O << Indent2 << "return ret;\n"
     << Indent1 << "};\n\n};\n\n";
@@ -1116,12 +1150,12 @@
   for (unsigned i = 0; i < edges->size(); ++i) {
     Record* Edge = edges->getElementAsRecord(i);
     Record* B = Edge->getValueAsDef("b");
-    ListInit* Props = Edge->getValueAsListInit("props");
+    DagInit* Weight = Edge->getValueAsDag("weight");
 
-    if (Props->empty())
+    if (isDagEmpty(Weight))
       continue;
 
-    EmitEdgeClass(i, B->getName(), Props, OptDescs, O);
+    EmitEdgeClass(i, B->getName(), Weight, OptDescs, O);
   }
 }
 
@@ -1156,11 +1190,11 @@
     Record* Edge = edges->getElementAsRecord(i);
     Record* A = Edge->getValueAsDef("a");
     Record* B = Edge->getValueAsDef("b");
-    ListInit* Props = Edge->getValueAsListInit("props");
+    DagInit* Weight = Edge->getValueAsDag("weight");
 
     O << Indent1 << "G.insertEdge(\"" << A->getName() << "\", ";
 
-    if (Props->empty())
+    if (isDagEmpty(Weight))
       O << "new SimpleEdge(\"" << B->getName() << "\")";
     else
       O << "new Edge" << i << "()";