xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/OptionParserEmitter.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
1 //===- OptionParserEmitter.cpp - Table Driven Command Option Line Parsing -===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Common/OptEmitter.h"
10 #include "llvm/ADT/STLExtras.h"
11 #include "llvm/ADT/SmallString.h"
12 #include "llvm/ADT/StringExtras.h"
13 #include "llvm/ADT/Twine.h"
14 #include "llvm/Support/InterleavedRange.h"
15 #include "llvm/Support/raw_ostream.h"
16 #include "llvm/TableGen/Record.h"
17 #include "llvm/TableGen/StringToOffsetTable.h"
18 #include "llvm/TableGen/TableGenBackend.h"
19 #include <cstring>
20 #include <map>
21 
22 using namespace llvm;
23 
24 static std::string getOptionName(const Record &R) {
25   // Use the record name unless EnumName is defined.
26   if (isa<UnsetInit>(R.getValueInit("EnumName")))
27     return R.getName().str();
28 
29   return R.getValueAsString("EnumName").str();
30 }
31 
32 static raw_ostream &writeStrTableOffset(raw_ostream &OS,
33                                         const StringToOffsetTable &Table,
34                                         llvm::StringRef Str) {
35   OS << Table.GetStringOffset(Str) << " /* ";
36   OS.write_escaped(Str);
37   OS << " */";
38   return OS;
39 }
40 
41 static raw_ostream &writeCstring(raw_ostream &OS, llvm::StringRef Str) {
42   OS << '"';
43   OS.write_escaped(Str);
44   OS << '"';
45   return OS;
46 }
47 
48 static std::string getOptionPrefixedName(const Record &R) {
49   std::vector<StringRef> Prefixes = R.getValueAsListOfStrings("Prefixes");
50   StringRef Name = R.getValueAsString("Name");
51 
52   if (Prefixes.empty())
53     return Name.str();
54 
55   return (Prefixes[0] + Twine(Name)).str();
56 }
57 
58 class MarshallingInfo {
59 public:
60   static constexpr const char *MacroName = "OPTION_WITH_MARSHALLING";
61   const Record &R;
62   bool ShouldAlwaysEmit = false;
63   StringRef MacroPrefix;
64   StringRef KeyPath;
65   StringRef DefaultValue;
66   StringRef NormalizedValuesScope;
67   StringRef ImpliedCheck;
68   StringRef ImpliedValue;
69   StringRef ShouldParse;
70   StringRef Normalizer;
71   StringRef Denormalizer;
72   StringRef ValueMerger;
73   StringRef ValueExtractor;
74   int TableIndex = -1;
75   std::vector<StringRef> Values;
76   std::vector<StringRef> NormalizedValues;
77   std::string ValueTableName;
78 
79   static size_t NextTableIndex;
80 
81   static constexpr const char *ValueTablePreamble = R"(
82 struct SimpleEnumValue {
83   const char *Name;
84   unsigned Value;
85 };
86 
87 struct SimpleEnumValueTable {
88   const SimpleEnumValue *Table;
89   unsigned Size;
90 };
91 )";
92 
93   static constexpr const char *ValueTablesDecl =
94       "static const SimpleEnumValueTable SimpleEnumValueTables[] = ";
95 
96   MarshallingInfo(const Record &R) : R(R) {}
97 
98   std::string getMacroName() const {
99     return (MacroPrefix + MarshallingInfo::MacroName).str();
100   }
101 
102   void emit(raw_ostream &OS) const {
103     OS << ShouldParse;
104     OS << ", ";
105     OS << ShouldAlwaysEmit;
106     OS << ", ";
107     OS << KeyPath;
108     OS << ", ";
109     emitScopedNormalizedValue(OS, DefaultValue);
110     OS << ", ";
111     OS << ImpliedCheck;
112     OS << ", ";
113     emitScopedNormalizedValue(OS, ImpliedValue);
114     OS << ", ";
115     OS << Normalizer;
116     OS << ", ";
117     OS << Denormalizer;
118     OS << ", ";
119     OS << ValueMerger;
120     OS << ", ";
121     OS << ValueExtractor;
122     OS << ", ";
123     OS << TableIndex;
124   }
125 
126   std::optional<StringRef> emitValueTable(raw_ostream &OS) const {
127     if (TableIndex == -1)
128       return {};
129     OS << "static const SimpleEnumValue " << ValueTableName << "[] = {\n";
130     for (unsigned I = 0, E = Values.size(); I != E; ++I) {
131       OS << "{";
132       writeCstring(OS, Values[I]);
133       OS << ",";
134       OS << "static_cast<unsigned>(";
135       emitScopedNormalizedValue(OS, NormalizedValues[I]);
136       OS << ")},";
137     }
138     OS << "};\n";
139     return StringRef(ValueTableName);
140   }
141 
142 private:
143   void emitScopedNormalizedValue(raw_ostream &OS,
144                                  StringRef NormalizedValue) const {
145     if (!NormalizedValuesScope.empty())
146       OS << NormalizedValuesScope << "::";
147     OS << NormalizedValue;
148   }
149 };
150 
151 size_t MarshallingInfo::NextTableIndex = 0;
152 
153 static MarshallingInfo createMarshallingInfo(const Record &R) {
154   assert(!isa<UnsetInit>(R.getValueInit("KeyPath")) &&
155          !isa<UnsetInit>(R.getValueInit("DefaultValue")) &&
156          !isa<UnsetInit>(R.getValueInit("ValueMerger")) &&
157          "MarshallingInfo must have a provide a keypath, default value and a "
158          "value merger");
159 
160   MarshallingInfo Ret(R);
161 
162   Ret.ShouldAlwaysEmit = R.getValueAsBit("ShouldAlwaysEmit");
163   Ret.MacroPrefix = R.getValueAsString("MacroPrefix");
164   Ret.KeyPath = R.getValueAsString("KeyPath");
165   Ret.DefaultValue = R.getValueAsString("DefaultValue");
166   Ret.NormalizedValuesScope = R.getValueAsString("NormalizedValuesScope");
167   Ret.ImpliedCheck = R.getValueAsString("ImpliedCheck");
168   Ret.ImpliedValue =
169       R.getValueAsOptionalString("ImpliedValue").value_or(Ret.DefaultValue);
170 
171   Ret.ShouldParse = R.getValueAsString("ShouldParse");
172   Ret.Normalizer = R.getValueAsString("Normalizer");
173   Ret.Denormalizer = R.getValueAsString("Denormalizer");
174   Ret.ValueMerger = R.getValueAsString("ValueMerger");
175   Ret.ValueExtractor = R.getValueAsString("ValueExtractor");
176 
177   if (!isa<UnsetInit>(R.getValueInit("NormalizedValues"))) {
178     assert(!isa<UnsetInit>(R.getValueInit("Values")) &&
179            "Cannot provide normalized values for value-less options");
180     Ret.TableIndex = MarshallingInfo::NextTableIndex++;
181     Ret.NormalizedValues = R.getValueAsListOfStrings("NormalizedValues");
182     Ret.Values.reserve(Ret.NormalizedValues.size());
183     Ret.ValueTableName = getOptionName(R) + "ValueTable";
184 
185     StringRef ValuesStr = R.getValueAsString("Values");
186     for (;;) {
187       size_t Idx = ValuesStr.find(',');
188       if (Idx == StringRef::npos)
189         break;
190       if (Idx > 0)
191         Ret.Values.push_back(ValuesStr.slice(0, Idx));
192       ValuesStr = ValuesStr.substr(Idx + 1);
193     }
194     if (!ValuesStr.empty())
195       Ret.Values.push_back(ValuesStr);
196 
197     assert(Ret.Values.size() == Ret.NormalizedValues.size() &&
198            "The number of normalized values doesn't match the number of "
199            "values");
200   }
201 
202   return Ret;
203 }
204 
205 static void emitHelpTextsForVariants(
206     raw_ostream &OS, std::vector<std::pair<std::vector<std::string>, StringRef>>
207                          HelpTextsForVariants) {
208   // OptTable must be constexpr so it uses std::arrays with these capacities.
209   const unsigned MaxVisibilityPerHelp = 2;
210   const unsigned MaxVisibilityHelp = 1;
211 
212   assert(HelpTextsForVariants.size() <= MaxVisibilityHelp &&
213          "Too many help text variants to store in "
214          "OptTable::HelpTextsForVariants");
215 
216   // This function must initialise any unused elements of those arrays.
217   for (auto [Visibilities, _] : HelpTextsForVariants)
218     while (Visibilities.size() < MaxVisibilityPerHelp)
219       Visibilities.push_back("0");
220 
221   while (HelpTextsForVariants.size() < MaxVisibilityHelp)
222     HelpTextsForVariants.push_back(
223         {std::vector<std::string>(MaxVisibilityPerHelp, "0"), ""});
224 
225   OS << ", (std::array<std::pair<std::array<unsigned, " << MaxVisibilityPerHelp
226      << ">, const char*>, " << MaxVisibilityHelp << ">{{ ";
227 
228   auto VisibilityHelpEnd = HelpTextsForVariants.cend();
229   for (auto VisibilityHelp = HelpTextsForVariants.cbegin();
230        VisibilityHelp != VisibilityHelpEnd; ++VisibilityHelp) {
231     auto [Visibilities, Help] = *VisibilityHelp;
232 
233     assert(Visibilities.size() <= MaxVisibilityPerHelp &&
234            "Too many visibilities to store in an "
235            "OptTable::HelpTextsForVariants entry");
236     OS << "{std::array<unsigned, " << MaxVisibilityPerHelp << ">{{"
237        << llvm::interleaved(Visibilities) << "}}, ";
238 
239     if (Help.size())
240       writeCstring(OS, Help);
241     else
242       OS << "nullptr";
243     OS << "}";
244 
245     if (std::next(VisibilityHelp) != VisibilityHelpEnd)
246       OS << ", ";
247   }
248   OS << " }})";
249 }
250 
251 /// OptionParserEmitter - This tablegen backend takes an input .td file
252 /// describing a list of options and emits a data structure for parsing and
253 /// working with those options when given an input command line.
254 static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
255   // Get the option groups and options.
256   ArrayRef<const Record *> Groups =
257       Records.getAllDerivedDefinitions("OptionGroup");
258   std::vector<const Record *> Opts = Records.getAllDerivedDefinitions("Option");
259   llvm::sort(Opts, IsOptionRecordsLess);
260 
261   emitSourceFileHeader("Option Parsing Definitions", OS);
262 
263   // Generate prefix groups.
264   typedef SmallVector<SmallString<2>, 2> PrefixKeyT;
265   typedef std::map<PrefixKeyT, unsigned> PrefixesT;
266   PrefixesT Prefixes;
267   Prefixes.try_emplace(PrefixKeyT(), 0);
268   for (const Record &R : llvm::make_pointee_range(Opts)) {
269     std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings("Prefixes");
270     PrefixKeyT PrefixKey(RPrefixes.begin(), RPrefixes.end());
271     Prefixes.try_emplace(PrefixKey, 0);
272   }
273 
274   DenseSet<StringRef> PrefixesUnionSet;
275   for (const auto &[Prefix, _] : Prefixes)
276     PrefixesUnionSet.insert_range(Prefix);
277   SmallVector<StringRef> PrefixesUnion(PrefixesUnionSet.begin(),
278                                        PrefixesUnionSet.end());
279   array_pod_sort(PrefixesUnion.begin(), PrefixesUnion.end());
280 
281   llvm::StringToOffsetTable Table;
282   // We can add all the prefixes via the union.
283   for (const auto &Prefix : PrefixesUnion)
284     Table.GetOrAddStringOffset(Prefix);
285   for (const Record &R : llvm::make_pointee_range(Groups))
286     Table.GetOrAddStringOffset(R.getValueAsString("Name"));
287   for (const Record &R : llvm::make_pointee_range(Opts))
288     Table.GetOrAddStringOffset(getOptionPrefixedName(R));
289 
290   // Dump string table.
291   OS << "/////////\n";
292   OS << "// String table\n\n";
293   OS << "#ifdef OPTTABLE_STR_TABLE_CODE\n";
294   Table.EmitStringTableDef(OS, "OptionStrTable");
295   OS << "#endif // OPTTABLE_STR_TABLE_CODE\n\n";
296 
297   // Dump prefixes.
298   OS << "/////////\n";
299   OS << "// Prefixes\n\n";
300   OS << "#ifdef OPTTABLE_PREFIXES_TABLE_CODE\n";
301   OS << "static constexpr llvm::StringTable::Offset OptionPrefixesTable[] = "
302         "{\n";
303   {
304     // Ensure the first prefix set is always empty.
305     assert(!Prefixes.empty() &&
306            "We should always emit an empty set of prefixes");
307     assert(Prefixes.begin()->first.empty() &&
308            "First prefix set should always be empty");
309     llvm::ListSeparator Sep(",\n");
310     unsigned CurIndex = 0;
311     for (auto &[Prefix, PrefixIndex] : Prefixes) {
312       // First emit the number of prefix strings in this list of prefixes.
313       OS << Sep << "  " << Prefix.size() << " /* prefixes */";
314       PrefixIndex = CurIndex;
315       assert((CurIndex == 0 || !Prefix.empty()) &&
316              "Only first prefix set should be empty!");
317       for (const auto &PrefixKey : Prefix)
318         OS << ", " << *Table.GetStringOffset(PrefixKey) << " /* '" << PrefixKey
319            << "' */";
320       CurIndex += Prefix.size() + 1;
321     }
322   }
323   OS << "\n};\n";
324   OS << "#endif // OPTTABLE_PREFIXES_TABLE_CODE\n\n";
325 
326   // Dump prefixes union.
327   OS << "/////////\n";
328   OS << "// Prefix Union\n\n";
329   OS << "#ifdef OPTTABLE_PREFIXES_UNION_CODE\n";
330   OS << "static constexpr llvm::StringTable::Offset OptionPrefixesUnion[] = "
331         "{\n";
332   {
333     llvm::ListSeparator Sep(", ");
334     for (auto Prefix : PrefixesUnion)
335       OS << Sep << "  " << *Table.GetStringOffset(Prefix) << " /* '" << Prefix
336          << "' */";
337   }
338   OS << "\n};\n";
339   OS << "#endif // OPTTABLE_PREFIXES_UNION_CODE\n\n";
340 
341   // Dump groups.
342   OS << "/////////\n";
343   OS << "// ValuesCode\n\n";
344   OS << "#ifdef OPTTABLE_VALUES_CODE\n";
345   for (const Record &R : llvm::make_pointee_range(Opts)) {
346     // The option values, if any;
347     if (!isa<UnsetInit>(R.getValueInit("ValuesCode"))) {
348       assert(isa<UnsetInit>(R.getValueInit("Values")) &&
349              "Cannot choose between Values and ValuesCode");
350       OS << "#define VALUES_CODE " << getOptionName(R) << "_Values\n";
351       OS << R.getValueAsString("ValuesCode") << "\n";
352       OS << "#undef VALUES_CODE\n";
353     }
354   }
355   OS << "#endif\n";
356 
357   OS << "/////////\n";
358   OS << "// Groups\n\n";
359   OS << "#ifdef OPTION\n";
360   for (const Record &R : llvm::make_pointee_range(Groups)) {
361     // Start a single option entry.
362     OS << "OPTION(";
363 
364     // A zero prefix offset corresponds to an empty set of prefixes.
365     OS << "0 /* no prefixes */";
366 
367     // The option string offset.
368     OS << ", ";
369     writeStrTableOffset(OS, Table, R.getValueAsString("Name"));
370 
371     // The option identifier name.
372     OS << ", " << getOptionName(R);
373 
374     // The option kind.
375     OS << ", Group";
376 
377     // The containing option group (if any).
378     OS << ", ";
379     if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
380       OS << getOptionName(*DI->getDef());
381     else
382       OS << "INVALID";
383 
384     // The other option arguments (unused for groups).
385     OS << ", INVALID, nullptr, 0, 0, 0";
386 
387     // The option help text.
388     if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
389       OS << ",\n";
390       OS << "       ";
391       writeCstring(OS, R.getValueAsString("HelpText"));
392     } else {
393       OS << ", nullptr";
394     }
395 
396     // Not using Visibility specific text for group help.
397     emitHelpTextsForVariants(OS, {});
398 
399     // The option meta-variable name (unused).
400     OS << ", nullptr";
401 
402     // The option Values (unused for groups).
403     OS << ", nullptr)\n";
404   }
405   OS << "\n";
406 
407   OS << "//////////\n";
408   OS << "// Options\n\n";
409 
410   auto WriteOptRecordFields = [&](raw_ostream &OS, const Record &R) {
411     // The option prefix;
412     std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings("Prefixes");
413     OS << Prefixes[PrefixKeyT(RPrefixes.begin(), RPrefixes.end())] << ", ";
414 
415     // The option prefixed name.
416     writeStrTableOffset(OS, Table, getOptionPrefixedName(R));
417 
418     // The option identifier name.
419     OS << ", " << getOptionName(R);
420 
421     // The option kind.
422     OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name");
423 
424     // The containing option group (if any).
425     OS << ", ";
426     const ListInit *GroupFlags = nullptr;
427     const ListInit *GroupVis = nullptr;
428     if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
429       GroupFlags = DI->getDef()->getValueAsListInit("Flags");
430       GroupVis = DI->getDef()->getValueAsListInit("Visibility");
431       OS << getOptionName(*DI->getDef());
432     } else {
433       OS << "INVALID";
434     }
435 
436     // The option alias (if any).
437     OS << ", ";
438     if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Alias")))
439       OS << getOptionName(*DI->getDef());
440     else
441       OS << "INVALID";
442 
443     // The option alias arguments (if any).
444     // Emitted as a \0 separated list in a string, e.g. ["foo", "bar"]
445     // would become "foo\0bar\0". Note that the compiler adds an implicit
446     // terminating \0 at the end.
447     OS << ", ";
448     std::vector<StringRef> AliasArgs = R.getValueAsListOfStrings("AliasArgs");
449     if (AliasArgs.size() == 0) {
450       OS << "nullptr";
451     } else {
452       OS << "\"";
453       for (StringRef AliasArg : AliasArgs)
454         OS << AliasArg << "\\0";
455       OS << "\"";
456     }
457 
458     // "Flags" for the option, such as HelpHidden and Render*
459     OS << ", ";
460     int NumFlags = 0;
461     const ListInit *LI = R.getValueAsListInit("Flags");
462     for (const Init *I : *LI)
463       OS << (NumFlags++ ? " | " : "") << cast<DefInit>(I)->getDef()->getName();
464     if (GroupFlags) {
465       for (const Init *I : *GroupFlags)
466         OS << (NumFlags++ ? " | " : "")
467            << cast<DefInit>(I)->getDef()->getName();
468     }
469     if (NumFlags == 0)
470       OS << '0';
471 
472     // Option visibility, for sharing options between drivers.
473     OS << ", ";
474     int NumVisFlags = 0;
475     LI = R.getValueAsListInit("Visibility");
476     for (const Init *I : *LI)
477       OS << (NumVisFlags++ ? " | " : "")
478          << cast<DefInit>(I)->getDef()->getName();
479     if (GroupVis) {
480       for (const Init *I : *GroupVis)
481         OS << (NumVisFlags++ ? " | " : "")
482            << cast<DefInit>(I)->getDef()->getName();
483     }
484     if (NumVisFlags == 0)
485       OS << '0';
486 
487     // The option parameter field.
488     OS << ", " << R.getValueAsInt("NumArgs");
489 
490     // The option help text.
491     if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
492       OS << ",\n";
493       OS << "       ";
494       writeCstring(OS, R.getValueAsString("HelpText"));
495     } else {
496       OS << ", nullptr";
497     }
498 
499     std::vector<std::pair<std::vector<std::string>, StringRef>>
500         HelpTextsForVariants;
501     for (const Record *VisibilityHelp :
502          R.getValueAsListOfDefs("HelpTextsForVariants")) {
503       ArrayRef<const Init *> Visibilities =
504           VisibilityHelp->getValueAsListInit("Visibilities")->getElements();
505 
506       std::vector<std::string> VisibilityNames;
507       for (const Init *Visibility : Visibilities)
508         VisibilityNames.push_back(Visibility->getAsUnquotedString());
509 
510       HelpTextsForVariants.emplace_back(
511           VisibilityNames, VisibilityHelp->getValueAsString("Text"));
512     }
513     emitHelpTextsForVariants(OS, std::move(HelpTextsForVariants));
514 
515     // The option meta-variable name.
516     OS << ", ";
517     if (!isa<UnsetInit>(R.getValueInit("MetaVarName")))
518       writeCstring(OS, R.getValueAsString("MetaVarName"));
519     else
520       OS << "nullptr";
521 
522     // The option Values. Used for shell autocompletion.
523     OS << ", ";
524     if (!isa<UnsetInit>(R.getValueInit("Values")))
525       writeCstring(OS, R.getValueAsString("Values"));
526     else if (!isa<UnsetInit>(R.getValueInit("ValuesCode")))
527       OS << getOptionName(R) << "_Values";
528     else
529       OS << "nullptr";
530   };
531 
532   auto IsMarshallingOption = [](const Record &R) {
533     return !isa<UnsetInit>(R.getValueInit("KeyPath")) &&
534            !R.getValueAsString("KeyPath").empty();
535   };
536 
537   std::vector<const Record *> OptsWithMarshalling;
538   for (const Record &R : llvm::make_pointee_range(Opts)) {
539     // Start a single option entry.
540     OS << "OPTION(";
541     WriteOptRecordFields(OS, R);
542     OS << ")\n";
543     if (IsMarshallingOption(R))
544       OptsWithMarshalling.push_back(&R);
545   }
546   OS << "#endif // OPTION\n";
547 
548   auto CmpMarshallingOpts = [](const Record *const *A, const Record *const *B) {
549     unsigned AID = (*A)->getID();
550     unsigned BID = (*B)->getID();
551 
552     if (AID < BID)
553       return -1;
554     if (AID > BID)
555       return 1;
556     return 0;
557   };
558   // The RecordKeeper stores records (options) in lexicographical order, and we
559   // have reordered the options again when generating prefix groups. We need to
560   // restore the original definition order of options with marshalling to honor
561   // the topology of the dependency graph implied by `DefaultAnyOf`.
562   array_pod_sort(OptsWithMarshalling.begin(), OptsWithMarshalling.end(),
563                  CmpMarshallingOpts);
564 
565   std::vector<MarshallingInfo> MarshallingInfos;
566   MarshallingInfos.reserve(OptsWithMarshalling.size());
567   for (const auto *R : OptsWithMarshalling)
568     MarshallingInfos.push_back(createMarshallingInfo(*R));
569 
570   for (const auto &MI : MarshallingInfos) {
571     OS << "#ifdef " << MI.getMacroName() << "\n";
572     OS << MI.getMacroName() << "(";
573     WriteOptRecordFields(OS, MI.R);
574     OS << ", ";
575     MI.emit(OS);
576     OS << ")\n";
577     OS << "#endif // " << MI.getMacroName() << "\n";
578   }
579 
580   OS << "\n";
581   OS << "#ifdef SIMPLE_ENUM_VALUE_TABLE";
582   OS << "\n";
583   OS << MarshallingInfo::ValueTablePreamble;
584   std::vector<StringRef> ValueTableNames;
585   for (const auto &MI : MarshallingInfos)
586     if (auto MaybeValueTableName = MI.emitValueTable(OS))
587       ValueTableNames.push_back(*MaybeValueTableName);
588 
589   OS << MarshallingInfo::ValueTablesDecl << "{";
590   for (auto ValueTableName : ValueTableNames)
591     OS << "{" << ValueTableName << ", std::size(" << ValueTableName << ")},\n";
592   OS << "};\n";
593   OS << "static const unsigned SimpleEnumValueTablesSize = "
594         "std::size(SimpleEnumValueTables);\n";
595 
596   OS << "#endif // SIMPLE_ENUM_VALUE_TABLE\n";
597   OS << "\n";
598 
599   OS << "\n";
600 }
601 
602 static TableGen::Emitter::Opt X("gen-opt-parser-defs", emitOptionParser,
603                                 "Generate option definitions");
604