| //===- OptionParserEmitter.cpp - Table Driven Command Option Line Parsing -===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "Common/OptEmitter.h" |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/ADT/SmallString.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/ADT/StringExtras.h" |
| #include "llvm/ADT/Twine.h" |
| #include "llvm/Option/OptTable.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include "llvm/TableGen/Error.h" |
| #include "llvm/TableGen/Record.h" |
| #include "llvm/TableGen/StringToOffsetTable.h" |
| #include "llvm/TableGen/TableGenBackend.h" |
| #include <array> |
| #include <cstring> |
| #include <map> |
| |
| using namespace llvm; |
| |
| static std::string getOptionName(const Record &R) { |
| // Use the record name unless EnumName is defined. |
| if (isa<UnsetInit>(R.getValueInit("EnumName"))) |
| return R.getName().str(); |
| |
| return R.getValueAsString("EnumName").str(); |
| } |
| |
| // Only pass EmitComment for short strings that cannot contain "*/". |
| static void writeStrTableOffset(raw_ostream &OS, |
| const StringToOffsetTable &Table, |
| llvm::StringRef Str, bool EmitComment = false) { |
| std::optional<unsigned> Offset = Table.GetStringOffset(Str); |
| if (!Offset) |
| PrintFatalError("string was not added to the option string table: " + Str); |
| OS << *Offset; |
| if (EmitComment) { |
| OS << " /* "; |
| OS.write_escaped(Str); |
| OS << " */"; |
| } |
| } |
| |
| static raw_ostream &writeCstring(raw_ostream &OS, llvm::StringRef Str) { |
| OS << '"'; |
| OS.write_escaped(Str); |
| OS << '"'; |
| return OS; |
| } |
| |
| static StringRef getOptionalString(const Record &R, StringRef Field) { |
| return R.getValueAsOptionalString(Field).value_or(""); |
| } |
| |
| // Offset zero is the empty string and stands for an unset HelpText. A |
| // HelpText<""> marks an option as deliberately undocumented, so it maps to a |
| // second empty string that the table does not put at offset zero. |
| static StringRef getHelpText(const Record &R) { |
| std::optional<StringRef> S = R.getValueAsOptionalString("HelpText"); |
| if (!S) |
| return StringRef(); |
| return S->empty() ? StringRef("\0", 1) : *S; |
| } |
| |
| // The string table appends the empty string that terminates the list. |
| static std::string getAliasArgsBlob(const Record &R) { |
| std::string Blob; |
| for (StringRef AliasArg : R.getValueAsListOfStrings("AliasArgs")) { |
| if (AliasArg.empty()) |
| PrintFatalError(R.getLoc(), "AliasArgs entries must not be empty"); |
| Blob += AliasArg; |
| Blob += '\0'; |
| } |
| return Blob; |
| } |
| |
| static std::string getOptionPrefixedName(const Record &R) { |
| std::vector<StringRef> Prefixes = R.getValueAsListOfStrings("Prefixes"); |
| StringRef Name = R.getValueAsString("Name"); |
| |
| if (Prefixes.empty()) |
| return Name.str(); |
| |
| return (Prefixes[0] + Twine(Name)).str(); |
| } |
| |
| class MarshallingInfo { |
| public: |
| static constexpr const char *MacroName = "OPTION_WITH_MARSHALLING"; |
| const Record &R; |
| bool ShouldAlwaysEmit = false; |
| StringRef MacroPrefix; |
| StringRef KeyPath; |
| StringRef DefaultValue; |
| StringRef NormalizedValuesScope; |
| StringRef ImpliedCheck; |
| StringRef ImpliedValue; |
| StringRef ShouldParse; |
| StringRef Normalizer; |
| StringRef Denormalizer; |
| int TableIndex = -1; |
| std::vector<StringRef> Values; |
| std::vector<StringRef> NormalizedValues; |
| std::string ValueTableName; |
| |
| static size_t NextTableIndex; |
| |
| static constexpr const char *ValueTablePreamble = R"( |
| struct SimpleEnumValue { |
| const char *Name; |
| unsigned Value; |
| }; |
| |
| struct SimpleEnumValueTable { |
| const SimpleEnumValue *Table; |
| unsigned Size; |
| }; |
| )"; |
| |
| static constexpr const char *ValueTablesDecl = |
| "static const SimpleEnumValueTable SimpleEnumValueTables[] = "; |
| |
| MarshallingInfo(const Record &R) : R(R) {} |
| |
| std::string getMacroName() const { |
| return (MacroPrefix + MarshallingInfo::MacroName).str(); |
| } |
| |
| void emit(raw_ostream &OS) const { |
| OS << ShouldParse; |
| OS << ", "; |
| OS << ShouldAlwaysEmit; |
| OS << ", "; |
| OS << KeyPath; |
| OS << ", "; |
| emitScopedNormalizedValue(OS, DefaultValue); |
| OS << ", "; |
| OS << ImpliedCheck; |
| OS << ", "; |
| emitScopedNormalizedValue(OS, ImpliedValue); |
| OS << ", "; |
| OS << Normalizer; |
| OS << ", "; |
| OS << Denormalizer; |
| OS << ", "; |
| OS << TableIndex; |
| } |
| |
| std::optional<StringRef> emitValueTable(raw_ostream &OS) const { |
| if (TableIndex == -1) |
| return {}; |
| OS << "static const SimpleEnumValue " << ValueTableName << "[] = {\n"; |
| for (unsigned I = 0, E = Values.size(); I != E; ++I) { |
| OS << "{"; |
| writeCstring(OS, Values[I]); |
| OS << ","; |
| OS << "static_cast<unsigned>("; |
| emitScopedNormalizedValue(OS, NormalizedValues[I]); |
| OS << ")},"; |
| } |
| OS << "};\n"; |
| return StringRef(ValueTableName); |
| } |
| |
| private: |
| void emitScopedNormalizedValue(raw_ostream &OS, |
| StringRef NormalizedValue) const { |
| if (!NormalizedValuesScope.empty()) |
| OS << NormalizedValuesScope << "::"; |
| OS << NormalizedValue; |
| } |
| }; |
| |
| size_t MarshallingInfo::NextTableIndex = 0; |
| |
| static MarshallingInfo createMarshallingInfo(const Record &R) { |
| assert(!isa<UnsetInit>(R.getValueInit("KeyPath")) && |
| !isa<UnsetInit>(R.getValueInit("DefaultValue")) && |
| "MarshallingInfo must have a provide a keypath, default value and a " |
| "value merger"); |
| |
| MarshallingInfo Ret(R); |
| |
| Ret.ShouldAlwaysEmit = R.getValueAsBit("ShouldAlwaysEmit"); |
| Ret.MacroPrefix = R.getValueAsString("MacroPrefix"); |
| Ret.KeyPath = R.getValueAsString("KeyPath"); |
| Ret.DefaultValue = R.getValueAsString("DefaultValue"); |
| Ret.NormalizedValuesScope = R.getValueAsString("NormalizedValuesScope"); |
| Ret.ImpliedCheck = R.getValueAsString("ImpliedCheck"); |
| Ret.ImpliedValue = |
| R.getValueAsOptionalString("ImpliedValue").value_or(Ret.DefaultValue); |
| |
| Ret.ShouldParse = R.getValueAsString("ShouldParse"); |
| Ret.Normalizer = R.getValueAsString("Normalizer"); |
| Ret.Denormalizer = R.getValueAsString("Denormalizer"); |
| |
| if (!isa<UnsetInit>(R.getValueInit("NormalizedValues"))) { |
| assert(!isa<UnsetInit>(R.getValueInit("Values")) && |
| "Cannot provide normalized values for value-less options"); |
| Ret.TableIndex = MarshallingInfo::NextTableIndex++; |
| Ret.NormalizedValues = R.getValueAsListOfStrings("NormalizedValues"); |
| Ret.Values.reserve(Ret.NormalizedValues.size()); |
| Ret.ValueTableName = getOptionName(R) + "ValueTable"; |
| |
| StringRef ValuesStr = R.getValueAsString("Values"); |
| for (;;) { |
| size_t Idx = ValuesStr.find(','); |
| if (Idx == StringRef::npos) |
| break; |
| if (Idx > 0) |
| Ret.Values.push_back(ValuesStr.slice(0, Idx)); |
| ValuesStr = ValuesStr.substr(Idx + 1); |
| } |
| if (!ValuesStr.empty()) |
| Ret.Values.push_back(ValuesStr); |
| |
| assert(Ret.Values.size() == Ret.NormalizedValues.size() && |
| "The number of normalized values doesn't match the number of " |
| "values"); |
| } |
| |
| return Ret; |
| } |
| |
| /// OptionParserEmitter - This tablegen backend takes an input .td file |
| /// describing a list of options and emits a data structure for parsing and |
| /// working with those options when given an input command line. |
| static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) { |
| // Get the option groups and options. |
| ArrayRef<const Record *> Groups = |
| Records.getAllDerivedDefinitions("OptionGroup"); |
| std::vector<const Record *> Opts = Records.getAllDerivedDefinitions("Option"); |
| llvm::sort(Opts, IsOptionRecordsLess); |
| |
| std::vector<const Record *> SubCommands = |
| Records.getAllDerivedDefinitions("SubCommand"); |
| |
| emitSourceFileHeader("Option Parsing Definitions", OS); |
| |
| // Generate prefix groups. |
| using PrefixKeyT = SmallVector<SmallString<2>, 2>; |
| using PrefixesT = std::map<PrefixKeyT, unsigned>; |
| PrefixesT Prefixes; |
| Prefixes.try_emplace(PrefixKeyT(), 0); |
| for (const Record &R : llvm::make_pointee_range(Opts)) { |
| std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings("Prefixes"); |
| PrefixKeyT PrefixKey(RPrefixes.begin(), RPrefixes.end()); |
| Prefixes.try_emplace(PrefixKey, 0); |
| } |
| |
| // Generate sub command groups. |
| using SubCommandKeyT = SmallVector<StringRef, 2>; |
| using SubCommandIDsT = std::map<SubCommandKeyT, unsigned>; |
| SubCommandIDsT SubCommandIDs; |
| |
| auto GetSubCommandIDsOffset = [&SubCommandIDs](const Record &R) { |
| SubCommandKeyT SubCommandKey; |
| for (const Record *SubCommand : R.getValueAsListOfDefs("SubCommands")) |
| SubCommandKey.push_back(SubCommand->getName()); |
| return SubCommandIDs[SubCommandKey]; |
| }; |
| |
| SubCommandIDs.try_emplace(SubCommandKeyT(), 0); |
| for (const Record &R : llvm::make_pointee_range(Opts)) { |
| std::vector<const Record *> RSubCommands = |
| R.getValueAsListOfDefs("SubCommands"); |
| SubCommandKeyT SubCommandKey; |
| for (const auto &SubCommand : RSubCommands) |
| SubCommandKey.push_back(SubCommand->getName()); |
| SubCommandIDs.try_emplace(SubCommandKey, 0); |
| } |
| |
| llvm::StringToOffsetTable Table; |
| for (const auto &[PrefixSet, _] : Prefixes) |
| for (const auto &Prefix : PrefixSet) |
| Table.GetOrAddStringOffset(Prefix); |
| for (const Record &R : llvm::make_pointee_range(Groups)) { |
| Table.GetOrAddStringOffset(R.getValueAsString("Name")); |
| Table.GetOrAddStringOffset(getHelpText(R)); |
| } |
| for (const Record &R : llvm::make_pointee_range(Opts)) { |
| Table.GetOrAddStringOffset(getOptionPrefixedName(R)); |
| Table.GetOrAddStringOffset(getHelpText(R)); |
| Table.GetOrAddStringOffset(getOptionalString(R, "MetaVarName")); |
| Table.GetOrAddStringOffset(getOptionalString(R, "Values")); |
| Table.GetOrAddStringOffset(getAliasArgsBlob(R)); |
| for (const Record *V : R.getValueAsListOfDefs("HelpTextsForVariants")) |
| Table.GetOrAddStringOffset(V->getValueAsString("Text")); |
| } |
| |
| // Flags and Visibility name enumerators of the including tool. An option |
| // inherits its group's. |
| auto GetMask = [](const Record &R, StringRef Field) { |
| std::string Mask; |
| raw_string_ostream MaskOS(Mask); |
| ListSeparator Sep(" | "); |
| for (const Init *I : *R.getValueAsListInit(Field)) |
| MaskOS << Sep << cast<DefInit>(I)->getDef()->getName(); |
| if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) |
| for (const Init *I : *DI->getDef()->getValueAsListInit(Field)) |
| MaskOS << Sep << cast<DefInit>(I)->getDef()->getName(); |
| return Mask.empty() ? std::string("0") : Mask; |
| }; |
| |
| // IDs are 1-based positions in the table, which lists groups first. |
| DenseMap<const Record *, unsigned> OptionID; |
| for (const Record &R : llvm::make_pointee_range(Groups)) |
| OptionID.try_emplace(&R, OptionID.size() + 1); |
| for (const Record &R : llvm::make_pointee_range(Opts)) |
| OptionID.try_emplace(&R, OptionID.size() + 1); |
| auto GetRefID = [&](const Record &R, StringRef Field) { |
| if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit(Field))) |
| return OptionID.lookup(DI->getDef()); |
| return 0u; |
| }; |
| |
| OS << "/////////\n"; |
| OS << "// Tables\n\n"; |
| OS << "#ifdef OPTTABLE_CODE\n"; |
| // A function rather than an object: the object needs dynamic relocations. |
| OS << "static llvm::opt::OptTable::Tables optionTables() {\n"; |
| Table.EmitStringTableDef(OS, "OptionStrTable"); |
| OS << "\n"; |
| |
| // Dump prefixes. |
| OS << " static constexpr llvm::StringTable::Offset OptionPrefixesTable[] = " |
| "{\n"; |
| { |
| // Ensure the first prefix set is always empty. |
| assert(!Prefixes.empty() && |
| "We should always emit an empty set of prefixes"); |
| assert(Prefixes.begin()->first.empty() && |
| "First prefix set should always be empty"); |
| llvm::ListSeparator Sep(",\n"); |
| unsigned CurIndex = 0; |
| for (auto &[Prefix, PrefixIndex] : Prefixes) { |
| // First emit the number of prefix strings in this list of prefixes. |
| OS << Sep << " " << Prefix.size() << " /* prefixes */"; |
| PrefixIndex = CurIndex; |
| assert((CurIndex == 0 || !Prefix.empty()) && |
| "Only first prefix set should be empty!"); |
| for (const auto &PrefixKey : Prefix) |
| OS << ", " << *Table.GetStringOffset(PrefixKey) << " /* '" << PrefixKey |
| << "' */"; |
| CurIndex += Prefix.size() + 1; |
| } |
| } |
| OS << "\n };\n\n"; |
| |
| // Dump help text variants. Each option's variants form a run ended by a zero |
| // row; offset 0 is the empty run. |
| OS << " static constexpr llvm::opt::OptTable::HelpTextVariant " |
| "OptionHelpTextVariantsTable[] = {\n"; |
| DenseMap<const Record *, unsigned> HelpTextVariantsOffset; |
| unsigned NumVariantRows = 1; |
| OS << " {0, 0},\n"; |
| for (const Record &R : llvm::make_pointee_range(Opts)) { |
| std::vector<const Record *> Variants = |
| R.getValueAsListOfDefs("HelpTextsForVariants"); |
| if (Variants.empty()) |
| continue; |
| HelpTextVariantsOffset[&R] = NumVariantRows; |
| NumVariantRows += Variants.size() + 1; |
| for (const Record *V : Variants) { |
| const ListInit *Vis = V->getValueAsListInit("Visibilities"); |
| if (Vis->empty()) |
| PrintFatalError(V->getLoc(), "HelpTextVariant needs a visibility"); |
| OS << " {"; |
| ListSeparator Sep(" | "); |
| for (const Init *I : *Vis) |
| OS << Sep << I->getAsUnquotedString(); |
| OS << ", "; |
| writeStrTableOffset(OS, Table, V->getValueAsString("Text")); |
| OS << "},\n"; |
| } |
| OS << " {0, 0},\n"; |
| } |
| OS << " };\n\n"; |
| |
| // Dump subcommands. |
| if (!SubCommands.empty()) { |
| OS << " static constexpr llvm::opt::OptTable::SubCommand " |
| "OptionSubCommands[] = {\n"; |
| for (const Record *SubCommand : SubCommands) { |
| OS << " { \"" << SubCommand->getValueAsString("Name") << "\", "; |
| OS << "\"" << SubCommand->getValueAsString("HelpText") << "\", "; |
| OS << "\"" << SubCommand->getValueAsString("Usage") << "\" },\n"; |
| } |
| OS << " };\n\n"; |
| } |
| |
| // Dump subcommand IDs. |
| OS << " static constexpr unsigned OptionSubCommandIDsTable[] = {\n"; |
| { |
| // Ensure the first subcommand set is always empty. |
| assert(!SubCommandIDs.empty() && |
| "We should always emit an empty set of subcommands"); |
| assert(SubCommandIDs.begin()->first.empty() && |
| "First subcommand set should always be empty"); |
| llvm::ListSeparator Sep(",\n"); |
| unsigned CurIndex = 0; |
| for (auto &[SubCommand, SubCommandIndex] : SubCommandIDs) { |
| // First emit the number of subcommand strings in this list of |
| // subcommands. |
| OS << Sep << " " << SubCommand.size() << " /* subcommands */"; |
| SubCommandIndex = CurIndex; |
| assert((CurIndex == 0 || !SubCommand.empty()) && |
| "Only first subcommand set should be empty!"); |
| for (const auto &SubCommandKey : SubCommand) { |
| auto It = llvm::find_if(SubCommands, [&](const Record *R) { |
| return R->getName() == SubCommandKey; |
| }); |
| assert(It != SubCommands.end() && "SubCommand not found"); |
| OS << ", " << std::distance(SubCommands.begin(), It) << " /* '" |
| << SubCommandKey << "' */"; |
| } |
| CurIndex += SubCommand.size() + 1; |
| } |
| } |
| OS << "\n };\n\n"; |
| |
| // Rarely set fields, in OptTable::InfoExtra order. Options with equal values |
| // share a row; row 0 is all zero. |
| OS << " static constexpr llvm::opt::OptTable::InfoExtra " |
| "OptionInfoExtrasTable[] = {\n {0, 0, 0, 0, 0},\n"; |
| std::map<std::array<unsigned, 5>, unsigned> ExtraRows; |
| ExtraRows.try_emplace({}, 0); |
| DenseMap<const Record *, unsigned> ExtraOffset; |
| for (const Record &R : llvm::make_pointee_range(Opts)) { |
| std::array<unsigned, 5> Row = { |
| *Table.GetStringOffset(getOptionalString(R, "MetaVarName")), |
| *Table.GetStringOffset(getAliasArgsBlob(R)), |
| *Table.GetStringOffset(getOptionalString(R, "Values")), |
| HelpTextVariantsOffset.lookup(&R), GetSubCommandIDsOffset(R)}; |
| auto [It, Inserted] = ExtraRows.try_emplace(Row, ExtraRows.size()); |
| if (Inserted) { |
| OS << " {"; |
| interleaveComma(Row, OS); |
| OS << "},\n"; |
| } |
| ExtraOffset[&R] = It->second; |
| } |
| OS << " };\n\n"; |
| |
| // Dump the option table in OptTable::Info field order. |
| OS << " static constexpr llvm::opt::OptTable::Info OptionInfoTable[] = {\n"; |
| for (const Record &R : llvm::make_pointee_range(Groups)) { |
| OS << " {"; |
| writeStrTableOffset(OS, Table, R.getValueAsString("Name"), |
| /*EmitComment=*/true); |
| OS << ", "; |
| writeStrTableOffset(OS, Table, getHelpText(R)); |
| OS << ", 0, 0, 0, " << GetRefID(R, "Group") |
| << ", 0, 0, llvm::opt::Option::GroupClass, 0},\n"; |
| } |
| for (const Record &R : llvm::make_pointee_range(Opts)) { |
| OS << " {"; |
| writeStrTableOffset(OS, Table, getOptionPrefixedName(R), |
| /*EmitComment=*/true); |
| OS << ", "; |
| writeStrTableOffset(OS, Table, getHelpText(R)); |
| OS << ", " << GetMask(R, "Flags") << ", " << GetMask(R, "Visibility"); |
| std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings("Prefixes"); |
| OS << ", " << Prefixes[PrefixKeyT(RPrefixes.begin(), RPrefixes.end())]; |
| OS << ", " << GetRefID(R, "Group") << ", " << GetRefID(R, "Alias"); |
| OS << ", " << ExtraOffset.lookup(&R) << ", llvm::opt::Option::" |
| << R.getValueAsDef("Kind")->getValueAsString("Name") << "Class, " |
| << R.getValueAsInt("NumArgs") << "},\n"; |
| } |
| OS << " };\n\n"; |
| |
| OS << " return {OptionStrTable, OptionPrefixesTable,\n"; |
| OS << " OptionInfoTable, OptionInfoExtrasTable, " |
| "OptionHelpTextVariantsTable, " |
| << (SubCommands.empty() ? "{}" : "OptionSubCommands") |
| << ", OptionSubCommandIDsTable};\n"; |
| OS << "}\n"; |
| OS << "#undef OPTTABLE_CODE\n"; |
| OS << "#endif // OPTTABLE_CODE\n\n"; |
| |
| // Dump ValuesCode. |
| OS << "/////////\n"; |
| OS << "// ValuesCode\n\n"; |
| OS << "#ifdef OPTTABLE_VALUES_CODE\n"; |
| std::vector<const Record *> ValuesCodeOpts; |
| for (const Record &R : llvm::make_pointee_range(Opts)) { |
| // The option values, if any; |
| if (!isa<UnsetInit>(R.getValueInit("ValuesCode"))) { |
| if (!isa<UnsetInit>(R.getValueInit("Values"))) |
| PrintFatalError(R.getLoc(), "cannot set both Values and ValuesCode"); |
| ValuesCodeOpts.push_back(&R); |
| OS << "#define VALUES_CODE " << getOptionName(R) << "_Values\n"; |
| OS << R.getValueAsString("ValuesCode") << "\n"; |
| OS << "#undef VALUES_CODE\n"; |
| } |
| } |
| // A function keeps these strings out of a relocated table. It names OPT_ IDs, |
| // so include this block after the option enum; a table that uses a different |
| // ID prefix cannot use ValuesCode. |
| OS << "static llvm::StringRef getOptionValuesCode(unsigned ID) {\n"; |
| OS << " switch (ID) {\n"; |
| for (const Record *R : ValuesCodeOpts) |
| OS << " case OPT_" << getOptionName(*R) << ": return " << getOptionName(*R) |
| << "_Values;\n"; |
| OS << " }\n return {};\n}\n"; |
| OS << "#undef OPTTABLE_VALUES_CODE\n"; |
| OS << "#endif // OPTTABLE_VALUES_CODE\n"; |
| |
| OS << "/////////\n"; |
| OS << "// Groups\n\n"; |
| OS << "#ifdef OPTION\n"; |
| for (const Record &R : llvm::make_pointee_range(Groups)) { |
| // Start a single option entry. |
| OS << "OPTION("; |
| |
| // A zero prefix offset corresponds to an empty set of prefixes. |
| OS << "0 /* no prefixes */"; |
| |
| // The option string offset. |
| OS << ", "; |
| writeStrTableOffset(OS, Table, R.getValueAsString("Name"), |
| /*EmitComment=*/true); |
| |
| // The option identifier name. |
| OS << ", " << getOptionName(R); |
| |
| // The option kind. |
| OS << ", Group"; |
| |
| // The containing option group (if any). |
| OS << ", "; |
| if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) |
| OS << getOptionName(*DI->getDef()); |
| else |
| OS << "INVALID"; |
| |
| // The other option arguments (unused for groups). |
| OS << ", INVALID, 0, 0, 0, 0"; |
| |
| // The option help text. |
| OS << ", "; |
| writeStrTableOffset(OS, Table, getHelpText(R)); |
| |
| // Groups have no help text variants. |
| OS << ", 0"; |
| |
| // The option meta-variable name (unused). |
| OS << ", 0"; |
| |
| // The option Values and SubCommandIDsOffset (unused for groups). |
| OS << ", 0, 0)\n"; |
| } |
| OS << "\n"; |
| |
| OS << "//////////\n"; |
| OS << "// Options\n\n"; |
| |
| auto WriteOptRecordFields = [&](raw_ostream &OS, const Record &R) { |
| // The option prefix; |
| std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings("Prefixes"); |
| OS << Prefixes[PrefixKeyT(RPrefixes.begin(), RPrefixes.end())] << ", "; |
| |
| // The option prefixed name. |
| writeStrTableOffset(OS, Table, getOptionPrefixedName(R), |
| /*EmitComment=*/true); |
| |
| // The option identifier name. |
| OS << ", " << getOptionName(R); |
| |
| // The option kind. |
| OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name"); |
| |
| // The containing option group (if any). |
| OS << ", "; |
| if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) |
| OS << getOptionName(*DI->getDef()); |
| else |
| OS << "INVALID"; |
| |
| // The option alias (if any). |
| OS << ", "; |
| if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Alias"))) |
| OS << getOptionName(*DI->getDef()); |
| else |
| OS << "INVALID"; |
| |
| // The option alias arguments (if any). |
| OS << ", "; |
| writeStrTableOffset(OS, Table, getAliasArgsBlob(R)); |
| |
| // "Flags" for the option, such as HelpHidden and Render* |
| OS << ", " << GetMask(R, "Flags"); |
| |
| // Option visibility, for sharing options between drivers. |
| OS << ", " << GetMask(R, "Visibility"); |
| |
| // The option parameter field. |
| OS << ", " << R.getValueAsInt("NumArgs"); |
| |
| // The option help text. |
| OS << ", "; |
| writeStrTableOffset(OS, Table, getHelpText(R)); |
| |
| // The option help text variants. |
| OS << ", " << HelpTextVariantsOffset.lookup(&R); |
| |
| // The option meta-variable name. |
| OS << ", "; |
| writeStrTableOffset(OS, Table, getOptionalString(R, "MetaVarName")); |
| |
| // The option Values. Used for shell autocompletion. |
| OS << ", "; |
| writeStrTableOffset(OS, Table, getOptionalString(R, "Values")); |
| |
| // The option SubCommandIDsOffset. |
| OS << ", " << GetSubCommandIDsOffset(R); |
| }; |
| |
| auto IsMarshallingOption = [](const Record &R) { |
| return !isa<UnsetInit>(R.getValueInit("KeyPath")) && |
| !R.getValueAsString("KeyPath").empty(); |
| }; |
| |
| std::vector<const Record *> OptsWithMarshalling; |
| for (const Record &R : llvm::make_pointee_range(Opts)) { |
| // Start a single option entry. |
| OS << "OPTION("; |
| WriteOptRecordFields(OS, R); |
| OS << ")\n"; |
| if (IsMarshallingOption(R)) |
| OptsWithMarshalling.push_back(&R); |
| } |
| OS << "#endif // OPTION\n"; |
| |
| auto CmpMarshallingOpts = [](const Record *const *A, const Record *const *B) { |
| unsigned AID = (*A)->getID(); |
| unsigned BID = (*B)->getID(); |
| |
| if (AID < BID) |
| return -1; |
| if (AID > BID) |
| return 1; |
| return 0; |
| }; |
| // The RecordKeeper stores records (options) in lexicographical order, and we |
| // have reordered the options again when generating prefix groups. We need to |
| // restore the original definition order of options with marshalling to honor |
| // the topology of the dependency graph implied by `DefaultAnyOf`. |
| array_pod_sort(OptsWithMarshalling.begin(), OptsWithMarshalling.end(), |
| CmpMarshallingOpts); |
| |
| std::vector<MarshallingInfo> MarshallingInfos; |
| MarshallingInfos.reserve(OptsWithMarshalling.size()); |
| for (const auto *R : OptsWithMarshalling) |
| MarshallingInfos.push_back(createMarshallingInfo(*R)); |
| |
| for (const auto &MI : MarshallingInfos) { |
| OS << "#ifdef " << MI.getMacroName() << "\n"; |
| OS << MI.getMacroName() << "("; |
| WriteOptRecordFields(OS, MI.R); |
| OS << ", "; |
| MI.emit(OS); |
| OS << ")\n"; |
| OS << "#endif // " << MI.getMacroName() << "\n"; |
| } |
| |
| OS << "\n"; |
| OS << "#ifdef SIMPLE_ENUM_VALUE_TABLE"; |
| OS << "\n"; |
| OS << MarshallingInfo::ValueTablePreamble; |
| std::vector<StringRef> ValueTableNames; |
| for (const auto &MI : MarshallingInfos) |
| if (auto MaybeValueTableName = MI.emitValueTable(OS)) |
| ValueTableNames.push_back(*MaybeValueTableName); |
| |
| OS << MarshallingInfo::ValueTablesDecl << "{"; |
| for (auto ValueTableName : ValueTableNames) |
| OS << "{" << ValueTableName << ", std::size(" << ValueTableName << ")},\n"; |
| OS << "};\n"; |
| OS << "static const unsigned SimpleEnumValueTablesSize = " |
| "std::size(SimpleEnumValueTables);\n"; |
| |
| OS << "#endif // SIMPLE_ENUM_VALUE_TABLE\n"; |
| } |
| |
| static TableGen::Emitter::Opt X("gen-opt-parser-defs", emitOptionParser, |
| "Generate option definitions"); |