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 EnumHelperFuncs += 112 (llvm::Twine("llvm::StringRef get") + llvm::Twine(DirLang.getName()) + 113 llvm::Twine(EnumName) + llvm::Twine("Name(") + 114 llvm::Twine(EnumName) + llvm::Twine(");\n")) 115 .str(); 116 } 117 } 118 } 119 120 bool HasDuplicateClauses(const std::vector<Record *> &Clauses, 121 const Directive &Directive, 122 llvm::StringSet<> &CrtClauses) { 123 bool HasError = false; 124 for (const auto &C : Clauses) { 125 VersionedClause VerClause{C}; 126 const auto insRes = CrtClauses.insert(VerClause.getClause().getName()); 127 if (!insRes.second) { 128 PrintError("Clause " + VerClause.getClause().getRecordName() + 129 " already defined on directive " + Directive.getRecordName()); 130 HasError = true; 131 } 132 } 133 return HasError; 134 } 135 136 // Check for duplicate clauses in lists. Clauses cannot appear twice in the 137 // three allowed list. Also, since required implies allowed, clauses cannot 138 // appear in both the allowedClauses and requiredClauses lists. 139 bool HasDuplicateClausesInDirectives(const std::vector<Record *> &Directives) { 140 bool HasDuplicate = false; 141 for (const auto &D : Directives) { 142 Directive Dir{D}; 143 llvm::StringSet<> Clauses; 144 // Check for duplicates in the three allowed lists. 145 if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) || 146 HasDuplicateClauses(Dir.getAllowedOnceClauses(), Dir, Clauses) || 147 HasDuplicateClauses(Dir.getAllowedExclusiveClauses(), Dir, Clauses)) { 148 HasDuplicate = true; 149 } 150 // Check for duplicate between allowedClauses and required 151 Clauses.clear(); 152 if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) || 153 HasDuplicateClauses(Dir.getRequiredClauses(), Dir, Clauses)) { 154 HasDuplicate = true; 155 } 156 if (HasDuplicate) 157 PrintFatalError("One or more clauses are defined multiple times on" 158 " directive " + 159 Dir.getRecordName()); 160 } 161 162 return HasDuplicate; 163 } 164 165 // Check consitency of records. Return true if an error has been detected. 166 // Return false if the records are valid. 167 bool DirectiveLanguage::HasValidityErrors() const { 168 if (getDirectiveLanguages().size() != 1) { 169 PrintFatalError("A single definition of DirectiveLanguage is needed."); 170 return true; 171 } 172 173 return HasDuplicateClausesInDirectives(getDirectives()); 174 } 175 176 // Generate the declaration section for the enumeration in the directive 177 // language 178 void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) { 179 const auto DirLang = DirectiveLanguage{Records}; 180 if (DirLang.HasValidityErrors()) 181 return; 182 183 OS << "#ifndef LLVM_" << DirLang.getName() << "_INC\n"; 184 OS << "#define LLVM_" << DirLang.getName() << "_INC\n"; 185 186 if (DirLang.hasEnableBitmaskEnumInNamespace()) 187 OS << "\n#include \"llvm/ADT/BitmaskEnum.h\"\n"; 188 189 OS << "\n"; 190 OS << "namespace llvm {\n"; 191 OS << "class StringRef;\n"; 192 193 // Open namespaces defined in the directive language 194 llvm::SmallVector<StringRef, 2> Namespaces; 195 llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::"); 196 for (auto Ns : Namespaces) 197 OS << "namespace " << Ns << " {\n"; 198 199 if (DirLang.hasEnableBitmaskEnumInNamespace()) 200 OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n"; 201 202 // Emit Directive enumeration 203 GenerateEnumClass(DirLang.getDirectives(), OS, "Directive", 204 DirLang.getDirectivePrefix(), DirLang); 205 206 // Emit Clause enumeration 207 GenerateEnumClass(DirLang.getClauses(), OS, "Clause", 208 DirLang.getClausePrefix(), DirLang); 209 210 // Emit ClauseVal enumeration 211 std::string EnumHelperFuncs; 212 GenerateEnumClauseVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs); 213 214 // Generic function signatures 215 OS << "\n"; 216 OS << "// Enumeration helper functions\n"; 217 OS << "Directive get" << DirLang.getName() 218 << "DirectiveKind(llvm::StringRef Str);\n"; 219 OS << "\n"; 220 OS << "llvm::StringRef get" << DirLang.getName() 221 << "DirectiveName(Directive D);\n"; 222 OS << "\n"; 223 OS << "Clause get" << DirLang.getName() 224 << "ClauseKind(llvm::StringRef Str);\n"; 225 OS << "\n"; 226 OS << "llvm::StringRef get" << DirLang.getName() << "ClauseName(Clause C);\n"; 227 OS << "\n"; 228 OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p " 229 << "Version.\n"; 230 OS << "bool isAllowedClauseForDirective(Directive D, " 231 << "Clause C, unsigned Version);\n"; 232 OS << "\n"; 233 if (EnumHelperFuncs.length() > 0) { 234 OS << EnumHelperFuncs; 235 OS << "\n"; 236 } 237 238 // Closing namespaces 239 for (auto Ns : llvm::reverse(Namespaces)) 240 OS << "} // namespace " << Ns << "\n"; 241 242 OS << "} // namespace llvm\n"; 243 244 OS << "#endif // LLVM_" << DirLang.getName() << "_INC\n"; 245 } 246 247 // Generate function implementation for get<Enum>Name(StringRef Str) 248 void GenerateGetName(const std::vector<Record *> &Records, raw_ostream &OS, 249 StringRef Enum, const DirectiveLanguage &DirLang, 250 StringRef Prefix) { 251 OS << "\n"; 252 OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get" 253 << DirLang.getName() << Enum << "Name(" << Enum << " Kind) {\n"; 254 OS << " switch (Kind) {\n"; 255 for (const auto &R : Records) { 256 BaseRecord Rec{R}; 257 OS << " case " << Prefix << Rec.getFormattedName() << ":\n"; 258 OS << " return \""; 259 if (Rec.getAlternativeName().empty()) 260 OS << Rec.getName(); 261 else 262 OS << Rec.getAlternativeName(); 263 OS << "\";\n"; 264 } 265 OS << " }\n"; // switch 266 OS << " llvm_unreachable(\"Invalid " << DirLang.getName() << " " << Enum 267 << " kind\");\n"; 268 OS << "}\n"; 269 } 270 271 // Generate function implementation for get<Enum>Kind(StringRef Str) 272 void GenerateGetKind(const std::vector<Record *> &Records, raw_ostream &OS, 273 StringRef Enum, const DirectiveLanguage &DirLang, 274 StringRef Prefix, bool ImplicitAsUnknown) { 275 276 auto DefaultIt = std::find_if(Records.begin(), Records.end(), [](Record *R) { 277 return R->getValueAsBit("isDefault") == true; 278 }); 279 280 if (DefaultIt == Records.end()) { 281 PrintError("At least one " + Enum + " must be defined as default."); 282 return; 283 } 284 285 BaseRecord DefaultRec{(*DefaultIt)}; 286 287 OS << "\n"; 288 OS << Enum << " llvm::" << DirLang.getCppNamespace() << "::get" 289 << DirLang.getName() << Enum << "Kind(llvm::StringRef Str) {\n"; 290 OS << " return llvm::StringSwitch<" << Enum << ">(Str)\n"; 291 292 for (const auto &R : Records) { 293 BaseRecord Rec{R}; 294 if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) { 295 OS << " .Case(\"" << Rec.getName() << "\"," << Prefix 296 << DefaultRec.getFormattedName() << ")\n"; 297 } else { 298 OS << " .Case(\"" << Rec.getName() << "\"," << Prefix 299 << Rec.getFormattedName() << ")\n"; 300 } 301 } 302 OS << " .Default(" << Prefix << DefaultRec.getFormattedName() << ");\n"; 303 OS << "}\n"; 304 } 305 306 // Generate function implementation for get<ClauseVal>Kind(StringRef Str) 307 void GenerateGetKindClauseVal(const DirectiveLanguage &DirLang, 308 raw_ostream &OS) { 309 for (const auto &R : DirLang.getClauses()) { 310 Clause C{R}; 311 const auto &ClauseVals = C.getClauseVals(); 312 if (ClauseVals.size() <= 0) 313 continue; 314 315 auto DefaultIt = 316 std::find_if(ClauseVals.begin(), ClauseVals.end(), [](Record *CV) { 317 return CV->getValueAsBit("isDefault") == true; 318 }); 319 320 if (DefaultIt == ClauseVals.end()) { 321 PrintError("At least one val in Clause " + C.getFormattedName() + 322 " must be defined as default."); 323 return; 324 } 325 const auto DefaultName = (*DefaultIt)->getName(); 326 327 const auto &EnumName = C.getEnumName(); 328 if (EnumName.size() == 0) { 329 PrintError("enumClauseValue field not set in Clause" + 330 C.getFormattedName() + "."); 331 return; 332 } 333 334 OS << "\n"; 335 OS << EnumName << " llvm::" << DirLang.getCppNamespace() << "::get" 336 << EnumName << "(llvm::StringRef Str) {\n"; 337 OS << " return llvm::StringSwitch<" << EnumName << ">(Str)\n"; 338 for (const auto &CV : ClauseVals) { 339 ClauseVal CVal{CV}; 340 OS << " .Case(\"" << CVal.getFormattedName() << "\"," << CV->getName() 341 << ")\n"; 342 } 343 OS << " .Default(" << DefaultName << ");\n"; 344 OS << "}\n"; 345 346 OS << "\n"; 347 OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get" 348 << DirLang.getName() << EnumName 349 << "Name(llvm::" << DirLang.getCppNamespace() << "::" << EnumName 350 << " x) {\n"; 351 OS << " switch (x) {\n"; 352 for (const auto &CV : ClauseVals) { 353 ClauseVal CVal{CV}; 354 OS << " case " << CV->getName() << ":\n"; 355 OS << " return \"" << CVal.getFormattedName() << "\";\n"; 356 } 357 OS << " }\n"; // switch 358 OS << " llvm_unreachable(\"Invalid " << DirLang.getName() << " " 359 << EnumName << " kind\");\n"; 360 OS << "}\n"; 361 } 362 } 363 364 void GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses, 365 raw_ostream &OS, StringRef DirectiveName, 366 const 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 DirectiveLanguage &DirLang, 385 raw_ostream &OS) { 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 : DirLang.getDirectives()) { 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 const 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 DirectiveLanguage &DirLang, 457 raw_ostream &OS) { 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 : DirLang.getDirectives()) { 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 DirectiveLanguage &DirLang, 497 raw_ostream &OS) { 498 499 IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_MAP", OS); 500 501 OS << "\n"; 502 OS << "{\n"; 503 504 for (const auto &D : DirLang.getDirectives()) { 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 DirectiveLanguage &DirLang, 532 raw_ostream &OS) { 533 534 IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS); 535 536 OS << "\n"; 537 538 for (const auto &C : DirLang.getClauses()) { 539 Clause Clause{C}; 540 // Clause has a non generic class. 541 if (!Clause.getFlangClass().empty()) 542 continue; 543 if (!Clause.getFlangClassValue().empty()) { 544 OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName() << ", "; 545 if (Clause.isValueOptional() && Clause.isValueList()) { 546 OS << "std::optional<std::list<" << Clause.getFlangClassValue() 547 << ">>"; 548 } else if (Clause.isValueOptional()) { 549 OS << "std::optional<" << Clause.getFlangClassValue() << ">"; 550 } else if (Clause.isValueList()) { 551 OS << "std::list<" << Clause.getFlangClassValue() << ">"; 552 } else { 553 OS << Clause.getFlangClassValue(); 554 } 555 } else { 556 OS << "EMPTY_CLASS(" << Clause.getFormattedParserClassName(); 557 } 558 OS << ");\n"; 559 } 560 } 561 562 // Generate a list of the different clause classes for Flang. 563 void GenerateFlangClauseParserClassList(const DirectiveLanguage &DirLang, 564 raw_ostream &OS) { 565 566 IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS); 567 568 OS << "\n"; 569 llvm::interleaveComma(DirLang.getClauses(), OS, [&](Record *C) { 570 Clause Clause{C}; 571 if (Clause.getFlangClass().empty()) 572 OS << Clause.getFormattedParserClassName() << "\n"; 573 else 574 OS << Clause.getFlangClass() << "\n"; 575 }); 576 } 577 578 // Generate dump node list for the clauses holding a generic class name. 579 void GenerateFlangClauseDump(const DirectiveLanguage &DirLang, 580 raw_ostream &OS) { 581 582 IfDefScope Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS); 583 584 OS << "\n"; 585 for (const auto &C : DirLang.getClauses()) { 586 Clause Clause{C}; 587 // Clause has a non generic class. 588 if (!Clause.getFlangClass().empty()) 589 continue; 590 591 OS << "NODE(" << DirLang.getFlangClauseBaseClass() << ", " 592 << Clause.getFormattedParserClassName() << ")\n"; 593 } 594 } 595 596 // Generate Unparse functions for clauses classes in the Flang parse-tree 597 // If the clause is a non-generic class, no entry is generated. 598 void GenerateFlangClauseUnparse(const DirectiveLanguage &DirLang, 599 raw_ostream &OS) { 600 601 IfDefScope Scope("GEN_FLANG_CLAUSE_UNPARSE", OS); 602 603 OS << "\n"; 604 605 for (const auto &C : DirLang.getClauses()) { 606 Clause Clause{C}; 607 // Clause has a non generic class. 608 if (!Clause.getFlangClass().empty()) 609 continue; 610 if (!Clause.getFlangClassValue().empty()) { 611 if (Clause.isValueOptional() && Clause.getDefaultValue().empty()) { 612 OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass() 613 << "::" << Clause.getFormattedParserClassName() << " &x) {\n"; 614 OS << " Word(\"" << Clause.getName().upper() << "\");\n"; 615 616 OS << " Walk(\"(\", x.v, \")\");\n"; 617 OS << "}\n"; 618 } else if (Clause.isValueOptional()) { 619 OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass() 620 << "::" << Clause.getFormattedParserClassName() << " &x) {\n"; 621 OS << " Word(\"" << Clause.getName().upper() << "\");\n"; 622 OS << " Put(\"(\");\n"; 623 OS << " if (x.v.has_value())\n"; 624 if (Clause.isValueList()) 625 OS << " Walk(x.v, \",\");\n"; 626 else 627 OS << " Walk(x.v);\n"; 628 OS << " else\n"; 629 OS << " Put(\"" << Clause.getDefaultValue() << "\");\n"; 630 OS << " Put(\")\");\n"; 631 OS << "}\n"; 632 } else { 633 OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass() 634 << "::" << Clause.getFormattedParserClassName() << " &x) {\n"; 635 OS << " Word(\"" << Clause.getName().upper() << "\");\n"; 636 OS << " Put(\"(\");\n"; 637 if (Clause.isValueList()) 638 OS << " Walk(x.v, \",\");\n"; 639 else 640 OS << " Walk(x.v);\n"; 641 OS << " Put(\")\");\n"; 642 OS << "}\n"; 643 } 644 } else { 645 OS << "void Before(const " << DirLang.getFlangClauseBaseClass() 646 << "::" << Clause.getFormattedParserClassName() << " &) { Word(\"" 647 << Clause.getName().upper() << "\"); }\n"; 648 } 649 } 650 } 651 652 // Generate the implementation section for the enumeration in the directive 653 // language 654 void EmitDirectivesFlangImpl(const DirectiveLanguage &DirLang, 655 raw_ostream &OS) { 656 657 GenerateDirectiveClauseSets(DirLang, OS); 658 659 GenerateDirectiveClauseMap(DirLang, OS); 660 661 GenerateFlangClauseParserClass(DirLang, OS); 662 663 GenerateFlangClauseParserClassList(DirLang, OS); 664 665 GenerateFlangClauseDump(DirLang, OS); 666 667 GenerateFlangClauseUnparse(DirLang, OS); 668 } 669 670 void GenerateClauseClassMacro(const DirectiveLanguage &DirLang, 671 raw_ostream &OS) { 672 // Generate macros style information for legacy code in clang 673 IfDefScope Scope("GEN_CLANG_CLAUSE_CLASS", OS); 674 675 OS << "\n"; 676 677 OS << "#ifndef CLAUSE\n"; 678 OS << "#define CLAUSE(Enum, Str, Implicit)\n"; 679 OS << "#endif\n"; 680 OS << "#ifndef CLAUSE_CLASS\n"; 681 OS << "#define CLAUSE_CLASS(Enum, Str, Class)\n"; 682 OS << "#endif\n"; 683 OS << "#ifndef CLAUSE_NO_CLASS\n"; 684 OS << "#define CLAUSE_NO_CLASS(Enum, Str)\n"; 685 OS << "#endif\n"; 686 OS << "\n"; 687 OS << "#define __CLAUSE(Name, Class) \\\n"; 688 OS << " CLAUSE(" << DirLang.getClausePrefix() 689 << "##Name, #Name, /* Implicit */ false) \\\n"; 690 OS << " CLAUSE_CLASS(" << DirLang.getClausePrefix() 691 << "##Name, #Name, Class)\n"; 692 OS << "#define __CLAUSE_NO_CLASS(Name) \\\n"; 693 OS << " CLAUSE(" << DirLang.getClausePrefix() 694 << "##Name, #Name, /* Implicit */ false) \\\n"; 695 OS << " CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, #Name)\n"; 696 OS << "#define __IMPLICIT_CLAUSE_CLASS(Name, Str, Class) \\\n"; 697 OS << " CLAUSE(" << DirLang.getClausePrefix() 698 << "##Name, Str, /* Implicit */ true) \\\n"; 699 OS << " CLAUSE_CLASS(" << DirLang.getClausePrefix() 700 << "##Name, Str, Class)\n"; 701 OS << "#define __IMPLICIT_CLAUSE_NO_CLASS(Name, Str) \\\n"; 702 OS << " CLAUSE(" << DirLang.getClausePrefix() 703 << "##Name, Str, /* Implicit */ true) \\\n"; 704 OS << " CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, Str)\n"; 705 OS << "\n"; 706 707 for (const auto &R : DirLang.getClauses()) { 708 Clause C{R}; 709 if (C.getClangClass().empty()) { // NO_CLASS 710 if (C.isImplicit()) { 711 OS << "__IMPLICIT_CLAUSE_NO_CLASS(" << C.getFormattedName() << ", \"" 712 << C.getFormattedName() << "\")\n"; 713 } else { 714 OS << "__CLAUSE_NO_CLASS(" << C.getFormattedName() << ")\n"; 715 } 716 } else { // CLASS 717 if (C.isImplicit()) { 718 OS << "__IMPLICIT_CLAUSE_CLASS(" << C.getFormattedName() << ", \"" 719 << C.getFormattedName() << "\", " << C.getClangClass() << ")\n"; 720 } else { 721 OS << "__CLAUSE(" << C.getFormattedName() << ", " << C.getClangClass() 722 << ")\n"; 723 } 724 } 725 } 726 727 OS << "\n"; 728 OS << "#undef __IMPLICIT_CLAUSE_NO_CLASS\n"; 729 OS << "#undef __IMPLICIT_CLAUSE_CLASS\n"; 730 OS << "#undef __CLAUSE\n"; 731 OS << "#undef CLAUSE_NO_CLASS\n"; 732 OS << "#undef CLAUSE_CLASS\n"; 733 OS << "#undef CLAUSE\n"; 734 } 735 736 // Generate the implementation section for the enumeration in the directive 737 // language. 738 void EmitDirectivesGen(RecordKeeper &Records, raw_ostream &OS) { 739 const auto DirLang = DirectiveLanguage{Records}; 740 if (DirLang.HasValidityErrors()) 741 return; 742 743 EmitDirectivesFlangImpl(DirLang, OS); 744 745 GenerateClauseClassMacro(DirLang, OS); 746 } 747 748 // Generate the implementation for the enumeration in the directive 749 // language. This code can be included in library. 750 void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) { 751 const auto DirLang = DirectiveLanguage{Records}; 752 if (DirLang.HasValidityErrors()) 753 return; 754 755 if (!DirLang.getIncludeHeader().empty()) 756 OS << "#include \"" << DirLang.getIncludeHeader() << "\"\n\n"; 757 758 OS << "#include \"llvm/ADT/StringRef.h\"\n"; 759 OS << "#include \"llvm/ADT/StringSwitch.h\"\n"; 760 OS << "#include \"llvm/Support/ErrorHandling.h\"\n"; 761 OS << "\n"; 762 OS << "using namespace llvm;\n"; 763 llvm::SmallVector<StringRef, 2> Namespaces; 764 llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::"); 765 for (auto Ns : Namespaces) 766 OS << "using namespace " << Ns << ";\n"; 767 768 // getDirectiveKind(StringRef Str) 769 GenerateGetKind(DirLang.getDirectives(), OS, "Directive", DirLang, 770 DirLang.getDirectivePrefix(), /*ImplicitAsUnknown=*/false); 771 772 // getDirectiveName(Directive Kind) 773 GenerateGetName(DirLang.getDirectives(), OS, "Directive", DirLang, 774 DirLang.getDirectivePrefix()); 775 776 // getClauseKind(StringRef Str) 777 GenerateGetKind(DirLang.getClauses(), OS, "Clause", DirLang, 778 DirLang.getClausePrefix(), 779 /*ImplicitAsUnknown=*/true); 780 781 // getClauseName(Clause Kind) 782 GenerateGetName(DirLang.getClauses(), OS, "Clause", DirLang, 783 DirLang.getClausePrefix()); 784 785 // get<ClauseVal>Kind(StringRef Str) 786 GenerateGetKindClauseVal(DirLang, OS); 787 788 // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version) 789 GenerateIsAllowedClause(DirLang, OS); 790 } 791 792 } // namespace llvm 793