Add support for option aliases.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@51749 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/utils/TableGen/LLVMCConfigurationEmitter.cpp b/utils/TableGen/LLVMCConfigurationEmitter.cpp
index 08f008e..f527def 100644
--- a/utils/TableGen/LLVMCConfigurationEmitter.cpp
+++ b/utils/TableGen/LLVMCConfigurationEmitter.cpp
@@ -93,7 +93,9 @@
 
 // A command-line option can have one of the following types:
 //
-// Switch - a simple switch w/o arguments, e.g. -O2
+// Alias - an alias for another option.
+//
+// Switch - a simple switch without arguments, e.g. -O2
 //
 // Parameter - an option that takes one(and only one) argument, e.g. -o file,
 // --output=file
@@ -105,10 +107,11 @@
 // e.g. -Wa,-foo,-bar, -DNAME=VALUE
 //
 // PrefixList - same as Prefix, but more than one option occurence is
-// allowed
+// allowed.
 
 namespace OptionType {
-  enum OptionType { Switch, Parameter, ParameterList, Prefix, PrefixList};
+  enum OptionType { Alias, Switch,
+                    Parameter, ParameterList, Prefix, PrefixList};
 }
 
 bool IsListOptionType (OptionType::OptionType t) {
@@ -133,6 +136,8 @@
 
   const char* GenTypeDeclaration() const {
     switch (Type) {
+    case OptionType::Alias:
+      return "cl::alias";
     case OptionType::PrefixList:
     case OptionType::ParameterList:
       return "cl::list<std::string>";
@@ -164,18 +169,20 @@
   std::string GenVariableName() const {
     const std::string& EscapedName = EscapeVariableName(Name);
     switch (Type) {
+    case OptionType::Alias:
+     return "AutoGeneratedAlias" + EscapedName;
     case OptionType::Switch:
-     return "AutoGeneratedSwitch" + EscapedName;
-   case OptionType::Prefix:
-     return "AutoGeneratedPrefix" + EscapedName;
-   case OptionType::PrefixList:
-     return "AutoGeneratedPrefixList" + EscapedName;
-   case OptionType::Parameter:
-     return "AutoGeneratedParameter" + EscapedName;
-   case OptionType::ParameterList:
-   default:
-     return "AutoGeneratedParameterList" + EscapedName;
-   }
+      return "AutoGeneratedSwitch" + EscapedName;
+    case OptionType::Prefix:
+      return "AutoGeneratedPrefix" + EscapedName;
+    case OptionType::PrefixList:
+      return "AutoGeneratedPrefixList" + EscapedName;
+    case OptionType::Parameter:
+      return "AutoGeneratedParameter" + EscapedName;
+    case OptionType::ParameterList:
+    default:
+      return "AutoGeneratedParameterList" + EscapedName;
+    }
   }
 
 };
@@ -195,8 +202,9 @@
   GlobalOptionDescription() : OptionDescription(), Flags(0)
   {}
 
-  GlobalOptionDescription (OptionType::OptionType t, const std::string& n)
-    : OptionDescription(t, n), Help(DefaultHelpString), Flags(0)
+  GlobalOptionDescription (OptionType::OptionType t, const std::string& n,
+                           const std::string& h = DefaultHelpString)
+    : OptionDescription(t, n), Help(h), Flags(0)
   {}
 
   bool isRequired() const {
@@ -399,6 +407,7 @@
         &CollectProperties::onPrefixList;
       propertyHandlers_["sink"] = &CollectProperties::onSink;
       propertyHandlers_["switch_option"] = &CollectProperties::onSwitch;
+      propertyHandlers_["alias_option"] = &CollectProperties::onAlias;
 
       // Init option property handlers
       optionPropertyHandlers_["append_cmd"] = &CollectProperties::onAppendCmd;
@@ -492,6 +501,15 @@
     toolProps_.setSink();
   }
 
+  void onAlias (const DagInit* d) {
+    checkNumberOfArguments(d, 2);
+    // We just need a GlobalOptionDescription for the aliases.
+    insertDescription
+      (GlobalOptionDescription(OptionType::Alias,
+                               InitPtrToString(d->getArg(0)),
+                               InitPtrToString(d->getArg(1))));
+  }
+
   void onSwitch (const DagInit* d) {
     addOption(d, OptionType::Switch);
   }
@@ -842,6 +860,9 @@
       << Indent4 << "vec.push_back(*B);\n"
       << Indent3 << "}\n";
     break;
+  case OptionType::Alias:
+  default:
+    throw std::string("Aliases are not allowed in tool option descriptions!");
   }
 }
 
@@ -1191,11 +1212,18 @@
 void EmitOptionDescriptions (const GlobalOptionDescriptions& descs,
                              std::ostream& O)
 {
+  std::vector<GlobalOptionDescription> Aliases;
+
   // Emit static cl::Option variables
   for (GlobalOptionDescriptions::const_iterator B = descs.begin(),
          E = descs.end(); B!=E; ++B) {
     const GlobalOptionDescription& val = B->second;
 
+    if (val.Type == OptionType::Alias) {
+      Aliases.push_back(val);
+      continue;
+    }
+
     O << val.GenTypeDeclaration() << ' '
       << val.GenVariableName()
       << "(\"" << val.Name << '\"';
@@ -1214,9 +1242,32 @@
       }
     }
 
-    O << ", cl::desc(\"" << val.Help << "\"));\n";
+    if (!val.Help.empty())
+      O << ", cl::desc(\"" << val.Help << "\")";
+
+    O << ");\n";
   }
 
+  // Emit the aliases (they should go after all the 'proper' options).
+  for (std::vector<GlobalOptionDescription>::const_iterator
+         B = Aliases.begin(), E = Aliases.end(); B != E; ++B) {
+    const GlobalOptionDescription& val = *B;
+
+    O << val.GenTypeDeclaration() << ' '
+      << val.GenVariableName()
+      << "(\"" << val.Name << '\"';
+
+    GlobalOptionDescriptions::container_type
+      ::const_iterator F = descs.Descriptions.find(val.Help);
+    if (F != descs.Descriptions.end())
+      O << ", cl::aliasopt(" << F->second.GenVariableName() << ")";
+    else
+      throw val.Name + ": alias to an unknown option!";
+
+    O << ", cl::desc(\"" << "An alias for -" + val.Help  << "\"));\n";
+  }
+
+  // Emit the sink option.
   if (descs.HasSink)
     O << "cl::list<std::string> " << SinkOptionName << "(cl::Sink);\n";