xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/OptParserEmitter.cpp (revision 95eb4b873b6a8b527c5bd78d7191975dfca38998)
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 "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 /// OptParserEmitter - This tablegen backend takes an input .td file
195 /// describing a list of options and emits a data structure for parsing and
196 /// working with those options when given an input command line.
197 static void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
198   // Get the option groups and options.
199   const std::vector<Record*> &Groups =
200     Records.getAllDerivedDefinitions("OptionGroup");
201   std::vector<Record*> Opts = Records.getAllDerivedDefinitions("Option");
202 
203   emitSourceFileHeader("Option Parsing Definitions", OS);
204 
205   array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords);
206   // Generate prefix groups.
207   typedef SmallVector<SmallString<2>, 2> PrefixKeyT;
208   typedef std::map<PrefixKeyT, std::string> PrefixesT;
209   PrefixesT Prefixes;
210   Prefixes.insert(std::make_pair(PrefixKeyT(), "prefix_0"));
211   unsigned CurPrefix = 0;
212   for (const Record &R : llvm::make_pointee_range(Opts)) {
213     std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings("Prefixes");
214     PrefixKeyT PrefixKey(RPrefixes.begin(), RPrefixes.end());
215     unsigned NewPrefix = CurPrefix + 1;
216     std::string Prefix = (Twine("prefix_") + Twine(NewPrefix)).str();
217     if (Prefixes.insert(std::make_pair(PrefixKey, Prefix)).second)
218       CurPrefix = NewPrefix;
219   }
220 
221   DenseSet<StringRef> PrefixesUnionSet;
222   for (const auto &Prefix : Prefixes)
223     PrefixesUnionSet.insert(Prefix.first.begin(), Prefix.first.end());
224   SmallVector<StringRef> PrefixesUnion(PrefixesUnionSet.begin(),
225                                        PrefixesUnionSet.end());
226   array_pod_sort(PrefixesUnion.begin(), PrefixesUnion.end());
227 
228   // Dump prefixes.
229   OS << "/////////\n";
230   OS << "// Prefixes\n\n";
231   OS << "#ifdef PREFIX\n";
232   OS << "#define COMMA ,\n";
233   for (const auto &Prefix : Prefixes) {
234     OS << "PREFIX(";
235 
236     // Prefix name.
237     OS << Prefix.second;
238 
239     // Prefix values.
240     OS << ", {";
241     for (const auto &PrefixKey : Prefix.first)
242       OS << "llvm::StringLiteral(\"" << PrefixKey << "\") COMMA ";
243     // Append an empty element to avoid ending up with an empty array.
244     OS << "llvm::StringLiteral(\"\")})\n";
245   }
246   OS << "#undef COMMA\n";
247   OS << "#endif // PREFIX\n\n";
248 
249   // Dump prefix unions.
250   OS << "/////////\n";
251   OS << "// Prefix Union\n\n";
252   OS << "#ifdef PREFIX_UNION\n";
253   OS << "#define COMMA ,\n";
254   OS << "PREFIX_UNION({\n";
255   for (const auto &Prefix : PrefixesUnion) {
256     OS << "llvm::StringLiteral(\"" << Prefix << "\") COMMA ";
257   }
258   OS << "llvm::StringLiteral(\"\")})\n";
259   OS << "#undef COMMA\n";
260   OS << "#endif // PREFIX_UNION\n\n";
261 
262   // Dump groups.
263   OS << "/////////\n";
264   OS << "// ValuesCode\n\n";
265   OS << "#ifdef OPTTABLE_VALUES_CODE\n";
266   for (const Record &R : llvm::make_pointee_range(Opts)) {
267     // The option values, if any;
268     if (!isa<UnsetInit>(R.getValueInit("ValuesCode"))) {
269       assert(isa<UnsetInit>(R.getValueInit("Values")) &&
270              "Cannot choose between Values and ValuesCode");
271       OS << "#define VALUES_CODE " << getOptionName(R) << "_Values\n";
272       OS << R.getValueAsString("ValuesCode") << "\n";
273       OS << "#undef VALUES_CODE\n";
274     }
275   }
276   OS << "#endif\n";
277 
278   OS << "/////////\n";
279   OS << "// Groups\n\n";
280   OS << "#ifdef OPTION\n";
281   for (const Record &R : llvm::make_pointee_range(Groups)) {
282     // Start a single option entry.
283     OS << "OPTION(";
284 
285     // The option prefix;
286     OS << "llvm::ArrayRef<llvm::StringLiteral>()";
287 
288     // The option string.
289     OS << ", \"" << R.getValueAsString("Name") << '"';
290 
291     // The option identifier name.
292     OS << ", " << getOptionName(R);
293 
294     // The option kind.
295     OS << ", Group";
296 
297     // The containing option group (if any).
298     OS << ", ";
299     if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
300       OS << getOptionName(*DI->getDef());
301     else
302       OS << "INVALID";
303 
304     // The other option arguments (unused for groups).
305     OS << ", INVALID, nullptr, 0, 0, 0";
306 
307     // The option help text.
308     if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
309       OS << ",\n";
310       OS << "       ";
311       write_cstring(OS, R.getValueAsString("HelpText"));
312     } else
313       OS << ", nullptr";
314 
315     // The option meta-variable name (unused).
316     OS << ", nullptr";
317 
318     // The option Values (unused for groups).
319     OS << ", nullptr)\n";
320   }
321   OS << "\n";
322 
323   OS << "//////////\n";
324   OS << "// Options\n\n";
325 
326   auto WriteOptRecordFields = [&](raw_ostream &OS, const Record &R) {
327     // The option prefix;
328     std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings("Prefixes");
329     OS << Prefixes[PrefixKeyT(RPrefixes.begin(), RPrefixes.end())] << ", ";
330 
331     // The option prefixed name.
332     write_cstring(OS, getOptionPrefixedName(R));
333 
334     // The option identifier name.
335     OS << ", " << getOptionName(R);
336 
337     // The option kind.
338     OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name");
339 
340     // The containing option group (if any).
341     OS << ", ";
342     const ListInit *GroupFlags = nullptr;
343     const ListInit *GroupVis = nullptr;
344     if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
345       GroupFlags = DI->getDef()->getValueAsListInit("Flags");
346       GroupVis = DI->getDef()->getValueAsListInit("Visibility");
347       OS << getOptionName(*DI->getDef());
348     } else
349       OS << "INVALID";
350 
351     // The option alias (if any).
352     OS << ", ";
353     if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Alias")))
354       OS << getOptionName(*DI->getDef());
355     else
356       OS << "INVALID";
357 
358     // The option alias arguments (if any).
359     // Emitted as a \0 separated list in a string, e.g. ["foo", "bar"]
360     // would become "foo\0bar\0". Note that the compiler adds an implicit
361     // terminating \0 at the end.
362     OS << ", ";
363     std::vector<StringRef> AliasArgs = R.getValueAsListOfStrings("AliasArgs");
364     if (AliasArgs.size() == 0) {
365       OS << "nullptr";
366     } else {
367       OS << "\"";
368       for (StringRef AliasArg : AliasArgs)
369         OS << AliasArg << "\\0";
370       OS << "\"";
371     }
372 
373     // "Flags" for the option, such as HelpHidden and Render*
374     OS << ", ";
375     int NumFlags = 0;
376     const ListInit *LI = R.getValueAsListInit("Flags");
377     for (Init *I : *LI)
378       OS << (NumFlags++ ? " | " : "") << cast<DefInit>(I)->getDef()->getName();
379     if (GroupFlags) {
380       for (Init *I : *GroupFlags)
381         OS << (NumFlags++ ? " | " : "")
382            << cast<DefInit>(I)->getDef()->getName();
383     }
384     if (NumFlags == 0)
385       OS << '0';
386 
387     // Option visibility, for sharing options between drivers.
388     OS << ", ";
389     int NumVisFlags = 0;
390     LI = R.getValueAsListInit("Visibility");
391     for (Init *I : *LI)
392       OS << (NumVisFlags++ ? " | " : "")
393          << cast<DefInit>(I)->getDef()->getName();
394     if (GroupVis) {
395       for (Init *I : *GroupVis)
396         OS << (NumVisFlags++ ? " | " : "")
397            << cast<DefInit>(I)->getDef()->getName();
398     }
399     if (NumVisFlags == 0)
400       OS << '0';
401 
402     // The option parameter field.
403     OS << ", " << R.getValueAsInt("NumArgs");
404 
405     // The option help text.
406     if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
407       OS << ",\n";
408       OS << "       ";
409       write_cstring(OS, R.getValueAsString("HelpText"));
410     } else
411       OS << ", nullptr";
412 
413     // The option meta-variable name.
414     OS << ", ";
415     if (!isa<UnsetInit>(R.getValueInit("MetaVarName")))
416       write_cstring(OS, R.getValueAsString("MetaVarName"));
417     else
418       OS << "nullptr";
419 
420     // The option Values. Used for shell autocompletion.
421     OS << ", ";
422     if (!isa<UnsetInit>(R.getValueInit("Values")))
423       write_cstring(OS, R.getValueAsString("Values"));
424     else if (!isa<UnsetInit>(R.getValueInit("ValuesCode"))) {
425       OS << getOptionName(R) << "_Values";
426     }
427     else
428       OS << "nullptr";
429   };
430 
431   auto IsMarshallingOption = [](const Record &R) {
432     return !isa<UnsetInit>(R.getValueInit("KeyPath")) &&
433            !R.getValueAsString("KeyPath").empty();
434   };
435 
436   std::vector<const Record *> OptsWithMarshalling;
437   for (const Record &R : llvm::make_pointee_range(Opts)) {
438     // Start a single option entry.
439     OS << "OPTION(";
440     WriteOptRecordFields(OS, R);
441     OS << ")\n";
442     if (IsMarshallingOption(R))
443       OptsWithMarshalling.push_back(&R);
444   }
445   OS << "#endif // OPTION\n";
446 
447   auto CmpMarshallingOpts = [](const Record *const *A, const Record *const *B) {
448     unsigned AID = (*A)->getID();
449     unsigned BID = (*B)->getID();
450 
451     if (AID < BID)
452       return -1;
453     if (AID > BID)
454       return 1;
455     return 0;
456   };
457   // The RecordKeeper stores records (options) in lexicographical order, and we
458   // have reordered the options again when generating prefix groups. We need to
459   // restore the original definition order of options with marshalling to honor
460   // the topology of the dependency graph implied by `DefaultAnyOf`.
461   array_pod_sort(OptsWithMarshalling.begin(), OptsWithMarshalling.end(),
462                  CmpMarshallingOpts);
463 
464   std::vector<MarshallingInfo> MarshallingInfos;
465   MarshallingInfos.reserve(OptsWithMarshalling.size());
466   for (const auto *R : OptsWithMarshalling)
467     MarshallingInfos.push_back(createMarshallingInfo(*R));
468 
469   for (const auto &MI : MarshallingInfos) {
470     OS << "#ifdef " << MI.getMacroName() << "\n";
471     OS << MI.getMacroName() << "(";
472     WriteOptRecordFields(OS, MI.R);
473     OS << ", ";
474     MI.emit(OS);
475     OS << ")\n";
476     OS << "#endif // " << MI.getMacroName() << "\n";
477   }
478 
479   OS << "\n";
480   OS << "#ifdef SIMPLE_ENUM_VALUE_TABLE";
481   OS << "\n";
482   OS << MarshallingInfo::ValueTablePreamble;
483   std::vector<StringRef> ValueTableNames;
484   for (const auto &MI : MarshallingInfos)
485     if (auto MaybeValueTableName = MI.emitValueTable(OS))
486       ValueTableNames.push_back(*MaybeValueTableName);
487 
488   OS << MarshallingInfo::ValueTablesDecl << "{";
489   for (auto ValueTableName : ValueTableNames)
490     OS << "{" << ValueTableName << ", std::size(" << ValueTableName << ")},\n";
491   OS << "};\n";
492   OS << "static const unsigned SimpleEnumValueTablesSize = "
493         "std::size(SimpleEnumValueTables);\n";
494 
495   OS << "#endif // SIMPLE_ENUM_VALUE_TABLE\n";
496   OS << "\n";
497 
498   OS << "\n";
499 }
500 
501 static TableGen::Emitter::Opt X("gen-opt-parser-defs", EmitOptParser,
502                                 "Generate option definitions");
503