xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/OptParserEmitter.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
10b57cec5SDimitry Andric //===- OptParserEmitter.cpp - Table Driven Command Line Parsing -----------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
9480093f4SDimitry Andric #include "OptEmitter.h"
100b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
110b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
120b57cec5SDimitry Andric #include "llvm/ADT/Twine.h"
135ffd83dbSDimitry Andric #include "llvm/Support/raw_ostream.h"
140b57cec5SDimitry Andric #include "llvm/TableGen/Record.h"
150b57cec5SDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
160b57cec5SDimitry Andric #include <cctype>
170b57cec5SDimitry Andric #include <cstring>
180b57cec5SDimitry Andric #include <map>
195ffd83dbSDimitry Andric #include <memory>
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric using namespace llvm;
220b57cec5SDimitry Andric 
23e8d8bef9SDimitry Andric static std::string getOptionName(const Record &R) {
240b57cec5SDimitry Andric   // Use the record name unless EnumName is defined.
250b57cec5SDimitry Andric   if (isa<UnsetInit>(R.getValueInit("EnumName")))
265ffd83dbSDimitry Andric     return std::string(R.getName());
270b57cec5SDimitry Andric 
285ffd83dbSDimitry Andric   return std::string(R.getValueAsString("EnumName"));
290b57cec5SDimitry Andric }
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric static raw_ostream &write_cstring(raw_ostream &OS, llvm::StringRef Str) {
320b57cec5SDimitry Andric   OS << '"';
330b57cec5SDimitry Andric   OS.write_escaped(Str);
340b57cec5SDimitry Andric   OS << '"';
350b57cec5SDimitry Andric   return OS;
360b57cec5SDimitry Andric }
370b57cec5SDimitry Andric 
38e8d8bef9SDimitry Andric static std::string getOptionSpelling(const Record &R, size_t &PrefixLength) {
395ffd83dbSDimitry Andric   std::vector<StringRef> Prefixes = R.getValueAsListOfStrings("Prefixes");
405ffd83dbSDimitry Andric   StringRef Name = R.getValueAsString("Name");
41e8d8bef9SDimitry Andric 
425ffd83dbSDimitry Andric   if (Prefixes.empty()) {
435ffd83dbSDimitry Andric     PrefixLength = 0;
445ffd83dbSDimitry Andric     return Name.str();
455ffd83dbSDimitry Andric   }
46e8d8bef9SDimitry Andric 
475ffd83dbSDimitry Andric   PrefixLength = Prefixes[0].size();
485ffd83dbSDimitry Andric   return (Twine(Prefixes[0]) + Twine(Name)).str();
495ffd83dbSDimitry Andric }
505ffd83dbSDimitry Andric 
51e8d8bef9SDimitry Andric static std::string getOptionSpelling(const Record &R) {
525ffd83dbSDimitry Andric   size_t PrefixLength;
535ffd83dbSDimitry Andric   return getOptionSpelling(R, PrefixLength);
545ffd83dbSDimitry Andric }
555ffd83dbSDimitry Andric 
565ffd83dbSDimitry Andric static void emitNameUsingSpelling(raw_ostream &OS, const Record &R) {
575ffd83dbSDimitry Andric   size_t PrefixLength;
585ffd83dbSDimitry Andric   OS << "&";
595ffd83dbSDimitry Andric   write_cstring(OS, StringRef(getOptionSpelling(R, PrefixLength)));
605ffd83dbSDimitry Andric   OS << "[" << PrefixLength << "]";
615ffd83dbSDimitry Andric }
625ffd83dbSDimitry Andric 
63e8d8bef9SDimitry Andric class MarshallingInfo {
645ffd83dbSDimitry Andric public:
65e8d8bef9SDimitry Andric   static constexpr const char *MacroName = "OPTION_WITH_MARSHALLING";
665ffd83dbSDimitry Andric   const Record &R;
675ffd83dbSDimitry Andric   bool ShouldAlwaysEmit;
68e8d8bef9SDimitry Andric   StringRef MacroPrefix;
695ffd83dbSDimitry Andric   StringRef KeyPath;
705ffd83dbSDimitry Andric   StringRef DefaultValue;
715ffd83dbSDimitry Andric   StringRef NormalizedValuesScope;
72e8d8bef9SDimitry Andric   StringRef ImpliedCheck;
73e8d8bef9SDimitry Andric   StringRef ImpliedValue;
74e8d8bef9SDimitry Andric   StringRef ShouldParse;
755ffd83dbSDimitry Andric   StringRef Normalizer;
765ffd83dbSDimitry Andric   StringRef Denormalizer;
77e8d8bef9SDimitry Andric   StringRef ValueMerger;
78e8d8bef9SDimitry Andric   StringRef ValueExtractor;
795ffd83dbSDimitry Andric   int TableIndex = -1;
805ffd83dbSDimitry Andric   std::vector<StringRef> Values;
815ffd83dbSDimitry Andric   std::vector<StringRef> NormalizedValues;
825ffd83dbSDimitry Andric   std::string ValueTableName;
835ffd83dbSDimitry Andric 
84e8d8bef9SDimitry Andric   static size_t NextTableIndex;
85e8d8bef9SDimitry Andric 
865ffd83dbSDimitry Andric   static constexpr const char *ValueTablePreamble = R"(
875ffd83dbSDimitry Andric struct SimpleEnumValue {
885ffd83dbSDimitry Andric   const char *Name;
895ffd83dbSDimitry Andric   unsigned Value;
905ffd83dbSDimitry Andric };
915ffd83dbSDimitry Andric 
925ffd83dbSDimitry Andric struct SimpleEnumValueTable {
935ffd83dbSDimitry Andric   const SimpleEnumValue *Table;
945ffd83dbSDimitry Andric   unsigned Size;
955ffd83dbSDimitry Andric };
965ffd83dbSDimitry Andric )";
975ffd83dbSDimitry Andric 
985ffd83dbSDimitry Andric   static constexpr const char *ValueTablesDecl =
995ffd83dbSDimitry Andric       "static const SimpleEnumValueTable SimpleEnumValueTables[] = ";
1005ffd83dbSDimitry Andric 
101e8d8bef9SDimitry Andric   MarshallingInfo(const Record &R) : R(R) {}
102e8d8bef9SDimitry Andric 
103e8d8bef9SDimitry Andric   std::string getMacroName() const {
104e8d8bef9SDimitry Andric     return (MacroPrefix + MarshallingInfo::MacroName).str();
105e8d8bef9SDimitry Andric   }
106e8d8bef9SDimitry Andric 
107e8d8bef9SDimitry Andric   void emit(raw_ostream &OS) const {
108e8d8bef9SDimitry Andric     write_cstring(OS, StringRef(getOptionSpelling(R)));
109e8d8bef9SDimitry Andric     OS << ", ";
110e8d8bef9SDimitry Andric     OS << ShouldParse;
111e8d8bef9SDimitry Andric     OS << ", ";
112e8d8bef9SDimitry Andric     OS << ShouldAlwaysEmit;
113e8d8bef9SDimitry Andric     OS << ", ";
114e8d8bef9SDimitry Andric     OS << KeyPath;
115e8d8bef9SDimitry Andric     OS << ", ";
116e8d8bef9SDimitry Andric     emitScopedNormalizedValue(OS, DefaultValue);
117e8d8bef9SDimitry Andric     OS << ", ";
118e8d8bef9SDimitry Andric     OS << ImpliedCheck;
119e8d8bef9SDimitry Andric     OS << ", ";
120e8d8bef9SDimitry Andric     emitScopedNormalizedValue(OS, ImpliedValue);
1215ffd83dbSDimitry Andric     OS << ", ";
1225ffd83dbSDimitry Andric     OS << Normalizer;
1235ffd83dbSDimitry Andric     OS << ", ";
1245ffd83dbSDimitry Andric     OS << Denormalizer;
1255ffd83dbSDimitry Andric     OS << ", ";
126e8d8bef9SDimitry Andric     OS << ValueMerger;
127e8d8bef9SDimitry Andric     OS << ", ";
128e8d8bef9SDimitry Andric     OS << ValueExtractor;
129e8d8bef9SDimitry Andric     OS << ", ";
1305ffd83dbSDimitry Andric     OS << TableIndex;
1315ffd83dbSDimitry Andric   }
1325ffd83dbSDimitry Andric 
133e8d8bef9SDimitry Andric   Optional<StringRef> emitValueTable(raw_ostream &OS) const {
1345ffd83dbSDimitry Andric     if (TableIndex == -1)
1355ffd83dbSDimitry Andric       return {};
1365ffd83dbSDimitry Andric     OS << "static const SimpleEnumValue " << ValueTableName << "[] = {\n";
1375ffd83dbSDimitry Andric     for (unsigned I = 0, E = Values.size(); I != E; ++I) {
1385ffd83dbSDimitry Andric       OS << "{";
1395ffd83dbSDimitry Andric       write_cstring(OS, Values[I]);
1405ffd83dbSDimitry Andric       OS << ",";
1415ffd83dbSDimitry Andric       OS << "static_cast<unsigned>(";
1425ffd83dbSDimitry Andric       emitScopedNormalizedValue(OS, NormalizedValues[I]);
1435ffd83dbSDimitry Andric       OS << ")},";
1445ffd83dbSDimitry Andric     }
1455ffd83dbSDimitry Andric     OS << "};\n";
1465ffd83dbSDimitry Andric     return StringRef(ValueTableName);
1475ffd83dbSDimitry Andric   }
1485ffd83dbSDimitry Andric 
149e8d8bef9SDimitry Andric private:
150e8d8bef9SDimitry Andric   void emitScopedNormalizedValue(raw_ostream &OS,
151e8d8bef9SDimitry Andric                                  StringRef NormalizedValue) const {
152e8d8bef9SDimitry Andric     if (!NormalizedValuesScope.empty())
153e8d8bef9SDimitry Andric       OS << NormalizedValuesScope << "::";
154e8d8bef9SDimitry Andric     OS << NormalizedValue;
155e8d8bef9SDimitry Andric   }
156e8d8bef9SDimitry Andric };
1575ffd83dbSDimitry Andric 
158e8d8bef9SDimitry Andric size_t MarshallingInfo::NextTableIndex = 0;
1595ffd83dbSDimitry Andric 
160e8d8bef9SDimitry Andric static MarshallingInfo createMarshallingInfo(const Record &R) {
161e8d8bef9SDimitry Andric   assert(!isa<UnsetInit>(R.getValueInit("KeyPath")) &&
162e8d8bef9SDimitry Andric          !isa<UnsetInit>(R.getValueInit("DefaultValue")) &&
163e8d8bef9SDimitry Andric          !isa<UnsetInit>(R.getValueInit("ValueMerger")) &&
164e8d8bef9SDimitry Andric          "MarshallingInfo must have a provide a keypath, default value and a "
165e8d8bef9SDimitry Andric          "value merger");
166e8d8bef9SDimitry Andric 
167e8d8bef9SDimitry Andric   MarshallingInfo Ret(R);
168e8d8bef9SDimitry Andric 
169e8d8bef9SDimitry Andric   Ret.ShouldAlwaysEmit = R.getValueAsBit("ShouldAlwaysEmit");
170e8d8bef9SDimitry Andric   Ret.MacroPrefix = R.getValueAsString("MacroPrefix");
171e8d8bef9SDimitry Andric   Ret.KeyPath = R.getValueAsString("KeyPath");
172e8d8bef9SDimitry Andric   Ret.DefaultValue = R.getValueAsString("DefaultValue");
173e8d8bef9SDimitry Andric   Ret.NormalizedValuesScope = R.getValueAsString("NormalizedValuesScope");
174e8d8bef9SDimitry Andric   Ret.ImpliedCheck = R.getValueAsString("ImpliedCheck");
175e8d8bef9SDimitry Andric   Ret.ImpliedValue =
176e8d8bef9SDimitry Andric       R.getValueAsOptionalString("ImpliedValue").getValueOr(Ret.DefaultValue);
177e8d8bef9SDimitry Andric 
178e8d8bef9SDimitry Andric   Ret.ShouldParse = R.getValueAsString("ShouldParse");
179e8d8bef9SDimitry Andric   Ret.Normalizer = R.getValueAsString("Normalizer");
180e8d8bef9SDimitry Andric   Ret.Denormalizer = R.getValueAsString("Denormalizer");
181e8d8bef9SDimitry Andric   Ret.ValueMerger = R.getValueAsString("ValueMerger");
182e8d8bef9SDimitry Andric   Ret.ValueExtractor = R.getValueAsString("ValueExtractor");
1835ffd83dbSDimitry Andric 
1845ffd83dbSDimitry Andric   if (!isa<UnsetInit>(R.getValueInit("NormalizedValues"))) {
1855ffd83dbSDimitry Andric     assert(!isa<UnsetInit>(R.getValueInit("Values")) &&
1865ffd83dbSDimitry Andric            "Cannot provide normalized values for value-less options");
187e8d8bef9SDimitry Andric     Ret.TableIndex = MarshallingInfo::NextTableIndex++;
188e8d8bef9SDimitry Andric     Ret.NormalizedValues = R.getValueAsListOfStrings("NormalizedValues");
189e8d8bef9SDimitry Andric     Ret.Values.reserve(Ret.NormalizedValues.size());
190e8d8bef9SDimitry Andric     Ret.ValueTableName = getOptionName(R) + "ValueTable";
1915ffd83dbSDimitry Andric 
1925ffd83dbSDimitry Andric     StringRef ValuesStr = R.getValueAsString("Values");
1935ffd83dbSDimitry Andric     for (;;) {
1945ffd83dbSDimitry Andric       size_t Idx = ValuesStr.find(',');
1955ffd83dbSDimitry Andric       if (Idx == StringRef::npos)
1965ffd83dbSDimitry Andric         break;
1975ffd83dbSDimitry Andric       if (Idx > 0)
198e8d8bef9SDimitry Andric         Ret.Values.push_back(ValuesStr.slice(0, Idx));
1995ffd83dbSDimitry Andric       ValuesStr = ValuesStr.slice(Idx + 1, StringRef::npos);
2005ffd83dbSDimitry Andric     }
2015ffd83dbSDimitry Andric     if (!ValuesStr.empty())
202e8d8bef9SDimitry Andric       Ret.Values.push_back(ValuesStr);
2035ffd83dbSDimitry Andric 
204e8d8bef9SDimitry Andric     assert(Ret.Values.size() == Ret.NormalizedValues.size() &&
2055ffd83dbSDimitry Andric            "The number of normalized values doesn't match the number of "
2065ffd83dbSDimitry Andric            "values");
2075ffd83dbSDimitry Andric   }
2085ffd83dbSDimitry Andric 
2095ffd83dbSDimitry Andric   return Ret;
2105ffd83dbSDimitry Andric }
2115ffd83dbSDimitry Andric 
2120b57cec5SDimitry Andric /// OptParserEmitter - This tablegen backend takes an input .td file
2130b57cec5SDimitry Andric /// describing a list of options and emits a data structure for parsing and
2140b57cec5SDimitry Andric /// working with those options when given an input command line.
2150b57cec5SDimitry Andric namespace llvm {
2160b57cec5SDimitry Andric void EmitOptParser(RecordKeeper &Records, raw_ostream &OS) {
2170b57cec5SDimitry Andric   // Get the option groups and options.
2180b57cec5SDimitry Andric   const std::vector<Record*> &Groups =
2190b57cec5SDimitry Andric     Records.getAllDerivedDefinitions("OptionGroup");
2200b57cec5SDimitry Andric   std::vector<Record*> Opts = Records.getAllDerivedDefinitions("Option");
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric   emitSourceFileHeader("Option Parsing Definitions", OS);
2230b57cec5SDimitry Andric 
2240b57cec5SDimitry Andric   array_pod_sort(Opts.begin(), Opts.end(), CompareOptionRecords);
2250b57cec5SDimitry Andric   // Generate prefix groups.
2260b57cec5SDimitry Andric   typedef SmallVector<SmallString<2>, 2> PrefixKeyT;
2270b57cec5SDimitry Andric   typedef std::map<PrefixKeyT, std::string> PrefixesT;
2280b57cec5SDimitry Andric   PrefixesT Prefixes;
2290b57cec5SDimitry Andric   Prefixes.insert(std::make_pair(PrefixKeyT(), "prefix_0"));
2300b57cec5SDimitry Andric   unsigned CurPrefix = 0;
231e8d8bef9SDimitry Andric   for (const Record &R : llvm::make_pointee_range(Opts)) {
232e8d8bef9SDimitry Andric     std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings("Prefixes");
233e8d8bef9SDimitry Andric     PrefixKeyT PrefixKey(RPrefixes.begin(), RPrefixes.end());
2340b57cec5SDimitry Andric     unsigned NewPrefix = CurPrefix + 1;
235e8d8bef9SDimitry Andric     std::string Prefix = (Twine("prefix_") + Twine(NewPrefix)).str();
236e8d8bef9SDimitry Andric     if (Prefixes.insert(std::make_pair(PrefixKey, Prefix)).second)
2370b57cec5SDimitry Andric       CurPrefix = NewPrefix;
2380b57cec5SDimitry Andric   }
2390b57cec5SDimitry Andric 
2400b57cec5SDimitry Andric   // Dump prefixes.
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric   OS << "/////////\n";
2430b57cec5SDimitry Andric   OS << "// Prefixes\n\n";
2440b57cec5SDimitry Andric   OS << "#ifdef PREFIX\n";
2450b57cec5SDimitry Andric   OS << "#define COMMA ,\n";
246e8d8bef9SDimitry Andric   for (const auto &Prefix : Prefixes) {
2470b57cec5SDimitry Andric     OS << "PREFIX(";
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric     // Prefix name.
250e8d8bef9SDimitry Andric     OS << Prefix.second;
2510b57cec5SDimitry Andric 
2520b57cec5SDimitry Andric     // Prefix values.
2530b57cec5SDimitry Andric     OS << ", {";
254*fe6060f1SDimitry Andric     for (const auto &PrefixKey : Prefix.first)
255e8d8bef9SDimitry Andric       OS << "\"" << PrefixKey << "\" COMMA ";
2560b57cec5SDimitry Andric     OS << "nullptr})\n";
2570b57cec5SDimitry Andric   }
2580b57cec5SDimitry Andric   OS << "#undef COMMA\n";
2590b57cec5SDimitry Andric   OS << "#endif // PREFIX\n\n";
2600b57cec5SDimitry Andric 
2610b57cec5SDimitry Andric   OS << "/////////\n";
2620b57cec5SDimitry Andric   OS << "// Groups\n\n";
2630b57cec5SDimitry Andric   OS << "#ifdef OPTION\n";
264e8d8bef9SDimitry Andric   for (const Record &R : llvm::make_pointee_range(Groups)) {
2650b57cec5SDimitry Andric     // Start a single option entry.
2660b57cec5SDimitry Andric     OS << "OPTION(";
2670b57cec5SDimitry Andric 
2680b57cec5SDimitry Andric     // The option prefix;
2690b57cec5SDimitry Andric     OS << "nullptr";
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric     // The option string.
2720b57cec5SDimitry Andric     OS << ", \"" << R.getValueAsString("Name") << '"';
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric     // The option identifier name.
2750b57cec5SDimitry Andric     OS << ", " << getOptionName(R);
2760b57cec5SDimitry Andric 
2770b57cec5SDimitry Andric     // The option kind.
2780b57cec5SDimitry Andric     OS << ", Group";
2790b57cec5SDimitry Andric 
2800b57cec5SDimitry Andric     // The containing option group (if any).
2810b57cec5SDimitry Andric     OS << ", ";
2820b57cec5SDimitry Andric     if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))
2830b57cec5SDimitry Andric       OS << getOptionName(*DI->getDef());
2840b57cec5SDimitry Andric     else
2850b57cec5SDimitry Andric       OS << "INVALID";
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric     // The other option arguments (unused for groups).
2880b57cec5SDimitry Andric     OS << ", INVALID, nullptr, 0, 0";
2890b57cec5SDimitry Andric 
2900b57cec5SDimitry Andric     // The option help text.
2910b57cec5SDimitry Andric     if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
2920b57cec5SDimitry Andric       OS << ",\n";
2930b57cec5SDimitry Andric       OS << "       ";
2940b57cec5SDimitry Andric       write_cstring(OS, R.getValueAsString("HelpText"));
2950b57cec5SDimitry Andric     } else
2960b57cec5SDimitry Andric       OS << ", nullptr";
2970b57cec5SDimitry Andric 
2980b57cec5SDimitry Andric     // The option meta-variable name (unused).
2990b57cec5SDimitry Andric     OS << ", nullptr";
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric     // The option Values (unused for groups).
3020b57cec5SDimitry Andric     OS << ", nullptr)\n";
3030b57cec5SDimitry Andric   }
3040b57cec5SDimitry Andric   OS << "\n";
3050b57cec5SDimitry Andric 
3060b57cec5SDimitry Andric   OS << "//////////\n";
3070b57cec5SDimitry Andric   OS << "// Options\n\n";
3080b57cec5SDimitry Andric 
3095ffd83dbSDimitry Andric   auto WriteOptRecordFields = [&](raw_ostream &OS, const Record &R) {
3100b57cec5SDimitry Andric     // The option prefix;
311e8d8bef9SDimitry Andric     std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings("Prefixes");
312e8d8bef9SDimitry Andric     OS << Prefixes[PrefixKeyT(RPrefixes.begin(), RPrefixes.end())] << ", ";
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric     // The option string.
3155ffd83dbSDimitry Andric     emitNameUsingSpelling(OS, R);
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric     // The option identifier name.
3180b57cec5SDimitry Andric     OS << ", " << getOptionName(R);
3190b57cec5SDimitry Andric 
3200b57cec5SDimitry Andric     // The option kind.
3210b57cec5SDimitry Andric     OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name");
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric     // The containing option group (if any).
3240b57cec5SDimitry Andric     OS << ", ";
3250b57cec5SDimitry Andric     const ListInit *GroupFlags = nullptr;
3260b57cec5SDimitry Andric     if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
3270b57cec5SDimitry Andric       GroupFlags = DI->getDef()->getValueAsListInit("Flags");
3280b57cec5SDimitry Andric       OS << getOptionName(*DI->getDef());
3290b57cec5SDimitry Andric     } else
3300b57cec5SDimitry Andric       OS << "INVALID";
3310b57cec5SDimitry Andric 
3320b57cec5SDimitry Andric     // The option alias (if any).
3330b57cec5SDimitry Andric     OS << ", ";
3340b57cec5SDimitry Andric     if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Alias")))
3350b57cec5SDimitry Andric       OS << getOptionName(*DI->getDef());
3360b57cec5SDimitry Andric     else
3370b57cec5SDimitry Andric       OS << "INVALID";
3380b57cec5SDimitry Andric 
3390b57cec5SDimitry Andric     // The option alias arguments (if any).
3400b57cec5SDimitry Andric     // Emitted as a \0 separated list in a string, e.g. ["foo", "bar"]
3410b57cec5SDimitry Andric     // would become "foo\0bar\0". Note that the compiler adds an implicit
3420b57cec5SDimitry Andric     // terminating \0 at the end.
3430b57cec5SDimitry Andric     OS << ", ";
3440b57cec5SDimitry Andric     std::vector<StringRef> AliasArgs = R.getValueAsListOfStrings("AliasArgs");
3450b57cec5SDimitry Andric     if (AliasArgs.size() == 0) {
3460b57cec5SDimitry Andric       OS << "nullptr";
3470b57cec5SDimitry Andric     } else {
3480b57cec5SDimitry Andric       OS << "\"";
349e8d8bef9SDimitry Andric       for (StringRef AliasArg : AliasArgs)
350e8d8bef9SDimitry Andric         OS << AliasArg << "\\0";
3510b57cec5SDimitry Andric       OS << "\"";
3520b57cec5SDimitry Andric     }
3530b57cec5SDimitry Andric 
3540b57cec5SDimitry Andric     // The option flags.
3550b57cec5SDimitry Andric     OS << ", ";
3560b57cec5SDimitry Andric     int NumFlags = 0;
3570b57cec5SDimitry Andric     const ListInit *LI = R.getValueAsListInit("Flags");
3580b57cec5SDimitry Andric     for (Init *I : *LI)
3595ffd83dbSDimitry Andric       OS << (NumFlags++ ? " | " : "") << cast<DefInit>(I)->getDef()->getName();
3600b57cec5SDimitry Andric     if (GroupFlags) {
3610b57cec5SDimitry Andric       for (Init *I : *GroupFlags)
3620b57cec5SDimitry Andric         OS << (NumFlags++ ? " | " : "")
3630b57cec5SDimitry Andric            << cast<DefInit>(I)->getDef()->getName();
3640b57cec5SDimitry Andric     }
3650b57cec5SDimitry Andric     if (NumFlags == 0)
3660b57cec5SDimitry Andric       OS << '0';
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric     // The option parameter field.
3690b57cec5SDimitry Andric     OS << ", " << R.getValueAsInt("NumArgs");
3700b57cec5SDimitry Andric 
3710b57cec5SDimitry Andric     // The option help text.
3720b57cec5SDimitry Andric     if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {
3730b57cec5SDimitry Andric       OS << ",\n";
3740b57cec5SDimitry Andric       OS << "       ";
3750b57cec5SDimitry Andric       write_cstring(OS, R.getValueAsString("HelpText"));
3760b57cec5SDimitry Andric     } else
3770b57cec5SDimitry Andric       OS << ", nullptr";
3780b57cec5SDimitry Andric 
3790b57cec5SDimitry Andric     // The option meta-variable name.
3800b57cec5SDimitry Andric     OS << ", ";
3810b57cec5SDimitry Andric     if (!isa<UnsetInit>(R.getValueInit("MetaVarName")))
3820b57cec5SDimitry Andric       write_cstring(OS, R.getValueAsString("MetaVarName"));
3830b57cec5SDimitry Andric     else
3840b57cec5SDimitry Andric       OS << "nullptr";
3850b57cec5SDimitry Andric 
3860b57cec5SDimitry Andric     // The option Values. Used for shell autocompletion.
3870b57cec5SDimitry Andric     OS << ", ";
3880b57cec5SDimitry Andric     if (!isa<UnsetInit>(R.getValueInit("Values")))
3890b57cec5SDimitry Andric       write_cstring(OS, R.getValueAsString("Values"));
3900b57cec5SDimitry Andric     else
3910b57cec5SDimitry Andric       OS << "nullptr";
3925ffd83dbSDimitry Andric   };
3930b57cec5SDimitry Andric 
394e8d8bef9SDimitry Andric   auto IsMarshallingOption = [](const Record &R) {
395e8d8bef9SDimitry Andric     return !isa<UnsetInit>(R.getValueInit("KeyPath")) &&
396e8d8bef9SDimitry Andric            !R.getValueAsString("KeyPath").empty();
397e8d8bef9SDimitry Andric   };
3985ffd83dbSDimitry Andric 
399e8d8bef9SDimitry Andric   std::vector<const Record *> OptsWithMarshalling;
400e8d8bef9SDimitry Andric   for (const Record &R : llvm::make_pointee_range(Opts)) {
4015ffd83dbSDimitry Andric     // Start a single option entry.
4025ffd83dbSDimitry Andric     OS << "OPTION(";
4035ffd83dbSDimitry Andric     WriteOptRecordFields(OS, R);
4040b57cec5SDimitry Andric     OS << ")\n";
405e8d8bef9SDimitry Andric     if (IsMarshallingOption(R))
406e8d8bef9SDimitry Andric       OptsWithMarshalling.push_back(&R);
4070b57cec5SDimitry Andric   }
4080b57cec5SDimitry Andric   OS << "#endif // OPTION\n";
4090b57cec5SDimitry Andric 
410e8d8bef9SDimitry Andric   auto CmpMarshallingOpts = [](const Record *const *A, const Record *const *B) {
411e8d8bef9SDimitry Andric     unsigned AID = (*A)->getID();
412e8d8bef9SDimitry Andric     unsigned BID = (*B)->getID();
413e8d8bef9SDimitry Andric 
414e8d8bef9SDimitry Andric     if (AID < BID)
415e8d8bef9SDimitry Andric       return -1;
416e8d8bef9SDimitry Andric     if (AID > BID)
417e8d8bef9SDimitry Andric       return 1;
418e8d8bef9SDimitry Andric     return 0;
419e8d8bef9SDimitry Andric   };
420e8d8bef9SDimitry Andric   // The RecordKeeper stores records (options) in lexicographical order, and we
421e8d8bef9SDimitry Andric   // have reordered the options again when generating prefix groups. We need to
422e8d8bef9SDimitry Andric   // restore the original definition order of options with marshalling to honor
423e8d8bef9SDimitry Andric   // the topology of the dependency graph implied by `DefaultAnyOf`.
424e8d8bef9SDimitry Andric   array_pod_sort(OptsWithMarshalling.begin(), OptsWithMarshalling.end(),
425e8d8bef9SDimitry Andric                  CmpMarshallingOpts);
426e8d8bef9SDimitry Andric 
427e8d8bef9SDimitry Andric   std::vector<MarshallingInfo> MarshallingInfos;
428e8d8bef9SDimitry Andric   for (const auto *R : OptsWithMarshalling)
429e8d8bef9SDimitry Andric     MarshallingInfos.push_back(createMarshallingInfo(*R));
430e8d8bef9SDimitry Andric 
431e8d8bef9SDimitry Andric   for (const auto &MI : MarshallingInfos) {
432e8d8bef9SDimitry Andric     OS << "#ifdef " << MI.getMacroName() << "\n";
433e8d8bef9SDimitry Andric     OS << MI.getMacroName() << "(";
434e8d8bef9SDimitry Andric     WriteOptRecordFields(OS, MI.R);
4355ffd83dbSDimitry Andric     OS << ", ";
436e8d8bef9SDimitry Andric     MI.emit(OS);
4375ffd83dbSDimitry Andric     OS << ")\n";
438e8d8bef9SDimitry Andric     OS << "#endif // " << MI.getMacroName() << "\n";
4395ffd83dbSDimitry Andric   }
4405ffd83dbSDimitry Andric 
4415ffd83dbSDimitry Andric   OS << "\n";
4425ffd83dbSDimitry Andric   OS << "#ifdef SIMPLE_ENUM_VALUE_TABLE";
4435ffd83dbSDimitry Andric   OS << "\n";
444e8d8bef9SDimitry Andric   OS << MarshallingInfo::ValueTablePreamble;
4455ffd83dbSDimitry Andric   std::vector<StringRef> ValueTableNames;
446e8d8bef9SDimitry Andric   for (const auto &MI : MarshallingInfos)
447e8d8bef9SDimitry Andric     if (auto MaybeValueTableName = MI.emitValueTable(OS))
4485ffd83dbSDimitry Andric       ValueTableNames.push_back(*MaybeValueTableName);
4495ffd83dbSDimitry Andric 
450e8d8bef9SDimitry Andric   OS << MarshallingInfo::ValueTablesDecl << "{";
4515ffd83dbSDimitry Andric   for (auto ValueTableName : ValueTableNames)
4525ffd83dbSDimitry Andric     OS << "{" << ValueTableName << ", sizeof(" << ValueTableName
4535ffd83dbSDimitry Andric        << ") / sizeof(SimpleEnumValue)"
4545ffd83dbSDimitry Andric        << "},\n";
4555ffd83dbSDimitry Andric   OS << "};\n";
4565ffd83dbSDimitry Andric   OS << "static const unsigned SimpleEnumValueTablesSize = "
4575ffd83dbSDimitry Andric         "sizeof(SimpleEnumValueTables) / sizeof(SimpleEnumValueTable);\n";
4585ffd83dbSDimitry Andric 
4595ffd83dbSDimitry Andric   OS << "#endif // SIMPLE_ENUM_VALUE_TABLE\n";
4605ffd83dbSDimitry Andric   OS << "\n";
4615ffd83dbSDimitry Andric 
4620b57cec5SDimitry Andric   OS << "\n";
4630b57cec5SDimitry Andric   OS << "#ifdef OPTTABLE_ARG_INIT\n";
4640b57cec5SDimitry Andric   OS << "//////////\n";
4650b57cec5SDimitry Andric   OS << "// Option Values\n\n";
466e8d8bef9SDimitry Andric   for (const Record &R : llvm::make_pointee_range(Opts)) {
4670b57cec5SDimitry Andric     if (isa<UnsetInit>(R.getValueInit("ValuesCode")))
4680b57cec5SDimitry Andric       continue;
4690b57cec5SDimitry Andric     OS << "{\n";
4700b57cec5SDimitry Andric     OS << "bool ValuesWereAdded;\n";
4710b57cec5SDimitry Andric     OS << R.getValueAsString("ValuesCode");
4720b57cec5SDimitry Andric     OS << "\n";
4735ffd83dbSDimitry Andric     for (StringRef Prefix : R.getValueAsListOfStrings("Prefixes")) {
4740b57cec5SDimitry Andric       OS << "ValuesWereAdded = Opt.addValues(";
4755ffd83dbSDimitry Andric       std::string S(Prefix);
476480093f4SDimitry Andric       S += R.getValueAsString("Name");
4770b57cec5SDimitry Andric       write_cstring(OS, S);
4780b57cec5SDimitry Andric       OS << ", Values);\n";
4790b57cec5SDimitry Andric       OS << "(void)ValuesWereAdded;\n";
4800b57cec5SDimitry Andric       OS << "assert(ValuesWereAdded && \"Couldn't add values to "
4810b57cec5SDimitry Andric             "OptTable!\");\n";
4820b57cec5SDimitry Andric     }
4830b57cec5SDimitry Andric     OS << "}\n";
4840b57cec5SDimitry Andric   }
4850b57cec5SDimitry Andric   OS << "\n";
4860b57cec5SDimitry Andric   OS << "#endif // OPTTABLE_ARG_INIT\n";
4870b57cec5SDimitry Andric }
4880b57cec5SDimitry Andric } // end namespace llvm
489