[Lldb-commits] [clang] [lld] [lldb] [llvm] [Option] Emit the Info table from TableGen. NFC (PR #224508)

Fangrui Song via lldb-commits lldb-commits at lists.llvm.org
Thu Sep 17 21:21:32 PDT 2026


https://github.com/MaskRay created https://github.com/llvm/llvm-project/pull/224508

Each tool expands OPTION into an Info array and passes it with up to
five side tables to GenericOptTable or PrecomputedOptTable, so a new
side table touches every tool.

Emit the Info table from TableGen with numeric group and alias IDs and
bundle all tables into an OptTable::Tables aggregate under one
OPTTABLE_CODE block, so a tool just constructs OptTable(OptionTables).
Every table now uses the precomputed prefix union, which removes
GenericOptTable and PrecomputedOptTable.

Aided by Opus 5

>From dd89607d3fcdf6d6c8e3794bd50d3ed16d4c25b0 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Thu, 17 Sep 2026 10:50:23 -0700
Subject: [PATCH 1/2] [Option] Shrink Info from 60 to 40 bytes

Drop ID, which is the entry's 1-based position, and narrow
PrefixesOffset and SubCommandIDsOffset to 16 bits like GroupID and
AliasID.

Move help text variants to a side table. Only 5 clang options have one,
yet every entry carries a 12-byte std::array holding at most one. Store
each option's variants as a zero-terminated run of (visibility mask,
text offset) rows, reached by a 16-bit offset in the entry's padding.

clang's table shrinks from 232 KB to 155 KB and Options.inc from 1.70 MB
to 1.29 MB. --help output is unchanged.

Aided by Opus 5
---
 clang/lib/Options/DriverOptions.cpp         |  5 ++
 llvm/include/llvm/Option/OptTable.h         | 72 +++++++++-------
 llvm/include/llvm/Option/Option.h           | 31 ++-----
 llvm/lib/Option/OptTable.cpp                |  4 +-
 llvm/unittests/Option/OptionParsingTest.cpp | 23 +++++
 llvm/unittests/Option/Opts.td               |  5 ++
 llvm/utils/TableGen/OptionParserEmitter.cpp | 93 +++++++++------------
 7 files changed, 125 insertions(+), 108 deletions(-)

diff --git a/clang/lib/Options/DriverOptions.cpp b/clang/lib/Options/DriverOptions.cpp
index 6f630843f7019..832c46c4f3eef 100644
--- a/clang/lib/Options/DriverOptions.cpp
+++ b/clang/lib/Options/DriverOptions.cpp
@@ -29,6 +29,10 @@ using namespace llvm::opt;
 #include "clang/Options/Options.inc"
 #undef OPTTABLE_PREFIXES_UNION_CODE
 
+#define OPTTABLE_HELP_TEXT_VARIANTS_TABLE_CODE
+#include "clang/Options/Options.inc"
+#undef OPTTABLE_HELP_TEXT_VARIANTS_TABLE_CODE
+
 static constexpr OptTable::Info InfoTable[] = {
 #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
 #include "clang/Options/Options.inc"
@@ -43,6 +47,7 @@ class DriverOptTable : public PrecomputedOptTable {
       : PrecomputedOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,
                             OptionPrefixesUnion) {
     setValuesCodeFn(getOptionValuesCode);
+    setHelpTextVariantsTable(OptionHelpTextVariantsTable);
   }
 };
 } // anonymous namespace
