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