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