xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/OptParserEmitter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
getOptionName(const Record & R)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 
write_cstring(raw_ostream & OS,llvm::StringRef Str)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 
getOptionPrefixedName(const Record & R)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 
MarshallingInfo(const Record & R)85   MarshallingInfo(const Record &R) : R(R) {}
86 
getMacroName() const87   std::string getMacroName() const {
88     return (MacroPrefix + MarshallingInfo::MacroName).str();
89   }
90 
emit(raw_ostream & OS) const91   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 
emitValueTable(raw_ostream & OS) const115   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:
emitScopedNormalizedValue(raw_ostream & OS,StringRef NormalizedValue) const132   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 
createMarshallingInfo(const Record & R)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 
EmitHelpTextsForVariants(raw_ostream & OS,std::vector<std::pair<std::vector<std::string>,StringRef>> HelpTextsForVariants)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.
EmitOptParser(RecordKeeper & Records,raw_ostream & OS)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