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 "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/StringMap.h"
15#include "llvm/ADT/Twine.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#include <set>
25
26using namespace llvm;
27
28static std::string getOptionName(const Record &R) {
29 // Use the record name unless EnumName is defined.
30 if (isa<UnsetInit>(Val: R.getValueInit(FieldName: "EnumName")))
31 return R.getName().str();
32
33 return R.getValueAsString(FieldName: "EnumName").str();
34}
35
36// Only pass EmitComment for short strings that cannot contain "*/".
37static void writeStrTableOffset(raw_ostream &OS,
38 const StringToOffsetTable &Table,
39 llvm::StringRef Str, bool EmitComment = false) {
40 std::optional<unsigned> Offset = Table.GetStringOffset(Str);
41 if (!Offset)
42 PrintFatalError(Msg: "string was not added to the option string table: " + Str);
43 OS << *Offset;
44 if (EmitComment) {
45 OS << " /* ";
46 OS.write_escaped(Str);
47 OS << " */";
48 }
49}
50
51static raw_ostream &writeCstring(raw_ostream &OS, llvm::StringRef Str) {
52 OS << '"';
53 OS.write_escaped(Str);
54 OS << '"';
55 return OS;
56}
57
58static StringRef getOptionalString(const Record &R, StringRef Field) {
59 return R.getValueAsOptionalString(FieldName: Field).value_or(u: "");
60}
61
62// Offset zero is the empty string and stands for an unset HelpText. A
63// HelpText<""> marks an option as deliberately undocumented, so it maps to a
64// second empty string that the table does not put at offset zero.
65static StringRef getHelpText(const Record &R) {
66 std::optional<StringRef> S = R.getValueAsOptionalString(FieldName: "HelpText");
67 if (!S)
68 return StringRef();
69 return S->empty() ? StringRef("\0", 1) : *S;
70}
71
72// The string table appends the empty string that terminates the list.
73static std::string getAliasArgsBlob(const Record &R) {
74 std::string Blob;
75 for (StringRef AliasArg : R.getValueAsListOfStrings(FieldName: "AliasArgs")) {
76 if (AliasArg.empty())
77 PrintFatalError(ErrorLoc: R.getLoc(), Msg: "AliasArgs entries must not be empty");
78 Blob += AliasArg;
79 Blob += '\0';
80 }
81 return Blob;
82}
83
84static std::string getOptionPrefixedName(const Record &R) {
85 std::vector<StringRef> Prefixes = R.getValueAsListOfStrings(FieldName: "Prefixes");
86 StringRef Name = R.getValueAsString(FieldName: "Name");
87
88 if (Prefixes.empty())
89 return Name.str();
90
91 return (Prefixes[0] + Twine(Name)).str();
92}
93
94class MarshallingInfo {
95public:
96 static constexpr const char *MacroName = "OPTION_WITH_MARSHALLING";
97 const Record &R;
98 bool ShouldAlwaysEmit = false;
99 StringRef MacroPrefix;
100 StringRef KeyPath;
101 StringRef DefaultValue;
102 StringRef NormalizedValuesScope;
103 StringRef ImpliedCheck;
104 StringRef ImpliedValue;
105 StringRef ShouldParse;
106 StringRef Normalizer;
107 StringRef Denormalizer;
108 int TableIndex = -1;
109 std::vector<StringRef> Values;
110 std::vector<StringRef> NormalizedValues;
111 std::string ValueTableName;
112
113 static size_t NextTableIndex;
114
115 static constexpr const char *ValueTablePreamble = R"(
116struct SimpleEnumValue {
117 const char *Name;
118 unsigned Value;
119};
120
121struct SimpleEnumValueTable {
122 const SimpleEnumValue *Table;
123 unsigned Size;
124};
125)";
126
127 static constexpr const char *ValueTablesDecl =
128 "static const SimpleEnumValueTable SimpleEnumValueTables[] = ";
129
130 MarshallingInfo(const Record &R) : R(R) {}
131
132 std::string getMacroName() const {
133 return (MacroPrefix + MarshallingInfo::MacroName).str();
134 }
135
136 void emit(raw_ostream &OS) const {
137 OS << ShouldParse;
138 OS << ", ";
139 OS << ShouldAlwaysEmit;
140 OS << ", ";
141 OS << KeyPath;
142 OS << ", ";
143 emitScopedNormalizedValue(OS, NormalizedValue: DefaultValue);
144 OS << ", ";
145 OS << ImpliedCheck;
146 OS << ", ";
147 emitScopedNormalizedValue(OS, NormalizedValue: ImpliedValue);
148 OS << ", ";
149 OS << Normalizer;
150 OS << ", ";
151 OS << Denormalizer;
152 OS << ", ";
153 OS << TableIndex;
154 }
155
156 std::optional<StringRef> emitValueTable(raw_ostream &OS) const {
157 if (TableIndex == -1)
158 return {};
159 OS << "static const SimpleEnumValue " << ValueTableName << "[] = {\n";
160 for (unsigned I = 0, E = Values.size(); I != E; ++I) {
161 OS << "{";
162 writeCstring(OS, Str: Values[I]);
163 OS << ",";
164 OS << "static_cast<unsigned>(";
165 emitScopedNormalizedValue(OS, NormalizedValue: NormalizedValues[I]);
166 OS << ")},";
167 }
168 OS << "};\n";
169 return StringRef(ValueTableName);
170 }
171
172private:
173 void emitScopedNormalizedValue(raw_ostream &OS,
174 StringRef NormalizedValue) const {
175 if (!NormalizedValuesScope.empty())
176 OS << NormalizedValuesScope << "::";
177 OS << NormalizedValue;
178 }
179};
180
181size_t MarshallingInfo::NextTableIndex = 0;
182
183static MarshallingInfo createMarshallingInfo(const Record &R) {
184 assert(!isa<UnsetInit>(R.getValueInit("KeyPath")) &&
185 !isa<UnsetInit>(R.getValueInit("DefaultValue")) &&
186 "MarshallingInfo must have a provide a keypath, default value and a "
187 "value merger");
188
189 MarshallingInfo Ret(R);
190
191 Ret.ShouldAlwaysEmit = R.getValueAsBit(FieldName: "ShouldAlwaysEmit");
192 Ret.MacroPrefix = R.getValueAsString(FieldName: "MacroPrefix");
193 Ret.KeyPath = R.getValueAsString(FieldName: "KeyPath");
194 Ret.DefaultValue = R.getValueAsString(FieldName: "DefaultValue");
195 Ret.NormalizedValuesScope = R.getValueAsString(FieldName: "NormalizedValuesScope");
196 Ret.ImpliedCheck = R.getValueAsString(FieldName: "ImpliedCheck");
197 Ret.ImpliedValue =
198 R.getValueAsOptionalString(FieldName: "ImpliedValue").value_or(u&: Ret.DefaultValue);
199
200 Ret.ShouldParse = R.getValueAsString(FieldName: "ShouldParse");
201 Ret.Normalizer = R.getValueAsString(FieldName: "Normalizer");
202 Ret.Denormalizer = R.getValueAsString(FieldName: "Denormalizer");
203
204 if (!isa<UnsetInit>(Val: R.getValueInit(FieldName: "NormalizedValues"))) {
205 assert(!isa<UnsetInit>(R.getValueInit("Values")) &&
206 "Cannot provide normalized values for value-less options");
207 Ret.TableIndex = MarshallingInfo::NextTableIndex++;
208 Ret.NormalizedValues = R.getValueAsListOfStrings(FieldName: "NormalizedValues");
209 Ret.Values.reserve(n: Ret.NormalizedValues.size());
210 Ret.ValueTableName = getOptionName(R) + "ValueTable";
211
212 StringRef ValuesStr = R.getValueAsString(FieldName: "Values");
213 for (;;) {
214 size_t Idx = ValuesStr.find(C: ',');
215 if (Idx == StringRef::npos)
216 break;
217 if (Idx > 0)
218 Ret.Values.push_back(x: ValuesStr.slice(Start: 0, End: Idx));
219 ValuesStr = ValuesStr.substr(Start: Idx + 1);
220 }
221 if (!ValuesStr.empty())
222 Ret.Values.push_back(x: ValuesStr);
223
224 assert(Ret.Values.size() == Ret.NormalizedValues.size() &&
225 "The number of normalized values doesn't match the number of "
226 "values");
227 }
228
229 return Ret;
230}
231
232// -foo-bar becomes foo_bar, or bar if Prefix is "foo-".
233static std::string getSpellingIdentifier(const Record &R,
234 StringRef Prefix = "") {
235 StringRef Spelling = R.getValueAsString(FieldName: "Name");
236 Spelling.consume_front(Prefix);
237 std::string ID = Spelling.str();
238 llvm::replace(Range&: ID, OldValue: '-', NewValue: '_');
239 if (ID.empty() || isDigit(C: ID[0]) ||
240 !all_of(Range&: ID, P: [](char C) { return isAlnum(C) || C == '_'; }))
241 PrintFatalError(ErrorLoc: R.getLoc(), Msg: "the spelling is not an identifier; name the "
242 "defm");
243 return ID;
244}
245
246// `defm : BoolField<"foo-bar", ...>` declares member foo_bar, and a named defm
247// names it.
248static std::string getMemberName(const Record &R, StringRef Prefix) {
249 StringRef Name = R.getValueAsString(FieldName: "FieldName");
250 return Name.starts_with(Prefix: "anonymous_") ? getSpellingIdentifier(R, Prefix)
251 : Name.str();
252}
253
254// The OPT_ name of an option of an OptionsStruct. `defm :` rows are named
255// after the spelling: -foo-bar is OPT_foo_bar.
256static std::string getStructOptionID(const Record &R) {
257 if (!R.getName().starts_with(Prefix: "anonymous_"))
258 return getOptionName(R);
259 return getSpellingIdentifier(R);
260}
261
262// Emits the struct an OptionsStruct def declares: its declaration under
263// OPTIONS_STRUCT_DECL, and under OPTIONS_STRUCT_DEFS the global instance, the
264// option table, and apply(), which sets the member an argument names.
265static void emitOptionsStruct(const Record &Struct,
266 ArrayRef<const Record *> Groups,
267 ArrayRef<const Record *> Opts, raw_ostream &OS) {
268 struct Member {
269 std::string Name;
270 StringRef Type, Default, Spelling;
271 };
272 std::vector<const Record *> Fields;
273 for (const Record *R : Opts) {
274 StringRef Kind = R->getValueAsDef(FieldName: "Kind")->getValueAsString(FieldName: "Name");
275 if (!R->getValue(Name: "FieldName")) {
276 if (Kind != "Input" && Kind != "Unknown" &&
277 isa<UnsetInit>(Val: R->getValueInit(FieldName: "Alias")))
278 PrintFatalError(ErrorLoc: R->getLoc(), Msg: "an option of an OptionsStruct must be "
279 "declared with BoolField or ValueField");
280 continue;
281 }
282 if (Kind != "FlagOrEq" && Kind != "SeparateOrEq")
283 PrintFatalError(ErrorLoc: R->getLoc(),
284 Msg: "a member is set by a FlagOrEq or SeparateOrEq");
285 StringRef Type = R->getValueAsString(FieldName: "FieldType");
286 if (Kind == "FlagOrEq" && Type != "bool" && Type != "llvm::BoolOrDefault" &&
287 !R->getValue(Name: "BareValue"))
288 PrintFatalError(ErrorLoc: R->getLoc(), Msg: "a FlagOrEq sets a bool or has a BareValue");
289 Fields.push_back(x: R);
290 }
291 // Members in declaration order.
292 std::vector<const Record *> ByID = Fields;
293 llvm::sort(C&: ByID, Comp: [](const Record *A, const Record *B) {
294 return A->getID() < B->getID();
295 });
296 StringRef Prefix = Struct.getValueAsString(FieldName: "MemberPrefix");
297 std::vector<Member> Members;
298 StringMap<StringRef> MemberSpelling;
299 for (const Record *R : ByID) {
300 Member M{.Name: getMemberName(R: *R, Prefix), .Type: R->getValueAsString(FieldName: "FieldType"),
301 .Default: R->getValueAsString(FieldName: "FieldDefault"), .Spelling: R->getValueAsString(FieldName: "Name")};
302 auto [It, Inserted] = MemberSpelling.try_emplace(Key: M.Name, Args&: M.Spelling);
303 if (!Inserted)
304 PrintFatalError(ErrorLoc: R->getLoc(),
305 Msg: "member '" + M.Name + "' is also set by -" + It->second);
306 Members.push_back(x: M);
307 }
308
309 StringRef Name = Struct.getName();
310 OS << "\n#ifdef OPTIONS_STRUCT_DECL\n#undef OPTIONS_STRUCT_DECL\n";
311 OS << "#include \"llvm/ADT/ArrayRef.h\"\n";
312 OS << "#include \"llvm/ADT/BoolOrDefault.h\"\n";
313 OS << "#include \"llvm/ADT/StringRef.h\"\n";
314 OS << "#include \"llvm/Support/Allocator.h\"\n\n";
315 StringRef Namespace = Struct.getValueAsString(FieldName: "Namespace");
316 OS << "namespace llvm {\nnamespace opt {\nclass Arg;\n"
317 "class OptTable;\n} // namespace opt\n} // namespace llvm\n\n";
318 OS << "namespace " << Namespace << " {\n";
319 OS << "struct " << Name << " {\n";
320 if (Namespace != "llvm")
321 OS << " using StringRef = llvm::StringRef;\n";
322 for (const Member &M : Members)
323 OS << " " << M.Type << " " << M.Name << "{" << M.Default << "};\n";
324 OS << "\n /// The instance cl::ParseCommandLineOptions sets.\n";
325 OS << " static " << Name << " Global;\n\n";
326 OS << " static const llvm::opt::OptTable &optTable();\n";
327 OS << " /// Sets the member that \\p A names, allocating a list from \\p "
328 "Alloc.\n /// Returns false if the value is invalid.\n";
329 OS << " bool apply(const llvm::opt::Arg &A, llvm::BumpPtrAllocator "
330 "&Alloc);\n";
331 OS << "};\n} // namespace " << Namespace << "\n";
332 OS << "#endif // OPTIONS_STRUCT_DECL\n";
333
334 std::string Qualified = (Namespace + "::" + Name).str();
335 OS << "\n#ifdef OPTIONS_STRUCT_DEFS\n#undef OPTIONS_STRUCT_DEFS\n";
336 OS << Qualified << " " << Qualified << "::Global;\n\n";
337 OS << "namespace {\nenum ID : unsigned {\n OPT_INVALID = 0,\n";
338 for (const Record *R : Groups)
339 OS << " OPT_" << getOptionName(R: *R) << ",\n";
340 for (const Record *R : Opts)
341 OS << " OPT_" << getStructOptionID(R: *R) << ",\n";
342 OS << "};\n} // namespace\n\n";
343 OS << "const llvm::opt::OptTable &" << Qualified << "::optTable() {\n";
344 OS << " static const llvm::opt::LibraryOptTable T(optionTables());\n";
345 OS << " return T;\n}\n\n";
346 OS << "bool " << Qualified
347 << "::apply(const llvm::opt::Arg &A, llvm::BumpPtrAllocator &Alloc) {\n";
348 OS << " switch (A.getOption().getID()) {\n";
349 for (const Record *R : Fields) {
350 OS << " case OPT_" << getStructOptionID(R: *R) << ":\n";
351 std::string Member = getMemberName(R: *R, Prefix);
352 if (R->getValue(Name: "BareValue"))
353 OS << " if (!A.getNumValues()) { " << Member << " = "
354 << R->getValueAsString(FieldName: "BareValue") << "; return true; }\n";
355 if (!isa<UnsetInit>(Val: R->getValueInit(FieldName: "NormalizedValues"))) {
356 SmallVector<StringRef> Values;
357 R->getValueAsString(FieldName: "Values").split(A&: Values, Separator: ',');
358 std::vector<StringRef> Enumerators =
359 R->getValueAsListOfStrings(FieldName: "NormalizedValues");
360 if (Values.size() != Enumerators.size())
361 PrintFatalError(ErrorLoc: R->getLoc(), Msg: "an EnumField needs one enumerator per "
362 "value");
363 // The generic lambda sets a scalar, a std::optional, or a list element.
364 OS << " return llvm::opt::parseArgValue(A.getValue(), " << Member
365 << ", Alloc, [](llvm::StringRef V, auto &X) {\n";
366 for (auto [Value, Enumerator] : llvm::zip_equal(t&: Values, u&: Enumerators))
367 OS << " if (V == \"" << Value
368 << "\") {\n X = " << Enumerator
369 << ";\n return true;\n }\n";
370 OS << " return false;\n });\n";
371 continue;
372 }
373 // A FlagOrEq without a value means =true.
374 StringRef Value =
375 R->getValueAsDef(FieldName: "Kind")->getValueAsString(FieldName: "Name") == "FlagOrEq"
376 ? "A.getNumValues() ? A.getValue() : \"true\""
377 : "A.getValue()";
378 OS << " return llvm::opt::parseArgValue(" << Value << ", " << Member
379 << ", Alloc);\n";
380 }
381 OS << " }\n llvm_unreachable(\"option without a member\");\n}\n";
382 OS << "#endif // OPTIONS_STRUCT_DEFS\n";
383}
384
385/// OptionParserEmitter - This tablegen backend takes an input .td file
386/// describing a list of options and emits a data structure for parsing and
387/// working with those options when given an input command line.
388static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {
389 // Get the option groups and options.
390 ArrayRef<const Record *> Groups =
391 Records.getAllDerivedDefinitions(ClassName: "OptionGroup");
392 std::vector<const Record *> Opts = Records.getAllDerivedDefinitions(ClassName: "Option");
393 llvm::sort(C&: Opts, Comp: IsOptionRecordsLess);
394
395 std::vector<const Record *> SubCommands =
396 Records.getAllDerivedDefinitions(ClassName: "SubCommand");
397
398 ArrayRef<const Record *> Structs =
399 Records.getAllDerivedDefinitionsIfDefined(ClassName: "OptionsStruct");
400 if (Structs.size() > 1)
401 PrintFatalError(ErrorLoc: Structs[1]->getLoc(), Msg: "only one OptionsStruct is allowed");
402
403 emitSourceFileHeader(Desc: "Option Parsing Definitions", OS);
404
405 // Generate prefix groups.
406 using PrefixKeyT = SmallVector<SmallString<2>, 2>;
407 using PrefixesT = std::map<PrefixKeyT, unsigned>;
408 PrefixesT Prefixes;
409 Prefixes.try_emplace(k: PrefixKeyT(), args: 0);
410 for (const Record &R : llvm::make_pointee_range(Range&: Opts)) {
411 std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings(FieldName: "Prefixes");
412 PrefixKeyT PrefixKey(RPrefixes.begin(), RPrefixes.end());
413 Prefixes.try_emplace(k: PrefixKey, args: 0);
414 }
415
416 // Generate sub command groups.
417 using SubCommandKeyT = SmallVector<StringRef, 2>;
418 using SubCommandIDsT = std::map<SubCommandKeyT, unsigned>;
419 SubCommandIDsT SubCommandIDs;
420
421 auto GetSubCommandIDsOffset = [&SubCommandIDs](const Record &R) {
422 SubCommandKeyT SubCommandKey;
423 for (const Record *SubCommand : R.getValueAsListOfDefs(FieldName: "SubCommands"))
424 SubCommandKey.push_back(Elt: SubCommand->getName());
425 return SubCommandIDs[SubCommandKey];
426 };
427
428 SubCommandIDs.try_emplace(k: SubCommandKeyT(), args: 0);
429 for (const Record &R : llvm::make_pointee_range(Range&: Opts)) {
430 std::vector<const Record *> RSubCommands =
431 R.getValueAsListOfDefs(FieldName: "SubCommands");
432 SubCommandKeyT SubCommandKey;
433 for (const auto &SubCommand : RSubCommands)
434 SubCommandKey.push_back(Elt: SubCommand->getName());
435 SubCommandIDs.try_emplace(k: SubCommandKey, args: 0);
436 }
437
438 llvm::StringToOffsetTable Table;
439 for (const auto &[PrefixSet, _] : Prefixes)
440 for (const auto &Prefix : PrefixSet)
441 Table.GetOrAddStringOffset(Str: Prefix);
442 for (const Record &R : llvm::make_pointee_range(Range&: Groups)) {
443 Table.GetOrAddStringOffset(Str: R.getValueAsString(FieldName: "Name"));
444 Table.GetOrAddStringOffset(Str: getHelpText(R));
445 }
446 for (const Record &R : llvm::make_pointee_range(Range&: Opts)) {
447 Table.GetOrAddStringOffset(Str: getOptionPrefixedName(R));
448 Table.GetOrAddStringOffset(Str: getHelpText(R));
449 Table.GetOrAddStringOffset(Str: getOptionalString(R, Field: "MetaVarName"));
450 Table.GetOrAddStringOffset(Str: getOptionalString(R, Field: "Values"));
451 Table.GetOrAddStringOffset(Str: getAliasArgsBlob(R));
452 for (const Record *V : R.getValueAsListOfDefs(FieldName: "HelpTextsForVariants"))
453 Table.GetOrAddStringOffset(Str: V->getValueAsString(FieldName: "Text"));
454 }
455
456 // Flags and Visibility name enumerators of the including tool. An option
457 // inherits its group's. Names are sorted so that equal masks share an
458 // InfoExtra row.
459 auto GetMask = [](const Record &R, StringRef Field) {
460 std::set<StringRef> Names;
461 for (const Init *I : *R.getValueAsListInit(FieldName: Field))
462 Names.insert(x: cast<DefInit>(Val: I)->getDef()->getName());
463 if (const DefInit *DI = dyn_cast<DefInit>(Val: R.getValueInit(FieldName: "Group")))
464 for (const Init *I : *DI->getDef()->getValueAsListInit(FieldName: Field))
465 Names.insert(x: cast<DefInit>(Val: I)->getDef()->getName());
466 std::string Mask;
467 raw_string_ostream MaskOS(Mask);
468 ListSeparator Sep(" | ");
469 for (StringRef Name : Names)
470 MaskOS << Sep << "static_cast<unsigned>(" << Name << ")";
471 return Mask.empty() ? std::string("0") : Mask;
472 };
473
474 // IDs are 1-based positions in the table, which lists groups first.
475 DenseMap<const Record *, unsigned> OptionID;
476 for (const Record &R : llvm::make_pointee_range(Range&: Groups))
477 OptionID.try_emplace(Key: &R, Args: OptionID.size() + 1);
478 for (const Record &R : llvm::make_pointee_range(Range&: Opts))
479 OptionID.try_emplace(Key: &R, Args: OptionID.size() + 1);
480 auto GetRefID = [&](const Record &R, StringRef Field) {
481 if (const DefInit *DI = dyn_cast<DefInit>(Val: R.getValueInit(FieldName: Field)))
482 return OptionID.lookup(Val: DI->getDef());
483 return 0u;
484 };
485
486 OS << "/////////\n";
487 OS << "// Tables\n\n";
488 // An OptionsStruct's definitions use the tables.
489 OS << (Structs.empty()
490 ? "#ifdef OPTTABLE_CODE\n"
491 : "#if defined(OPTTABLE_CODE) || defined(OPTIONS_STRUCT_DEFS)\n");
492 // A function rather than an object: the object needs dynamic relocations.
493 OS << "static llvm::opt::OptTable::Tables optionTables() {\n";
494 // An OptionsStruct's .cpp has no using-directive for llvm::opt.
495 if (!Structs.empty())
496 OS << " using llvm::opt::DefaultVis, llvm::opt::HelpHidden,\n"
497 " llvm::opt::RenderAsInput, llvm::opt::RenderJoined,\n"
498 " llvm::opt::RenderSeparate;\n";
499 Table.EmitStringTableDef(OS, Name: "OptionStrTable");
500 OS << "\n";
501
502 // Dump prefixes.
503 OS << " static constexpr llvm::StringTable::Offset OptionPrefixesTable[] = "
504 "{\n";
505 {
506 // Ensure the first prefix set is always empty.
507 assert(!Prefixes.empty() &&
508 "We should always emit an empty set of prefixes");
509 assert(Prefixes.begin()->first.empty() &&
510 "First prefix set should always be empty");
511 llvm::ListSeparator Sep(",\n");
512 unsigned CurIndex = 0;
513 for (auto &[Prefix, PrefixIndex] : Prefixes) {
514 // First emit the number of prefix strings in this list of prefixes.
515 OS << Sep << " " << Prefix.size() << " /* prefixes */";
516 PrefixIndex = CurIndex;
517 if (PrefixIndex > 255)
518 PrintFatalError(Msg: "too many distinct prefix sets");
519 assert((CurIndex == 0 || !Prefix.empty()) &&
520 "Only first prefix set should be empty!");
521 for (const auto &PrefixKey : Prefix)
522 OS << ", " << *Table.GetStringOffset(Str: PrefixKey) << " /* '" << PrefixKey
523 << "' */";
524 CurIndex += Prefix.size() + 1;
525 }
526 }
527 OS << "\n };\n\n";
528
529 // Dump help text variants. Each option's variants form a run ended by a zero
530 // row; offset 0 is the empty run.
531 OS << " static constexpr llvm::opt::OptTable::HelpTextVariant "
532 "OptionHelpTextVariantsTable[] = {\n";
533 DenseMap<const Record *, unsigned> HelpTextVariantsOffset;
534 unsigned NumVariantRows = 1;
535 OS << " {0, 0},\n";
536 for (const Record &R : llvm::make_pointee_range(Range&: Opts)) {
537 std::vector<const Record *> Variants =
538 R.getValueAsListOfDefs(FieldName: "HelpTextsForVariants");
539 if (Variants.empty())
540 continue;
541 HelpTextVariantsOffset[&R] = NumVariantRows;
542 NumVariantRows += Variants.size() + 1;
543 for (const Record *V : Variants) {
544 const ListInit *Vis = V->getValueAsListInit(FieldName: "Visibilities");
545 if (Vis->empty())
546 PrintFatalError(ErrorLoc: V->getLoc(), Msg: "HelpTextVariant needs a visibility");
547 OS << " {";
548 ListSeparator Sep(" | ");
549 for (const Init *I : *Vis)
550 OS << Sep << I->getAsUnquotedString();
551 OS << ", ";
552 writeStrTableOffset(OS, Table, Str: V->getValueAsString(FieldName: "Text"));
553 OS << "},\n";
554 }
555 OS << " {0, 0},\n";
556 }
557 OS << " };\n\n";
558
559 // Dump subcommands.
560 if (!SubCommands.empty()) {
561 OS << " static constexpr llvm::opt::OptTable::SubCommand "
562 "OptionSubCommands[] = {\n";
563 for (const Record *SubCommand : SubCommands) {
564 OS << " { \"" << SubCommand->getValueAsString(FieldName: "Name") << "\", ";
565 OS << "\"" << SubCommand->getValueAsString(FieldName: "HelpText") << "\", ";
566 OS << "\"" << SubCommand->getValueAsString(FieldName: "Usage") << "\" },\n";
567 }
568 OS << " };\n\n";
569 }
570
571 // Dump subcommand IDs.
572 OS << " static constexpr unsigned OptionSubCommandIDsTable[] = {\n";
573 {
574 // Ensure the first subcommand set is always empty.
575 assert(!SubCommandIDs.empty() &&
576 "We should always emit an empty set of subcommands");
577 assert(SubCommandIDs.begin()->first.empty() &&
578 "First subcommand set should always be empty");
579 llvm::ListSeparator Sep(",\n");
580 unsigned CurIndex = 0;
581 for (auto &[SubCommand, SubCommandIndex] : SubCommandIDs) {
582 // First emit the number of subcommand strings in this list of
583 // subcommands.
584 OS << Sep << " " << SubCommand.size() << " /* subcommands */";
585 SubCommandIndex = CurIndex;
586 assert((CurIndex == 0 || !SubCommand.empty()) &&
587 "Only first subcommand set should be empty!");
588 for (const auto &SubCommandKey : SubCommand) {
589 auto It = llvm::find_if(Range&: SubCommands, P: [&](const Record *R) {
590 return R->getName() == SubCommandKey;
591 });
592 assert(It != SubCommands.end() && "SubCommand not found");
593 OS << ", " << std::distance(first: SubCommands.begin(), last: It) << " /* '"
594 << SubCommandKey << "' */";
595 }
596 CurIndex += SubCommand.size() + 1;
597 }
598 }
599 OS << "\n };\n\n";
600
601 // Fields that are rarely set or take few distinct values, in
602 // OptTable::InfoExtra order. Options with equal values share a row; row 0 is
603 // all zero.
604 OS << " static constexpr llvm::opt::OptTable::InfoExtra "
605 "OptionInfoExtrasTable[] = {\n {0, 0, 0, 0, 0, 0, 0, 0},\n";
606 std::map<std::array<std::string, 8>, unsigned> ExtraRows;
607 ExtraRows.try_emplace(k: {"0", "0", "0", "0", "0", "0", "0", "0"}, args: 0);
608 DenseMap<const Record *, unsigned> ExtraOffset;
609 for (const Record &R : llvm::make_pointee_range(Range&: Opts)) {
610 int64_t NumArgs = R.getValueAsInt(FieldName: "NumArgs");
611 if (NumArgs < 0 || NumArgs > 255)
612 PrintFatalError(ErrorLoc: R.getLoc(), Msg: "NumArgs must be in [0, 255]");
613 std::array<std::string, 8> Row = {
614 utostr(X: *Table.GetStringOffset(Str: getOptionalString(R, Field: "MetaVarName"))),
615 utostr(X: *Table.GetStringOffset(Str: getAliasArgsBlob(R))),
616 utostr(X: *Table.GetStringOffset(Str: getOptionalString(R, Field: "Values"))),
617 GetMask(R, "Flags"),
618 GetMask(R, "Visibility"),
619 utostr(X: HelpTextVariantsOffset.lookup(Val: &R)),
620 utostr(X: GetSubCommandIDsOffset(R)),
621 utostr(X: NumArgs)};
622 auto [It, Inserted] = ExtraRows.try_emplace(k: Row, args: ExtraRows.size());
623 if (Inserted) {
624 OS << " {";
625 interleaveComma(c: Row, os&: OS);
626 OS << "},\n";
627 }
628 ExtraOffset[&R] = It->second;
629 }
630 OS << " };\n\n";
631
632 // Dump the option table in OptTable::Info field order.
633 OS << " static constexpr llvm::opt::OptTable::Info OptionInfoTable[] = {\n";
634 for (const Record &R : llvm::make_pointee_range(Range&: Groups)) {
635 OS << " {";
636 writeStrTableOffset(OS, Table, Str: R.getValueAsString(FieldName: "Name"),
637 /*EmitComment=*/true);
638 OS << ", ";
639 writeStrTableOffset(OS, Table, Str: getHelpText(R));
640 OS << ", " << GetRefID(R, "Group")
641 << ", 0, 0, 0, llvm::opt::Option::GroupClass},\n";
642 }
643 for (const Record &R : llvm::make_pointee_range(Range&: Opts)) {
644 OS << " {";
645 writeStrTableOffset(OS, Table, Str: getOptionPrefixedName(R),
646 /*EmitComment=*/true);
647 OS << ", ";
648 writeStrTableOffset(OS, Table, Str: getHelpText(R));
649 OS << ", " << GetRefID(R, "Group") << ", " << GetRefID(R, "Alias");
650 OS << ", " << ExtraOffset.lookup(Val: &R);
651 std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings(FieldName: "Prefixes");
652 OS << ", " << Prefixes[PrefixKeyT(RPrefixes.begin(), RPrefixes.end())];
653 OS << ", llvm::opt::Option::"
654 << R.getValueAsDef(FieldName: "Kind")->getValueAsString(FieldName: "Name") << "Class},\n";
655 }
656 OS << " };\n\n";
657
658 OS << " return {OptionStrTable, OptionPrefixesTable,\n";
659 OS << " OptionInfoTable, OptionInfoExtrasTable, "
660 "OptionHelpTextVariantsTable, "
661 << (SubCommands.empty() ? "{}" : "OptionSubCommands")
662 << ", OptionSubCommandIDsTable};\n";
663 OS << "}\n";
664 OS << "#undef OPTTABLE_CODE\n";
665 OS << (Structs.empty()
666 ? "#endif // OPTTABLE_CODE\n\n"
667 : "#endif // OPTTABLE_CODE || OPTIONS_STRUCT_DEFS\n\n");
668
669 if (!Structs.empty())
670 emitOptionsStruct(Struct: *Structs[0], Groups, Opts, OS);
671
672 // Dump ValuesCode.
673 OS << "/////////\n";
674 OS << "// ValuesCode\n\n";
675 OS << "#ifdef OPTTABLE_VALUES_CODE\n";
676 std::vector<const Record *> ValuesCodeOpts;
677 for (const Record &R : llvm::make_pointee_range(Range&: Opts)) {
678 // The option values, if any;
679 if (!isa<UnsetInit>(Val: R.getValueInit(FieldName: "ValuesCode"))) {
680 if (!isa<UnsetInit>(Val: R.getValueInit(FieldName: "Values")))
681 PrintFatalError(ErrorLoc: R.getLoc(), Msg: "cannot set both Values and ValuesCode");
682 ValuesCodeOpts.push_back(x: &R);
683 OS << "#define VALUES_CODE " << getOptionName(R) << "_Values\n";
684 OS << R.getValueAsString(FieldName: "ValuesCode") << "\n";
685 OS << "#undef VALUES_CODE\n";
686 }
687 }
688 // A function keeps these strings out of a relocated table. It names OPT_ IDs,
689 // so include this block after the option enum; a table that uses a different
690 // ID prefix cannot use ValuesCode.
691 OS << "static llvm::StringRef getOptionValuesCode(unsigned ID) {\n";
692 OS << " switch (ID) {\n";
693 for (const Record *R : ValuesCodeOpts)
694 OS << " case OPT_" << getOptionName(R: *R) << ": return " << getOptionName(R: *R)
695 << "_Values;\n";
696 OS << " }\n return {};\n}\n";
697 OS << "#undef OPTTABLE_VALUES_CODE\n";
698 OS << "#endif // OPTTABLE_VALUES_CODE\n";
699
700 OS << "/////////\n";
701 OS << "// Groups\n\n";
702 OS << "#ifdef OPTION\n";
703 for (const Record &R : llvm::make_pointee_range(Range&: Groups)) {
704 // Start a single option entry.
705 OS << "OPTION(";
706
707 // A zero prefix offset corresponds to an empty set of prefixes.
708 OS << "0 /* no prefixes */";
709
710 // The option string offset.
711 OS << ", ";
712 writeStrTableOffset(OS, Table, Str: R.getValueAsString(FieldName: "Name"),
713 /*EmitComment=*/true);
714
715 // The option identifier name.
716 OS << ", " << getOptionName(R);
717
718 // The option kind.
719 OS << ", Group";
720
721 // The containing option group (if any).
722 OS << ", ";
723 if (const DefInit *DI = dyn_cast<DefInit>(Val: R.getValueInit(FieldName: "Group")))
724 OS << getOptionName(R: *DI->getDef());
725 else
726 OS << "INVALID";
727
728 // The other option arguments (unused for groups).
729 OS << ", INVALID, 0, 0, 0, 0";
730
731 // The option help text.
732 OS << ", ";
733 writeStrTableOffset(OS, Table, Str: getHelpText(R));
734
735 // Groups have no help text variants.
736 OS << ", 0";
737
738 // The option meta-variable name (unused).
739 OS << ", 0";
740
741 // The option Values and SubCommandIDsOffset (unused for groups).
742 OS << ", 0, 0)\n";
743 }
744 OS << "\n";
745
746 OS << "//////////\n";
747 OS << "// Options\n\n";
748
749 auto WriteOptRecordFields = [&](raw_ostream &OS, const Record &R) {
750 // The option prefix;
751 std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings(FieldName: "Prefixes");
752 OS << Prefixes[PrefixKeyT(RPrefixes.begin(), RPrefixes.end())] << ", ";
753
754 // The option prefixed name.
755 writeStrTableOffset(OS, Table, Str: getOptionPrefixedName(R),
756 /*EmitComment=*/true);
757
758 // The option identifier name.
759 OS << ", " << getOptionName(R);
760
761 // The option kind.
762 OS << ", " << R.getValueAsDef(FieldName: "Kind")->getValueAsString(FieldName: "Name");
763
764 // The containing option group (if any).
765 OS << ", ";
766 if (const DefInit *DI = dyn_cast<DefInit>(Val: R.getValueInit(FieldName: "Group")))
767 OS << getOptionName(R: *DI->getDef());
768 else
769 OS << "INVALID";
770
771 // The option alias (if any).
772 OS << ", ";
773 if (const DefInit *DI = dyn_cast<DefInit>(Val: R.getValueInit(FieldName: "Alias")))
774 OS << getOptionName(R: *DI->getDef());
775 else
776 OS << "INVALID";
777
778 // The option alias arguments (if any).
779 OS << ", ";
780 writeStrTableOffset(OS, Table, Str: getAliasArgsBlob(R));
781
782 // "Flags" for the option, such as HelpHidden and Render*
783 OS << ", " << GetMask(R, "Flags");
784
785 // Option visibility, for sharing options between drivers.
786 OS << ", " << GetMask(R, "Visibility");
787
788 // The option parameter field.
789 OS << ", " << R.getValueAsInt(FieldName: "NumArgs");
790
791 // The option help text.
792 OS << ", ";
793 writeStrTableOffset(OS, Table, Str: getHelpText(R));
794
795 // The option help text variants.
796 OS << ", " << HelpTextVariantsOffset.lookup(Val: &R);
797
798 // The option meta-variable name.
799 OS << ", ";
800 writeStrTableOffset(OS, Table, Str: getOptionalString(R, Field: "MetaVarName"));
801
802 // The option Values. Used for shell autocompletion.
803 OS << ", ";
804 writeStrTableOffset(OS, Table, Str: getOptionalString(R, Field: "Values"));
805
806 // The option SubCommandIDsOffset.
807 OS << ", " << GetSubCommandIDsOffset(R);
808 };
809
810 auto IsMarshallingOption = [](const Record &R) {
811 return !isa<UnsetInit>(Val: R.getValueInit(FieldName: "KeyPath")) &&
812 !R.getValueAsString(FieldName: "KeyPath").empty();
813 };
814
815 std::vector<const Record *> OptsWithMarshalling;
816 for (const Record &R : llvm::make_pointee_range(Range&: Opts)) {
817 // Start a single option entry.
818 OS << "OPTION(";
819 WriteOptRecordFields(OS, R);
820 OS << ")\n";
821 if (IsMarshallingOption(R))
822 OptsWithMarshalling.push_back(x: &R);
823 }
824 OS << "#endif // OPTION\n";
825
826 auto CmpMarshallingOpts = [](const Record *const *A, const Record *const *B) {
827 unsigned AID = (*A)->getID();
828 unsigned BID = (*B)->getID();
829
830 if (AID < BID)
831 return -1;
832 if (AID > BID)
833 return 1;
834 return 0;
835 };
836 // The RecordKeeper stores records (options) in lexicographical order, and we
837 // have reordered the options again when generating prefix groups. We need to
838 // restore the original definition order of options with marshalling to honor
839 // the topology of the dependency graph implied by `DefaultAnyOf`.
840 array_pod_sort(Start: OptsWithMarshalling.begin(), End: OptsWithMarshalling.end(),
841 Compare: CmpMarshallingOpts);
842
843 std::vector<MarshallingInfo> MarshallingInfos;
844 MarshallingInfos.reserve(n: OptsWithMarshalling.size());
845 for (const auto *R : OptsWithMarshalling)
846 MarshallingInfos.push_back(x: createMarshallingInfo(R: *R));
847
848 for (const auto &MI : MarshallingInfos) {
849 OS << "#ifdef " << MI.getMacroName() << "\n";
850 OS << MI.getMacroName() << "(";
851 WriteOptRecordFields(OS, MI.R);
852 OS << ", ";
853 MI.emit(OS);
854 OS << ")\n";
855 OS << "#endif // " << MI.getMacroName() << "\n";
856 }
857
858 OS << "\n";
859 OS << "#ifdef SIMPLE_ENUM_VALUE_TABLE";
860 OS << "\n";
861 OS << MarshallingInfo::ValueTablePreamble;
862 std::vector<StringRef> ValueTableNames;
863 for (const auto &MI : MarshallingInfos)
864 if (auto MaybeValueTableName = MI.emitValueTable(OS))
865 ValueTableNames.push_back(x: *MaybeValueTableName);
866
867 OS << MarshallingInfo::ValueTablesDecl << "{";
868 for (auto ValueTableName : ValueTableNames)
869 OS << "{" << ValueTableName << ", std::size(" << ValueTableName << ")},\n";
870 OS << "};\n";
871 OS << "static const unsigned SimpleEnumValueTablesSize = "
872 "std::size(SimpleEnumValueTables);\n";
873
874 OS << "#endif // SIMPLE_ENUM_VALUE_TABLE\n";
875}
876
877static TableGen::Emitter::Opt X("gen-opt-parser-defs", emitOptionParser,
878 "Generate option definitions");
879