1 //===- DirectiveEmitter.cpp - Directive Language Emitter ------------------===// 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 // DirectiveEmitter uses the descriptions of directives and clauses to construct 10 // common code declarations to be used in Frontends. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/ADT/STLExtras.h" 15 #include "llvm/ADT/SmallVector.h" 16 #include "llvm/ADT/StringExtras.h" 17 #include "llvm/ADT/StringSet.h" 18 #include "llvm/TableGen/Error.h" 19 #include "llvm/TableGen/Record.h" 20 #include "llvm/TableGen/TableGenBackend.h" 21 22 23 using namespace llvm; 24 25 namespace { 26 // Simple RAII helper for defining ifdef-undef-endif scopes. 27 class IfDefScope { 28 public: 29 IfDefScope(StringRef Name, raw_ostream &OS) : Name(Name), OS(OS) { 30 OS << "#ifdef " << Name << "\n" 31 << "#undef " << Name << "\n"; 32 } 33 34 ~IfDefScope() { OS << "\n#endif // " << Name << "\n\n"; } 35 36 private: 37 StringRef Name; 38 raw_ostream &OS; 39 }; 40 } // end anonymous namespace 41 42 namespace llvm { 43 44 // Wrapper class that contains DirectiveLanguage's information defined in 45 // DirectiveBase.td and provides helper methods for accessing it. 46 class DirectiveLanguage { 47 public: 48 explicit DirectiveLanguage(const llvm::Record *Def) : Def(Def) {} 49 50 StringRef getName() const { return Def->getValueAsString("name"); } 51 52 StringRef getCppNamespace() const { 53 return Def->getValueAsString("cppNamespace"); 54 } 55 56 StringRef getDirectivePrefix() const { 57 return Def->getValueAsString("directivePrefix"); 58 } 59 60 StringRef getClausePrefix() const { 61 return Def->getValueAsString("clausePrefix"); 62 } 63 64 StringRef getIncludeHeader() const { 65 return Def->getValueAsString("includeHeader"); 66 } 67 68 StringRef getClauseEnumSetClass() const { 69 return Def->getValueAsString("clauseEnumSetClass"); 70 } 71 72 StringRef getFlangClauseBaseClass() const { 73 return Def->getValueAsString("flangClauseBaseClass"); 74 } 75 76 bool hasMakeEnumAvailableInNamespace() const { 77 return Def->getValueAsBit("makeEnumAvailableInNamespace"); 78 } 79 80 bool hasEnableBitmaskEnumInNamespace() const { 81 return Def->getValueAsBit("enableBitmaskEnumInNamespace"); 82 } 83 84 private: 85 const llvm::Record *Def; 86 }; 87 88 // Base record class used for Directive and Clause class defined in 89 // DirectiveBase.td. 90 class BaseRecord { 91 public: 92 explicit BaseRecord(const llvm::Record *Def) : Def(Def) {} 93 94 StringRef getName() const { return Def->getValueAsString("name"); } 95 96 StringRef getAlternativeName() const { 97 return Def->getValueAsString("alternativeName"); 98 } 99 100 // Returns the name of the directive formatted for output. Whitespace are 101 // replaced with underscores. 102 std::string getFormattedName() { 103 StringRef Name = Def->getValueAsString("name"); 104 std::string N = Name.str(); 105 std::replace(N.begin(), N.end(), ' ', '_'); 106 return N; 107 } 108 109 bool isDefault() const { return Def->getValueAsBit("isDefault"); } 110 111 protected: 112 const llvm::Record *Def; 113 }; 114 115 // Wrapper class that contains a Directive's information defined in 116 // DirectiveBase.td and provides helper methods for accessing it. 117 class Directive : public BaseRecord { 118 public: 119 explicit Directive(const llvm::Record *Def) : BaseRecord(Def) {} 120 121 std::vector<Record *> getAllowedClauses() const { 122 return Def->getValueAsListOfDefs("allowedClauses"); 123 } 124 125 std::vector<Record *> getAllowedOnceClauses() const { 126 return Def->getValueAsListOfDefs("allowedOnceClauses"); 127 } 128 129 std::vector<Record *> getAllowedExclusiveClauses() const { 130 return Def->getValueAsListOfDefs("allowedExclusiveClauses"); 131 } 132 133 std::vector<Record *> getRequiredClauses() const { 134 return Def->getValueAsListOfDefs("requiredClauses"); 135 } 136 }; 137 138 // Wrapper class that contains Clause's information defined in DirectiveBase.td 139 // and provides helper methods for accessing it. 140 class Clause : public BaseRecord { 141 public: 142 explicit Clause(const llvm::Record *Def) : BaseRecord(Def) {} 143 144 // Optional field. 145 StringRef getClangClass() const { 146 return Def->getValueAsString("clangClass"); 147 } 148 149 // Optional field. 150 StringRef getFlangClass() const { 151 return Def->getValueAsString("flangClass"); 152 } 153 154 // Optional field. 155 StringRef getFlangClassValue() const { 156 return Def->getValueAsString("flangClassValue"); 157 } 158 159 // Get the formatted name for Flang parser class. The generic formatted class 160 // name is constructed from the name were the first letter of each word is 161 // captitalized and the underscores are removed. 162 // ex: async -> Async 163 // num_threads -> NumThreads 164 std::string getFormattedParserClassName() { 165 StringRef Name = Def->getValueAsString("name"); 166 std::string N = Name.str(); 167 bool Cap = true; 168 std::transform(N.begin(), N.end(), N.begin(), [&Cap](unsigned char C) { 169 if (Cap == true) { 170 C = llvm::toUpper(C); 171 Cap = false; 172 } else if (C == '_') { 173 Cap = true; 174 } 175 return C; 176 }); 177 N.erase(std::remove(N.begin(), N.end(), '_'), N.end()); 178 return N; 179 } 180 181 bool isValueOptional() const { return Def->getValueAsBit("isValueOptional"); } 182 183 bool isImplict() const { return Def->getValueAsBit("isImplicit"); } 184 }; 185 186 // Wrapper class that contains VersionedClause's information defined in 187 // DirectiveBase.td and provides helper methods for accessing it. 188 class VersionedClause { 189 public: 190 explicit VersionedClause(const llvm::Record *Def) : Def(Def) {} 191 192 // Return the specific clause record wrapped in the Clause class. 193 Clause getClause() const { return Clause{Def->getValueAsDef("clause")}; } 194 195 int64_t getMinVersion() const { return Def->getValueAsInt("minVersion"); } 196 197 int64_t getMaxVersion() const { return Def->getValueAsInt("maxVersion"); } 198 199 private: 200 const llvm::Record *Def; 201 }; 202 203 // Generate enum class 204 void GenerateEnumClass(const std::vector<Record *> &Records, raw_ostream &OS, 205 StringRef Enum, StringRef Prefix, 206 DirectiveLanguage &DirLang) { 207 OS << "\n"; 208 OS << "enum class " << Enum << " {\n"; 209 for (const auto &R : Records) { 210 BaseRecord Rec{R}; 211 OS << " " << Prefix << Rec.getFormattedName() << ",\n"; 212 } 213 OS << "};\n"; 214 OS << "\n"; 215 OS << "static constexpr std::size_t " << Enum 216 << "_enumSize = " << Records.size() << ";\n"; 217 218 // Make the enum values available in the defined namespace. This allows us to 219 // write something like Enum_X if we have a `using namespace <CppNamespace>`. 220 // At the same time we do not loose the strong type guarantees of the enum 221 // class, that is we cannot pass an unsigned as Directive without an explicit 222 // cast. 223 if (DirLang.hasMakeEnumAvailableInNamespace()) { 224 OS << "\n"; 225 for (const auto &R : Records) { 226 BaseRecord Rec{R}; 227 OS << "constexpr auto " << Prefix << Rec.getFormattedName() << " = " 228 << "llvm::" << DirLang.getCppNamespace() << "::" << Enum 229 << "::" << Prefix << Rec.getFormattedName() << ";\n"; 230 } 231 } 232 } 233 234 // Generate the declaration section for the enumeration in the directive 235 // language 236 void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) { 237 238 const auto &DirectiveLanguages = 239 Records.getAllDerivedDefinitions("DirectiveLanguage"); 240 241 if (DirectiveLanguages.size() != 1) { 242 PrintError("A single definition of DirectiveLanguage is needed."); 243 return; 244 } 245 246 DirectiveLanguage DirLang{DirectiveLanguages[0]}; 247 248 OS << "#ifndef LLVM_" << DirLang.getName() << "_INC\n"; 249 OS << "#define LLVM_" << DirLang.getName() << "_INC\n"; 250 251 if (DirLang.hasEnableBitmaskEnumInNamespace()) 252 OS << "\n#include \"llvm/ADT/BitmaskEnum.h\"\n"; 253 254 OS << "\n"; 255 OS << "namespace llvm {\n"; 256 OS << "class StringRef;\n"; 257 258 // Open namespaces defined in the directive language 259 llvm::SmallVector<StringRef, 2> Namespaces; 260 llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::"); 261 for (auto Ns : Namespaces) 262 OS << "namespace " << Ns << " {\n"; 263 264 if (DirLang.hasEnableBitmaskEnumInNamespace()) 265 OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n"; 266 267 // Emit Directive enumeration 268 const auto &Directives = Records.getAllDerivedDefinitions("Directive"); 269 GenerateEnumClass(Directives, OS, "Directive", DirLang.getDirectivePrefix(), 270 DirLang); 271 272 // Emit Clause enumeration 273 const auto &Clauses = Records.getAllDerivedDefinitions("Clause"); 274 GenerateEnumClass(Clauses, OS, "Clause", DirLang.getClausePrefix(), DirLang); 275 276 // Generic function signatures 277 OS << "\n"; 278 OS << "// Enumeration helper functions\n"; 279 OS << "Directive get" << DirLang.getName() 280 << "DirectiveKind(llvm::StringRef Str);\n"; 281 OS << "\n"; 282 OS << "llvm::StringRef get" << DirLang.getName() 283 << "DirectiveName(Directive D);\n"; 284 OS << "\n"; 285 OS << "Clause get" << DirLang.getName() 286 << "ClauseKind(llvm::StringRef Str);\n"; 287 OS << "\n"; 288 OS << "llvm::StringRef get" << DirLang.getName() << "ClauseName(Clause C);\n"; 289 OS << "\n"; 290 OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p " 291 << "Version.\n"; 292 OS << "bool isAllowedClauseForDirective(Directive D, " 293 << "Clause C, unsigned Version);\n"; 294 OS << "\n"; 295 296 // Closing namespaces 297 for (auto Ns : llvm::reverse(Namespaces)) 298 OS << "} // namespace " << Ns << "\n"; 299 300 OS << "} // namespace llvm\n"; 301 302 OS << "#endif // LLVM_" << DirLang.getName() << "_INC\n"; 303 } 304 305 // Generate function implementation for get<Enum>Name(StringRef Str) 306 void GenerateGetName(const std::vector<Record *> &Records, raw_ostream &OS, 307 StringRef Enum, DirectiveLanguage &DirLang, 308 StringRef Prefix) { 309 OS << "\n"; 310 OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get" 311 << DirLang.getName() << Enum << "Name(" << Enum << " Kind) {\n"; 312 OS << " switch (Kind) {\n"; 313 for (const auto &R : Records) { 314 BaseRecord Rec{R}; 315 OS << " case " << Prefix << Rec.getFormattedName() << ":\n"; 316 OS << " return \""; 317 if (Rec.getAlternativeName().empty()) 318 OS << Rec.getName(); 319 else 320 OS << Rec.getAlternativeName(); 321 OS << "\";\n"; 322 } 323 OS << " }\n"; // switch 324 OS << " llvm_unreachable(\"Invalid " << DirLang.getName() << " " << Enum 325 << " kind\");\n"; 326 OS << "}\n"; 327 } 328 329 // Generate function implementation for get<Enum>Kind(StringRef Str) 330 void GenerateGetKind(const std::vector<Record *> &Records, raw_ostream &OS, 331 StringRef Enum, DirectiveLanguage &DirLang, 332 StringRef Prefix, bool ImplicitAsUnknown) { 333 334 auto DefaultIt = std::find_if(Records.begin(), Records.end(), [](Record *R) { 335 return R->getValueAsBit("isDefault") == true; 336 }); 337 338 if (DefaultIt == Records.end()) { 339 PrintError("A least one " + Enum + " must be defined as default."); 340 return; 341 } 342 343 BaseRecord DefaultRec{(*DefaultIt)}; 344 345 OS << "\n"; 346 OS << Enum << " llvm::" << DirLang.getCppNamespace() << "::get" 347 << DirLang.getName() << Enum << "Kind(llvm::StringRef Str) {\n"; 348 OS << " return llvm::StringSwitch<" << Enum << ">(Str)\n"; 349 350 for (const auto &R : Records) { 351 BaseRecord Rec{R}; 352 if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) { 353 OS << " .Case(\"" << Rec.getName() << "\"," << Prefix 354 << DefaultRec.getFormattedName() << ")\n"; 355 } else { 356 OS << " .Case(\"" << Rec.getName() << "\"," << Prefix 357 << Rec.getFormattedName() << ")\n"; 358 } 359 } 360 OS << " .Default(" << Prefix << DefaultRec.getFormattedName() << ");\n"; 361 OS << "}\n"; 362 } 363 364 void GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses, 365 raw_ostream &OS, StringRef DirectiveName, 366 DirectiveLanguage &DirLang, 367 llvm::StringSet<> &Cases) { 368 for (const auto &C : Clauses) { 369 VersionedClause VerClause{C}; 370 371 const auto ClauseFormattedName = VerClause.getClause().getFormattedName(); 372 373 if (Cases.find(ClauseFormattedName) == Cases.end()) { 374 Cases.insert(ClauseFormattedName); 375 OS << " case " << DirLang.getClausePrefix() << ClauseFormattedName 376 << ":\n"; 377 OS << " return " << VerClause.getMinVersion() 378 << " <= Version && " << VerClause.getMaxVersion() << " >= Version;\n"; 379 } 380 } 381 } 382 383 // Generate the isAllowedClauseForDirective function implementation. 384 void GenerateIsAllowedClause(const std::vector<Record *> &Directives, 385 raw_ostream &OS, DirectiveLanguage &DirLang) { 386 OS << "\n"; 387 OS << "bool llvm::" << DirLang.getCppNamespace() 388 << "::isAllowedClauseForDirective(" 389 << "Directive D, Clause C, unsigned Version) {\n"; 390 OS << " assert(unsigned(D) <= llvm::" << DirLang.getCppNamespace() 391 << "::Directive_enumSize);\n"; 392 OS << " assert(unsigned(C) <= llvm::" << DirLang.getCppNamespace() 393 << "::Clause_enumSize);\n"; 394 395 OS << " switch (D) {\n"; 396 397 for (const auto &D : Directives) { 398 Directive Dir{D}; 399 400 OS << " case " << DirLang.getDirectivePrefix() << Dir.getFormattedName() 401 << ":\n"; 402 if (Dir.getAllowedClauses().size() == 0 && 403 Dir.getAllowedOnceClauses().size() == 0 && 404 Dir.getAllowedExclusiveClauses().size() == 0 && 405 Dir.getRequiredClauses().size() == 0) { 406 OS << " return false;\n"; 407 } else { 408 OS << " switch (C) {\n"; 409 410 llvm::StringSet<> Cases; 411 412 GenerateCaseForVersionedClauses(Dir.getAllowedClauses(), OS, 413 Dir.getName(), DirLang, Cases); 414 415 GenerateCaseForVersionedClauses(Dir.getAllowedOnceClauses(), OS, 416 Dir.getName(), DirLang, Cases); 417 418 GenerateCaseForVersionedClauses(Dir.getAllowedExclusiveClauses(), OS, 419 Dir.getName(), DirLang, Cases); 420 421 GenerateCaseForVersionedClauses(Dir.getRequiredClauses(), OS, 422 Dir.getName(), DirLang, Cases); 423 424 OS << " default:\n"; 425 OS << " return false;\n"; 426 OS << " }\n"; // End of clauses switch 427 } 428 OS << " break;\n"; 429 } 430 431 OS << " }\n"; // End of directives switch 432 OS << " llvm_unreachable(\"Invalid " << DirLang.getName() 433 << " Directive kind\");\n"; 434 OS << "}\n"; // End of function isAllowedClauseForDirective 435 } 436 437 // Generate a simple enum set with the give clauses. 438 void GenerateClauseSet(const std::vector<Record *> &Clauses, raw_ostream &OS, 439 StringRef ClauseSetPrefix, Directive &Dir, 440 DirectiveLanguage &DirLang) { 441 442 OS << "\n"; 443 OS << " static " << DirLang.getClauseEnumSetClass() << " " << ClauseSetPrefix 444 << DirLang.getDirectivePrefix() << Dir.getFormattedName() << " {\n"; 445 446 for (const auto &C : Clauses) { 447 VersionedClause VerClause{C}; 448 OS << " llvm::" << DirLang.getCppNamespace() 449 << "::Clause::" << DirLang.getClausePrefix() 450 << VerClause.getClause().getFormattedName() << ",\n"; 451 } 452 OS << " };\n"; 453 } 454 455 // Generate an enum set for the 4 kinds of clauses linked to a directive. 456 void GenerateDirectiveClauseSets(const std::vector<Record *> &Directives, 457 raw_ostream &OS, DirectiveLanguage &DirLang) { 458 459 IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_SETS", OS); 460 461 OS << "\n"; 462 OS << "namespace llvm {\n"; 463 464 // Open namespaces defined in the directive language. 465 llvm::SmallVector<StringRef, 2> Namespaces; 466 llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::"); 467 for (auto Ns : Namespaces) 468 OS << "namespace " << Ns << " {\n"; 469 470 for (const auto &D : Directives) { 471 Directive Dir{D}; 472 473 OS << "\n"; 474 OS << " // Sets for " << Dir.getName() << "\n"; 475 476 GenerateClauseSet(Dir.getAllowedClauses(), OS, "allowedClauses_", Dir, 477 DirLang); 478 GenerateClauseSet(Dir.getAllowedOnceClauses(), OS, "allowedOnceClauses_", 479 Dir, DirLang); 480 GenerateClauseSet(Dir.getAllowedExclusiveClauses(), OS, 481 "allowedExclusiveClauses_", Dir, DirLang); 482 GenerateClauseSet(Dir.getRequiredClauses(), OS, "requiredClauses_", Dir, 483 DirLang); 484 } 485 486 // Closing namespaces 487 for (auto Ns : llvm::reverse(Namespaces)) 488 OS << "} // namespace " << Ns << "\n"; 489 490 OS << "} // namespace llvm\n"; 491 } 492 493 // Generate a map of directive (key) with DirectiveClauses struct as values. 494 // The struct holds the 4 sets of enumeration for the 4 kinds of clauses 495 // allowances (allowed, allowed once, allowed exclusive and required). 496 void GenerateDirectiveClauseMap(const std::vector<Record *> &Directives, 497 raw_ostream &OS, DirectiveLanguage &DirLang) { 498 499 IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_MAP", OS); 500 501 OS << "\n"; 502 OS << "{\n"; 503 504 for (const auto &D : Directives) { 505 Directive Dir{D}; 506 OS << " {llvm::" << DirLang.getCppNamespace() 507 << "::Directive::" << DirLang.getDirectivePrefix() 508 << Dir.getFormattedName() << ",\n"; 509 OS << " {\n"; 510 OS << " llvm::" << DirLang.getCppNamespace() << "::allowedClauses_" 511 << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n"; 512 OS << " llvm::" << DirLang.getCppNamespace() << "::allowedOnceClauses_" 513 << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n"; 514 OS << " llvm::" << DirLang.getCppNamespace() 515 << "::allowedExclusiveClauses_" << DirLang.getDirectivePrefix() 516 << Dir.getFormattedName() << ",\n"; 517 OS << " llvm::" << DirLang.getCppNamespace() << "::requiredClauses_" 518 << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n"; 519 OS << " }\n"; 520 OS << " },\n"; 521 } 522 523 OS << "}\n"; 524 } 525 526 // Generate classes entry for Flang clauses in the Flang parse-tree 527 // If the clause as a non-generic class, no entry is generated. 528 // If the clause does not hold a value, an EMPTY_CLASS is used. 529 // If the clause class is generic then a WRAPPER_CLASS is used. When the value 530 // is optional, the value class is wrapped into a std::optional. 531 void GenerateFlangClauseParserClass(const std::vector<Record *> &Clauses, 532 raw_ostream &OS) { 533 534 IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS); 535 536 OS << "\n"; 537 538 for (const auto &C : Clauses) { 539 Clause Clause{C}; 540 // Clause has a non generic class. 541 if (!Clause.getFlangClass().empty()) 542 continue; 543 // G 544 if (!Clause.getFlangClassValue().empty()) { 545 if (Clause.isValueOptional()) { 546 OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName() 547 << ", std::optional<" << Clause.getFlangClassValue() << ">);\n"; 548 } else { 549 OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName() << ", " 550 << Clause.getFlangClassValue() << ");\n"; 551 } 552 } else { 553 OS << "EMPTY_CLASS(" << Clause.getFormattedParserClassName() << ");\n"; 554 } 555 } 556 } 557 558 // Generate a list of the different clause classes for Flang. 559 void GenerateFlangClauseParserClassList(const std::vector<Record *> &Clauses, 560 raw_ostream &OS) { 561 562 IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS); 563 564 OS << "\n"; 565 llvm::interleaveComma(Clauses, OS, [&](Record *C) { 566 Clause Clause{C}; 567 if (Clause.getFlangClass().empty()) 568 OS << Clause.getFormattedParserClassName() << "\n"; 569 else 570 OS << Clause.getFlangClass() << "\n"; 571 }); 572 } 573 574 // Generate dump node list for the clauses holding a generic class name. 575 void GenerateFlangClauseDump(const std::vector<Record *> &Clauses, 576 const DirectiveLanguage &DirLang, 577 raw_ostream &OS) { 578 579 IfDefScope Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS); 580 581 OS << "\n"; 582 for (const auto &C : Clauses) { 583 Clause Clause{C}; 584 // Clause has a non generic class. 585 if (!Clause.getFlangClass().empty()) 586 continue; 587 588 OS << "NODE(" << DirLang.getFlangClauseBaseClass() << ", " 589 << Clause.getFormattedParserClassName() << ")\n"; 590 } 591 } 592 593 // Generate the implemenation section for the enumeration in the directive 594 // language 595 void EmitDirectivesFlangImpl(const std::vector<Record *> &Directives, 596 const std::vector<Record *> &Clauses, 597 raw_ostream &OS, 598 DirectiveLanguage &DirectiveLanguage) { 599 600 GenerateDirectiveClauseSets(Directives, OS, DirectiveLanguage); 601 602 GenerateDirectiveClauseMap(Directives, OS, DirectiveLanguage); 603 604 GenerateFlangClauseParserClass(Clauses, OS); 605 606 GenerateFlangClauseParserClassList(Clauses, OS); 607 608 GenerateFlangClauseDump(Clauses, DirectiveLanguage, OS); 609 } 610 611 // Generate the implemenation section for the enumeration in the directive 612 // language. 613 void EmitDirectivesGen(RecordKeeper &Records, raw_ostream &OS) { 614 615 const auto &DirectiveLanguages = 616 Records.getAllDerivedDefinitions("DirectiveLanguage"); 617 618 if (DirectiveLanguages.size() != 1) { 619 PrintError("A single definition of DirectiveLanguage is needed."); 620 return; 621 } 622 623 const auto &Directives = Records.getAllDerivedDefinitions("Directive"); 624 const auto &Clauses = Records.getAllDerivedDefinitions("Clause"); 625 DirectiveLanguage DirectiveLanguage{DirectiveLanguages[0]}; 626 EmitDirectivesFlangImpl(Directives, Clauses, OS, DirectiveLanguage); 627 } 628 629 // Generate the implemenation for the enumeration in the directive 630 // language. This code can be included in library. 631 void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) { 632 633 const auto &DirectiveLanguages = 634 Records.getAllDerivedDefinitions("DirectiveLanguage"); 635 636 if (DirectiveLanguages.size() != 1) { 637 PrintError("A single definition of DirectiveLanguage is needed."); 638 return; 639 } 640 641 const auto &Directives = Records.getAllDerivedDefinitions("Directive"); 642 643 DirectiveLanguage DirLang = DirectiveLanguage{DirectiveLanguages[0]}; 644 645 const auto &Clauses = Records.getAllDerivedDefinitions("Clause"); 646 647 if (!DirLang.getIncludeHeader().empty()) 648 OS << "#include \"" << DirLang.getIncludeHeader() << "\"\n\n"; 649 650 OS << "#include \"llvm/ADT/StringRef.h\"\n"; 651 OS << "#include \"llvm/ADT/StringSwitch.h\"\n"; 652 OS << "#include \"llvm/Support/ErrorHandling.h\"\n"; 653 OS << "\n"; 654 OS << "using namespace llvm;\n"; 655 llvm::SmallVector<StringRef, 2> Namespaces; 656 llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::"); 657 for (auto Ns : Namespaces) 658 OS << "using namespace " << Ns << ";\n"; 659 660 // getDirectiveKind(StringRef Str) 661 GenerateGetKind(Directives, OS, "Directive", DirLang, 662 DirLang.getDirectivePrefix(), /*ImplicitAsUnknown=*/false); 663 664 // getDirectiveName(Directive Kind) 665 GenerateGetName(Directives, OS, "Directive", DirLang, 666 DirLang.getDirectivePrefix()); 667 668 // getClauseKind(StringRef Str) 669 GenerateGetKind(Clauses, OS, "Clause", DirLang, DirLang.getClausePrefix(), 670 /*ImplicitAsUnknown=*/true); 671 672 // getClauseName(Clause Kind) 673 GenerateGetName(Clauses, OS, "Clause", DirLang, DirLang.getClausePrefix()); 674 675 // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version) 676 GenerateIsAllowedClause(Directives, OS, DirLang); 677 } 678 679 } // namespace llvm 680