694 lines · cpp
1//===- OptionParserEmitter.cpp - Table Driven Command Option 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-exception6//7//===----------------------------------------------------------------------===//8 9#include "Common/OptEmitter.h"10#include "llvm/ADT/STLExtras.h"11#include "llvm/ADT/SmallString.h"12#include "llvm/ADT/SmallVector.h"13#include "llvm/ADT/StringExtras.h"14#include "llvm/ADT/Twine.h"15#include "llvm/Option/OptTable.h"16#include "llvm/Support/InterleavedRange.h"17#include "llvm/Support/raw_ostream.h"18#include "llvm/TableGen/Record.h"19#include "llvm/TableGen/StringToOffsetTable.h"20#include "llvm/TableGen/TableGenBackend.h"21#include <cstring>22#include <map>23 24using namespace llvm;25 26static std::string getOptionName(const Record &R) {27 // Use the record name unless EnumName is defined.28 if (isa<UnsetInit>(R.getValueInit("EnumName")))29 return R.getName().str();30 31 return R.getValueAsString("EnumName").str();32}33 34static raw_ostream &writeStrTableOffset(raw_ostream &OS,35 const StringToOffsetTable &Table,36 llvm::StringRef Str) {37 OS << Table.GetStringOffset(Str) << " /* ";38 OS.write_escaped(Str);39 OS << " */";40 return OS;41}42 43static raw_ostream &writeCstring(raw_ostream &OS, llvm::StringRef Str) {44 OS << '"';45 OS.write_escaped(Str);46 OS << '"';47 return OS;48}49 50static std::string getOptionPrefixedName(const Record &R) {51 std::vector<StringRef> Prefixes = R.getValueAsListOfStrings("Prefixes");52 StringRef Name = R.getValueAsString("Name");53 54 if (Prefixes.empty())55 return Name.str();56 57 return (Prefixes[0] + Twine(Name)).str();58}59 60class MarshallingInfo {61public:62 static constexpr const char *MacroName = "OPTION_WITH_MARSHALLING";63 const Record &R;64 bool ShouldAlwaysEmit = false;65 StringRef MacroPrefix;66 StringRef KeyPath;67 StringRef DefaultValue;68 StringRef NormalizedValuesScope;69 StringRef ImpliedCheck;70 StringRef ImpliedValue;71 StringRef ShouldParse;72 StringRef Normalizer;73 StringRef Denormalizer;74 StringRef ValueMerger;75 StringRef ValueExtractor;76 int TableIndex = -1;77 std::vector<StringRef> Values;78 std::vector<StringRef> NormalizedValues;79 std::string ValueTableName;80 81 static size_t NextTableIndex;82 83 static constexpr const char *ValueTablePreamble = R"(84struct SimpleEnumValue {85 const char *Name;86 unsigned Value;87};88 89struct SimpleEnumValueTable {90 const SimpleEnumValue *Table;91 unsigned Size;92};93)";94 95 static constexpr const char *ValueTablesDecl =96 "static const SimpleEnumValueTable SimpleEnumValueTables[] = ";97 98 MarshallingInfo(const Record &R) : R(R) {}99 100 std::string getMacroName() const {101 return (MacroPrefix + MarshallingInfo::MacroName).str();102 }103 104 void emit(raw_ostream &OS) const {105 OS << ShouldParse;106 OS << ", ";107 OS << ShouldAlwaysEmit;108 OS << ", ";109 OS << KeyPath;110 OS << ", ";111 emitScopedNormalizedValue(OS, DefaultValue);112 OS << ", ";113 OS << ImpliedCheck;114 OS << ", ";115 emitScopedNormalizedValue(OS, ImpliedValue);116 OS << ", ";117 OS << Normalizer;118 OS << ", ";119 OS << Denormalizer;120 OS << ", ";121 OS << ValueMerger;122 OS << ", ";123 OS << ValueExtractor;124 OS << ", ";125 OS << TableIndex;126 }127 128 std::optional<StringRef> emitValueTable(raw_ostream &OS) const {129 if (TableIndex == -1)130 return {};131 OS << "static const SimpleEnumValue " << ValueTableName << "[] = {\n";132 for (unsigned I = 0, E = Values.size(); I != E; ++I) {133 OS << "{";134 writeCstring(OS, Values[I]);135 OS << ",";136 OS << "static_cast<unsigned>(";137 emitScopedNormalizedValue(OS, NormalizedValues[I]);138 OS << ")},";139 }140 OS << "};\n";141 return StringRef(ValueTableName);142 }143 144private:145 void emitScopedNormalizedValue(raw_ostream &OS,146 StringRef NormalizedValue) const {147 if (!NormalizedValuesScope.empty())148 OS << NormalizedValuesScope << "::";149 OS << NormalizedValue;150 }151};152 153size_t MarshallingInfo::NextTableIndex = 0;154 155static MarshallingInfo createMarshallingInfo(const Record &R) {156 assert(!isa<UnsetInit>(R.getValueInit("KeyPath")) &&157 !isa<UnsetInit>(R.getValueInit("DefaultValue")) &&158 !isa<UnsetInit>(R.getValueInit("ValueMerger")) &&159 "MarshallingInfo must have a provide a keypath, default value and a "160 "value merger");161 162 MarshallingInfo Ret(R);163 164 Ret.ShouldAlwaysEmit = R.getValueAsBit("ShouldAlwaysEmit");165 Ret.MacroPrefix = R.getValueAsString("MacroPrefix");166 Ret.KeyPath = R.getValueAsString("KeyPath");167 Ret.DefaultValue = R.getValueAsString("DefaultValue");168 Ret.NormalizedValuesScope = R.getValueAsString("NormalizedValuesScope");169 Ret.ImpliedCheck = R.getValueAsString("ImpliedCheck");170 Ret.ImpliedValue =171 R.getValueAsOptionalString("ImpliedValue").value_or(Ret.DefaultValue);172 173 Ret.ShouldParse = R.getValueAsString("ShouldParse");174 Ret.Normalizer = R.getValueAsString("Normalizer");175 Ret.Denormalizer = R.getValueAsString("Denormalizer");176 Ret.ValueMerger = R.getValueAsString("ValueMerger");177 Ret.ValueExtractor = R.getValueAsString("ValueExtractor");178 179 if (!isa<UnsetInit>(R.getValueInit("NormalizedValues"))) {180 assert(!isa<UnsetInit>(R.getValueInit("Values")) &&181 "Cannot provide normalized values for value-less options");182 Ret.TableIndex = MarshallingInfo::NextTableIndex++;183 Ret.NormalizedValues = R.getValueAsListOfStrings("NormalizedValues");184 Ret.Values.reserve(Ret.NormalizedValues.size());185 Ret.ValueTableName = getOptionName(R) + "ValueTable";186 187 StringRef ValuesStr = R.getValueAsString("Values");188 for (;;) {189 size_t Idx = ValuesStr.find(',');190 if (Idx == StringRef::npos)191 break;192 if (Idx > 0)193 Ret.Values.push_back(ValuesStr.slice(0, Idx));194 ValuesStr = ValuesStr.substr(Idx + 1);195 }196 if (!ValuesStr.empty())197 Ret.Values.push_back(ValuesStr);198 199 assert(Ret.Values.size() == Ret.NormalizedValues.size() &&200 "The number of normalized values doesn't match the number of "201 "values");202 }203 204 return Ret;205}206 207static void emitHelpTextsForVariants(208 raw_ostream &OS, std::vector<std::pair<std::vector<std::string>, StringRef>>209 HelpTextsForVariants) {210 // OptTable must be constexpr so it uses std::arrays with these capacities.211 const unsigned MaxVisibilityPerHelp = 2;212 const unsigned MaxVisibilityHelp = 1;213 214 assert(HelpTextsForVariants.size() <= MaxVisibilityHelp &&215 "Too many help text variants to store in "216 "OptTable::HelpTextsForVariants");217 218 // This function must initialise any unused elements of those arrays.219 for (auto [Visibilities, _] : HelpTextsForVariants)220 while (Visibilities.size() < MaxVisibilityPerHelp)221 Visibilities.push_back("0");222 223 while (HelpTextsForVariants.size() < MaxVisibilityHelp)224 HelpTextsForVariants.push_back(225 {std::vector<std::string>(MaxVisibilityPerHelp, "0"), ""});226 227 OS << ", (std::array<std::pair<std::array<unsigned, " << MaxVisibilityPerHelp228 << ">, const char*>, " << MaxVisibilityHelp << ">{{ ";229 230 auto VisibilityHelpEnd = HelpTextsForVariants.cend();231 for (auto VisibilityHelp = HelpTextsForVariants.cbegin();232 VisibilityHelp != VisibilityHelpEnd; ++VisibilityHelp) {233 auto [Visibilities, Help] = *VisibilityHelp;234 235 assert(Visibilities.size() <= MaxVisibilityPerHelp &&236 "Too many visibilities to store in an "237 "OptTable::HelpTextsForVariants entry");238 OS << "{std::array<unsigned, " << MaxVisibilityPerHelp << ">{{"239 << llvm::interleaved(Visibilities) << "}}, ";240 241 if (Help.size())242 writeCstring(OS, Help);243 else244 OS << "nullptr";245 OS << "}";246 247 if (std::next(VisibilityHelp) != VisibilityHelpEnd)248 OS << ", ";249 }250 OS << " }})";251}252 253/// OptionParserEmitter - This tablegen backend takes an input .td file254/// describing a list of options and emits a data structure for parsing and255/// working with those options when given an input command line.256static void emitOptionParser(const RecordKeeper &Records, raw_ostream &OS) {257 // Get the option groups and options.258 ArrayRef<const Record *> Groups =259 Records.getAllDerivedDefinitions("OptionGroup");260 std::vector<const Record *> Opts = Records.getAllDerivedDefinitions("Option");261 llvm::sort(Opts, IsOptionRecordsLess);262 263 std::vector<const Record *> SubCommands =264 Records.getAllDerivedDefinitions("SubCommand");265 266 emitSourceFileHeader("Option Parsing Definitions", OS);267 268 // Generate prefix groups.269 using PrefixKeyT = SmallVector<SmallString<2>, 2>;270 using PrefixesT = std::map<PrefixKeyT, unsigned>;271 PrefixesT Prefixes;272 Prefixes.try_emplace(PrefixKeyT(), 0);273 for (const Record &R : llvm::make_pointee_range(Opts)) {274 std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings("Prefixes");275 PrefixKeyT PrefixKey(RPrefixes.begin(), RPrefixes.end());276 Prefixes.try_emplace(PrefixKey, 0);277 }278 279 // Generate sub command groups.280 using SubCommandKeyT = SmallVector<StringRef, 2>;281 using SubCommandIDsT = std::map<SubCommandKeyT, unsigned>;282 SubCommandIDsT SubCommandIDs;283 284 auto PrintSubCommandIdsOffset = [&SubCommandIDs, &OS](const Record &R) {285 if (R.getValue("SubCommands") != nullptr) {286 std::vector<const Record *> SubCommands =287 R.getValueAsListOfDefs("SubCommands");288 SubCommandKeyT SubCommandKey;289 for (const auto &SubCommand : SubCommands)290 SubCommandKey.push_back(SubCommand->getName());291 OS << SubCommandIDs[SubCommandKey];292 } else {293 // The option SubCommandIDsOffset (for default top level toolname is 0).294 OS << " 0";295 }296 };297 298 SubCommandIDs.try_emplace(SubCommandKeyT(), 0);299 for (const Record &R : llvm::make_pointee_range(Opts)) {300 std::vector<const Record *> RSubCommands =301 R.getValueAsListOfDefs("SubCommands");302 SubCommandKeyT SubCommandKey;303 for (const auto &SubCommand : RSubCommands)304 SubCommandKey.push_back(SubCommand->getName());305 SubCommandIDs.try_emplace(SubCommandKey, 0);306 }307 308 DenseSet<StringRef> PrefixesUnionSet;309 for (const auto &[Prefix, _] : Prefixes)310 PrefixesUnionSet.insert_range(Prefix);311 SmallVector<StringRef> PrefixesUnion(PrefixesUnionSet.begin(),312 PrefixesUnionSet.end());313 array_pod_sort(PrefixesUnion.begin(), PrefixesUnion.end());314 315 llvm::StringToOffsetTable Table;316 // We can add all the prefixes via the union.317 for (const auto &Prefix : PrefixesUnion)318 Table.GetOrAddStringOffset(Prefix);319 for (const Record &R : llvm::make_pointee_range(Groups))320 Table.GetOrAddStringOffset(R.getValueAsString("Name"));321 for (const Record &R : llvm::make_pointee_range(Opts))322 Table.GetOrAddStringOffset(getOptionPrefixedName(R));323 324 // Dump string table.325 OS << "/////////\n";326 OS << "// String table\n\n";327 OS << "#ifdef OPTTABLE_STR_TABLE_CODE\n";328 Table.EmitStringTableDef(OS, "OptionStrTable");329 OS << "#endif // OPTTABLE_STR_TABLE_CODE\n\n";330 331 // Dump prefixes.332 OS << "/////////\n";333 OS << "// Prefixes\n\n";334 OS << "#ifdef OPTTABLE_PREFIXES_TABLE_CODE\n";335 OS << "static constexpr llvm::StringTable::Offset OptionPrefixesTable[] = "336 "{\n";337 {338 // Ensure the first prefix set is always empty.339 assert(!Prefixes.empty() &&340 "We should always emit an empty set of prefixes");341 assert(Prefixes.begin()->first.empty() &&342 "First prefix set should always be empty");343 llvm::ListSeparator Sep(",\n");344 unsigned CurIndex = 0;345 for (auto &[Prefix, PrefixIndex] : Prefixes) {346 // First emit the number of prefix strings in this list of prefixes.347 OS << Sep << " " << Prefix.size() << " /* prefixes */";348 PrefixIndex = CurIndex;349 assert((CurIndex == 0 || !Prefix.empty()) &&350 "Only first prefix set should be empty!");351 for (const auto &PrefixKey : Prefix)352 OS << ", " << *Table.GetStringOffset(PrefixKey) << " /* '" << PrefixKey353 << "' */";354 CurIndex += Prefix.size() + 1;355 }356 }357 OS << "\n};\n";358 OS << "#endif // OPTTABLE_PREFIXES_TABLE_CODE\n\n";359 360 // Dump subcommand IDs.361 OS << "/////////";362 OS << "// SubCommand IDs\n\n";363 OS << "#ifdef OPTTABLE_SUBCOMMAND_IDS_TABLE_CODE\n";364 OS << "static constexpr unsigned OptionSubCommandIDsTable[] = {\n";365 {366 // Ensure the first subcommand set is always empty.367 assert(!SubCommandIDs.empty() &&368 "We should always emit an empty set of subcommands");369 assert(SubCommandIDs.begin()->first.empty() &&370 "First subcommand set should always be empty");371 llvm::ListSeparator Sep(",\n");372 unsigned CurIndex = 0;373 for (auto &[SubCommand, SubCommandIndex] : SubCommandIDs) {374 // First emit the number of subcommand strings in this list of375 // subcommands.376 OS << Sep << " " << SubCommand.size() << " /* subcommands */";377 SubCommandIndex = CurIndex;378 assert((CurIndex == 0 || !SubCommand.empty()) &&379 "Only first subcommand set should be empty!");380 for (const auto &SubCommandKey : SubCommand) {381 auto It = llvm::find_if(SubCommands, [&](const Record *R) {382 return R->getName() == SubCommandKey;383 });384 assert(It != SubCommands.end() && "SubCommand not found");385 OS << ", " << std::distance(SubCommands.begin(), It) << " /* '"386 << SubCommandKey << "' */";387 }388 CurIndex += SubCommand.size() + 1;389 }390 }391 OS << "\n};\n";392 OS << "#endif // OPTTABLE_SUBCOMMAND_IDS_TABLE_CODE\n\n";393 394 // Dump prefixes union.395 OS << "/////////\n";396 OS << "// Prefix Union\n\n";397 OS << "#ifdef OPTTABLE_PREFIXES_UNION_CODE\n";398 OS << "static constexpr llvm::StringTable::Offset OptionPrefixesUnion[] = "399 "{\n";400 {401 llvm::ListSeparator Sep(", ");402 for (auto Prefix : PrefixesUnion)403 OS << Sep << " " << *Table.GetStringOffset(Prefix) << " /* '" << Prefix404 << "' */";405 }406 OS << "\n};\n";407 OS << "#endif // OPTTABLE_PREFIXES_UNION_CODE\n\n";408 409 // Dump groups.410 OS << "/////////\n";411 OS << "// ValuesCode\n\n";412 OS << "#ifdef OPTTABLE_VALUES_CODE\n";413 for (const Record &R : llvm::make_pointee_range(Opts)) {414 // The option values, if any;415 if (!isa<UnsetInit>(R.getValueInit("ValuesCode"))) {416 assert(isa<UnsetInit>(R.getValueInit("Values")) &&417 "Cannot choose between Values and ValuesCode");418 OS << "#define VALUES_CODE " << getOptionName(R) << "_Values\n";419 OS << R.getValueAsString("ValuesCode") << "\n";420 OS << "#undef VALUES_CODE\n";421 }422 }423 OS << "#endif\n";424 425 OS << "/////////\n";426 OS << "// Groups\n\n";427 OS << "#ifdef OPTION\n";428 for (const Record &R : llvm::make_pointee_range(Groups)) {429 // Start a single option entry.430 OS << "OPTION(";431 432 // A zero prefix offset corresponds to an empty set of prefixes.433 OS << "0 /* no prefixes */";434 435 // The option string offset.436 OS << ", ";437 writeStrTableOffset(OS, Table, R.getValueAsString("Name"));438 439 // The option identifier name.440 OS << ", " << getOptionName(R);441 442 // The option kind.443 OS << ", Group";444 445 // The containing option group (if any).446 OS << ", ";447 if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group")))448 OS << getOptionName(*DI->getDef());449 else450 OS << "INVALID";451 452 // The other option arguments (unused for groups).453 OS << ", INVALID, nullptr, 0, 0, 0";454 455 // The option help text.456 if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {457 OS << ",\n";458 OS << " ";459 writeCstring(OS, R.getValueAsString("HelpText"));460 } else {461 OS << ", nullptr";462 }463 464 // Not using Visibility specific text for group help.465 emitHelpTextsForVariants(OS, {});466 467 // The option meta-variable name (unused).468 OS << ", nullptr";469 470 // The option Values (unused for groups).471 OS << ", nullptr";472 473 // The option SubCommandIDsOffset.474 OS << ", ";475 PrintSubCommandIdsOffset(R);476 OS << ")\n";477 }478 OS << "\n";479 480 OS << "//////////\n";481 OS << "// Options\n\n";482 483 auto WriteOptRecordFields = [&](raw_ostream &OS, const Record &R) {484 // The option prefix;485 std::vector<StringRef> RPrefixes = R.getValueAsListOfStrings("Prefixes");486 OS << Prefixes[PrefixKeyT(RPrefixes.begin(), RPrefixes.end())] << ", ";487 488 // The option prefixed name.489 writeStrTableOffset(OS, Table, getOptionPrefixedName(R));490 491 // The option identifier name.492 OS << ", " << getOptionName(R);493 494 // The option kind.495 OS << ", " << R.getValueAsDef("Kind")->getValueAsString("Name");496 497 // The containing option group (if any).498 OS << ", ";499 const ListInit *GroupFlags = nullptr;500 const ListInit *GroupVis = nullptr;501 if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {502 GroupFlags = DI->getDef()->getValueAsListInit("Flags");503 GroupVis = DI->getDef()->getValueAsListInit("Visibility");504 OS << getOptionName(*DI->getDef());505 } else {506 OS << "INVALID";507 }508 509 // The option alias (if any).510 OS << ", ";511 if (const DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Alias")))512 OS << getOptionName(*DI->getDef());513 else514 OS << "INVALID";515 516 // The option alias arguments (if any).517 // Emitted as a \0 separated list in a string, e.g. ["foo", "bar"]518 // would become "foo\0bar\0". Note that the compiler adds an implicit519 // terminating \0 at the end.520 OS << ", ";521 std::vector<StringRef> AliasArgs = R.getValueAsListOfStrings("AliasArgs");522 if (AliasArgs.size() == 0) {523 OS << "nullptr";524 } else {525 OS << "\"";526 for (StringRef AliasArg : AliasArgs)527 OS << AliasArg << "\\0";528 OS << "\"";529 }530 531 // "Flags" for the option, such as HelpHidden and Render*532 OS << ", ";533 int NumFlags = 0;534 const ListInit *LI = R.getValueAsListInit("Flags");535 for (const Init *I : *LI)536 OS << (NumFlags++ ? " | " : "") << cast<DefInit>(I)->getDef()->getName();537 if (GroupFlags) {538 for (const Init *I : *GroupFlags)539 OS << (NumFlags++ ? " | " : "")540 << cast<DefInit>(I)->getDef()->getName();541 }542 if (NumFlags == 0)543 OS << '0';544 545 // Option visibility, for sharing options between drivers.546 OS << ", ";547 int NumVisFlags = 0;548 LI = R.getValueAsListInit("Visibility");549 for (const Init *I : *LI)550 OS << (NumVisFlags++ ? " | " : "")551 << cast<DefInit>(I)->getDef()->getName();552 if (GroupVis) {553 for (const Init *I : *GroupVis)554 OS << (NumVisFlags++ ? " | " : "")555 << cast<DefInit>(I)->getDef()->getName();556 }557 if (NumVisFlags == 0)558 OS << '0';559 560 // The option parameter field.561 OS << ", " << R.getValueAsInt("NumArgs");562 563 // The option help text.564 if (!isa<UnsetInit>(R.getValueInit("HelpText"))) {565 OS << ",\n";566 OS << " ";567 writeCstring(OS, R.getValueAsString("HelpText"));568 } else {569 OS << ", nullptr";570 }571 572 std::vector<std::pair<std::vector<std::string>, StringRef>>573 HelpTextsForVariants;574 for (const Record *VisibilityHelp :575 R.getValueAsListOfDefs("HelpTextsForVariants")) {576 ArrayRef<const Init *> Visibilities =577 VisibilityHelp->getValueAsListInit("Visibilities")->getElements();578 579 std::vector<std::string> VisibilityNames;580 for (const Init *Visibility : Visibilities)581 VisibilityNames.push_back(Visibility->getAsUnquotedString());582 583 HelpTextsForVariants.emplace_back(584 VisibilityNames, VisibilityHelp->getValueAsString("Text"));585 }586 emitHelpTextsForVariants(OS, std::move(HelpTextsForVariants));587 588 // The option meta-variable name.589 OS << ", ";590 if (!isa<UnsetInit>(R.getValueInit("MetaVarName")))591 writeCstring(OS, R.getValueAsString("MetaVarName"));592 else593 OS << "nullptr";594 595 // The option Values. Used for shell autocompletion.596 OS << ", ";597 if (!isa<UnsetInit>(R.getValueInit("Values")))598 writeCstring(OS, R.getValueAsString("Values"));599 else if (!isa<UnsetInit>(R.getValueInit("ValuesCode")))600 OS << getOptionName(R) << "_Values";601 else602 OS << "nullptr";603 604 // The option SubCommandIDsOffset.605 OS << ", ";606 PrintSubCommandIdsOffset(R);607 };608 609 auto IsMarshallingOption = [](const Record &R) {610 return !isa<UnsetInit>(R.getValueInit("KeyPath")) &&611 !R.getValueAsString("KeyPath").empty();612 };613 614 std::vector<const Record *> OptsWithMarshalling;615 for (const Record &R : llvm::make_pointee_range(Opts)) {616 // Start a single option entry.617 OS << "OPTION(";618 WriteOptRecordFields(OS, R);619 OS << ")\n";620 if (IsMarshallingOption(R))621 OptsWithMarshalling.push_back(&R);622 }623 OS << "#endif // OPTION\n";624 625 auto CmpMarshallingOpts = [](const Record *const *A, const Record *const *B) {626 unsigned AID = (*A)->getID();627 unsigned BID = (*B)->getID();628 629 if (AID < BID)630 return -1;631 if (AID > BID)632 return 1;633 return 0;634 };635 // The RecordKeeper stores records (options) in lexicographical order, and we636 // have reordered the options again when generating prefix groups. We need to637 // restore the original definition order of options with marshalling to honor638 // the topology of the dependency graph implied by `DefaultAnyOf`.639 array_pod_sort(OptsWithMarshalling.begin(), OptsWithMarshalling.end(),640 CmpMarshallingOpts);641 642 std::vector<MarshallingInfo> MarshallingInfos;643 MarshallingInfos.reserve(OptsWithMarshalling.size());644 for (const auto *R : OptsWithMarshalling)645 MarshallingInfos.push_back(createMarshallingInfo(*R));646 647 for (const auto &MI : MarshallingInfos) {648 OS << "#ifdef " << MI.getMacroName() << "\n";649 OS << MI.getMacroName() << "(";650 WriteOptRecordFields(OS, MI.R);651 OS << ", ";652 MI.emit(OS);653 OS << ")\n";654 OS << "#endif // " << MI.getMacroName() << "\n";655 }656 657 OS << "\n";658 OS << "#ifdef SIMPLE_ENUM_VALUE_TABLE";659 OS << "\n";660 OS << MarshallingInfo::ValueTablePreamble;661 std::vector<StringRef> ValueTableNames;662 for (const auto &MI : MarshallingInfos)663 if (auto MaybeValueTableName = MI.emitValueTable(OS))664 ValueTableNames.push_back(*MaybeValueTableName);665 666 OS << MarshallingInfo::ValueTablesDecl << "{";667 for (auto ValueTableName : ValueTableNames)668 OS << "{" << ValueTableName << ", std::size(" << ValueTableName << ")},\n";669 OS << "};\n";670 OS << "static const unsigned SimpleEnumValueTablesSize = "671 "std::size(SimpleEnumValueTables);\n";672 673 OS << "#endif // SIMPLE_ENUM_VALUE_TABLE\n";674 OS << "\n";675 OS << "/////////\n";676 OS << "\n// SubCommands\n\n";677 OS << "#ifdef OPTTABLE_SUBCOMMANDS_CODE\n";678 OS << "static constexpr llvm::opt::OptTable::SubCommand OptionSubCommands[] "679 "= "680 "{\n";681 for (const Record *SubCommand : SubCommands) {682 OS << " { \"" << SubCommand->getValueAsString("Name") << "\", ";683 OS << "\"" << SubCommand->getValueAsString("HelpText") << "\", ";684 OS << "\"" << SubCommand->getValueAsString("Usage") << "\" },\n";685 }686 OS << "};\n";687 OS << "#endif // OPTTABLE_SUBCOMMANDS_CODE\n\n";688 689 OS << "\n";690}691 692static TableGen::Emitter::Opt X("gen-opt-parser-defs", emitOptionParser,693 "Generate option definitions");694