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