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
22using namespace llvm;
23
24static std::string getOptionName(const Record &R) {
25 // Use the record name unless EnumName is defined.
26 if (isa<UnsetInit>(Val: R.getValueInit(FieldName: "EnumName")))
27 return R.getName().str();
28
29 return R.getValueAsString(FieldName: "EnumName").str();
30}
31
32static 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
41static raw_ostream &writeCstring(raw_ostream &OS, llvm::StringRef Str) {
42 OS << '"';
43 OS.write_escaped(Str);
44 OS << '"';
45 return OS;
46}
47
48static std::string getOptionPrefixedName(const Record &R) {
49 std::vector<StringRef> Prefixes = R.getValueAsListOfStrings(FieldName: "Prefixes");
50 StringRef Name = R.getValueAsString(FieldName: "Name");
51
52 if (Prefixes.empty())
53 return Name.str();
54
55 return (Prefixes[0] + Twine(Name)).str();
56}
57
58class MarshallingInfo {
59public:
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"(
82struct SimpleEnumValue {
83 const char *Name;
84 unsigned Value;
85};
86
87struct 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, NormalizedValue: DefaultValue);
110 OS << ", ";
111 OS << ImpliedCheck;
112 OS << ", ";
113 emitScopedNormalizedValue(OS, NormalizedValue: 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, Str: Values[I]);
133 OS << ",";
134 OS << "static_cast<unsigned>(";
135 emitScopedNormalizedValue(OS, NormalizedValue: NormalizedValues[I]);
136 OS << ")},";
137 }
138 OS << "};\n";
139 return StringRef(ValueTableName);
140 }
141
142private:
143 void emitScopedNormalizedValue(raw_ostream &OS,
144 StringRef NormalizedValue) const {
145 if (!NormalizedValuesScope.empty())
146 OS << NormalizedValuesScope << "::";
147 OS << NormalizedValue;
148 }
149};
150
151size_t MarshallingInfo::NextTableIndex = 0;
152
153static 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(FieldName: "ShouldAlwaysEmit");
163 Ret.MacroPrefix = R.getValueAsString(FieldName: "MacroPrefix");
164 Ret.KeyPath = R.getValueAsString(FieldName: "KeyPath");
165 Ret.DefaultValue = R.getValueAsString(FieldName: "DefaultValue");
166 Ret.NormalizedValuesScope = R.getValueAsString(FieldName: "NormalizedValuesScope");
167 Ret.ImpliedCheck = R.getValueAsString(FieldName: "ImpliedCheck");
168 Ret.ImpliedValue =
169 R.getValueAsOptionalString(FieldName: "ImpliedValue").value_or(u&: Ret.DefaultValue);
170
171 Ret.ShouldParse = R.getValueAsString(FieldName: "ShouldParse");
172 Ret.Normalizer = R.getValueAsString(FieldName: "Normalizer");
173 Ret.Denormalizer = R.getValueAsString(FieldName: "Denormalizer");
174 Ret.ValueMerger = R.getValueAsString(FieldName: "ValueMerger");
175 Ret.ValueExtractor = R.getValueAsString(FieldName: "ValueExtractor");
176
177 if (!isa<UnsetInit>(Val: R.getValueInit(FieldName: "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(FieldName: "NormalizedValues");
182 Ret.Values.reserve(n: Ret.NormalizedValues.size());
183 Ret.ValueTableName = getOptionName(R) + "ValueTable";
184
185 StringRef ValuesStr = R.getValueAsString(FieldName: "Values");
186 for (;;) {
187 size_t Idx = ValuesStr.find(C: ',');
188 if (Idx == StringRef::npos)
189 break;
190 if (Idx > 0)
191 Ret.Values.push_back(x: ValuesStr.slice(Start: 0, End: Idx));
192 ValuesStr = ValuesStr.substr(Start: Idx + 1);
193 }
194 if (!ValuesStr.empty())
195 Ret.Values.push_back(x: 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
205static 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(x: "0");
220
221 while (HelpTextsForVariants.size() < MaxVisibilityHelp)
222 HelpTextsForVariants.push_back(
223 x: {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(R: Visibilities) << "}}, ";
238
239 if (Help.size())
240 writeCstring(OS, Str: Help);
241 else
242 OS << "nullptr";
243 OS << "}";
244
245 if (std::next(x: 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.
254static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
255 // Get the option groups and options.
256 ArrayRef<const Record *> Groups =
257 Records.getAllDerivedDefinitions(ClassName: "OptionGroup");
258 std::vector<const Record *> Opts = Records.getAllDerivedDefinitions(ClassName: "Option");
259 llvm::sort(C&: Opts, Comp: IsOptionRecordsLess);
260
261 emitSourceFileHeader(Desc: "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(k: PrefixKeyT(), args: 0);
268 for (const Record &R : llvm::make_pointee_range(Range&: Opts)) {
269 std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings(FieldName: "Prefixes");
270 PrefixKeyT PrefixKey(RPrefixes.begin(), RPrefixes.end());
271 Prefixes.try_emplace(k: PrefixKey, args: 0);
272 }
273
274 DenseSet<StringRef> PrefixesUnionSet;
275 for (const auto &[Prefix, _] : Prefixes)
276 PrefixesUnionSet.insert_range(R: Prefix);
277 SmallVector<StringRef> PrefixesUnion(PrefixesUnionSet.begin(),
278 PrefixesUnionSet.end());
279 array_pod_sort(Start: PrefixesUnion.begin(), End: 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(Str: Prefix);
285 for (const Record &R : llvm::make_pointee_range(Range&: Groups))
286 Table.GetOrAddStringOffset(Str: R.getValueAsString(FieldName: "Name"));
287 for (const Record &R : llvm::make_pointee_range(Range&: Opts))
288 Table.GetOrAddStringOffset(Str: 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, Name: "OptionStrTable", /*Indent=*/"");
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(Str: 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(Str: 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(Range&: Opts)) {
346 // The option values, if any;
347 if (!isa<UnsetInit>(Val: R.getValueInit(FieldName: "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(FieldName: "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(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, Str: R.getValueAsString(FieldName: "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>(Val: R.getValueInit(FieldName: "Group")))
380 OS << getOptionName(R: *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>(Val: R.getValueInit(FieldName: "HelpText"))) {
389 OS << ",\n";
390 OS << " ";
391 writeCstring(OS, Str: R.getValueAsString(FieldName: "HelpText"));
392 } else {
393 OS << ", nullptr";
394 }
395
396 // Not using Visibility specific text for group help.
397 emitHelpTextsForVariants(OS, HelpTextsForVariants: {});
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(FieldName: "Prefixes");
413 OS << Prefixes[PrefixKeyT(RPrefixes.begin(), RPrefixes.end())] << ", ";
414
415 // The option prefixed name.
416 writeStrTableOffset(OS, Table, Str: getOptionPrefixedName(R));
417
418 // The option identifier name.
419 OS << ", " << getOptionName(R);
420
421 // The option kind.
422 OS << ", " << R.getValueAsDef(FieldName: "Kind")->getValueAsString(FieldName: "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>(Val: R.getValueInit(FieldName: "Group"))) {
429 GroupFlags = DI->getDef()->getValueAsListInit(FieldName: "Flags");
430 GroupVis = DI->getDef()->getValueAsListInit(FieldName: "Visibility");
431 OS << getOptionName(R: *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>(Val: R.getValueInit(FieldName: "Alias")))
439 OS << getOptionName(R: *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(FieldName: "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(FieldName: "Flags");
462 for (const Init *I : *LI)
463 OS << (NumFlags++ ? " | " : "") << cast<DefInit>(Val: I)->getDef()->getName();
464 if (GroupFlags) {
465 for (const Init *I : *GroupFlags)
466 OS << (NumFlags++ ? " | " : "")
467 << cast<DefInit>(Val: 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(FieldName: "Visibility");
476 for (const Init *I : *LI)
477 OS << (NumVisFlags++ ? " | " : "")
478 << cast<DefInit>(Val: I)->getDef()->getName();
479 if (GroupVis) {
480 for (const Init *I : *GroupVis)
481 OS << (NumVisFlags++ ? " | " : "")
482 << cast<DefInit>(Val: I)->getDef()->getName();
483 }
484 if (NumVisFlags == 0)
485 OS << '0';
486
487 // The option parameter field.
488 OS << ", " << R.getValueAsInt(FieldName: "NumArgs");
489
490 // The option help text.
491 if (!isa<UnsetInit>(Val: R.getValueInit(FieldName: "HelpText"))) {
492 OS << ",\n";
493 OS << " ";
494 writeCstring(OS, Str: R.getValueAsString(FieldName: "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(FieldName: "HelpTextsForVariants")) {
503 ArrayRef<const Init *> Visibilities =
504 VisibilityHelp->getValueAsListInit(FieldName: "Visibilities")->getElements();
505
506 std::vector<std::string> VisibilityNames;
507 for (const Init *Visibility : Visibilities)
508 VisibilityNames.push_back(x: Visibility->getAsUnquotedString());
509
510 HelpTextsForVariants.emplace_back(
511 args&: VisibilityNames, args: VisibilityHelp->getValueAsString(FieldName: "Text"));
512 }
513 emitHelpTextsForVariants(OS, HelpTextsForVariants: std::move(HelpTextsForVariants));
514
515 // The option meta-variable name.
516 OS << ", ";
517 if (!isa<UnsetInit>(Val: R.getValueInit(FieldName: "MetaVarName")))
518 writeCstring(OS, Str: R.getValueAsString(FieldName: "MetaVarName"));
519 else
520 OS << "nullptr";
521
522 // The option Values. Used for shell autocompletion.
523 OS << ", ";
524 if (!isa<UnsetInit>(Val: R.getValueInit(FieldName: "Values")))
525 writeCstring(OS, Str: R.getValueAsString(FieldName: "Values"));
526 else if (!isa<UnsetInit>(Val: R.getValueInit(FieldName: "ValuesCode")))
527 OS << getOptionName(R) << "_Values";
528 else
529 OS << "nullptr";
530 };
531
532 auto IsMarshallingOption = [](const Record &R) {
533 return !isa<UnsetInit>(Val: R.getValueInit(FieldName: "KeyPath")) &&
534 !R.getValueAsString(FieldName: "KeyPath").empty();
535 };
536
537 std::vector<const Record *> OptsWithMarshalling;
538 for (const Record &R : llvm::make_pointee_range(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(x: &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(Start: OptsWithMarshalling.begin(), End: OptsWithMarshalling.end(),
563 Compare: CmpMarshallingOpts);
564
565 std::vector<MarshallingInfo> MarshallingInfos;
566 MarshallingInfos.reserve(n: OptsWithMarshalling.size());
567 for (const auto *R : OptsWithMarshalling)
568 MarshallingInfos.push_back(x: createMarshallingInfo(R: *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(x: *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
602static TableGen::Emitter::Opt X("gen-opt-parser-defs", emitOptionParser,
603 "Generate option definitions");
604