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