Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/OptParserEmitter.cpp
35258 views
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
20
using namespace llvm;
21
22
static std::string getOptionName(const Record &R) {
23
// Use the record name unless EnumName is defined.
24
if (isa<UnsetInit>(R.getValueInit("EnumName")))
25
return std::string(R.getName());
26
27
return std::string(R.getValueAsString("EnumName"));
28
}
29
30
static raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) {
31
OS << '"';
32
OS.write_escaped(Str);
33
OS << '"';
34
return OS;
35
}
36
37
static std::string getOptionPrefixedName(const Record &R) {
38
std::vector<StringRef> Prefixes = R.getValueAsListOfStrings("Prefixes");
39
StringRef Name = R.getValueAsString("Name");
40
41
if (Prefixes.empty())
42
return Name.str();
43
44
return (Prefixes[0] + Twine(Name)).str();
45
}
46
47
class MarshallingInfo {
48
public:
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"(
71
struct SimpleEnumValue {
72
const char *Name;
73
unsigned Value;
74
};
75
76
struct 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, DefaultValue);
99
OS << ", ";
100
OS << ImpliedCheck;
101
OS << ", ";
102
emitScopedNormalizedValue(OS, 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, Values[I]);
122
OS << ",";
123
OS << "static_cast<unsigned>(";
124
emitScopedNormalizedValue(OS, NormalizedValues[I]);
125
OS << ")},";
126
}
127
OS << "};\n";
128
return StringRef(ValueTableName);
129
}
130
131
private:
132
void emitScopedNormalizedValue(raw_ostream &OS,
133
StringRef NormalizedValue) const {
134
if (!NormalizedValuesScope.empty())
135
OS << NormalizedValuesScope << "::";
136
OS << NormalizedValue;
137
}
138
};
139
140
size_t MarshallingInfo::NextTableIndex = 0;
141
142
static 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("ShouldAlwaysEmit");
152
Ret.MacroPrefix = R.getValueAsString("MacroPrefix");
153
Ret.KeyPath = R.getValueAsString("KeyPath");
154
Ret.DefaultValue = R.getValueAsString("DefaultValue");
155
Ret.NormalizedValuesScope = R.getValueAsString("NormalizedValuesScope");
156
Ret.ImpliedCheck = R.getValueAsString("ImpliedCheck");
157
Ret.ImpliedValue =
158
R.getValueAsOptionalString("ImpliedValue").value_or(Ret.DefaultValue);
159
160
Ret.ShouldParse = R.getValueAsString("ShouldParse");
161
Ret.Normalizer = R.getValueAsString("Normalizer");
162
Ret.Denormalizer = R.getValueAsString("Denormalizer");
163
Ret.ValueMerger = R.getValueAsString("ValueMerger");
164
Ret.ValueExtractor = R.getValueAsString("ValueExtractor");
165
166
if (!isa<UnsetInit>(R.getValueInit("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("NormalizedValues");
171
Ret.Values.reserve(Ret.NormalizedValues.size());
172
Ret.ValueTableName = getOptionName(R) + "ValueTable";
173
174
StringRef ValuesStr = R.getValueAsString("Values");
175
for (;;) {
176
size_t Idx = ValuesStr.find(',');
177
if (Idx == StringRef::npos)
178
break;
179
if (Idx > 0)
180
Ret.Values.push_back(ValuesStr.slice(0, Idx));
181
ValuesStr = ValuesStr.slice(Idx + 1, StringRef::npos);
182
}
183
if (!ValuesStr.empty())
184
Ret.Values.push_back(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
194
static 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("0");
209
210
while (HelpTextsForVariants.size() < MaxVisibilityHelp)
211
HelpTextsForVariants.push_back(
212
{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(Visibility) != VisibilityEnd)
233
OS << ", ";
234
}
235
236
OS << "}}, ";
237
238
if (Help.size())
239
write_cstring(OS, Help);
240
else
241
OS << "nullptr";
242
OS << ")";
243
244
if (std::next(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.
253
static void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
254
// Get the option groups and options.
255
const std::vector<Record *> &Groups =
256
Records.getAllDerivedDefinitions("OptionGroup");
257
std::vector<Record *> Opts = Records.getAllDerivedDefinitions("Option");
258
259
emitSourceFileHeader("Option Parsing Definitions", OS);
260
261
array_pod_sort(Opts.begin(), Opts.end(), 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(std::pair(PrefixKeyT(), "prefix_0"));
267
unsigned CurPrefix = 0;
268
for (const Record &R : llvm::make_pointee_range(Opts)) {
269
std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings("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(std::pair(PrefixKey, Prefix)).second)
274
CurPrefix = NewPrefix;
275
}
276
277
DenseSet<StringRef> PrefixesUnionSet;
278
for (const auto &Prefix : Prefixes)
279
PrefixesUnionSet.insert(Prefix.first.begin(), Prefix.first.end());
280
SmallVector<StringRef> PrefixesUnion(PrefixesUnionSet.begin(),
281
PrefixesUnionSet.end());
282
array_pod_sort(PrefixesUnion.begin(), 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(Opts)) {
323
// The option values, if any;
324
if (!isa<UnsetInit>(R.getValueInit("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("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(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("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>(R.getValueInit("Group")))
356
OS << getOptionName(*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>(R.getValueInit("HelpText"))) {
365
OS << ",\n";
366
OS << " ";
367
write_cstring(OS, R.getValueAsString("HelpText"));
368
} else
369
OS << ", nullptr";
370
371
// Not using Visibility specific text for group help.
372
EmitHelpTextsForVariants(OS, {});
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("Prefixes");
388
OS << Prefixes[PrefixKeyT(RPrefixes.begin(), RPrefixes.end())] << ", ";
389
390
// The option prefixed name.
391
write_cstring(OS, getOptionPrefixedName(R));
392
393
// The option identifier name.
394
OS << ", " << getOptionName(R);
395
396
// The option kind.
397
OS << ", " << R.getValueAsDef("Kind")->getValueAsString("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>(R.getValueInit("Group"))) {
404
GroupFlags = DI->getDef()->getValueAsListInit("Flags");
405
GroupVis = DI->getDef()->getValueAsListInit("Visibility");
406
OS << getOptionName(*DI->getDef());
407
} else
408
OS << "INVALID";
409
410
// The option alias (if any).
411
OS << ", ";
412
if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Alias")))
413
OS << getOptionName(*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("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("Flags");
436
for (Init *I : *LI)
437
OS << (NumFlags++ ? " | " : "") << cast<DefInit>(I)->getDef()->getName();
438
if (GroupFlags) {
439
for (Init *I : *GroupFlags)
440
OS << (NumFlags++ ? " | " : "")
441
<< cast<DefInit>(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("Visibility");
450
for (Init *I : *LI)
451
OS << (NumVisFlags++ ? " | " : "")
452
<< cast<DefInit>(I)->getDef()->getName();
453
if (GroupVis) {
454
for (Init *I : *GroupVis)
455
OS << (NumVisFlags++ ? " | " : "")
456
<< cast<DefInit>(I)->getDef()->getName();
457
}
458
if (NumVisFlags == 0)
459
OS << '0';
460
461
// The option parameter field.
462
OS << ", " << R.getValueAsInt("NumArgs");
463
464
// The option help text.
465
if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
466
OS << ",\n";
467
OS << " ";
468
write_cstring(OS, R.getValueAsString("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("HelpTextsForVariants")) {
476
ArrayRef<Init *> Visibilities =
477
VisibilityHelp->getValueAsListInit("Visibilities")->getValues();
478
479
std::vector<std::string> VisibilityNames;
480
for (Init *Visibility : Visibilities)
481
VisibilityNames.push_back(Visibility->getAsUnquotedString());
482
483
HelpTextsForVariants.push_back(std::make_pair(
484
VisibilityNames, VisibilityHelp->getValueAsString("Text")));
485
}
486
EmitHelpTextsForVariants(OS, HelpTextsForVariants);
487
488
// The option meta-variable name.
489
OS << ", ";
490
if (!isa<UnsetInit>(R.getValueInit("MetaVarName")))
491
write_cstring(OS, R.getValueAsString("MetaVarName"));
492
else
493
OS << "nullptr";
494
495
// The option Values. Used for shell autocompletion.
496
OS << ", ";
497
if (!isa<UnsetInit>(R.getValueInit("Values")))
498
write_cstring(OS, R.getValueAsString("Values"));
499
else if (!isa<UnsetInit>(R.getValueInit("ValuesCode"))) {
500
OS << getOptionName(R) << "_Values";
501
} else
502
OS << "nullptr";
503
};
504
505
auto IsMarshallingOption = [](const Record &R) {
506
return !isa<UnsetInit>(R.getValueInit("KeyPath")) &&
507
!R.getValueAsString("KeyPath").empty();
508
};
509
510
std::vector<const Record *> OptsWithMarshalling;
511
for (const Record &R : llvm::make_pointee_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(&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(OptsWithMarshalling.begin(), OptsWithMarshalling.end(),
536
CmpMarshallingOpts);
537
538
std::vector<MarshallingInfo> MarshallingInfos;
539
MarshallingInfos.reserve(OptsWithMarshalling.size());
540
for (const auto *R : OptsWithMarshalling)
541
MarshallingInfos.push_back(createMarshallingInfo(*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(*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
575
static TableGen::Emitter::Opt X("gen-opt-parser-defs", EmitOptParser,
576
"Generate option definitions");
577
578