diff --git a/llvm/include/llvm/Option/OptTable.h b/llvm/include/llvm/Option/OptTable.h
index ceb22c68ccb3b..a694e12ef7239 100644
--- a/llvm/include/llvm/Option/OptTable.h
+++ b/llvm/include/llvm/Option/OptTable.h
@@ -65,38 +65,38 @@ class LLVM_ABI OptTable {
   /// table supplies getOptionValuesCode() for this.
   using ValuesCodeFnTy = StringRef (*)(unsigned);
 
-  /// Entry for a single option instance in the option data table.
+  /// Help text that replaces Info::HelpTextOffset when the visibility mask
+  /// being printed intersects Visibility. An option's variants form a run
+  /// ended by a zero Visibility.
+  struct HelpTextVariant {
+    unsigned Visibility;
+    StringTable::Offset HelpTextOffset;
+  };
+
+  /// Entry for a single option instance in the option data table. An option's
+  /// ID is its 1-based position in the table.
   struct Info {
-    unsigned PrefixesOffset;
     StringTable::Offset PrefixedNameOffset;
     /// Offset 0 means the .td supplied no HelpText. A HelpText<""> maps to a
     /// distinct empty string, marking the option deliberately undocumented.
     StringTable::Offset HelpTextOffset;
-    // Help text for specific visibilities. A list of pairs, where each pair
-    // is a list of visibilities and a specific help string for those
-    // visibilities. If no help text is found in this list for the visibility of
-    // the program, HelpTextOffset is used instead. This cannot use std::vector
-    // because OptTable is used in constexpr contexts. Increase the array sizes
-    // here if you need more entries and adjust the constants in
-    // OptionParserEmitter::EmitHelpTextsForVariants.
-    std::array<std::pair<std::array<unsigned int, 2 /*MaxVisibilityPerHelp*/>,
-                         StringTable::Offset>,
-               1 /*MaxVisibilityHelp*/>
-        HelpTextsForVariants;
     StringTable::Offset MetaVarOffset;
-    unsigned ID;
-    unsigned char Kind;
-    unsigned char Param;
-    unsigned int Flags;
-    unsigned int Visibility;
-    unsigned short GroupID;
-    unsigned short AliasID;
     StringTable::Offset AliasArgsOffset;
     /// The possible values as a comma separated list, empty for an option whose
     /// values only getOptionValuesCode() knows.
     StringTable::Offset ValuesOffset;
+    unsigned Flags;
+    unsigned Visibility;
+    // Offset into OptTable's PrefixesTable.
+    unsigned short PrefixesOffset;
+    unsigned short GroupID;
+    unsigned short AliasID;
+    // Offset into OptTable's HelpTextVariantsTable; 0 for none.
+    unsigned short HelpTextVariantsOffset;
     // Offset into OptTable's SubCommandIDsTable.
-    unsigned SubCommandIDsOffset;
+    unsigned short SubCommandIDsOffset;
+    unsigned char Kind;
+    unsigned char Param;
 
     bool hasNoPrefix() const { return PrefixesOffset == 0; }
 
@@ -191,6 +191,8 @@ class LLVM_ABI OptTable {
   /// The subcommand IDs table.
   ArrayRef<unsigned> SubCommandIDsTable;
 
+  ArrayRef<HelpTextVariant> HelpTextVariantsTable;
+
   ValuesCodeFnTy ValuesCodeFn = nullptr;
 
   bool GroupedShortOptions = false;
@@ -221,17 +223,19 @@ class LLVM_ABI OptTable {
 
   StringTable::Offset getHelpTextOffset(const Info &I,
                                         Visibility VisibilityMask) const {
-    for (const auto &[Visibilities, TextOffset] : I.HelpTextsForVariants)
-      for (auto Vis : Visibilities)
-        if (VisibilityMask & Vis)
-          return TextOffset;
+    if (I.HelpTextVariantsOffset)
+      for (const HelpTextVariant *V =
+               &HelpTextVariantsTable[I.HelpTextVariantsOffset];
+           V->Visibility; ++V)
+        if (VisibilityMask & V->Visibility)
+          return V->HelpTextOffset;
     return I.HelpTextOffset;
   }
 
   StringRef getOptionValues(const Info &I) const {
     StringRef Values = (*StrTable)[I.ValuesOffset];
     if (Values.empty() && ValuesCodeFn)
-      Values = ValuesCodeFn(I.ID);
+      Values = ValuesCodeFn(getOptionID(I));
     return Values;
   }
 
@@ -249,6 +253,10 @@ class LLVM_ABI OptTable {
 
   void setValuesCodeFn(ValuesCodeFnTy Fn) { ValuesCodeFn = Fn; }
 
+  void setHelpTextVariantsTable(ArrayRef<HelpTextVariant> Table) {
+    HelpTextVariantsTable = Table;
+  }
+
   /// Build (or rebuild) the PrefixChars member.
   void buildPrefixChars();
 
@@ -268,6 +276,10 @@ class LLVM_ABI OptTable {
   /// Return the total number of option classes.
   unsigned getNumOptions() const { return OptionInfos.size(); }
 
+  unsigned getOptionID(const Info &I) const {
+    return &I - OptionInfos.data() + 1;
+  }
+
   /// Get the given Opt's Option instance, lazily creating it
   /// if necessary.
   ///
@@ -552,10 +564,10 @@ class PrecomputedOptTable : public OptTable {
     ALIASARGS, FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS,       \
     METAVAR, VALUES, SUBCOMMANDIDS_OFFSET)                                     \
   llvm::opt::OptTable::Info {                                                  \
-    PREFIXES_OFFSET, PREFIXED_NAME_OFFSET, HELPTEXT, HELPTEXTSFORVARIANTS,     \
-        METAVAR, ID_PREFIX##ID, llvm::opt::Option::KIND##Class, PARAM, FLAGS,  \
-        VISIBILITY, ID_PREFIX##GROUP, ID_PREFIX##ALIAS, ALIASARGS, VALUES,     \
-        SUBCOMMANDIDS_OFFSET                                                   \
+    PREFIXED_NAME_OFFSET, HELPTEXT, METAVAR, ALIASARGS, VALUES, FLAGS,         \
+        VISIBILITY, PREFIXES_OFFSET, ID_PREFIX##GROUP, ID_PREFIX##ALIAS,       \
+        HELPTEXTSFORVARIANTS, SUBCOMMANDIDS_OFFSET,                            \
+        llvm::opt::Option::KIND##Class, PARAM                                  \
   }
 
 #define LLVM_CONSTRUCT_OPT_INFO(                                               \
diff --git a/llvm/include/llvm/Option/Option.h b/llvm/include/llvm/Option/Option.h
index 68945c046b642..1233ca5a42228 100644
--- a/llvm/include/llvm/Option/Option.h
+++ b/llvm/include/llvm/Option/Option.h
@@ -90,7 +90,8 @@ class Option {
 
   unsigned getID() const {
     assert(Info && "Must have a valid info!");
-    return Info->ID;
+    assert(Owner && "Must have a valid owner!");
+    return Owner->getOptionID(*Info);
   }
 
   OptionClass getKind() const {
@@ -99,11 +100,7 @@ class Option {
   }
 
   /// Get the name of this option without any prefix.
-  StringRef getName() const {
-    assert(Info && "Must have a valid info!");
-    assert(Owner && "Must have a valid owner!");
-    return Owner->getOptionName(Info->ID);
-  }
+  StringRef getName() const { return Owner->getOptionName(getID()); }
 
   const Option getGroup() const {
     assert(Info && "Must have a valid info!");
@@ -131,32 +128,18 @@ class Option {
   }
 
   /// Get the default prefix for this option.
-  StringRef getPrefix() const {
-    assert(Info && "Must have a valid info!");
-    assert(Owner && "Must have a valid owner!");
-    return Owner->getOptionPrefix(Info->ID);
-  }
+  StringRef getPrefix() const { return Owner->getOptionPrefix(getID()); }
 
   /// Get the name of this option with the default prefix.
   StringRef getPrefixedName() const {
-    assert(Info && "Must have a valid info!");
-    assert(Owner && "Must have a valid owner!");
-    return Owner->getOptionPrefixedName(Info->ID);
+    return Owner->getOptionPrefixedName(getID());
   }
 
   /// Get the help text for this option.
-  StringRef getHelpText() const {
-    assert(Info && "Must have a valid info!");
-    assert(Owner && "Must have a valid owner!");
-    return Owner->getOptionHelpText(Info->ID);
-  }
+  StringRef getHelpText() const { return Owner->getOptionHelpText(getID()); }
 
   /// Get the meta-variable list for this option.
-  StringRef getMetaVar() const {
-    assert(Info && "Must have a valid info!");
-    assert(Owner && "Must have a valid owner!");
-    return Owner->getOptionMetaVar(Info->ID);
-  }
+  StringRef getMetaVar() const { return Owner->getOptionMetaVar(getID()); }
 
   unsigned getNumArgs() const { return Info->Param; }
 
diff --git a/llvm/lib/Option/OptTable.cpp b/llvm/lib/Option/OptTable.cpp
index ef3a4c694b6c2..15a01f8cf62c6 100644
--- a/llvm/lib/Option/OptTable.cpp
+++ b/llvm/lib/Option/OptTable.cpp
@@ -90,10 +90,10 @@ OptTable::OptTable(const StringTable &StrTable,
     unsigned Kind = getInfo(i + 1).Kind;
     if (Kind == Option::InputClass) {
       assert(!InputOptionID && "Cannot have multiple input options!");
-      InputOptionID = getInfo(i + 1).ID;
+      InputOptionID = i + 1;
     } else if (Kind == Option::UnknownClass) {
       assert(!UnknownOptionID && "Cannot have multiple unknown options!");
-      UnknownOptionID = getInfo(i + 1).ID;
+      UnknownOptionID = i + 1;
     } else if (Kind != Option::GroupClass) {
       FirstSearchableIndex = i;
       break;
diff --git a/llvm/unittests/Option/OptionParsingTest.cpp b/llvm/unittests/Option/OptionParsingTest.cpp
index f494ada47b57f..d63602d262a00 100644
--- a/llvm/unittests/Option/OptionParsingTest.cpp
+++ b/llvm/unittests/Option/OptionParsingTest.cpp
@@ -55,6 +55,10 @@ enum OptionVisibility {
   MultiLineVis = (1 << 3),
 };
 
+#define OPTTABLE_HELP_TEXT_VARIANTS_TABLE_CODE
+#include "Opts.inc"
+#undef OPTTABLE_HELP_TEXT_VARIANTS_TABLE_CODE
+
 static constexpr OptTable::Info InfoTable[] = {
 #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
 #include "Opts.inc"
@@ -68,6 +72,7 @@ class TestOptTable : public GenericOptTable {
       : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,
                         IgnoreCase) {
     setValuesCodeFn(getOptionValuesCode);
+    setHelpTextVariantsTable(OptionHelpTextVariantsTable);
   }
 };
 
@@ -77,6 +82,7 @@ class TestPrecomputedOptTable : public PrecomputedOptTable {
       : PrecomputedOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,
                             OptionPrefixesUnion, IgnoreCase) {
     setValuesCodeFn(getOptionValuesCode);
+    setHelpTextVariantsTable(OptionHelpTextVariantsTable);
   }
 };
 }
@@ -569,6 +575,23 @@ TYPED_TEST(OptTableTest, UnknownGroupedShortOptions) {
   EXPECT_EQ("-z", Unknown[3]);
 }
 
+TYPED_TEST(OptTableTest, HelpTextForVariants) {
+  TypeParam T;
+  EXPECT_EQ("The xyzzy2 option", T.getOptionHelpText(OPT_Xyzzy2));
+  EXPECT_EQ("The xyzzy2 option",
+            T.getOptionHelpText(OPT_Xyzzy2, Visibility(SubtoolVis)));
+  EXPECT_EQ("The xyzzy3 option", T.getOptionHelpText(OPT_Xyzzy3));
+  EXPECT_EQ("The xyzzy3 option",
+            T.getOptionHelpText(OPT_Xyzzy3, Visibility(DefaultVis)));
+  EXPECT_EQ("The xyzzy3 option for the subtool",
+            T.getOptionHelpText(OPT_Xyzzy3, Visibility(SubtoolVis)));
+  EXPECT_EQ(
+      "The xyzzy3 option for the subtool",
+      T.getOptionHelpText(OPT_Xyzzy3, Visibility(DefaultVis | SubtoolVis)));
+  EXPECT_EQ("The xyzzy3 option for multiline",
+            T.getOptionHelpText(OPT_Xyzzy3, Visibility(MultiLineVis)));
+}
+
 TYPED_TEST(OptTableTest, PrintMultilineHelpText) {
   TypeParam T;
   std::string Help;
diff --git a/llvm/unittests/Option/Opts.td b/llvm/unittests/Option/Opts.td
index 89c20359bd2a0..5cec8a9821701 100644
--- a/llvm/unittests/Option/Opts.td
+++ b/llvm/unittests/Option/Opts.td
@@ -46,6 +46,11 @@ def Doopf1 : Flag<["-"], "doopf1">, HelpText<"The doopf1 option">, Flags<[OptFla
 def Doopf2 : Flag<["-"], "doopf2">, HelpText<"The doopf2 option">, Flags<[OptFlag2]>;
 def Xyzzy1 : Flag<["-"], "xyzzy1">, HelpText<"The xyzzy1 option">, Visibility<[SubtoolVis]>;
 def Xyzzy2 : Flag<["-"], "xyzzy2">, HelpText<"The xyzzy2 option">, Visibility<[DefaultVis]>;
+def Xyzzy3 : Flag<["-"], "xyzzy3">, HelpText<"The xyzzy3 option"> {
+  let HelpTextsForVariants = [
+    HelpTextVariant<[SubtoolVis], "The xyzzy3 option for the subtool">,
+    HelpTextVariant<[MultiLineVis], "The xyzzy3 option for multiline">];
+}
 def Ermgh : Joined<["--"], "ermgh">, HelpText<"The ermgh option">, MetaVarName<"ERMGH">, Flags<[OptFlag1]>;
 def Fjormp : Flag<["--"], "fjormp">, HelpText<"The fjormp option">, Flags<[OptFlag1]>;
 
diff --git a/llvm/utils/TableGen/OptionParserEmitter.cpp b/llvm/utils/TableGen/OptionParserEmitter.cpp
index ebc5a1a8aa6cc..49b809cfb05f0 100644
--- a/llvm/utils/TableGen/OptionParserEmitter.cpp
+++ b/llvm/utils/TableGen/OptionParserEmitter.cpp
@@ -13,7 +13,6 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/Twine.h"
 #include "llvm/Option/OptTable.h"
-#include "llvm/Support/InterleavedRange.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/TableGen/Error.h"
 #include "llvm/TableGen/Record.h"
@@ -228,37 +227,6 @@ static MarshallingInfo createMarshallingInfo(const Record &R) {
   return Ret;
 }
 
-static void emitHelpTextsForVariants(
-    raw_ostream &OS, const StringToOffsetTable &Table,
-    ArrayRef<std::pair<std::vector<std::string>, StringRef>>
-        HelpTextsForVariants) {
-  // OptTable must be constexpr so it uses std::arrays with these capacities.
-  const unsigned MaxVisibilityPerHelp = 2;
-  const unsigned MaxVisibilityHelp = 1;
-
-  assert(HelpTextsForVariants.size() <= MaxVisibilityHelp &&
-         "Too many help text variants to store in "
-         "OptTable::HelpTextsForVariants");
-
-  OS << ", (std::array<std::pair<std::array<unsigned, " << MaxVisibilityPerHelp
-     << ">, llvm::StringTable::Offset>, " << MaxVisibilityHelp << ">{{ ";
-
-  ListSeparator Sep;
-  for (const auto &[Visibilities, Help] : HelpTextsForVariants) {
-    assert(Visibilities.size() <= MaxVisibilityPerHelp &&
-           "Too many visibilities to store in an "
-           "OptTable::HelpTextsForVariants entry");
-    OS << Sep << "{std::array<unsigned, " << MaxVisibilityPerHelp << ">{{"
-       << llvm::interleaved(Visibilities) << "}}, ";
-    writeStrTableOffset(OS, Table, Help);
-    OS << "}";
-  }
-  // Unused entries are value-initialized.
-  for (size_t I = HelpTextsForVariants.size(); I < MaxVisibilityHelp; ++I)
-    OS << Sep << "{}";
-  OS << " }})";
-}
-
 /// OptionParserEmitter - This tablegen backend takes an input .td file
 /// describing a list of options and emits a data structure for parsing and
 /// working with those options when given an input command line.
@@ -335,9 +303,8 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
     Table.GetOrAddStringOffset(getOptionalString(R, "MetaVarName"));
     Table.GetOrAddStringOffset(getOptionalString(R, "Values"));
     Table.GetOrAddStringOffset(getAliasArgsBlob(R));
-    for (const Record *VisibilityHelp :
-         R.getValueAsListOfDefs("HelpTextsForVariants"))
-      Table.GetOrAddStringOffset(VisibilityHelp->getValueAsString("Text"));
+    for (const Record *V : R.getValueAsListOfDefs("HelpTextsForVariants"))
+      Table.GetOrAddStringOffset(V->getValueAsString("Text"));
   }
 
   // Dump string table.
@@ -410,6 +377,41 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
   OS << "\n};\n";
   OS << "#endif // OPTTABLE_SUBCOMMAND_IDS_TABLE_CODE\n\n";
 
+  // Dump help text variants.
+  OS << "/////////\n";
+  OS << "// Help text variants\n\n";
+  OS << "#ifdef OPTTABLE_HELP_TEXT_VARIANTS_TABLE_CODE\n";
+  OS << "static constexpr llvm::opt::OptTable::HelpTextVariant "
+        "OptionHelpTextVariantsTable[] = {\n";
+  // Each option's variants form a run ended by a zero row; offset 0 is the
+  // empty run.
+  DenseMap<const Record *, unsigned> HelpTextVariantsOffset;
+  unsigned NumVariantRows = 1;
+  OS << "  {0, 0},\n";
+  for (const Record &R : llvm::make_pointee_range(Opts)) {
+    std::vector<const Record *> Variants =
+        R.getValueAsListOfDefs("HelpTextsForVariants");
+    if (Variants.empty())
+      continue;
+    HelpTextVariantsOffset[&R] = NumVariantRows;
+    NumVariantRows += Variants.size() + 1;
+    for (const Record *V : Variants) {
+      const ListInit *Vis = V->getValueAsListInit("Visibilities");
+      if (Vis->empty())
+        PrintFatalError(V->getLoc(), "HelpTextVariant needs a visibility");
+      OS << "  {";
+      ListSeparator Sep(" | ");
+      for (const Init *I : *Vis)
+        OS << Sep << I->getAsUnquotedString();
+      OS << ", ";
+      writeStrTableOffset(OS, Table, V->getValueAsString("Text"));
+      OS << "},\n";
+    }
+    OS << "  {0, 0},\n";
+  }
+  OS << "};\n";
+  OS << "#endif // OPTTABLE_HELP_TEXT_VARIANTS_TABLE_CODE\n\n";
+
   // Dump prefixes union.
   OS << "/////////\n";
   OS << "// Prefix Union\n\n";
@@ -487,8 +489,8 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
     OS << ", ";
     writeStrTableOffset(OS, Table, getHelpText(R));
 
-    // Not using Visibility specific text for group help.
-    emitHelpTextsForVariants(OS, Table, {});
+    // Groups have no help text variants.
+    OS << ", 0";
 
     // The option meta-variable name (unused).
     OS << ", 0";
@@ -580,21 +582,8 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
     OS << ", ";
     writeStrTableOffset(OS, Table, getHelpText(R));
 
-    std::vector<std::pair<std::vector<std::string>, StringRef>>
-        HelpTextsForVariants;
-    for (const Record *VisibilityHelp :
-         R.getValueAsListOfDefs("HelpTextsForVariants")) {
-      ArrayRef<const Init *> Visibilities =
-          VisibilityHelp->getValueAsListInit("Visibilities")->getElements();
-
-      std::vector<std::string> VisibilityNames;
-      for (const Init *Visibility : Visibilities)
-        VisibilityNames.push_back(Visibility->getAsUnquotedString());
-
-      HelpTextsForVariants.emplace_back(
-          VisibilityNames, VisibilityHelp->getValueAsString("Text"));
-    }
-    emitHelpTextsForVariants(OS, Table, HelpTextsForVariants);
+    // The option help text variants.
+    OS << ", " << HelpTextVariantsOffset.lookup(&R);
 
     // The option meta-variable name.
     OS << ", ";

>From 66b82d397064e703809f2e7e2191dd03c5fe9968 Mon Sep 17 00:00:00 2001
From: Fangrui Song <i at maskray.me>
Date: Thu, 17 Sep 2026 20:56:59 -0700
Subject: [PATCH 2/2] [Option] Emit the Info table from TableGen. NFC

Each tool expands OPTION into an Info array and passes it with up to
five side tables to GenericOptTable or PrecomputedOptTable, so a new
side table touches every tool.

Emit the Info table from TableGen with numeric group and alias IDs and
bundle all tables into an OptTable::Tables aggregate under one
OPTTABLE_CODE block, so a tool just constructs OptTable(OptionTables).
Every table now uses the precomputed prefix union, which removes
GenericOptTable and PrecomputedOptTable.

Aided by Opus 5
---
 clang/lib/Options/DriverOptions.cpp           |  29 +--
 clang/tools/clang-installapi/Options.cpp      |  25 +-
 .../ClangLinkerWrapper.cpp                    |  19 +-
 .../ClangNVLinkWrapper.cpp                    |  19 +-
 clang/tools/clang-scan-deps/ClangScanDeps.cpp |  21 +-
 .../clang-sycl-linker/ClangSYCLLinker.cpp     |  19 +-
 lld/COFF/Driver.h                             |   2 +-
 lld/COFF/DriverUtils.cpp                      |  19 +-
 lld/ELF/Driver.h                              |   2 +-
 lld/ELF/DriverUtils.cpp                       |  19 +-
 lld/MachO/Driver.h                            |   2 +-
 lld/MachO/DriverUtils.cpp                     |  19 +-
 lld/MinGW/Driver.cpp                          |  21 +-
 lld/wasm/Driver.cpp                           |  20 +-
 lldb/tools/driver/Driver.cpp                  |  19 +-
 lldb/tools/lldb-dap/tool/lldb-dap.cpp         |  20 +-
 lldb/tools/lldb-server/lldb-gdbserver.cpp     |  19 +-
 lldb/tools/lldb-server/lldb-platform.cpp      |  19 +-
 .../examples/OptSubcommand/llvm-hello-sub.cpp |  29 +--
 llvm/include/llvm/Option/OptTable.h           |  75 +-----
 .../JITLink/COFFDirectiveParser.cpp           |  25 +-
 llvm/lib/Option/OptTable.cpp                  |  52 +---
 .../llvm-dlltool/DlltoolDriver.cpp            |  20 +-
 llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp   |  20 +-
 llvm/tools/dsymutil/dsymutil.cpp              |  19 +-
 llvm/tools/llvm-cas/llvm-cas.cpp              |  19 +-
 llvm/tools/llvm-cgdata/llvm-cgdata.cpp        |  19 +-
 llvm/tools/llvm-cvtres/llvm-cvtres.cpp        |  20 +-
 llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp      |  19 +-
 .../llvm-debuginfod-find.cpp                  |  19 +-
 .../tools/llvm-debuginfod/llvm-debuginfod.cpp |  19 +-
 llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp  |  19 +-
 llvm/tools/llvm-dwp/llvm-dwp.cpp              |  19 +-
 llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp    |  21 +-
 llvm/tools/llvm-ifs/llvm-ifs.cpp              |  21 +-
 .../llvm-libtool-darwin.cpp                   |  19 +-
 llvm/tools/llvm-lipo/llvm-lipo.cpp            |  20 +-
 llvm/tools/llvm-ml/llvm-ml.cpp                |  20 +-
 llvm/tools/llvm-mt/llvm-mt.cpp                |  20 +-
 llvm/tools/llvm-nm/llvm-nm.cpp                |  21 +-
 llvm/tools/llvm-objcopy/ObjcopyOptions.cpp    | 108 ++------
 llvm/tools/llvm-objdump/llvm-objdump.cpp      |  53 +---
 llvm/tools/llvm-rc/llvm-rc.cpp                |  43 +--
 llvm/tools/llvm-readobj/llvm-readobj.cpp      |  19 +-
 llvm/tools/llvm-readtapi/llvm-readtapi.cpp    |  21 +-
 llvm/tools/llvm-size/llvm-size.cpp            |  21 +-
 llvm/tools/llvm-strings/llvm-strings.cpp      |  19 +-
 .../tools/llvm-symbolizer/llvm-symbolizer.cpp |  19 +-
 .../llvm-tli-checker/llvm-tli-checker.cpp     |  19 +-
 llvm/tools/sancov/sancov.cpp                  |  19 +-
 llvm/unittests/Option/OptionParsingTest.cpp   | 155 ++++-------
 .../Option/OptionSubCommandsTest.cpp          |  28 +-
 llvm/utils/TableGen/OptionParserEmitter.cpp   | 244 ++++++++++--------
 53 files changed, 429 insertions(+), 1187 deletions(-)

diff --git a/clang/lib/Options/DriverOptions.cpp b/clang/lib/Options/DriverOptions.cpp
index 832c46c4f3eef..2f73b307dbdea 100644
--- a/clang/lib/Options/DriverOptions.cpp
+++ b/clang/lib/Options/DriverOptions.cpp
@@ -13,41 +13,20 @@
 using namespace clang::options;
 using namespace llvm::opt;
 
-#define OPTTABLE_STR_TABLE_CODE
-#include "clang/Options/Options.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
 #define OPTTABLE_VALUES_CODE
 #include "clang/Options/Options.inc"
 #undef OPTTABLE_VALUES_CODE
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
+#define OPTTABLE_CODE
 #include "clang/Options/Options.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_UNION_CODE
-#include "clang/Options/Options.inc"
-#undef OPTTABLE_PREFIXES_UNION_CODE
-
-#define OPTTABLE_HELP_TEXT_VARIANTS_TABLE_CODE
-#include "clang/Options/Options.inc"
-#undef OPTTABLE_HELP_TEXT_VARIANTS_TABLE_CODE
-
-static constexpr OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "clang/Options/Options.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
 namespace {
 
-class DriverOptTable : public PrecomputedOptTable {
+class DriverOptTable : public OptTable {
 public:
-  DriverOptTable()
-      : PrecomputedOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,
-                            OptionPrefixesUnion) {
+  DriverOptTable() : OptTable(OptionTables) {
     setValuesCodeFn(getOptionValuesCode);
-    setHelpTextVariantsTable(OptionHelpTextVariantsTable);
   }
 };
 } // anonymous namespace
diff --git a/clang/tools/clang-installapi/Options.cpp b/clang/tools/clang-installapi/Options.cpp
index f0ad4501a4593..99b495ad7eebb 100644
--- a/clang/tools/clang-installapi/Options.cpp
+++ b/clang/tools/clang-installapi/Options.cpp
@@ -30,33 +30,16 @@ using namespace llvm::MachO;
 namespace clang {
 namespace installapi {
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "InstallAPIOpts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "InstallAPIOpts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_UNION_CODE
-#include "InstallAPIOpts.inc"
-#undef OPTTABLE_PREFIXES_UNION_CODE
-
-/// Create table mapping all options defined in InstallAPIOpts.td.
-static constexpr OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "InstallAPIOpts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
 namespace {
 
 /// \brief Create OptTable class for parsing actual command line arguments.
-class DriverOptTable : public opt::PrecomputedOptTable {
+class DriverOptTable : public opt::OptTable {
 public:
-  DriverOptTable()
-      : PrecomputedOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,
-                            OptionPrefixesUnion) {}
+  DriverOptTable() : OptTable(OptionTables) {}
 };
 
 } // end anonymous namespace.
diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
index 59faf38dda140..366cedcebddfa 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -174,24 +174,13 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "LinkerWrapperOpts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "LinkerWrapperOpts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "LinkerWrapperOpts.inc"
-#undef OPTION
-};
-
-class WrapperOptTable : public opt::GenericOptTable {
+class WrapperOptTable : public opt::OptTable {
 public:
-  WrapperOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}
+  WrapperOptTable() : opt::OptTable(OptionTables) {}
 };
 
 const OptTable &getOptTable() {
diff --git a/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp b/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp
index 4e06d1c149bb6..61b5eb56eaa2f 100644
--- a/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp
+++ b/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp
@@ -111,24 +111,13 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "NVLinkOpts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "NVLinkOpts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "NVLinkOpts.inc"
-#undef OPTION
-};
-
-class WrapperOptTable : public opt::GenericOptTable {
+class WrapperOptTable : public opt::OptTable {
 public:
-  WrapperOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}
+  WrapperOptTable() : opt::OptTable(OptionTables) {}
 };
 
 const OptTable &getOptTable() {
diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index 83b4860c130c3..ac3c329707d0a 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -54,26 +54,13 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-const llvm::opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "Opts.inc"
-#undef OPTION
-};
-
-class ScanDepsOptTable : public llvm::opt::GenericOptTable {
+class ScanDepsOptTable : public llvm::opt::OptTable {
 public:
-  ScanDepsOptTable()
-      : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {
-    setGroupedShortOptions(true);
-  }
+  ScanDepsOptTable() : OptTable(OptionTables) { setGroupedShortOptions(true); }
 };
 
 enum ResourceDirRecipeKind {
diff --git a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
index 70afc6d6c4cea..f8c07b6eb9edd 100644
--- a/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
+++ b/clang/tools/clang-sycl-linker/ClangSYCLLinker.cpp
@@ -98,24 +98,13 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "SYCLLinkOpts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "SYCLLinkOpts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-constexpr OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "SYCLLinkOpts.inc"
-#undef OPTION
-};
-
-class LinkerOptTable : public opt::GenericOptTable {
+class LinkerOptTable : public opt::OptTable {
 public:
-  LinkerOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}
+  LinkerOptTable() : opt::OptTable(OptionTables) {}
 };
 } // namespace
 
diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h
index 7eea9aee279a1..9f4f181379d2b 100644
--- a/lld/COFF/Driver.h
+++ b/lld/COFF/Driver.h
@@ -33,7 +33,7 @@ using llvm::COFF::MachineTypes;
 using llvm::COFF::WindowsSubsystem;
 using std::optional;
 
-class COFFOptTable : public llvm::opt::GenericOptTable {
+class COFFOptTable : public llvm::opt::OptTable {
 public:
   COFFOptTable();
 };
diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp
index 3b69a6d9b3d14..2fb126a68f383 100644
--- a/lld/COFF/DriverUtils.cpp
+++ b/lld/COFF/DriverUtils.cpp
@@ -748,24 +748,11 @@ MemoryBufferRef LinkerDriver::convertResToCOFF(ArrayRef<MemoryBufferRef> mbs,
 
 // Create OptTable
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "Options.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-// Create prefix string literals used in Options.td
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Options.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-// Create table mapping all options defined in Options.td
-static constexpr llvm::opt::OptTable::Info infoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "Options.inc"
-#undef OPTION
-};
-
-COFFOptTable::COFFOptTable()
-    : GenericOptTable(OptionStrTable, OptionPrefixesTable, infoTable, true) {}
+COFFOptTable::COFFOptTable() : OptTable(OptionTables, true) {}
 
 // Set color diagnostics according to --color-diagnostics={auto,always,never}
 // or --no-color-diagnostics flags.
diff --git a/lld/ELF/Driver.h b/lld/ELF/Driver.h
index b5d41633141e2..473b5eca77c52 100644
--- a/lld/ELF/Driver.h
+++ b/lld/ELF/Driver.h
@@ -18,7 +18,7 @@ namespace lld::elf {
 struct Ctx;
 
 // Parses command line options.
-class ELFOptTable : public llvm::opt::GenericOptTable {
+class ELFOptTable : public llvm::opt::OptTable {
 public:
   ELFOptTable();
   llvm::opt::InputArgList parse(Ctx &, ArrayRef<const char *> argv);
diff --git a/lld/ELF/DriverUtils.cpp b/lld/ELF/DriverUtils.cpp
index 6d027c529c19e..03e568ac46acd 100644
--- a/lld/ELF/DriverUtils.cpp
+++ b/lld/ELF/DriverUtils.cpp
@@ -33,24 +33,11 @@ using namespace lld::elf;
 
 // Create OptTable
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "Options.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-// Create prefix string literals used in Options.td
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Options.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-// Create table mapping all options defined in Options.td
-static constexpr opt::OptTable::Info optInfo[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "Options.inc"
-#undef OPTION
-};
-
-ELFOptTable::ELFOptTable()
-    : GenericOptTable(OptionStrTable, OptionPrefixesTable, optInfo) {}
+ELFOptTable::ELFOptTable() : OptTable(OptionTables) {}
 
 // Set color diagnostics according to --color-diagnostics={auto,always,never}
 // or --no-color-diagnostics flags.
diff --git a/lld/MachO/Driver.h b/lld/MachO/Driver.h
index 9374dffffd8bd..8af7afdf45a93 100644
--- a/lld/MachO/Driver.h
+++ b/lld/MachO/Driver.h
@@ -29,7 +29,7 @@ namespace lld::macho {
 class DylibFile;
 class InputFile;
 
-class MachOOptTable : public llvm::opt::GenericOptTable {
+class MachOOptTable : public llvm::opt::OptTable {
 public:
   MachOOptTable();
   llvm::opt::InputArgList parse(CommonLinkerContext &ctx,
diff --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp
index 46ad681ffaa5d..e9b59dd71263d 100644
--- a/lld/MachO/DriverUtils.cpp
+++ b/lld/MachO/DriverUtils.cpp
@@ -32,24 +32,11 @@ using namespace llvm::sys;
 using namespace lld;
 using namespace lld::macho;
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "Options.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-// Create prefix string literals used in Options.td
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Options.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-// Create table mapping all options defined in Options.td
-static constexpr OptTable::Info optInfo[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "Options.inc"
-#undef OPTION
-};
-
-MachOOptTable::MachOOptTable()
-    : GenericOptTable(OptionStrTable, OptionPrefixesTable, optInfo) {}
+MachOOptTable::MachOOptTable() : OptTable(OptionTables) {}
 
 // Set color diagnostics according to --color-diagnostics={auto,always,never}
 // or --no-color-diagnostics flags.
diff --git a/lld/MinGW/Driver.cpp b/lld/MinGW/Driver.cpp
index 11ccb110f7684..3f4ac149eb341 100644
--- a/lld/MinGW/Driver.cpp
+++ b/lld/MinGW/Driver.cpp
@@ -58,27 +58,14 @@ enum {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "Options.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Options.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-// Create table mapping all options defined in Options.td
-static constexpr opt::OptTable::Info infoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "Options.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
 namespace {
-class MinGWOptTable : public opt::GenericOptTable {
+class MinGWOptTable : public opt::OptTable {
 public:
-  MinGWOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, infoTable,
-                             false) {}
+  MinGWOptTable() : opt::OptTable(OptionTables, false) {}
   opt::InputArgList parse(ArrayRef<const char *> argv);
 };
 } // namespace
diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
index e6b3bcc2d438a..380df3f7824dc 100644
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -145,26 +145,14 @@ bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
   return errorCount() == 0;
 }
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "Options.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Options.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-// Create table mapping all options defined in Options.td
-static constexpr opt::OptTable::Info optInfo[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "Options.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
 namespace {
-class WasmOptTable : public opt::GenericOptTable {
+class WasmOptTable : public opt::OptTable {
 public:
-  WasmOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, optInfo) {}
+  WasmOptTable() : opt::OptTable(OptionTables) {}
   opt::InputArgList parse(ArrayRef<const char *> argv);
 };
 } // namespace
diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp
index a66552e0428bf..0ffe296eb274a 100644
--- a/lldb/tools/driver/Driver.cpp
+++ b/lldb/tools/driver/Driver.cpp
@@ -79,24 +79,13 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "Options.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Options.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "Options.inc"
-#undef OPTION
-};
-
-class LLDBOptTable : public opt::GenericOptTable {
+class LLDBOptTable : public opt::OptTable {
 public:
-  LLDBOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}
+  LLDBOptTable() : opt::OptTable(OptionTables) {}
 };
 } // namespace
 
diff --git a/lldb/tools/lldb-dap/tool/lldb-dap.cpp b/lldb/tools/lldb-dap/tool/lldb-dap.cpp
index 0882e593dc330..370a029dbb221 100644
--- a/lldb/tools/lldb-dap/tool/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/tool/lldb-dap.cpp
@@ -110,24 +110,12 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "Options.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Options.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr llvm::opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "Options.inc"
-#undef OPTION
-};
-class LLDBDAPOptTable : public llvm::opt::GenericOptTable {
+#undef OPTTABLE_CODE
+class LLDBDAPOptTable : public llvm::opt::OptTable {
 public:
-  LLDBDAPOptTable()
-      : llvm::opt::GenericOptTable(OptionStrTable, OptionPrefixesTable,
-                                   InfoTable, true) {}
+  LLDBDAPOptTable() : llvm::opt::OptTable(OptionTables, true) {}
 };
 } // anonymous namespace
 
diff --git a/lldb/tools/lldb-server/lldb-gdbserver.cpp b/lldb/tools/lldb-server/lldb-gdbserver.cpp
index 91e0379f05585..ecf8ab10045f0 100644
--- a/lldb/tools/lldb-server/lldb-gdbserver.cpp
+++ b/lldb/tools/lldb-server/lldb-gdbserver.cpp
@@ -302,24 +302,13 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "LLGSOptions.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "LLGSOptions.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "LLGSOptions.inc"
-#undef OPTION
-};
-
-class LLGSOptTable : public opt::GenericOptTable {
+class LLGSOptTable : public opt::OptTable {
 public:
-  LLGSOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}
+  LLGSOptTable() : opt::OptTable(OptionTables) {}
 
   void PrintHelp(llvm::StringRef Name) {
     std::string Usage =
diff --git a/lldb/tools/lldb-server/lldb-platform.cpp b/lldb/tools/lldb-server/lldb-platform.cpp
index 1b13ca65b8318..2f44c306c6f3b 100644
--- a/lldb/tools/lldb-server/lldb-platform.cpp
+++ b/lldb/tools/lldb-server/lldb-platform.cpp
@@ -68,24 +68,13 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "PlatformOptions.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "PlatformOptions.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "PlatformOptions.inc"
-#undef OPTION
-};
-
-class PlatformOptTable : public opt::GenericOptTable {
+class PlatformOptTable : public opt::OptTable {
 public:
-  PlatformOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}
+  PlatformOptTable() : opt::OptTable(OptionTables) {}
 
   void PrintHelp(llvm::StringRef Name) {
     std::string Usage =
diff --git a/llvm/examples/OptSubcommand/llvm-hello-sub.cpp b/llvm/examples/OptSubcommand/llvm-hello-sub.cpp
index bcf433f2179c3..1777f30ed4174 100644
--- a/llvm/examples/OptSubcommand/llvm-hello-sub.cpp
+++ b/llvm/examples/OptSubcommand/llvm-hello-sub.cpp
@@ -19,34 +19,13 @@ enum ID {
 #include "Opts.inc"
 #undef OPTION
 };
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-#define OPTTABLE_SUBCOMMAND_IDS_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_SUBCOMMAND_IDS_TABLE_CODE
-
-#define OPTTABLE_SUBCOMMANDS_CODE
-#include "Opts.inc"
-#undef OPTTABLE_SUBCOMMANDS_CODE
-
-static constexpr OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "Opts.inc"
-#undef OPTION
-};
-
-class HelloSubOptTable : public GenericOptTable {
+class HelloSubOptTable : public OptTable {
 public:
-  HelloSubOptTable()
-      : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,
-                        /*IgnoreCase=*/false, OptionSubCommands,
-                        OptionSubCommandIDsTable) {};
+  HelloSubOptTable() : OptTable(OptionTables) {};
 };
 } // namespace
 
diff --git a/llvm/include/llvm/Option/OptTable.h b/llvm/include/llvm/Option/OptTable.h
index a694e12ef7239..1532f18b105bd 100644
--- a/llvm/include/llvm/Option/OptTable.h
+++ b/llvm/include/llvm/Option/OptTable.h
@@ -155,6 +155,17 @@ class LLVM_ABI OptTable {
     }
   };
 
+  /// The tables TableGen emits for an option set under OPTTABLE_CODE.
+  struct Tables {
+    const StringTable &StrTable;
+    ArrayRef<StringTable::Offset> PrefixesTable;
+    ArrayRef<StringTable::Offset> PrefixesUnion;
+    ArrayRef<Info> Infos;
+    ArrayRef<HelpTextVariant> HelpTextVariants;
+    ArrayRef<SubCommand> SubCommands;
+    ArrayRef<unsigned> SubCommandIDs;
+  };
+
 public:
   bool isValidForSubCommand(const Info *CandidateInfo,
                             StringRef SubCommand) const {
@@ -202,7 +213,6 @@ class LLVM_ABI OptTable {
   unsigned InputOptionID = 0;
   unsigned UnknownOptionID = 0;
 
-protected:
   /// The index of the first option which can be parsed (i.e., is not a
   /// special option like 'input' or 'unknown', and is not an option group).
   unsigned FirstSearchableIndex = 0;
@@ -214,7 +224,6 @@ class LLVM_ABI OptTable {
   /// The union of the first element of all option prefixes.
   SmallString<8> PrefixChars;
 
-private:
   const Info &getInfo(OptSpecifier Opt) const {
     unsigned id = Opt.getID();
     assert(id > 0 && id - 1 < getNumOptions() && "Invalid Option ID.");
@@ -243,23 +252,10 @@ class LLVM_ABI OptTable {
                                           unsigned &Index) const;
 
 protected:
-  /// Initialize OptTable using Tablegen'ed OptionInfos. Child class must
-  /// manually call \c buildPrefixChars once they are fully constructed.
-  OptTable(const StringTable &StrTable,
-           ArrayRef<StringTable::Offset> PrefixesTable,
-           ArrayRef<Info> OptionInfos, bool IgnoreCase = false,
-           ArrayRef<SubCommand> SubCommands = {},
-           ArrayRef<unsigned> SubCommandIDsTable = {});
+  OptTable(const Tables &Tables, bool IgnoreCase = false);
 
   void setValuesCodeFn(ValuesCodeFnTy Fn) { ValuesCodeFn = Fn; }
 
-  void setHelpTextVariantsTable(ArrayRef<HelpTextVariant> Table) {
-    HelpTextVariantsTable = Table;
-  }
-
-  /// Build (or rebuild) the PrefixChars member.
-  void buildPrefixChars();
-
 public:
   virtual ~OptTable();
 
@@ -513,33 +509,6 @@ class LLVM_ABI OptTable {
                          Visibility VisibilityMask) const;
 };
 
-/// Specialization of OptTable
-class GenericOptTable : public OptTable {
-protected:
-  LLVM_ABI GenericOptTable(const StringTable &StrTable,
-                           ArrayRef<StringTable::Offset> PrefixesTable,
-                           ArrayRef<Info> OptionInfos, bool IgnoreCase = false,
-                           ArrayRef<SubCommand> SubCommands = {},
-                           ArrayRef<unsigned> SubCommandIDsTable = {});
-};
-
-class PrecomputedOptTable : public OptTable {
-protected:
-  PrecomputedOptTable(const StringTable &StrTable,
-                      ArrayRef<StringTable::Offset> PrefixesTable,
-                      ArrayRef<Info> OptionInfos,
-                      ArrayRef<StringTable::Offset> PrefixesUnionOffsets,
-                      bool IgnoreCase = false,
-                      ArrayRef<SubCommand> SubCommands = {},
-                      ArrayRef<unsigned> SubCommandIDsTable = {})
-      : OptTable(StrTable, PrefixesTable, OptionInfos, IgnoreCase, SubCommands,
-                 SubCommandIDsTable) {
-    for (auto PrefixOffset : PrefixesUnionOffsets)
-      PrefixesUnion.push_back(StrTable[PrefixOffset]);
-    buildPrefixChars();
-  }
-};
-
 } // end namespace opt
 
 } // end namespace llvm
@@ -559,24 +528,4 @@ class PrecomputedOptTable : public OptTable {
       ALIASARGS, FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS,     \
       METAVAR, VALUES, SUBCOMMANDIDS_OFFSET)
 
-#define LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(                                \
-    ID_PREFIX, PREFIXES_OFFSET, PREFIXED_NAME_OFFSET, ID, KIND, GROUP, ALIAS,  \
-    ALIASARGS, FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS,       \
-    METAVAR, VALUES, SUBCOMMANDIDS_OFFSET)                                     \
-  llvm::opt::OptTable::Info {                                                  \
-    PREFIXED_NAME_OFFSET, HELPTEXT, METAVAR, ALIASARGS, VALUES, FLAGS,         \
-        VISIBILITY, PREFIXES_OFFSET, ID_PREFIX##GROUP, ID_PREFIX##ALIAS,       \
-        HELPTEXTSFORVARIANTS, SUBCOMMANDIDS_OFFSET,                            \
-        llvm::opt::Option::KIND##Class, PARAM                                  \
-  }
-
-#define LLVM_CONSTRUCT_OPT_INFO(                                               \
-    PREFIXES_OFFSET, PREFIXED_NAME_OFFSET, ID, KIND, GROUP, ALIAS, ALIASARGS,  \
-    FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, VALUES, \
-    SUBCOMMANDIDS_OFFSET)                                                      \
-  LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(                                      \
-      OPT_, PREFIXES_OFFSET, PREFIXED_NAME_OFFSET, ID, KIND, GROUP, ALIAS,     \
-      ALIASARGS, FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS,     \
-      METAVAR, VALUES, SUBCOMMANDIDS_OFFSET)
-
 #endif // LLVM_OPTION_OPTTABLE_H
diff --git a/llvm/lib/ExecutionEngine/JITLink/COFFDirectiveParser.cpp b/llvm/lib/ExecutionEngine/JITLink/COFFDirectiveParser.cpp
index 4a5d5a8ffab64..63648774ce8ee 100644
--- a/llvm/lib/ExecutionEngine/JITLink/COFFDirectiveParser.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/COFFDirectiveParser.cpp
@@ -17,32 +17,15 @@ using namespace jitlink;
 
 #define DEBUG_TYPE "jitlink"
 
-#define OPTTABLE_STR_TABLE_CODE
-#include "COFFOptions.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "COFFOptions.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_UNION_CODE
-#include "COFFOptions.inc"
-#undef OPTTABLE_PREFIXES_UNION_CODE
-
 // Create table mapping all options defined in COFFOptions.td
 using namespace llvm::opt;
-static constexpr opt::OptTable::Info infoTable[] = {
-#define OPTION(...)                                                            \
-  LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(COFF_OPT_, __VA_ARGS__),
+#define OPTTABLE_CODE
 #include "COFFOptions.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
-class COFFOptTable : public opt::PrecomputedOptTable {
+class COFFOptTable : public opt::OptTable {
 public:
-  COFFOptTable()
-      : PrecomputedOptTable(OptionStrTable, OptionPrefixesTable, infoTable,
-                            OptionPrefixesUnion, true) {}
+  COFFOptTable() : OptTable(OptionTables, true) {}
 };
 
 static COFFOptTable optTable;
diff --git a/llvm/lib/Option/OptTable.cpp b/llvm/lib/Option/OptTable.cpp
index 15a01f8cf62c6..c444235076586 100644
--- a/llvm/lib/Option/OptTable.cpp
+++ b/llvm/lib/Option/OptTable.cpp
@@ -21,7 +21,6 @@
 #include <algorithm>
 #include <cassert>
 #include <map>
-#include <set>
 #include <string>
 #include <vector>
 
@@ -74,16 +73,18 @@ struct OptNameLess {
 
 OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {}
 
-OptTable::OptTable(const StringTable &StrTable,
-                   ArrayRef<StringTable::Offset> PrefixesTable,
-                   ArrayRef<Info> OptionInfos, bool IgnoreCase,
-                   ArrayRef<SubCommand> SubCommands,
-                   ArrayRef<unsigned> SubCommandIDsTable)
-    : StrTable(&StrTable), PrefixesTable(PrefixesTable),
-      OptionInfos(OptionInfos), IgnoreCase(IgnoreCase),
-      SubCommands(SubCommands), SubCommandIDsTable(SubCommandIDsTable) {
-  // Explicitly zero initialize the error to work around a bug in array
-  // value-initialization on MinGW with gcc 4.3.5.
+OptTable::OptTable(const Tables &T, bool IgnoreCase)
+    : StrTable(&T.StrTable), PrefixesTable(T.PrefixesTable),
+      OptionInfos(T.Infos), IgnoreCase(IgnoreCase), SubCommands(T.SubCommands),
+      SubCommandIDsTable(T.SubCommandIDs),
+      HelpTextVariantsTable(T.HelpTextVariants) {
+  for (StringTable::Offset PrefixOffset : T.PrefixesUnion) {
+    StringRef Prefix = (*StrTable)[PrefixOffset];
+    PrefixesUnion.push_back(Prefix);
+    for (char C : Prefix)
+      if (!is_contained(PrefixChars, C))
+        PrefixChars.push_back(C);
+  }
 
   // Find start of normal options.
   for (unsigned i = 0, e = getNumOptions(); i != e; ++i) {
@@ -113,7 +114,7 @@ OptTable::OptTable(const StringTable &StrTable,
 
   // Check that options are in order.
   for (unsigned i = FirstSearchableIndex + 1, e = getNumOptions(); i != e; ++i){
-    if (!(OptNameLess(StrTable, PrefixesTable)(getInfo(i), getInfo(i + 1)))) {
+    if (!(OptNameLess(*StrTable, PrefixesTable)(getInfo(i), getInfo(i + 1)))) {
       getOption(i).dump();
       getOption(i + 1).dump();
       llvm_unreachable("Options are not in order!");
@@ -122,17 +123,6 @@ OptTable::OptTable(const StringTable &StrTable,
 #endif
 }
 
-void OptTable::buildPrefixChars() {
-  assert(PrefixChars.empty() && "rebuilding a non-empty prefix char");
-
-  // Build prefix chars.
-  for (StringRef Prefix : PrefixesUnion) {
-    for (char C : Prefix)
-      if (!is_contained(PrefixChars, C))
-        PrefixChars.push_back(C);
-  }
-}
-
 OptTable::~OptTable() = default;
 
 const Option OptTable::getOption(OptSpecifier Opt) const {
@@ -838,19 +828,3 @@ void OptTable::internalPrintHelp(
 
   OS.flush();
 }
-
-GenericOptTable::GenericOptTable(const StringTable &StrTable,
-                                 ArrayRef<StringTable::Offset> PrefixesTable,
-                                 ArrayRef<Info> OptionInfos, bool IgnoreCase,
-                                 ArrayRef<SubCommand> SubCommands,
-                                 ArrayRef<unsigned> SubCommandIDsTable)
-    : OptTable(StrTable, PrefixesTable, OptionInfos, IgnoreCase, SubCommands,
-               SubCommandIDsTable) {
-
-  std::set<StringRef> TmpPrefixesUnion;
-  for (auto const &Info : OptionInfos.drop_front(FirstSearchableIndex))
-    for (auto PrefixOffset : Info.getPrefixOffsets(PrefixesTable))
-      TmpPrefixesUnion.insert(StrTable[PrefixOffset]);
-  PrefixesUnion.append(TmpPrefixesUnion.begin(), TmpPrefixesUnion.end());
-  buildPrefixChars();
-}
diff --git a/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp b/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp
index 380fbd8b6fc6c..9cec62c5b9aac 100644
--- a/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp
+++ b/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp
@@ -32,10 +32,6 @@ using namespace llvm::COFF;
 
 namespace {
 
-#define OPTTABLE_STR_TABLE_CODE
-#include "Options.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
 enum {
   OPT_INVALID = 0,
 #define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
@@ -43,22 +39,14 @@ enum {
 #undef OPTION
 };
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Options.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
 using namespace llvm::opt;
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#define OPTTABLE_CODE
 #include "Options.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
-class DllOptTable : public opt::GenericOptTable {
+class DllOptTable : public opt::OptTable {
 public:
-  DllOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,
-                             false) {}
+  DllOptTable() : opt::OptTable(OptionTables, false) {}
 };
 
 // Opens a file. Path has to be resolved already.
diff --git a/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp b/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp
index 15d959d7712dd..270283e132034 100644
--- a/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp
+++ b/llvm/lib/ToolDrivers/llvm-lib/LibDriver.cpp
@@ -37,10 +37,6 @@ using namespace llvm::object;
 
 namespace {
 
-#define OPTTABLE_STR_TABLE_CODE
-#include "Options.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
 enum {
   OPT_INVALID = 0,
 #define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
@@ -48,22 +44,14 @@ enum {
 #undef OPTION
 };
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Options.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
 using namespace llvm::opt;
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#define OPTTABLE_CODE
 #include "Options.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
-class LibOptTable : public opt::GenericOptTable {
+class LibOptTable : public opt::OptTable {
 public:
-  LibOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,
-                             true) {}
+  LibOptTable() : opt::OptTable(OptionTables, true) {}
 };
 } // namespace
 
diff --git a/llvm/tools/dsymutil/dsymutil.cpp b/llvm/tools/dsymutil/dsymutil.cpp
index 76c4d4140488c..009fc2a4dfc96 100644
--- a/llvm/tools/dsymutil/dsymutil.cpp
+++ b/llvm/tools/dsymutil/dsymutil.cpp
@@ -68,25 +68,14 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
-#include "Options.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Options.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
 using namespace llvm::opt;
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#define OPTTABLE_CODE
 #include "Options.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
-class DsymutilOptTable : public opt::GenericOptTable {
+class DsymutilOptTable : public opt::OptTable {
 public:
-  DsymutilOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}
+  DsymutilOptTable() : opt::OptTable(OptionTables) {}
 };
 } // namespace
 
diff --git a/llvm/tools/llvm-cas/llvm-cas.cpp b/llvm/tools/llvm-cas/llvm-cas.cpp
index e72ee470d2319..eaaacb94048d4 100644
--- a/llvm/tools/llvm-cas/llvm-cas.cpp
+++ b/llvm/tools/llvm-cas/llvm-cas.cpp
@@ -33,25 +33,14 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
-#include "Options.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Options.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
 using namespace llvm::opt;
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#define OPTTABLE_CODE
 #include "Options.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
-class LLVMCASOptTable : public opt::GenericOptTable {
+class LLVMCASOptTable : public opt::OptTable {
 public:
-  LLVMCASOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}
+  LLVMCASOptTable() : opt::OptTable(OptionTables) {}
 };
 
 enum class CommandKind {
diff --git a/llvm/tools/llvm-cgdata/llvm-cgdata.cpp b/llvm/tools/llvm-cgdata/llvm-cgdata.cpp
index 66a7410782922..797488575a439 100644
--- a/llvm/tools/llvm-cgdata/llvm-cgdata.cpp
+++ b/llvm/tools/llvm-cgdata/llvm-cgdata.cpp
@@ -51,25 +51,14 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
 using namespace llvm::opt;
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
-class CGDataOptTable : public opt::GenericOptTable {
+class CGDataOptTable : public opt::OptTable {
 public:
-  CGDataOptTable()
-      : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}
+  CGDataOptTable() : OptTable(OptionTables) {}
 };
 } // end anonymous namespace
 
diff --git a/llvm/tools/llvm-cvtres/llvm-cvtres.cpp b/llvm/tools/llvm-cvtres/llvm-cvtres.cpp
index 8ef8d6e239cfe..c46ff70e0ea6a 100644
--- a/llvm/tools/llvm-cvtres/llvm-cvtres.cpp
+++ b/llvm/tools/llvm-cvtres/llvm-cvtres.cpp
@@ -42,26 +42,14 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
 using namespace llvm::opt;
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
-class CvtResOptTable : public opt::GenericOptTable {
+class CvtResOptTable : public opt::OptTable {
 public:
-  CvtResOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,
-                             true) {}
+  CvtResOptTable() : opt::OptTable(OptionTables, true) {}
 };
 }
 
diff --git a/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp b/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
index 1467093e78c0b..4085bc950d867 100644
--- a/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
+++ b/llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp
@@ -31,25 +31,14 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
 using namespace llvm::opt;
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
-class CxxfiltOptTable : public opt::GenericOptTable {
+class CxxfiltOptTable : public opt::OptTable {
 public:
-  CxxfiltOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {
+  CxxfiltOptTable() : opt::OptTable(OptionTables) {
     setGroupedShortOptions(true);
   }
 };
diff --git a/llvm/tools/llvm-debuginfod-find/llvm-debuginfod-find.cpp b/llvm/tools/llvm-debuginfod-find/llvm-debuginfod-find.cpp
index 9aeda9f55bb96..91132da5f298e 100644
--- a/llvm/tools/llvm-debuginfod-find/llvm-debuginfod-find.cpp
+++ b/llvm/tools/llvm-debuginfod-find/llvm-debuginfod-find.cpp
@@ -37,25 +37,14 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
 using namespace llvm::opt;
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
-class DebuginfodFindOptTable : public opt::GenericOptTable {
+class DebuginfodFindOptTable : public opt::OptTable {
 public:
-  DebuginfodFindOptTable()
-      : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}
+  DebuginfodFindOptTable() : OptTable(OptionTables) {}
 };
 
 } // end anonymous namespace
diff --git a/llvm/tools/llvm-debuginfod/llvm-debuginfod.cpp b/llvm/tools/llvm-debuginfod/llvm-debuginfod.cpp
index c44bf915361f1..3e121b5607595 100644
--- a/llvm/tools/llvm-debuginfod/llvm-debuginfod.cpp
+++ b/llvm/tools/llvm-debuginfod/llvm-debuginfod.cpp
@@ -36,25 +36,14 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
 using namespace llvm::opt;
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
-class DebuginfodOptTable : public opt::GenericOptTable {
+class DebuginfodOptTable : public opt::OptTable {
 public:
-  DebuginfodOptTable()
-      : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}
+  DebuginfodOptTable() : OptTable(OptionTables) {}
 };
 } // end anonymous namespace
 
diff --git a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
index 3fa64dba7979e..5a2c19b84340e 100644
--- a/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
+++ b/llvm/tools/llvm-dwarfutil/llvm-dwarfutil.cpp
@@ -39,25 +39,14 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
-#include "Options.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Options.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
 using namespace llvm::opt;
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#define OPTTABLE_CODE
 #include "Options.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
-class DwarfutilOptTable : public opt::GenericOptTable {
+class DwarfutilOptTable : public opt::OptTable {
 public:
-  DwarfutilOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}
+  DwarfutilOptTable() : opt::OptTable(OptionTables) {}
 };
 } // namespace
 
diff --git a/llvm/tools/llvm-dwp/llvm-dwp.cpp b/llvm/tools/llvm-dwp/llvm-dwp.cpp
index b8c3f6e3d754a..27059be335caa 100644
--- a/llvm/tools/llvm-dwp/llvm-dwp.cpp
+++ b/llvm/tools/llvm-dwp/llvm-dwp.cpp
@@ -34,25 +34,14 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
 using namespace llvm::opt;
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
-class DwpOptTable : public opt::GenericOptTable {
+class DwpOptTable : public opt::OptTable {
 public:
-  DwpOptTable()
-      : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}
+  DwpOptTable() : OptTable(OptionTables) {}
 };
 } // end anonymous namespace
 
diff --git a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
index ab1eb70e780e9..d03fafe595f86 100644
--- a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
+++ b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp
@@ -70,26 +70,13 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-const opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "Opts.inc"
-#undef OPTION
-};
-
-class GSYMUtilOptTable : public llvm::opt::GenericOptTable {
+class GSYMUtilOptTable : public llvm::opt::OptTable {
 public:
-  GSYMUtilOptTable()
-      : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {
-    setGroupedShortOptions(true);
-  }
+  GSYMUtilOptTable() : OptTable(OptionTables) { setGroupedShortOptions(true); }
 };
 
 static bool Verbose;
diff --git a/llvm/tools/llvm-ifs/llvm-ifs.cpp b/llvm/tools/llvm-ifs/llvm-ifs.cpp
index 3e9014b7f52f9..8424aea4cd662 100644
--- a/llvm/tools/llvm-ifs/llvm-ifs.cpp
+++ b/llvm/tools/llvm-ifs/llvm-ifs.cpp
@@ -58,26 +58,13 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "Opts.inc"
-#undef OPTION
-};
-
-class IFSOptTable : public opt::GenericOptTable {
+class IFSOptTable : public opt::OptTable {
 public:
-  IFSOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {
-    setGroupedShortOptions(true);
-  }
+  IFSOptTable() : opt::OptTable(OptionTables) { setGroupedShortOptions(true); }
 };
 
 struct DriverConfig {
diff --git a/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp b/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp
index 40065270fb7ef..8a84ae63d0322 100644
--- a/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp
+++ b/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp
@@ -48,24 +48,13 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "Opts.inc"
-#undef OPTION
-};
-
-class LibtoolDarwinOptTable : public opt::GenericOptTable {
+class LibtoolDarwinOptTable : public opt::OptTable {
 public:
-  LibtoolDarwinOptTable()
-      : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}
+  LibtoolDarwinOptTable() : OptTable(OptionTables) {}
 };
 } // end anonymous namespace
 
diff --git a/llvm/tools/llvm-lipo/llvm-lipo.cpp b/llvm/tools/llvm-lipo/llvm-lipo.cpp
index 66ac0eecb8396..a3cc6de51e6a7 100644
--- a/llvm/tools/llvm-lipo/llvm-lipo.cpp
+++ b/llvm/tools/llvm-lipo/llvm-lipo.cpp
@@ -70,27 +70,15 @@ enum LipoID {
 };
 
 namespace lipo {
-#define OPTTABLE_STR_TABLE_CODE
-#include "LipoOpts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "LipoOpts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
 using namespace llvm::opt;
-static constexpr opt::OptTable::Info LipoInfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(LIPO_, __VA_ARGS__),
+#define OPTTABLE_CODE
 #include "LipoOpts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 } // namespace lipo
 
-class LipoOptTable : public opt::GenericOptTable {
+class LipoOptTable : public opt::OptTable {
 public:
-  LipoOptTable()
-      : opt::GenericOptTable(lipo::OptionStrTable, lipo::OptionPrefixesTable,
-                             lipo::LipoInfoTable) {}
+  LipoOptTable() : opt::OptTable(lipo::OptionTables) {}
 };
 
 enum class LipoAction {
diff --git a/llvm/tools/llvm-ml/llvm-ml.cpp b/llvm/tools/llvm-ml/llvm-ml.cpp
index 21fdb010bab83..dbfb8416c99db 100644
--- a/llvm/tools/llvm-ml/llvm-ml.cpp
+++ b/llvm/tools/llvm-ml/llvm-ml.cpp
@@ -59,25 +59,13 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "Opts.inc"
-#undef OPTION
-};
-
-class MLOptTable : public opt::GenericOptTable {
+class MLOptTable : public opt::OptTable {
 public:
-  MLOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,
-                             /*IgnoreCase=*/false) {}
+  MLOptTable() : opt::OptTable(OptionTables, /*IgnoreCase=*/false) {}
 };
 } // namespace
 
diff --git a/llvm/tools/llvm-mt/llvm-mt.cpp b/llvm/tools/llvm-mt/llvm-mt.cpp
index 3bd1bc786f86d..2b9ab48088d99 100644
--- a/llvm/tools/llvm-mt/llvm-mt.cpp
+++ b/llvm/tools/llvm-mt/llvm-mt.cpp
@@ -40,26 +40,14 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
 using namespace llvm::opt;
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
-class CvtResOptTable : public opt::GenericOptTable {
+class CvtResOptTable : public opt::OptTable {
 public:
-  CvtResOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,
-                             true) {}
+  CvtResOptTable() : opt::OptTable(OptionTables, true) {}
 };
 } // namespace
 
diff --git a/llvm/tools/llvm-nm/llvm-nm.cpp b/llvm/tools/llvm-nm/llvm-nm.cpp
index 170bf0b7fc22e..8058bbe07413f 100644
--- a/llvm/tools/llvm-nm/llvm-nm.cpp
+++ b/llvm/tools/llvm-nm/llvm-nm.cpp
@@ -67,26 +67,13 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "Opts.inc"
-#undef OPTION
-};
-
-class NmOptTable : public opt::GenericOptTable {
+class NmOptTable : public opt::OptTable {
 public:
-  NmOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {
-    setGroupedShortOptions(true);
-  }
+  NmOptTable() : opt::OptTable(OptionTables) { setGroupedShortOptions(true); }
 };
 
 enum OutputFormatTy { bsd, sysv, posix, darwin, just_symbols };
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
index 2e0ad6481c28e..ae638d0bbda85 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
+++ b/llvm/tools/llvm-objcopy/ObjcopyOptions.cpp
@@ -40,28 +40,14 @@ enum ObjcopyID {
 };
 
 namespace objcopy_opt {
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "ObjcopyOpts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "ObjcopyOpts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr opt::OptTable::Info ObjcopyInfoTable[] = {
-#define OPTION(...)                                                            \
-  LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(OBJCOPY_, __VA_ARGS__),
-#include "ObjcopyOpts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 } // namespace objcopy_opt
 
-class ObjcopyOptTable : public opt::GenericOptTable {
+class ObjcopyOptTable : public opt::OptTable {
 public:
-  ObjcopyOptTable()
-      : opt::GenericOptTable(objcopy_opt::OptionStrTable,
-                             objcopy_opt::OptionPrefixesTable,
-                             objcopy_opt::ObjcopyInfoTable) {
+  ObjcopyOptTable() : opt::OptTable(objcopy_opt::OptionTables) {
     setGroupedShortOptions(true);
     setDashDashParsing(true);
   }
@@ -76,28 +62,14 @@ enum InstallNameToolID {
 };
 
 namespace install_name_tool {
-#define OPTTABLE_STR_TABLE_CODE
-#include "InstallNameToolOpts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
+#define OPTTABLE_CODE
 #include "InstallNameToolOpts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr opt::OptTable::Info InstallNameToolInfoTable[] = {
-#define OPTION(...)                                                            \
-  LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(INSTALL_NAME_TOOL_, __VA_ARGS__),
-#include "InstallNameToolOpts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 } // namespace install_name_tool
 
-class InstallNameToolOptTable : public opt::GenericOptTable {
+class InstallNameToolOptTable : public opt::OptTable {
 public:
-  InstallNameToolOptTable()
-      : GenericOptTable(install_name_tool::OptionStrTable,
-                        install_name_tool::OptionPrefixesTable,
-                        install_name_tool::InstallNameToolInfoTable) {}
+  InstallNameToolOptTable() : OptTable(install_name_tool::OptionTables) {}
 };
 
 enum BitcodeStripID {
@@ -109,28 +81,14 @@ enum BitcodeStripID {
 };
 
 namespace bitcode_strip {
-#define OPTTABLE_STR_TABLE_CODE
-#include "BitcodeStripOpts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "BitcodeStripOpts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr opt::OptTable::Info BitcodeStripInfoTable[] = {
-#define OPTION(...)                                                            \
-  LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(BITCODE_STRIP_, __VA_ARGS__),
+#define OPTTABLE_CODE
 #include "BitcodeStripOpts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 } // namespace bitcode_strip
 
-class BitcodeStripOptTable : public opt::GenericOptTable {
+class BitcodeStripOptTable : public opt::OptTable {
 public:
-  BitcodeStripOptTable()
-      : opt::GenericOptTable(bitcode_strip::OptionStrTable,
-                             bitcode_strip::OptionPrefixesTable,
-                             bitcode_strip::BitcodeStripInfoTable) {}
+  BitcodeStripOptTable() : opt::OptTable(bitcode_strip::OptionTables) {}
 };
 
 enum StripID {
@@ -141,26 +99,14 @@ enum StripID {
 };
 
 namespace strip {
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "StripOpts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "StripOpts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr opt::OptTable::Info StripInfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(STRIP_, __VA_ARGS__),
-#include "StripOpts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 } // namespace strip
 
-class StripOptTable : public opt::GenericOptTable {
+class StripOptTable : public opt::OptTable {
 public:
-  StripOptTable()
-      : GenericOptTable(strip::OptionStrTable, strip::OptionPrefixesTable,
-                        strip::StripInfoTable) {
+  StripOptTable() : OptTable(strip::OptionTables) {
     setGroupedShortOptions(true);
   }
 };
@@ -174,28 +120,14 @@ enum ExtractBundleEntryID {
 };
 
 namespace extract_bundle_entry {
-#define OPTTABLE_STR_TABLE_CODE
-#include "ExtractBundleEntryOpts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "ExtractBundleEntryOpts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr opt::OptTable::Info ExtractBundleEntryInfoTable[] = {
-#define OPTION(...)                                                            \
-  LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(EXTRACT_BUNDLE_ENTRY_, __VA_ARGS__),
+#define OPTTABLE_CODE
 #include "ExtractBundleEntryOpts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 } // namespace extract_bundle_entry
 
-class ExtractBundleEntryOptTable : public opt::GenericOptTable {
+class ExtractBundleEntryOptTable : public opt::OptTable {
 public:
-  ExtractBundleEntryOptTable()
-      : GenericOptTable(extract_bundle_entry::OptionStrTable,
-                        extract_bundle_entry::OptionPrefixesTable,
-                        extract_bundle_entry::ExtractBundleEntryInfoTable) {
+  ExtractBundleEntryOptTable() : OptTable(extract_bundle_entry::OptionTables) {
     setGroupedShortOptions(true);
   }
 };
diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp
index 92c1c2da3d025..0df2f42e8a978 100644
--- a/llvm/tools/llvm-objdump/llvm-objdump.cpp
+++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp
@@ -92,21 +92,17 @@ using namespace llvm::opt;
 
 namespace {
 
-class CommonOptTable : public opt::GenericOptTable {
+class CommonOptTable : public opt::OptTable {
 public:
-  CommonOptTable(const StringTable &StrTable,
-                 ArrayRef<StringTable::Offset> PrefixesTable,
-                 ArrayRef<Info> OptionInfos, const char *Usage,
-                 const char *Description)
-      : opt::GenericOptTable(StrTable, PrefixesTable, OptionInfos),
-        Usage(Usage), Description(Description) {
+  CommonOptTable(const Tables &T, const char *Usage, const char *Description)
+      : opt::OptTable(T), Usage(Usage), Description(Description) {
     setGroupedShortOptions(true);
   }
 
   void printHelp(StringRef Argv0, bool ShowHidden = false) const {
     Argv0 = sys::path::filename(Argv0);
-    opt::GenericOptTable::printHelp(outs(), (Argv0 + Usage).str().c_str(),
-                                    Description, ShowHidden, ShowHidden);
+    opt::OptTable::printHelp(outs(), (Argv0 + Usage).str().c_str(), Description,
+                             ShowHidden, ShowHidden);
     // TODO Replace this with OptTable API once it adds extrahelp support.
     outs() << "\nPass @FILE as argument to read options from FILE.\n";
   }
@@ -118,29 +114,17 @@ class CommonOptTable : public opt::GenericOptTable {
 
 // ObjdumpOptID is in ObjdumpOptID.h
 namespace objdump_opt {
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "ObjdumpOpts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "ObjdumpOpts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr opt::OptTable::Info ObjdumpInfoTable[] = {
-#define OPTION(...)                                                            \
-  LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(OBJDUMP_, __VA_ARGS__),
-#include "ObjdumpOpts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 } // namespace objdump_opt
 
 class ObjdumpOptTable : public CommonOptTable {
 public:
   ObjdumpOptTable()
-      : CommonOptTable(
-            objdump_opt::OptionStrTable, objdump_opt::OptionPrefixesTable,
-            objdump_opt::ObjdumpInfoTable, " [options] <input object files>",
-            "llvm object file dumper") {}
+      : CommonOptTable(objdump_opt::OptionTables,
+                       " [options] <input object files>",
+                       "llvm object file dumper") {}
 };
 
 enum OtoolOptID {
@@ -151,26 +135,15 @@ enum OtoolOptID {
 };
 
 namespace otool {
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "OtoolOpts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "OtoolOpts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr opt::OptTable::Info OtoolInfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(OTOOL_, __VA_ARGS__),
-#include "OtoolOpts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 } // namespace otool
 
 class OtoolOptTable : public CommonOptTable {
 public:
   OtoolOptTable()
-      : CommonOptTable(otool::OptionStrTable, otool::OptionPrefixesTable,
-                       otool::OtoolInfoTable, " [option...] [file...]",
+      : CommonOptTable(otool::OptionTables, " [option...] [file...]",
                        "Mach-O object file displaying tool") {}
 };
 
diff --git a/llvm/tools/llvm-rc/llvm-rc.cpp b/llvm/tools/llvm-rc/llvm-rc.cpp
index 7afecf667fed0..0aedbb0d4247f 100644
--- a/llvm/tools/llvm-rc/llvm-rc.cpp
+++ b/llvm/tools/llvm-rc/llvm-rc.cpp
@@ -57,27 +57,14 @@ enum ID {
 };
 
 namespace rc_opt {
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "Opts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 } // namespace rc_opt
 
-class RcOptTable : public opt::GenericOptTable {
+class RcOptTable : public opt::OptTable {
 public:
-  RcOptTable()
-      : GenericOptTable(rc_opt::OptionStrTable, rc_opt::OptionPrefixesTable,
-                        rc_opt::InfoTable,
-                        /* IgnoreCase = */ true) {}
+  RcOptTable() : OptTable(rc_opt::OptionTables, /* IgnoreCase = */ true) {}
 };
 
 enum Windres_ID {
@@ -88,29 +75,15 @@ enum Windres_ID {
 };
 
 namespace windres_opt {
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "WindresOpts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "WindresOpts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...)                                                            \
-  LLVM_CONSTRUCT_OPT_INFO_WITH_ID_PREFIX(WINDRES_, __VA_ARGS__),
-#include "WindresOpts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 } // namespace windres_opt
 
-class WindresOptTable : public opt::GenericOptTable {
+class WindresOptTable : public opt::OptTable {
 public:
   WindresOptTable()
-      : GenericOptTable(windres_opt::OptionStrTable,
-                        windres_opt::OptionPrefixesTable,
-                        windres_opt::InfoTable,
-                        /* IgnoreCase = */ false) {}
+      : OptTable(windres_opt::OptionTables, /* IgnoreCase = */ false) {}
 };
 
 static ExitOnError ExitOnErr;
diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp
index d06221fbfd5b8..9d9596059c110 100644
--- a/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -59,24 +59,13 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "Opts.inc"
-#undef OPTION
-};
-
-class ReadobjOptTable : public opt::GenericOptTable {
+class ReadobjOptTable : public opt::OptTable {
 public:
-  ReadobjOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {
+  ReadobjOptTable() : opt::OptTable(OptionTables) {
     setGroupedShortOptions(true);
   }
 };
diff --git a/llvm/tools/llvm-readtapi/llvm-readtapi.cpp b/llvm/tools/llvm-readtapi/llvm-readtapi.cpp
index 312f298a86256..24e508c0746ab 100644
--- a/llvm/tools/llvm-readtapi/llvm-readtapi.cpp
+++ b/llvm/tools/llvm-readtapi/llvm-readtapi.cpp
@@ -45,26 +45,13 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "TapiOpts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "TapiOpts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "TapiOpts.inc"
-#undef OPTION
-};
-
-class TAPIOptTable : public opt::GenericOptTable {
+class TAPIOptTable : public opt::OptTable {
 public:
-  TAPIOptTable()
-      : opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {
-    setGroupedShortOptions(true);
-  }
+  TAPIOptTable() : opt::OptTable(OptionTables) { setGroupedShortOptions(true); }
 };
 
 struct StubOptions {
diff --git a/llvm/tools/llvm-size/llvm-size.cpp b/llvm/tools/llvm-size/llvm-size.cpp
index 77058368bf4c3..e6e5d073def64 100644
--- a/llvm/tools/llvm-size/llvm-size.cpp
+++ b/llvm/tools/llvm-size/llvm-size.cpp
@@ -45,26 +45,13 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "Opts.inc"
-#undef OPTION
-};
-
-class SizeOptTable : public opt::GenericOptTable {
+class SizeOptTable : public opt::OptTable {
 public:
-  SizeOptTable()
-      : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {
-    setGroupedShortOptions(true);
-  }
+  SizeOptTable() : OptTable(OptionTables) { setGroupedShortOptions(true); }
 };
 
 enum OutputFormatTy { berkeley, sysv, darwin };
diff --git a/llvm/tools/llvm-strings/llvm-strings.cpp b/llvm/tools/llvm-strings/llvm-strings.cpp
index f834dd2b55fc0..9121e6aff5ca4 100644
--- a/llvm/tools/llvm-strings/llvm-strings.cpp
+++ b/llvm/tools/llvm-strings/llvm-strings.cpp
@@ -38,25 +38,14 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
 using namespace llvm::opt;
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
-class StringsOptTable : public opt::GenericOptTable {
+class StringsOptTable : public opt::OptTable {
 public:
-  StringsOptTable()
-      : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {
+  StringsOptTable() : OptTable(OptionTables) {
     setGroupedShortOptions(true);
     setDashDashParsing(true);
   }
diff --git a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
index 0496df84fc8eb..850a0451547b5 100644
--- a/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
+++ b/llvm/tools/llvm-symbolizer/llvm-symbolizer.cpp
@@ -56,25 +56,14 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
 using namespace llvm::opt;
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
-class SymbolizerOptTable : public opt::GenericOptTable {
+class SymbolizerOptTable : public opt::OptTable {
 public:
-  SymbolizerOptTable()
-      : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {
+  SymbolizerOptTable() : OptTable(OptionTables) {
     setGroupedShortOptions(true);
   }
 };
diff --git a/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp b/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp
index b558236a0979d..460229028afe3 100644
--- a/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp
+++ b/llvm/tools/llvm-tli-checker/llvm-tli-checker.cpp
@@ -33,25 +33,14 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
 using namespace llvm::opt;
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
-class TLICheckerOptTable : public opt::GenericOptTable {
+class TLICheckerOptTable : public opt::OptTable {
 public:
-  TLICheckerOptTable()
-      : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}
+  TLICheckerOptTable() : OptTable(OptionTables) {}
 };
 } // end anonymous namespace
 
diff --git a/llvm/tools/sancov/sancov.cpp b/llvm/tools/sancov/sancov.cpp
index d6fdac2583d5d..704aa1541d865 100644
--- a/llvm/tools/sancov/sancov.cpp
+++ b/llvm/tools/sancov/sancov.cpp
@@ -68,24 +68,13 @@ enum ID {
 #undef OPTION
 };
 
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-static constexpr opt::OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "Opts.inc"
-#undef OPTION
-};
-
-class SancovOptTable : public opt::GenericOptTable {
+class SancovOptTable : public opt::OptTable {
 public:
-  SancovOptTable()
-      : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {}
+  SancovOptTable() : OptTable(OptionTables) {}
 };
 } // namespace
 
diff --git a/llvm/unittests/Option/OptionParsingTest.cpp b/llvm/unittests/Option/OptionParsingTest.cpp
index d63602d262a00..5e7535eb131b5 100644
--- a/llvm/unittests/Option/OptionParsingTest.cpp
+++ b/llvm/unittests/Option/OptionParsingTest.cpp
@@ -20,10 +20,6 @@ using namespace llvm::opt;
 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 #endif
 
-#define OPTTABLE_STR_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
-
 enum ID {
   OPT_INVALID = 0, // This is not an option ID.
 #define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
@@ -36,14 +32,6 @@ enum ID {
 #include "Opts.inc"
 #undef OPTTABLE_VALUES_CODE
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-#define OPTTABLE_PREFIXES_UNION_CODE
-#include "Opts.inc"
-#undef OPTTABLE_PREFIXES_UNION_CODE
-
 enum OptionFlags {
   OptFlag1 = (1 << 4),
   OptFlag2 = (1 << 5),
@@ -55,34 +43,15 @@ enum OptionVisibility {
   MultiLineVis = (1 << 3),
 };
 
-#define OPTTABLE_HELP_TEXT_VARIANTS_TABLE_CODE
-#include "Opts.inc"
-#undef OPTTABLE_HELP_TEXT_VARIANTS_TABLE_CODE
-
-static constexpr OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
+#define OPTTABLE_CODE
 #include "Opts.inc"
-#undef OPTION
-};
+#undef OPTTABLE_CODE
 
 namespace {
-class TestOptTable : public GenericOptTable {
+class TestOptTable : public OptTable {
 public:
-  TestOptTable(bool IgnoreCase = false)
-      : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,
-                        IgnoreCase) {
+  TestOptTable(bool IgnoreCase = false) : OptTable(OptionTables, IgnoreCase) {
     setValuesCodeFn(getOptionValuesCode);
-    setHelpTextVariantsTable(OptionHelpTextVariantsTable);
-  }
-};
-
-class TestPrecomputedOptTable : public PrecomputedOptTable {
-public:
-  TestPrecomputedOptTable(bool IgnoreCase = false)
-      : PrecomputedOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,
-                            OptionPrefixesUnion, IgnoreCase) {
-    setValuesCodeFn(getOptionValuesCode);
-    setHelpTextVariantsTable(OptionHelpTextVariantsTable);
   }
 };
 }
@@ -99,20 +68,8 @@ const char *Args[] = {
   "-Gchuu", "2"
   };
 
-// Test fixture
-template <typename T> class OptTableTest : public ::testing::Test {};
-
-template <typename T> class DISABLED_OptTableTest : public ::testing::Test {};
-
-// Test both precomputed and computed OptTables with the same suite of tests.
-using OptTableTestTypes =
-    ::testing::Types<TestOptTable, TestPrecomputedOptTable>;
-
-TYPED_TEST_SUITE(OptTableTest, OptTableTestTypes, );
-TYPED_TEST_SUITE(DISABLED_OptTableTest, OptTableTestTypes, );
-
-TYPED_TEST(OptTableTest, OptionParsing) {
-  TypeParam T;
+TEST(OptTableTest, OptionParsing) {
+  TestOptTable T;
   unsigned MAI, MAC;
   InputArgList AL = T.ParseArgs(Args, MAI, MAC);
 
@@ -158,8 +115,8 @@ TYPED_TEST(OptTableTest, OptionParsing) {
   EXPECT_EQ("desu", StringRef(ASL[1]));
 }
 
-TYPED_TEST(OptTableTest, ParseWithFlagExclusions) {
-  TypeParam T;
+TEST(OptTableTest, ParseWithFlagExclusions) {
+  TestOptTable T;
   unsigned MAI, MAC;
 
   // Exclude flag3 to avoid parsing as OPT_SLASH_C.
@@ -186,8 +143,8 @@ TYPED_TEST(OptTableTest, ParseWithFlagExclusions) {
   EXPECT_EQ("bar", AL.getLastArgValue(OPT_C));
 }
 
-TYPED_TEST(OptTableTest, ParseWithVisibility) {
-  TypeParam T;
+TEST(OptTableTest, ParseWithVisibility) {
+  TestOptTable T;
   unsigned MAI, MAC;
 
   const char *STArgs[] = {"-A", "-Q", "-R"};
@@ -223,8 +180,8 @@ TYPED_TEST(OptTableTest, ParseWithVisibility) {
   EXPECT_TRUE(AL.hasArg(OPT_R));
 }
 
-TYPED_TEST(OptTableTest, ParseAliasInGroup) {
-  TypeParam T;
+TEST(OptTableTest, ParseAliasInGroup) {
+  TestOptTable T;
   unsigned MAI, MAC;
 
   const char *MyArgs[] = { "-I" };
@@ -232,8 +189,8 @@ TYPED_TEST(OptTableTest, ParseAliasInGroup) {
   EXPECT_TRUE(AL.hasArg(OPT_H));
 }
 
-TYPED_TEST(OptTableTest, AliasArgs) {
-  TypeParam T;
+TEST(OptTableTest, AliasArgs) {
+  TestOptTable T;
   unsigned MAI, MAC;
 
   const char *MyArgs[] = { "-J", "-Joo" };
@@ -243,8 +200,8 @@ TYPED_TEST(OptTableTest, AliasArgs) {
   EXPECT_EQ("bar", AL.getAllArgValues(OPT_B)[1]);
 }
 
-TYPED_TEST(OptTableTest, AliasArgsMultiple) {
-  TypeParam T;
+TEST(OptTableTest, AliasArgsMultiple) {
+  TestOptTable T;
   unsigned MAI, MAC;
 
   const char *MyArgs[] = {"-Jmulti"};
@@ -254,8 +211,8 @@ TYPED_TEST(OptTableTest, AliasArgsMultiple) {
             AL.getAllArgValues(OPT_D));
 }
 
-TYPED_TEST(OptTableTest, SuggestValueCompletions) {
-  TypeParam T;
+TEST(OptTableTest, SuggestValueCompletions) {
+  TestOptTable T;
 
   EXPECT_EQ((std::vector<std::string>{"inline1", "inline2"}),
             T.suggestValueCompletions("-values-inline=", ""));
@@ -264,8 +221,8 @@ TYPED_TEST(OptTableTest, SuggestValueCompletions) {
             T.suggestValueCompletions("-values-from-code=", ""));
 }
 
-TYPED_TEST(OptTableTest, IgnoreCase) {
-  TypeParam T(true);
+TEST(OptTableTest, IgnoreCase) {
+  TestOptTable T(true);
   unsigned MAI, MAC;
 
   const char *MyArgs[] = { "-a", "-joo" };
@@ -280,8 +237,8 @@ TYPED_TEST(OptTableTest, IgnoreCase) {
 #pragma clang diagnostic ignored "-Wself-move"
 #endif
 
-TYPED_TEST(OptTableTest, InputArgListSelfAssign) {
-  TypeParam T;
+TEST(OptTableTest, InputArgListSelfAssign) {
+  TestOptTable T;
   unsigned MAI, MAC;
   InputArgList AL = T.ParseArgs(Args, MAI, MAC,
                                 /*FlagsToInclude=*/0,
@@ -301,8 +258,8 @@ TYPED_TEST(OptTableTest, InputArgListSelfAssign) {
 #pragma clang diagnostic pop
 #endif
 
-TYPED_TEST(OptTableTest, DoNotIgnoreCase) {
-  TypeParam T;
+TEST(OptTableTest, DoNotIgnoreCase) {
+  TestOptTable T;
   unsigned MAI, MAC;
 
   const char *MyArgs[] = { "-a", "-joo" };
@@ -311,8 +268,8 @@ TYPED_TEST(OptTableTest, DoNotIgnoreCase) {
   EXPECT_FALSE(AL.hasArg(OPT_B));
 }
 
-TYPED_TEST(OptTableTest, SlurpEmpty) {
-  TypeParam T;
+TEST(OptTableTest, SlurpEmpty) {
+  TestOptTable T;
   unsigned MAI, MAC;
 
   const char *MyArgs[] = { "-A", "-slurp" };
@@ -322,8 +279,8 @@ TYPED_TEST(OptTableTest, SlurpEmpty) {
   EXPECT_EQ(0U, AL.getAllArgValues(OPT_Slurp).size());
 }
 
-TYPED_TEST(OptTableTest, Slurp) {
-  TypeParam T;
+TEST(OptTableTest, Slurp) {
+  TestOptTable T;
   unsigned MAI, MAC;
 
   const char *MyArgs[] = { "-A", "-slurp", "-B", "--", "foo" };
@@ -338,8 +295,8 @@ TYPED_TEST(OptTableTest, Slurp) {
   EXPECT_EQ("foo", AL.getAllArgValues(OPT_Slurp)[2]);
 }
 
-TYPED_TEST(OptTableTest, SlurpJoinedEmpty) {
-  TypeParam T;
+TEST(OptTableTest, SlurpJoinedEmpty) {
+  TestOptTable T;
   unsigned MAI, MAC;
 
   const char *MyArgs[] = { "-A", "-slurpjoined" };
@@ -349,8 +306,8 @@ TYPED_TEST(OptTableTest, SlurpJoinedEmpty) {
   EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined).size(), 0U);
 }
 
-TYPED_TEST(OptTableTest, SlurpJoinedOneJoined) {
-  TypeParam T;
+TEST(OptTableTest, SlurpJoinedOneJoined) {
+  TestOptTable T;
   unsigned MAI, MAC;
 
   const char *MyArgs[] = { "-A", "-slurpjoinedfoo" };
@@ -361,8 +318,8 @@ TYPED_TEST(OptTableTest, SlurpJoinedOneJoined) {
   EXPECT_EQ(AL.getAllArgValues(OPT_SlurpJoined)[0], "foo");
 }
 
-TYPED_TEST(OptTableTest, SlurpJoinedAndSeparate) {
-  TypeParam T;
+TEST(OptTableTest, SlurpJoinedAndSeparate) {
+  TestOptTable T;
   unsigned MAI, MAC;
 
   const char *MyArgs[] = { "-A", "-slurpjoinedfoo", "bar", "baz" };
@@ -375,8 +332,8 @@ TYPED_TEST(OptTableTest, SlurpJoinedAndSeparate) {
   EXPECT_EQ("baz", AL.getAllArgValues(OPT_SlurpJoined)[2]);
 }
 
-TYPED_TEST(OptTableTest, SlurpJoinedButSeparate) {
-  TypeParam T;
+TEST(OptTableTest, SlurpJoinedButSeparate) {
+  TestOptTable T;
   unsigned MAI, MAC;
 
   const char *MyArgs[] = { "-A", "-slurpjoined", "foo", "bar", "baz" };
@@ -389,8 +346,8 @@ TYPED_TEST(OptTableTest, SlurpJoinedButSeparate) {
   EXPECT_EQ("baz", AL.getAllArgValues(OPT_SlurpJoined)[2]);
 }
 
-TYPED_TEST(OptTableTest, FlagAliasToJoined) {
-  TypeParam T;
+TEST(OptTableTest, FlagAliasToJoined) {
+  TestOptTable T;
   unsigned MAI, MAC;
 
   // Check that a flag alias provides an empty argument to a joined option.
@@ -402,8 +359,8 @@ TYPED_TEST(OptTableTest, FlagAliasToJoined) {
   EXPECT_EQ("", AL.getAllArgValues(OPT_B)[0]);
 }
 
-TYPED_TEST(OptTableTest, FindNearest) {
-  TypeParam T;
+TEST(OptTableTest, FindNearest) {
+  TestOptTable T;
   std::string Nearest;
 
   // Options that are too short should not be considered
@@ -461,8 +418,8 @@ TYPED_TEST(OptTableTest, FindNearest) {
   EXPECT_EQ(Nearest, "-xyzzy1");
 }
 
-TYPED_TEST(DISABLED_OptTableTest, FindNearestFIXME) {
-  TypeParam T;
+TEST(DISABLED_OptTableTest, FindNearestFIXME) {
+  TestOptTable T;
   std::string Nearest;
 
   // FIXME: Options with joined values should not have those values considered
@@ -472,8 +429,8 @@ TYPED_TEST(DISABLED_OptTableTest, FindNearestFIXME) {
   EXPECT_EQ(Nearest, "--ermghFoo");
 }
 
-TYPED_TEST(OptTableTest, ParseGroupedShortOptions) {
-  TypeParam T;
+TEST(OptTableTest, ParseGroupedShortOptions) {
+  TestOptTable T;
   T.setGroupedShortOptions(true);
   unsigned MAI, MAC;
 
@@ -502,8 +459,8 @@ TYPED_TEST(OptTableTest, ParseGroupedShortOptions) {
   EXPECT_TRUE(AL3.hasArg(OPT_Blorp));
 }
 
-TYPED_TEST(OptTableTest, ParseDashDash) {
-  TypeParam T;
+TEST(OptTableTest, ParseDashDash) {
+  TestOptTable T;
   T.setDashDashParsing(true);
   unsigned MAI, MAC;
 
@@ -535,8 +492,8 @@ TYPED_TEST(OptTableTest, ParseDashDash) {
   EXPECT_EQ("--", Unknown[1]);
 }
 
-TYPED_TEST(OptTableTest, UnknownOptions) {
-  TypeParam T;
+TEST(OptTableTest, UnknownOptions) {
+  TestOptTable T;
   unsigned MAI, MAC;
   const char *Args[] = {"-u", "--long", "0"};
   for (int I = 0; I < 2; ++I) {
@@ -549,8 +506,8 @@ TYPED_TEST(OptTableTest, UnknownOptions) {
   }
 }
 
-TYPED_TEST(OptTableTest, FlagsWithoutValues) {
-  TypeParam T;
+TEST(OptTableTest, FlagsWithoutValues) {
+  TestOptTable T;
   T.setGroupedShortOptions(true);
   unsigned MAI, MAC;
   const char *Args[] = {"-A=1", "-A="};
@@ -561,8 +518,8 @@ TYPED_TEST(OptTableTest, FlagsWithoutValues) {
   EXPECT_EQ("-A=", Unknown[1]);
 }
 
-TYPED_TEST(OptTableTest, UnknownGroupedShortOptions) {
-  TypeParam T;
+TEST(OptTableTest, UnknownGroupedShortOptions) {
+  TestOptTable T;
   T.setGroupedShortOptions(true);
   unsigned MAI, MAC;
   const char *Args[] = {"-AuzK", "-AuzK"};
@@ -575,8 +532,8 @@ TYPED_TEST(OptTableTest, UnknownGroupedShortOptions) {
   EXPECT_EQ("-z", Unknown[3]);
 }
 
-TYPED_TEST(OptTableTest, HelpTextForVariants) {
-  TypeParam T;
+TEST(OptTableTest, HelpTextForVariants) {
+  TestOptTable T;
   EXPECT_EQ("The xyzzy2 option", T.getOptionHelpText(OPT_Xyzzy2));
   EXPECT_EQ("The xyzzy2 option",
             T.getOptionHelpText(OPT_Xyzzy2, Visibility(SubtoolVis)));
@@ -592,8 +549,8 @@ TYPED_TEST(OptTableTest, HelpTextForVariants) {
             T.getOptionHelpText(OPT_Xyzzy3, Visibility(MultiLineVis)));
 }
 
-TYPED_TEST(OptTableTest, PrintMultilineHelpText) {
-  TypeParam T;
+TEST(OptTableTest, PrintMultilineHelpText) {
+  TestOptTable T;
   std::string Help;
   raw_string_ostream RSO(Help);
   T.printHelp(RSO, "usage", "title", /*ShowHidden=*/false,
diff --git a/llvm/unittests/Option/OptionSubCommandsTest.cpp b/llvm/unittests/Option/OptionSubCommandsTest.cpp
index d4744c90b0069..e07030f48a093 100644
--- a/llvm/unittests/Option/OptionSubCommandsTest.cpp
+++ b/llvm/unittests/Option/OptionSubCommandsTest.cpp
@@ -31,34 +31,14 @@ enum ID {
 #include "SubCommandOpts.inc"
 #undef OPTION
 };
-#define OPTTABLE_STR_TABLE_CODE
+#define OPTTABLE_CODE
 #include "SubCommandOpts.inc"
-#undef OPTTABLE_STR_TABLE_CODE
+#undef OPTTABLE_CODE
 
-#define OPTTABLE_PREFIXES_TABLE_CODE
-#include "SubCommandOpts.inc"
-#undef OPTTABLE_PREFIXES_TABLE_CODE
-
-#define OPTTABLE_SUBCOMMAND_IDS_TABLE_CODE
-#include "SubCommandOpts.inc"
-#undef OPTTABLE_SUBCOMMAND_IDS_TABLE_CODE
-
-#define OPTTABLE_SUBCOMMANDS_CODE
-#include "SubCommandOpts.inc"
-#undef OPTTABLE_SUBCOMMANDS_CODE
-
-static constexpr OptTable::Info InfoTable[] = {
-#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
-#include "SubCommandOpts.inc"
-#undef OPTION
-};
-
-class TestOptSubCommandTable : public GenericOptTable {
+class TestOptSubCommandTable : public OptTable {
 public:
   TestOptSubCommandTable(bool IgnoreCase = false)
-      : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable,
-                        /*IgnoreCase=*/false, OptionSubCommands,
-                        OptionSubCommandIDsTable) {}
+      : OptTable(OptionTables, IgnoreCase) {}
 };
 
 // Test fixture
diff --git a/llvm/utils/TableGen/OptionParserEmitter.cpp b/llvm/utils/TableGen/OptionParserEmitter.cpp
index 49b809cfb05f0..be57a71d6b089 100644
--- a/llvm/utils/TableGen/OptionParserEmitter.cpp
+++ b/llvm/utils/TableGen/OptionParserEmitter.cpp
@@ -268,7 +268,7 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
       OS << SubCommandIDs[SubCommandKey];
     } else {
       // The option SubCommandIDsOffset (for default top level toolname is 0).
-      OS << " 0";
+      OS << '0';
     }
   };
 
@@ -307,17 +307,44 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
       Table.GetOrAddStringOffset(V->getValueAsString("Text"));
   }
 
+  // Flags and Visibility name enumerators of the including tool. An option
+  // inherits its group's.
+  auto GetMask = [](const Record &R, StringRef Field) {
+    std::string Mask;
+    raw_string_ostream MaskOS(Mask);
+    ListSeparator Sep(" | ");
+    for (const Init *I : *R.getValueAsListInit(Field))
+      MaskOS << Sep << cast<DefInit>(I)->getDef()->getName();
+    if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
+      for (const Init *I : *DI->getDef()->getValueAsListInit(Field))
+        MaskOS << Sep << cast<DefInit>(I)->getDef()->getName();
+    return Mask.empty() ? std::string("0") : Mask;
+  };
+
+  // IDs are 1-based positions in the table, which lists groups first.
+  DenseMap<const Record *, unsigned> OptionID;
+  for (const Record &R : llvm::make_pointee_range(Groups))
+    OptionID.try_emplace(&R, OptionID.size() + 1);
+  for (const Record &R : llvm::make_pointee_range(Opts))
+    OptionID.try_emplace(&R, OptionID.size() + 1);
+  auto GetRefID = [&](const Record &R, StringRef Field) {
+    if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit(Field)))
+      return OptionID.lookup(DI->getDef());
+    return 0u;
+  };
+
   // Dump string table.
   OS << "/////////\n";
   OS << "// String table\n\n";
-  OS << "#ifdef OPTTABLE_STR_TABLE_CODE\n";
+  OS << "#if defined(OPTTABLE_STR_TABLE_CODE) || defined(OPTTABLE_CODE)\n";
   Table.EmitStringTableDef(OS, "OptionStrTable");
-  OS << "#endif // OPTTABLE_STR_TABLE_CODE\n\n";
+  OS << "#endif // OPTTABLE_STR_TABLE_CODE || OPTTABLE_CODE\n\n";
 
-  // Dump prefixes.
   OS << "/////////\n";
-  OS << "// Prefixes\n\n";
-  OS << "#ifdef OPTTABLE_PREFIXES_TABLE_CODE\n";
+  OS << "// Tables\n\n";
+  OS << "#ifdef OPTTABLE_CODE\n";
+
+  // Dump prefixes.
   OS << "static constexpr llvm::StringTable::Offset OptionPrefixesTable[] = "
         "{\n";
   {
@@ -340,51 +367,23 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
       CurIndex += Prefix.size() + 1;
     }
   }
-  OS << "\n};\n";
-  OS << "#endif // OPTTABLE_PREFIXES_TABLE_CODE\n\n";
+  OS << "\n};\n\n";
 
-  // Dump subcommand IDs.
-  OS << "/////////";
-  OS << "// SubCommand IDs\n\n";
-  OS << "#ifdef OPTTABLE_SUBCOMMAND_IDS_TABLE_CODE\n";
-  OS << "static constexpr unsigned OptionSubCommandIDsTable[] = {\n";
-  {
-    // Ensure the first subcommand set is always empty.
-    assert(!SubCommandIDs.empty() &&
-           "We should always emit an empty set of subcommands");
-    assert(SubCommandIDs.begin()->first.empty() &&
-           "First subcommand set should always be empty");
-    llvm::ListSeparator Sep(",\n");
-    unsigned CurIndex = 0;
-    for (auto &[SubCommand, SubCommandIndex] : SubCommandIDs) {
-      // First emit the number of subcommand strings in this list of
-      // subcommands.
-      OS << Sep << "  " << SubCommand.size() << " /* subcommands */";
-      SubCommandIndex = CurIndex;
-      assert((CurIndex == 0 || !SubCommand.empty()) &&
-             "Only first subcommand set should be empty!");
-      for (const auto &SubCommandKey : SubCommand) {
-        auto It = llvm::find_if(SubCommands, [&](const Record *R) {
-          return R->getName() == SubCommandKey;
-        });
-        assert(It != SubCommands.end() && "SubCommand not found");
-        OS << ", " << std::distance(SubCommands.begin(), It) << " /* '"
-           << SubCommandKey << "' */";
-      }
-      CurIndex += SubCommand.size() + 1;
-    }
+  // Dump prefixes union.
+  if (!PrefixesUnion.empty()) {
+    OS << "static constexpr llvm::StringTable::Offset OptionPrefixesUnion[] = "
+          "{\n";
+    llvm::ListSeparator Sep(", ");
+    for (auto Prefix : PrefixesUnion)
+      OS << Sep << "  " << *Table.GetStringOffset(Prefix) << " /* '" << Prefix
+         << "' */";
+    OS << "\n};\n\n";
   }
-  OS << "\n};\n";
-  OS << "#endif // OPTTABLE_SUBCOMMAND_IDS_TABLE_CODE\n\n";
 
-  // Dump help text variants.
-  OS << "/////////\n";
-  OS << "// Help text variants\n\n";
-  OS << "#ifdef OPTTABLE_HELP_TEXT_VARIANTS_TABLE_CODE\n";
+  // Dump help text variants. Each option's variants form a run ended by a zero
+  // row; offset 0 is the empty run.
   OS << "static constexpr llvm::opt::OptTable::HelpTextVariant "
         "OptionHelpTextVariantsTable[] = {\n";
-  // Each option's variants form a run ended by a zero row; offset 0 is the
-  // empty run.
   DenseMap<const Record *, unsigned> HelpTextVariantsOffset;
   unsigned NumVariantRows = 1;
   OS << "  {0, 0},\n";
@@ -409,25 +408,96 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
     }
     OS << "  {0, 0},\n";
   }
-  OS << "};\n";
-  OS << "#endif // OPTTABLE_HELP_TEXT_VARIANTS_TABLE_CODE\n\n";
+  OS << "};\n\n";
+
+  // Dump subcommands.
+  if (!SubCommands.empty()) {
+    OS << "static constexpr llvm::opt::OptTable::SubCommand "
+          "OptionSubCommands[] = {\n";
+    for (const Record *SubCommand : SubCommands) {
+      OS << "  { \"" << SubCommand->getValueAsString("Name") << "\", ";
+      OS << "\"" << SubCommand->getValueAsString("HelpText") << "\", ";
+      OS << "\"" << SubCommand->getValueAsString("Usage") << "\" },\n";
+    }
+    OS << "};\n\n";
+  }
 
-  // Dump prefixes union.
-  OS << "/////////\n";
-  OS << "// Prefix Union\n\n";
-  OS << "#ifdef OPTTABLE_PREFIXES_UNION_CODE\n";
-  OS << "static constexpr llvm::StringTable::Offset OptionPrefixesUnion[] = "
-        "{\n";
+  // Dump subcommand IDs.
+  OS << "static constexpr unsigned OptionSubCommandIDsTable[] = {\n";
   {
-    llvm::ListSeparator Sep(", ");
-    for (auto Prefix : PrefixesUnion)
-      OS << Sep << "  " << *Table.GetStringOffset(Prefix) << " /* '" << Prefix
-         << "' */";
+    // Ensure the first subcommand set is always empty.
+    assert(!SubCommandIDs.empty() &&
+           "We should always emit an empty set of subcommands");
+    assert(SubCommandIDs.begin()->first.empty() &&
+           "First subcommand set should always be empty");
+    llvm::ListSeparator Sep(",\n");
+    unsigned CurIndex = 0;
+    for (auto &[SubCommand, SubCommandIndex] : SubCommandIDs) {
+      // First emit the number of subcommand strings in this list of
+      // subcommands.
+      OS << Sep << "  " << SubCommand.size() << " /* subcommands */";
+      SubCommandIndex = CurIndex;
+      assert((CurIndex == 0 || !SubCommand.empty()) &&
+             "Only first subcommand set should be empty!");
+      for (const auto &SubCommandKey : SubCommand) {
+        auto It = llvm::find_if(SubCommands, [&](const Record *R) {
+          return R->getName() == SubCommandKey;
+        });
+        assert(It != SubCommands.end() && "SubCommand not found");
+        OS << ", " << std::distance(SubCommands.begin(), It) << " /* '"
+           << SubCommandKey << "' */";
+      }
+      CurIndex += SubCommand.size() + 1;
+    }
   }
-  OS << "\n};\n";
-  OS << "#endif // OPTTABLE_PREFIXES_UNION_CODE\n\n";
+  OS << "\n};\n\n";
 
-  // Dump groups.
+  // Dump the option table in OptTable::Info field order.
+  OS << "static constexpr llvm::opt::OptTable::Info OptionInfoTable[] = {\n";
+  for (const Record &R : llvm::make_pointee_range(Groups)) {
+    OS << "  {";
+    writeStrTableOffset(OS, Table, R.getValueAsString("Name"),
+                        /*EmitComment=*/true);
+    OS << ", ";
+    writeStrTableOffset(OS, Table, getHelpText(R));
+    OS << ", 0, 0, 0, 0, 0, 0, " << GetRefID(R, "Group") << ", 0, 0, ";
+    PrintSubCommandIdsOffset(R);
+    OS << ", llvm::opt::Option::GroupClass, 0},\n";
+  }
+  for (const Record &R : llvm::make_pointee_range(Opts)) {
+    OS << "  {";
+    writeStrTableOffset(OS, Table, getOptionPrefixedName(R),
+                        /*EmitComment=*/true);
+    OS << ", ";
+    writeStrTableOffset(OS, Table, getHelpText(R));
+    OS << ", ";
+    writeStrTableOffset(OS, Table, getOptionalString(R, "MetaVarName"));
+    OS << ", ";
+    writeStrTableOffset(OS, Table, getAliasArgsBlob(R));
+    OS << ", ";
+    writeStrTableOffset(OS, Table, getOptionalString(R, "Values"));
+    OS << ", " << GetMask(R, "Flags") << ", " << GetMask(R, "Visibility");
+    std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings("Prefixes");
+    OS << ", " << Prefixes[PrefixKeyT(RPrefixes.begin(), RPrefixes.end())];
+    OS << ", " << GetRefID(R, "Group") << ", " << GetRefID(R, "Alias");
+    OS << ", " << HelpTextVariantsOffset.lookup(&R) << ", ";
+    PrintSubCommandIdsOffset(R);
+    OS << ", llvm::opt::Option::"
+       << R.getValueAsDef("Kind")->getValueAsString("Name") << "Class, "
+       << R.getValueAsInt("NumArgs") << "},\n";
+  }
+  OS << "};\n\n";
+
+  OS << "static constexpr llvm::opt::OptTable::Tables OptionTables = {\n";
+  OS << "    OptionStrTable, OptionPrefixesTable, "
+     << (PrefixesUnion.empty() ? "{}" : "OptionPrefixesUnion")
+     << ", OptionInfoTable,\n";
+  OS << "    OptionHelpTextVariantsTable, "
+     << (SubCommands.empty() ? "{}" : "OptionSubCommands")
+     << ", OptionSubCommandIDsTable};\n";
+  OS << "#endif // OPTTABLE_CODE\n\n";
+
+  // Dump ValuesCode.
   OS << "/////////\n";
   OS << "// ValuesCode\n\n";
   OS << "#ifdef OPTTABLE_VALUES_CODE\n";
@@ -525,15 +595,10 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
 
     // The containing option group (if any).
     OS << ", ";
-    const ListInit *GroupFlags = nullptr;
-    const ListInit *GroupVis = nullptr;
-    if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
-      GroupFlags = DI->getDef()->getValueAsListInit("Flags");
-      GroupVis = DI->getDef()->getValueAsListInit("Visibility");
+    if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
       OS << getOptionName(*DI->getDef());
-    } else {
+    else
       OS << "INVALID";
-    }
 
     // The option alias (if any).
     OS << ", ";
@@ -547,33 +612,10 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
     writeStrTableOffset(OS, Table, getAliasArgsBlob(R));
 
     // "Flags" for the option, such as HelpHidden and Render*
-    OS << ", ";
-    int NumFlags = 0;
-    const ListInit *LI = R.getValueAsListInit("Flags");
-    for (const Init *I : *LI)
-      OS << (NumFlags++ ? " | " : "") << cast<DefInit>(I)->getDef()->getName();
-    if (GroupFlags) {
-      for (const Init *I : *GroupFlags)
-        OS << (NumFlags++ ? " | " : "")
-           << cast<DefInit>(I)->getDef()->getName();
-    }
-    if (NumFlags == 0)
-      OS << '0';
+    OS << ", " << GetMask(R, "Flags");
 
     // Option visibility, for sharing options between drivers.
-    OS << ", ";
-    int NumVisFlags = 0;
-    LI = R.getValueAsListInit("Visibility");
-    for (const Init *I : *LI)
-      OS << (NumVisFlags++ ? " | " : "")
-         << cast<DefInit>(I)->getDef()->getName();
-    if (GroupVis) {
-      for (const Init *I : *GroupVis)
-        OS << (NumVisFlags++ ? " | " : "")
-           << cast<DefInit>(I)->getDef()->getName();
-    }
-    if (NumVisFlags == 0)
-      OS << '0';
+    OS << ", " << GetMask(R, "Visibility");
 
     // The option parameter field.
     OS << ", " << R.getValueAsInt("NumArgs");
@@ -663,22 +705,6 @@ static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
         "std::size(SimpleEnumValueTables);\n";
 
   OS << "#endif // SIMPLE_ENUM_VALUE_TABLE\n";
-  OS << "\n";
-  OS << "/////////\n";
-  OS << "\n// SubCommands\n\n";
-  OS << "#ifdef OPTTABLE_SUBCOMMANDS_CODE\n";
-  OS << "static constexpr llvm::opt::OptTable::SubCommand OptionSubCommands[] "
-        "= "
-        "{\n";
-  for (const Record *SubCommand : SubCommands) {
-    OS << "  { \"" << SubCommand->getValueAsString("Name") << "\", ";
-    OS << "\"" << SubCommand->getValueAsString("HelpText") << "\", ";
-    OS << "\"" << SubCommand->getValueAsString("Usage") << "\" },\n";
-  }
-  OS << "};\n";
-  OS << "#endif // OPTTABLE_SUBCOMMANDS_CODE\n\n";
-
-  OS << "\n";
 }
 
 static TableGen::Emitter::Opt X("gen-opt-parser-defs", emitOptionParser,



More information about the lldb-commits mailing list