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