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 16 #include "llvm/ADT/DenseMap.h" 17 #include "llvm/ADT/DenseSet.h" 18 #include "llvm/ADT/STLExtras.h" 19 #include "llvm/ADT/SmallVector.h" 20 #include "llvm/ADT/StringSet.h" 21 #include "llvm/ADT/StringSwitch.h" 22 #include "llvm/TableGen/Error.h" 23 #include "llvm/TableGen/Record.h" 24 #include "llvm/TableGen/TableGenBackend.h" 25 26 #include <numeric> 27 #include <string> 28 #include <vector> 29 30 using namespace llvm; 31 32 namespace { 33 // Simple RAII helper for defining ifdef-undef-endif scopes. 34 class IfDefScope { 35 public: 36 IfDefScope(StringRef Name, raw_ostream &OS) : Name(Name), OS(OS) { 37 OS << "#ifdef " << Name << "\n" 38 << "#undef " << Name << "\n"; 39 } 40 41 ~IfDefScope() { OS << "\n#endif // " << Name << "\n\n"; } 42 43 private: 44 StringRef Name; 45 raw_ostream &OS; 46 }; 47 } // namespace 48 49 namespace { 50 enum class Frontend { LLVM, Flang, Clang }; 51 52 StringRef getFESpelling(Frontend FE) { 53 switch (FE) { 54 case Frontend::LLVM: 55 return "llvm"; 56 case Frontend::Flang: 57 return "flang"; 58 case Frontend::Clang: 59 return "clang"; 60 } 61 llvm_unreachable("unknown FE kind"); 62 } 63 } // namespace 64 65 // Get the full namespace qualifier for the directive language. 66 static std::string getQualifier(const DirectiveLanguage &DirLang, 67 Frontend FE = Frontend::LLVM) { 68 return (Twine(getFESpelling(FE)) + "::" + DirLang.getCppNamespace().str() + 69 "::") 70 .str(); 71 } 72 73 // Get prefixed formatted name, e.g. for "target data", get "OMPD_target_data". 74 // This should work for any Record as long as BaseRecord::getFormattedName 75 // works. 76 static std::string getIdentifierName(const Record *Rec, StringRef Prefix) { 77 return Prefix.str() + BaseRecord(Rec).getFormattedName(); 78 } 79 80 using RecordWithSpelling = std::pair<const Record *, Spelling::Value>; 81 82 static std::vector<RecordWithSpelling> 83 getSpellings(ArrayRef<const Record *> Records) { 84 std::vector<RecordWithSpelling> List; 85 for (const Record *R : Records) { 86 BaseRecord Rec(R); 87 llvm::transform(Rec.getSpellings(), std::back_inserter(List), 88 [R](Spelling::Value V) { return std::make_pair(R, V); }); 89 } 90 return List; 91 } 92 93 static void generateEnumExports(ArrayRef<const Record *> Records, 94 raw_ostream &OS, StringRef Enum, 95 StringRef Prefix) { 96 for (const Record *R : Records) { 97 std::string N = getIdentifierName(R, Prefix); 98 OS << "constexpr auto " << N << " = " << Enum << "::" << N << ";\n"; 99 } 100 } 101 102 // Generate enum class. Entries are emitted in the order in which they appear 103 // in the `Records` vector. 104 static void generateEnumClass(ArrayRef<const Record *> Records, raw_ostream &OS, 105 StringRef Enum, StringRef Prefix, 106 bool ExportEnums) { 107 OS << "\n"; 108 OS << "enum class " << Enum << " {\n"; 109 for (const Record *R : Records) { 110 OS << " " << getIdentifierName(R, Prefix) << ",\n"; 111 } 112 OS << "};\n"; 113 OS << "\n"; 114 OS << "static constexpr std::size_t " << Enum 115 << "_enumSize = " << Records.size() << ";\n"; 116 117 // Make the enum values available in the defined namespace. This allows us to 118 // write something like Enum_X if we have a `using namespace <CppNamespace>`. 119 // At the same time we do not loose the strong type guarantees of the enum 120 // class, that is we cannot pass an unsigned as Directive without an explicit 121 // cast. 122 if (ExportEnums) { 123 OS << "\n"; 124 generateEnumExports(Records, OS, Enum, Prefix); 125 } 126 } 127 128 // Generate enum class with values corresponding to different bit positions. 129 // Entries are emitted in the order in which they appear in the `Records` 130 // vector. 131 static void generateEnumBitmask(ArrayRef<const Record *> Records, 132 raw_ostream &OS, StringRef Enum, 133 StringRef Prefix, bool ExportEnums) { 134 assert(Records.size() <= 64 && "Too many values for a bitmask"); 135 StringRef Type = Records.size() <= 32 ? "uint32_t" : "uint64_t"; 136 StringRef TypeSuffix = Records.size() <= 32 ? "U" : "ULL"; 137 138 OS << "\n"; 139 OS << "enum class " << Enum << " : " << Type << " {\n"; 140 std::string LastName; 141 for (auto [I, R] : llvm::enumerate(Records)) { 142 LastName = getIdentifierName(R, Prefix); 143 OS << " " << LastName << " = " << (1ull << I) << TypeSuffix << ",\n"; 144 } 145 OS << " LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/" << LastName << ")\n"; 146 OS << "};\n"; 147 OS << "\n"; 148 OS << "static constexpr std::size_t " << Enum 149 << "_enumSize = " << Records.size() << ";\n"; 150 151 // Make the enum values available in the defined namespace. This allows us to 152 // write something like Enum_X if we have a `using namespace <CppNamespace>`. 153 // At the same time we do not loose the strong type guarantees of the enum 154 // class, that is we cannot pass an unsigned as Directive without an explicit 155 // cast. 156 if (ExportEnums) { 157 OS << "\n"; 158 generateEnumExports(Records, OS, Enum, Prefix); 159 } 160 } 161 162 // Generate enums for values that clauses can take. 163 // Also generate function declarations for get<Enum>Name(StringRef Str). 164 static void generateClauseEnumVal(ArrayRef<const Record *> Records, 165 raw_ostream &OS, 166 const DirectiveLanguage &DirLang, 167 std::string &EnumHelperFuncs) { 168 for (const Record *R : Records) { 169 Clause C(R); 170 const auto &ClauseVals = C.getClauseVals(); 171 if (ClauseVals.size() <= 0) 172 continue; 173 174 StringRef Enum = C.getEnumName(); 175 if (Enum.empty()) { 176 PrintError("enumClauseValue field not set in Clause" + 177 C.getFormattedName() + "."); 178 return; 179 } 180 181 OS << "\n"; 182 OS << "enum class " << Enum << " {\n"; 183 for (const EnumVal Val : ClauseVals) 184 OS << " " << Val.getRecordName() << "=" << Val.getValue() << ",\n"; 185 OS << "};\n"; 186 187 if (DirLang.hasMakeEnumAvailableInNamespace()) { 188 OS << "\n"; 189 for (const auto &CV : ClauseVals) { 190 OS << "constexpr auto " << CV->getName() << " = " << Enum 191 << "::" << CV->getName() << ";\n"; 192 } 193 EnumHelperFuncs += (Twine("LLVM_ABI ") + Twine(Enum) + Twine(" get") + 194 Twine(Enum) + Twine("(StringRef Str);\n")) 195 .str(); 196 197 EnumHelperFuncs += 198 (Twine("LLVM_ABI StringRef get") + Twine(DirLang.getName()) + 199 Twine(Enum) + Twine("Name(") + Twine(Enum) + Twine(" x);\n")) 200 .str(); 201 } 202 } 203 } 204 205 static bool hasDuplicateClauses(ArrayRef<const Record *> Clauses, 206 const Directive &Directive, 207 StringSet<> &CrtClauses) { 208 bool HasError = false; 209 for (const VersionedClause VerClause : Clauses) { 210 StringRef Name = VerClause.getClause().getRecordName(); 211 const auto InsRes = CrtClauses.insert(Name); 212 if (!InsRes.second) { 213 PrintError("Clause " + Name + " already defined on directive " + 214 Directive.getRecordName()); 215 HasError = true; 216 } 217 } 218 return HasError; 219 } 220 221 // Check for duplicate clauses in lists. Clauses cannot appear twice in the 222 // three allowed list. Also, since required implies allowed, clauses cannot 223 // appear in both the allowedClauses and requiredClauses lists. 224 static bool 225 hasDuplicateClausesInDirectives(ArrayRef<const Record *> Directives) { 226 bool HasDuplicate = false; 227 for (const Directive Dir : Directives) { 228 StringSet<> Clauses; 229 // Check for duplicates in the three allowed lists. 230 if (hasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) || 231 hasDuplicateClauses(Dir.getAllowedOnceClauses(), Dir, Clauses) || 232 hasDuplicateClauses(Dir.getAllowedExclusiveClauses(), Dir, Clauses)) { 233 HasDuplicate = true; 234 } 235 // Check for duplicate between allowedClauses and required 236 Clauses.clear(); 237 if (hasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) || 238 hasDuplicateClauses(Dir.getRequiredClauses(), Dir, Clauses)) { 239 HasDuplicate = true; 240 } 241 if (HasDuplicate) 242 PrintFatalError("One or more clauses are defined multiple times on" 243 " directive " + 244 Dir.getRecordName()); 245 } 246 247 return HasDuplicate; 248 } 249 250 // Check consitency of records. Return true if an error has been detected. 251 // Return false if the records are valid. 252 bool DirectiveLanguage::HasValidityErrors() const { 253 if (getDirectiveLanguages().size() != 1) { 254 PrintFatalError("A single definition of DirectiveLanguage is needed."); 255 return true; 256 } 257 258 return hasDuplicateClausesInDirectives(getDirectives()); 259 } 260 261 // Count the maximum number of leaf constituents per construct. 262 static size_t getMaxLeafCount(const DirectiveLanguage &DirLang) { 263 size_t MaxCount = 0; 264 for (const Directive D : DirLang.getDirectives()) 265 MaxCount = std::max(MaxCount, D.getLeafConstructs().size()); 266 return MaxCount; 267 } 268 269 // Generate the declaration section for the enumeration in the directive 270 // language. 271 static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) { 272 const auto DirLang = DirectiveLanguage(Records); 273 if (DirLang.HasValidityErrors()) 274 return; 275 276 StringRef Lang = DirLang.getName(); 277 278 OS << "#ifndef LLVM_" << Lang << "_INC\n"; 279 OS << "#define LLVM_" << Lang << "_INC\n"; 280 OS << "\n#include \"llvm/ADT/ArrayRef.h\"\n"; 281 282 if (DirLang.hasEnableBitmaskEnumInNamespace()) 283 OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n"; 284 285 OS << "#include \"llvm/ADT/StringRef.h\"\n"; 286 OS << "#include \"llvm/Frontend/Directive/Spelling.h\"\n"; 287 OS << "#include \"llvm/Support/Compiler.h\"\n"; 288 OS << "#include <cstddef>\n"; // for size_t 289 OS << "#include <utility>\n"; // for std::pair 290 OS << "\n"; 291 OS << "namespace llvm {\n"; 292 293 // Open namespaces defined in the directive language 294 SmallVector<StringRef, 2> Namespaces; 295 SplitString(DirLang.getCppNamespace(), Namespaces, "::"); 296 for (auto Ns : Namespaces) 297 OS << "namespace " << Ns << " {\n"; 298 299 if (DirLang.hasEnableBitmaskEnumInNamespace()) 300 OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n"; 301 302 // Emit Directive associations 303 std::vector<const Record *> Associations; 304 copy_if(DirLang.getAssociations(), std::back_inserter(Associations), 305 // Skip the "special" value 306 [](const Record *Def) { return Def->getName() != "AS_FromLeaves"; }); 307 generateEnumClass(Associations, OS, "Association", 308 /*Prefix=*/"", /*ExportEnums=*/false); 309 310 generateEnumClass(DirLang.getCategories(), OS, "Category", /*Prefix=*/"", 311 /*ExportEnums=*/false); 312 313 generateEnumBitmask(DirLang.getSourceLanguages(), OS, "SourceLanguage", 314 /*Prefix=*/"", /*ExportEnums=*/false); 315 316 // Emit Directive enumeration 317 generateEnumClass(DirLang.getDirectives(), OS, "Directive", 318 DirLang.getDirectivePrefix(), 319 DirLang.hasMakeEnumAvailableInNamespace()); 320 321 // Emit Clause enumeration 322 generateEnumClass(DirLang.getClauses(), OS, "Clause", 323 DirLang.getClausePrefix(), 324 DirLang.hasMakeEnumAvailableInNamespace()); 325 326 // Emit ClauseVals enumeration 327 std::string EnumHelperFuncs; 328 generateClauseEnumVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs); 329 330 // Generic function signatures 331 OS << "\n"; 332 OS << "// Enumeration helper functions\n"; 333 334 OS << "LLVM_ABI std::pair<Directive, directive::VersionRange> get" << Lang 335 << "DirectiveKindAndVersions(StringRef Str);\n"; 336 337 OS << "inline Directive get" << Lang << "DirectiveKind(StringRef Str) {\n"; 338 OS << " return get" << Lang << "DirectiveKindAndVersions(Str).first;\n"; 339 OS << "}\n"; 340 OS << "\n"; 341 342 OS << "LLVM_ABI StringRef get" << Lang 343 << "DirectiveName(Directive D, unsigned Ver = 0);\n"; 344 OS << "\n"; 345 346 OS << "LLVM_ABI std::pair<Clause, directive::VersionRange> get" << Lang 347 << "ClauseKindAndVersions(StringRef Str);\n"; 348 OS << "\n"; 349 350 OS << "inline Clause get" << Lang << "ClauseKind(StringRef Str) {\n"; 351 OS << " return get" << Lang << "ClauseKindAndVersions(Str).first;\n"; 352 OS << "}\n"; 353 OS << "\n"; 354 355 OS << "LLVM_ABI StringRef get" << Lang 356 << "ClauseName(Clause C, unsigned Ver = 0);\n"; 357 OS << "\n"; 358 359 OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p " 360 << "Version.\n"; 361 OS << "LLVM_ABI bool isAllowedClauseForDirective(Directive D, " 362 << "Clause C, unsigned Version);\n"; 363 OS << "\n"; 364 OS << "constexpr std::size_t getMaxLeafCount() { return " 365 << getMaxLeafCount(DirLang) << "; }\n"; 366 OS << "LLVM_ABI Association getDirectiveAssociation(Directive D);\n"; 367 OS << "LLVM_ABI Category getDirectiveCategory(Directive D);\n"; 368 OS << "LLVM_ABI SourceLanguage getDirectiveLanguages(Directive D);\n"; 369 if (EnumHelperFuncs.length() > 0) { 370 OS << EnumHelperFuncs; 371 OS << "\n"; 372 } 373 374 // Closing namespaces 375 for (auto Ns : reverse(Namespaces)) 376 OS << "} // namespace " << Ns << "\n"; 377 378 OS << "} // namespace llvm\n"; 379 380 OS << "#endif // LLVM_" << Lang << "_INC\n"; 381 } 382 383 // Given a list of spellings (for a given clause/directive), order them 384 // in a way that allows the use of binary search to locate a spelling 385 // for a specified version. 386 static std::vector<Spelling::Value> 387 orderSpellings(ArrayRef<Spelling::Value> Spellings) { 388 std::vector<Spelling::Value> List(Spellings.begin(), Spellings.end()); 389 390 llvm::stable_sort(List, 391 [](const Spelling::Value &A, const Spelling::Value &B) { 392 return A.Versions < B.Versions; 393 }); 394 return List; 395 } 396 397 // Generate function implementation for get<Enum>Name(StringRef Str) 398 static void generateGetName(ArrayRef<const Record *> Records, raw_ostream &OS, 399 StringRef Enum, const DirectiveLanguage &DirLang, 400 StringRef Prefix) { 401 StringRef Lang = DirLang.getName(); 402 std::string Qual = getQualifier(DirLang); 403 OS << "\n"; 404 OS << "llvm::StringRef " << Qual << "get" << Lang << Enum << "Name(" << Qual 405 << Enum << " Kind, unsigned Version) {\n"; 406 OS << " switch (Kind) {\n"; 407 for (const Record *R : Records) { 408 BaseRecord Rec(R); 409 std::string Ident = getIdentifierName(R, Prefix); 410 OS << " case " << Ident << ":"; 411 std::vector<Spelling::Value> Spellings(orderSpellings(Rec.getSpellings())); 412 assert(Spellings.size() != 0 && "No spellings for this item"); 413 if (Spellings.size() == 1) { 414 OS << "\n"; 415 OS << " return \"" << Spellings.front().Name << "\";\n"; 416 } else { 417 OS << " {\n"; 418 std::string SpellingsName = Ident + "_spellings"; 419 OS << " static constexpr llvm::directive::Spelling " << SpellingsName 420 << "[] = {\n"; 421 for (auto &S : Spellings) { 422 OS << " {\"" << S.Name << "\", {" << S.Versions.Min << ", " 423 << S.Versions.Max << "}},\n"; 424 } 425 OS << " };\n"; 426 OS << " return llvm::directive::FindName(" << SpellingsName 427 << ", Version);\n"; 428 OS << " }\n"; 429 } 430 } 431 OS << " }\n"; // switch 432 OS << " llvm_unreachable(\"Invalid " << Lang << " " << Enum << " kind\");\n"; 433 OS << "}\n"; 434 } 435 436 // Generate function implementation for get<Enum>KindAndVersions(StringRef Str) 437 static void generateGetKind(ArrayRef<const Record *> Records, raw_ostream &OS, 438 StringRef Enum, const DirectiveLanguage &DirLang, 439 StringRef Prefix, bool ImplicitAsUnknown) { 440 441 const auto *DefaultIt = find_if( 442 Records, [](const Record *R) { return R->getValueAsBit("isDefault"); }); 443 444 if (DefaultIt == Records.end()) { 445 PrintError("At least one " + Enum + " must be defined as default."); 446 return; 447 } 448 449 BaseRecord DefaultRec(*DefaultIt); 450 std::string Qual = getQualifier(DirLang); 451 std::string DefaultName = getIdentifierName(*DefaultIt, Prefix); 452 453 // std::pair<<Enum>, VersionRange> 454 // get<DirLang><Enum>KindAndVersions(StringRef Str); 455 OS << "\n"; 456 OS << "std::pair<" << Qual << Enum << ", llvm::directive::VersionRange> " 457 << Qual << "get" << DirLang.getName() << Enum 458 << "KindAndVersions(llvm::StringRef Str) {\n"; 459 OS << " directive::VersionRange All; // Default-initialized to \"all " 460 "versions\"\n"; 461 OS << " return StringSwitch<std::pair<" << Enum << ", " 462 << "directive::VersionRange>>(Str)\n"; 463 464 directive::VersionRange All; 465 466 for (const Record *R : Records) { 467 BaseRecord Rec(R); 468 std::string Ident = ImplicitAsUnknown && R->getValueAsBit("isImplicit") 469 ? DefaultName 470 : getIdentifierName(R, Prefix); 471 472 for (auto &[Name, Versions] : Rec.getSpellings()) { 473 OS << " .Case(\"" << Name << "\", {" << Ident << ", "; 474 if (Versions.Min == All.Min && Versions.Max == All.Max) 475 OS << "All})\n"; 476 else 477 OS << "{" << Versions.Min << ", " << Versions.Max << "}})\n"; 478 } 479 } 480 OS << " .Default({" << DefaultName << ", All});\n"; 481 OS << "}\n"; 482 } 483 484 // Generate function implementations for 485 // <enumClauseValue> get<enumClauseValue>(StringRef Str) and 486 // StringRef get<enumClauseValue>Name(<enumClauseValue>) 487 static void generateGetClauseVal(const DirectiveLanguage &DirLang, 488 raw_ostream &OS) { 489 StringRef Lang = DirLang.getName(); 490 std::string Qual = getQualifier(DirLang); 491 492 for (const Clause C : DirLang.getClauses()) { 493 const auto &ClauseVals = C.getClauseVals(); 494 if (ClauseVals.size() <= 0) 495 continue; 496 497 auto DefaultIt = find_if(ClauseVals, [](const Record *CV) { 498 return CV->getValueAsBit("isDefault"); 499 }); 500 501 if (DefaultIt == ClauseVals.end()) { 502 PrintError("At least one val in Clause " + C.getRecordName() + 503 " must be defined as default."); 504 return; 505 } 506 const auto DefaultName = (*DefaultIt)->getName(); 507 508 StringRef Enum = C.getEnumName(); 509 if (Enum.empty()) { 510 PrintError("enumClauseValue field not set in Clause" + C.getRecordName() + 511 "."); 512 return; 513 } 514 515 OS << "\n"; 516 OS << Qual << Enum << " " << Qual << "get" << Enum 517 << "(llvm::StringRef Str) {\n"; 518 OS << " return StringSwitch<" << Enum << ">(Str)\n"; 519 for (const EnumVal Val : ClauseVals) { 520 OS << " .Case(\"" << Val.getFormattedName() << "\"," 521 << Val.getRecordName() << ")\n"; 522 } 523 OS << " .Default(" << DefaultName << ");\n"; 524 OS << "}\n"; 525 526 OS << "\n"; 527 OS << "llvm::StringRef " << Qual << "get" << Lang << Enum << "Name(" << Qual 528 << Enum << " x) {\n"; 529 OS << " switch (x) {\n"; 530 for (const EnumVal Val : ClauseVals) { 531 OS << " case " << Val.getRecordName() << ":\n"; 532 OS << " return \"" << Val.getFormattedName() << "\";\n"; 533 } 534 OS << " }\n"; // switch 535 OS << " llvm_unreachable(\"Invalid " << Lang << " " << Enum 536 << " kind\");\n"; 537 OS << "}\n"; 538 } 539 } 540 541 static void generateCaseForVersionedClauses(ArrayRef<const Record *> VerClauses, 542 raw_ostream &OS, 543 const DirectiveLanguage &DirLang, 544 StringSet<> &Cases) { 545 StringRef Prefix = DirLang.getClausePrefix(); 546 for (const Record *R : VerClauses) { 547 VersionedClause VerClause(R); 548 std::string Name = 549 getIdentifierName(VerClause.getClause().getRecord(), Prefix); 550 if (Cases.insert(Name).second) { 551 OS << " case " << Name << ":\n"; 552 OS << " return " << VerClause.getMinVersion() 553 << " <= Version && " << VerClause.getMaxVersion() << " >= Version;\n"; 554 } 555 } 556 } 557 558 // Generate the isAllowedClauseForDirective function implementation. 559 static void generateIsAllowedClause(const DirectiveLanguage &DirLang, 560 raw_ostream &OS) { 561 std::string Qual = getQualifier(DirLang); 562 563 OS << "\n"; 564 OS << "bool " << Qual << "isAllowedClauseForDirective(" << Qual 565 << "Directive D, " << Qual << "Clause C, unsigned Version) {\n"; 566 OS << " assert(unsigned(D) <= Directive_enumSize);\n"; 567 OS << " assert(unsigned(C) <= Clause_enumSize);\n"; 568 569 OS << " switch (D) {\n"; 570 571 StringRef Prefix = DirLang.getDirectivePrefix(); 572 for (const Record *R : DirLang.getDirectives()) { 573 Directive Dir(R); 574 OS << " case " << getIdentifierName(R, Prefix) << ":\n"; 575 if (Dir.getAllowedClauses().empty() && 576 Dir.getAllowedOnceClauses().empty() && 577 Dir.getAllowedExclusiveClauses().empty() && 578 Dir.getRequiredClauses().empty()) { 579 OS << " return false;\n"; 580 } else { 581 OS << " switch (C) {\n"; 582 583 StringSet<> Cases; 584 585 generateCaseForVersionedClauses(Dir.getAllowedClauses(), OS, DirLang, 586 Cases); 587 588 generateCaseForVersionedClauses(Dir.getAllowedOnceClauses(), OS, DirLang, 589 Cases); 590 591 generateCaseForVersionedClauses(Dir.getAllowedExclusiveClauses(), OS, 592 DirLang, Cases); 593 594 generateCaseForVersionedClauses(Dir.getRequiredClauses(), OS, DirLang, 595 Cases); 596 597 OS << " default:\n"; 598 OS << " return false;\n"; 599 OS << " }\n"; // End of clauses switch 600 } 601 OS << " break;\n"; 602 } 603 604 OS << " }\n"; // End of directives switch 605 OS << " llvm_unreachable(\"Invalid " << DirLang.getName() 606 << " Directive kind\");\n"; 607 OS << "}\n"; // End of function isAllowedClauseForDirective 608 } 609 610 static void emitLeafTable(const DirectiveLanguage &DirLang, raw_ostream &OS, 611 StringRef TableName) { 612 // The leaf constructs are emitted in a form of a 2D table, where each 613 // row corresponds to a directive (and there is a row for each directive). 614 // 615 // Each row consists of 616 // - the id of the directive itself, 617 // - number of leaf constructs that will follow (0 for leafs), 618 // - ids of the leaf constructs (none if the directive is itself a leaf). 619 // The total number of these entries is at most MaxLeafCount+2. If this 620 // number is less than that, it is padded to occupy exactly MaxLeafCount+2 621 // entries in memory. 622 // 623 // The rows are stored in the table in the lexicographical order. This 624 // is intended to enable binary search when mapping a sequence of leafs 625 // back to the compound directive. 626 // The consequence of that is that in order to find a row corresponding 627 // to the given directive, we'd need to scan the first element of each 628 // row. To avoid this, an auxiliary ordering table is created, such that 629 // row for Dir_A = table[auxiliary[Dir_A]]. 630 631 ArrayRef<const Record *> Directives = DirLang.getDirectives(); 632 DenseMap<const Record *, int> DirId; // Record * -> llvm::omp::Directive 633 634 for (auto [Idx, Rec] : enumerate(Directives)) 635 DirId.try_emplace(Rec, Idx); 636 637 using LeafList = std::vector<int>; 638 int MaxLeafCount = getMaxLeafCount(DirLang); 639 640 // The initial leaf table, rows order is same as directive order. 641 std::vector<LeafList> LeafTable(Directives.size()); 642 for (auto [Idx, Rec] : enumerate(Directives)) { 643 Directive Dir(Rec); 644 std::vector<const Record *> Leaves = Dir.getLeafConstructs(); 645 646 auto &List = LeafTable[Idx]; 647 List.resize(MaxLeafCount + 2); 648 List[0] = Idx; // The id of the directive itself. 649 List[1] = Leaves.size(); // The number of leaves to follow. 650 651 for (int I = 0; I != MaxLeafCount; ++I) 652 List[I + 2] = 653 static_cast<size_t>(I) < Leaves.size() ? DirId.at(Leaves[I]) : -1; 654 } 655 656 // Some Fortran directives are delimited, i.e. they have the form of 657 // "directive"---"end directive". If "directive" is a compound construct, 658 // then the set of leaf constituents will be nonempty and the same for 659 // both directives. Given this set of leafs, looking up the corresponding 660 // compound directive should return "directive", and not "end directive". 661 // To avoid this problem, gather all "end directives" at the end of the 662 // leaf table, and only do the search on the initial segment of the table 663 // that excludes the "end directives". 664 // It's safe to find all directives whose names begin with "end ". The 665 // problem only exists for compound directives, like "end do simd". 666 // All existing directives with names starting with "end " are either 667 // "end directives" for an existing "directive", or leaf directives 668 // (such as "end declare target"). 669 DenseSet<int> EndDirectives; 670 for (auto [Rec, Id] : DirId) { 671 // FIXME: This will need to recognize different spellings for different 672 // versions. 673 StringRef Name = Directive(Rec).getSpellingForIdentifier(); 674 if (Name.starts_with_insensitive("end ")) 675 EndDirectives.insert(Id); 676 } 677 678 // Avoid sorting the vector<vector> array, instead sort an index array. 679 // It will also be useful later to create the auxiliary indexing array. 680 std::vector<int> Ordering(Directives.size()); 681 std::iota(Ordering.begin(), Ordering.end(), 0); 682 683 llvm::sort(Ordering, [&](int A, int B) { 684 auto &LeavesA = LeafTable[A]; 685 auto &LeavesB = LeafTable[B]; 686 int DirA = LeavesA[0], DirB = LeavesB[0]; 687 // First of all, end directives compare greater than non-end directives. 688 bool IsEndA = EndDirectives.contains(DirA); 689 bool IsEndB = EndDirectives.contains(DirB); 690 if (IsEndA != IsEndB) 691 return IsEndA < IsEndB; 692 if (LeavesA[1] == 0 && LeavesB[1] == 0) 693 return DirA < DirB; 694 return std::lexicographical_compare(&LeavesA[2], &LeavesA[2] + LeavesA[1], 695 &LeavesB[2], &LeavesB[2] + LeavesB[1]); 696 }); 697 698 // Emit the table 699 700 // The directives are emitted into a scoped enum, for which the underlying 701 // type is `int` (by default). The code above uses `int` to store directive 702 // ids, so make sure that we catch it when something changes in the 703 // underlying type. 704 StringRef Prefix = DirLang.getDirectivePrefix(); 705 std::string Qual = getQualifier(DirLang); 706 std::string DirectiveType = Qual + "Directive"; 707 OS << "\nstatic_assert(sizeof(" << DirectiveType << ") == sizeof(int));\n"; 708 709 OS << "[[maybe_unused]] static const " << DirectiveType << ' ' << TableName 710 << "[][" << MaxLeafCount + 2 << "] = {\n"; 711 for (size_t I = 0, E = Directives.size(); I != E; ++I) { 712 auto &Leaves = LeafTable[Ordering[I]]; 713 OS << " {" << Qual << getIdentifierName(Directives[Leaves[0]], Prefix); 714 OS << ", static_cast<" << DirectiveType << ">(" << Leaves[1] << "),"; 715 for (size_t I = 2, E = Leaves.size(); I != E; ++I) { 716 int Idx = Leaves[I]; 717 if (Idx >= 0) 718 OS << ' ' << Qual << getIdentifierName(Directives[Leaves[I]], Prefix) 719 << ','; 720 else 721 OS << " static_cast<" << DirectiveType << ">(-1),"; 722 } 723 OS << "},\n"; 724 } 725 OS << "};\n\n"; 726 727 // Emit a marker where the first "end directive" is. 728 auto FirstE = find_if(Ordering, [&](int RowIdx) { 729 return EndDirectives.contains(LeafTable[RowIdx][0]); 730 }); 731 OS << "[[maybe_unused]] static auto " << TableName 732 << "EndDirective = " << TableName << " + " 733 << std::distance(Ordering.begin(), FirstE) << ";\n\n"; 734 735 // Emit the auxiliary index table: it's the inverse of the `Ordering` 736 // table above. 737 OS << "[[maybe_unused]] static const int " << TableName << "Ordering[] = {\n"; 738 OS << " "; 739 std::vector<int> Reverse(Ordering.size()); 740 for (int I = 0, E = Ordering.size(); I != E; ++I) 741 Reverse[Ordering[I]] = I; 742 for (int Idx : Reverse) 743 OS << ' ' << Idx << ','; 744 OS << "\n};\n"; 745 } 746 747 static void generateGetDirectiveAssociation(const DirectiveLanguage &DirLang, 748 raw_ostream &OS) { 749 enum struct Association { 750 None = 0, // None should be the smallest value. 751 Block, // The values of the rest don't matter. 752 Declaration, 753 Delimited, 754 Loop, 755 Separating, 756 FromLeaves, 757 Invalid, 758 }; 759 760 ArrayRef<const Record *> Associations = DirLang.getAssociations(); 761 762 auto GetAssocValue = [](StringRef Name) -> Association { 763 return StringSwitch<Association>(Name) 764 .Case("AS_Block", Association::Block) 765 .Case("AS_Declaration", Association::Declaration) 766 .Case("AS_Delimited", Association::Delimited) 767 .Case("AS_Loop", Association::Loop) 768 .Case("AS_None", Association::None) 769 .Case("AS_Separating", Association::Separating) 770 .Case("AS_FromLeaves", Association::FromLeaves) 771 .Default(Association::Invalid); 772 }; 773 774 auto GetAssocName = [&](Association A) -> StringRef { 775 if (A != Association::Invalid && A != Association::FromLeaves) { 776 const auto *F = find_if(Associations, [&](const Record *R) { 777 return GetAssocValue(R->getName()) == A; 778 }); 779 if (F != Associations.end()) 780 return (*F)->getValueAsString("name"); // enum name 781 } 782 llvm_unreachable("Unexpected association value"); 783 }; 784 785 auto ErrorPrefixFor = [&](Directive D) -> std::string { 786 return (Twine("Directive '") + D.getRecordName() + "' in namespace '" + 787 DirLang.getCppNamespace() + "' ") 788 .str(); 789 }; 790 791 auto Reduce = [&](Association A, Association B) -> Association { 792 if (A > B) 793 std::swap(A, B); 794 795 // Calculate the result using the following rules: 796 // x + x = x 797 // AS_None + x = x 798 // AS_Block + AS_Loop = AS_Loop 799 if (A == Association::None || A == B) 800 return B; 801 if (A == Association::Block && B == Association::Loop) 802 return B; 803 if (A == Association::Loop && B == Association::Block) 804 return A; 805 return Association::Invalid; 806 }; 807 808 DenseMap<const Record *, Association> AsMap; 809 810 auto CompAssocImpl = [&](const Record *R, auto &&Self) -> Association { 811 if (auto F = AsMap.find(R); F != AsMap.end()) 812 return F->second; 813 814 Directive D(R); 815 Association AS = GetAssocValue(D.getAssociation()->getName()); 816 if (AS == Association::Invalid) { 817 PrintFatalError(ErrorPrefixFor(D) + 818 "has an unrecognized value for association: '" + 819 D.getAssociation()->getName() + "'"); 820 } 821 if (AS != Association::FromLeaves) { 822 AsMap.try_emplace(R, AS); 823 return AS; 824 } 825 // Compute the association from leaf constructs. 826 std::vector<const Record *> Leaves = D.getLeafConstructs(); 827 if (Leaves.empty()) { 828 PrintFatalError(ErrorPrefixFor(D) + 829 "requests association to be computed from leaves, " 830 "but it has no leaves"); 831 } 832 833 Association Result = Self(Leaves[0], Self); 834 for (int I = 1, E = Leaves.size(); I < E; ++I) { 835 Association A = Self(Leaves[I], Self); 836 Association R = Reduce(Result, A); 837 if (R == Association::Invalid) { 838 PrintFatalError(ErrorPrefixFor(D) + 839 "has leaves with incompatible association values: " + 840 GetAssocName(A) + " and " + GetAssocName(R)); 841 } 842 Result = R; 843 } 844 845 assert(Result != Association::Invalid); 846 assert(Result != Association::FromLeaves); 847 AsMap.try_emplace(R, Result); 848 return Result; 849 }; 850 851 for (const Record *R : DirLang.getDirectives()) 852 CompAssocImpl(R, CompAssocImpl); // Updates AsMap. 853 854 OS << '\n'; 855 856 StringRef Prefix = DirLang.getDirectivePrefix(); 857 std::string Qual = getQualifier(DirLang); 858 859 OS << Qual << "Association " << Qual << "getDirectiveAssociation(" << Qual 860 << "Directive Dir) {\n"; 861 OS << " switch (Dir) {\n"; 862 for (const Record *R : DirLang.getDirectives()) { 863 if (auto F = AsMap.find(R); F != AsMap.end()) { 864 OS << " case " << getIdentifierName(R, Prefix) << ":\n"; 865 OS << " return Association::" << GetAssocName(F->second) << ";\n"; 866 } 867 } 868 OS << " } // switch (Dir)\n"; 869 OS << " llvm_unreachable(\"Unexpected directive\");\n"; 870 OS << "}\n"; 871 } 872 873 static void generateGetDirectiveCategory(const DirectiveLanguage &DirLang, 874 raw_ostream &OS) { 875 std::string Qual = getQualifier(DirLang); 876 877 OS << '\n'; 878 OS << Qual << "Category " << Qual << "getDirectiveCategory(" << Qual 879 << "Directive Dir) {\n"; 880 OS << " switch (Dir) {\n"; 881 882 StringRef Prefix = DirLang.getDirectivePrefix(); 883 884 for (const Record *R : DirLang.getDirectives()) { 885 Directive D(R); 886 OS << " case " << getIdentifierName(R, Prefix) << ":\n"; 887 OS << " return Category::" << D.getCategory()->getValueAsString("name") 888 << ";\n"; 889 } 890 OS << " } // switch (Dir)\n"; 891 OS << " llvm_unreachable(\"Unexpected directive\");\n"; 892 OS << "}\n"; 893 } 894 895 static void generateGetDirectiveLanguages(const DirectiveLanguage &DirLang, 896 raw_ostream &OS) { 897 std::string Qual = getQualifier(DirLang); 898 899 OS << '\n'; 900 OS << Qual << "SourceLanguage " << Qual << "getDirectiveLanguages(" << Qual 901 << "Directive D) {\n"; 902 OS << " switch (D) {\n"; 903 904 StringRef Prefix = DirLang.getDirectivePrefix(); 905 906 for (const Record *R : DirLang.getDirectives()) { 907 Directive D(R); 908 OS << " case " << getIdentifierName(R, Prefix) << ":\n"; 909 OS << " return "; 910 llvm::interleave( 911 D.getSourceLanguages(), OS, 912 [&](const Record *L) { 913 StringRef N = L->getValueAsString("name"); 914 OS << "SourceLanguage::" << BaseRecord::getSnakeName(N); 915 }, 916 " | "); 917 OS << ";\n"; 918 } 919 OS << " } // switch(D)\n"; 920 OS << " llvm_unreachable(\"Unexpected directive\");\n"; 921 OS << "}\n"; 922 } 923 924 // Generate a simple enum set with the give clauses. 925 static void generateClauseSet(ArrayRef<const Record *> VerClauses, 926 raw_ostream &OS, StringRef ClauseSetPrefix, 927 const Directive &Dir, 928 const DirectiveLanguage &DirLang, Frontend FE) { 929 930 OS << "\n"; 931 OS << "static " << DirLang.getClauseEnumSetClass() << " " << ClauseSetPrefix 932 << DirLang.getDirectivePrefix() << Dir.getFormattedName() << " {\n"; 933 934 StringRef Prefix = DirLang.getClausePrefix(); 935 936 for (const VersionedClause VerClause : VerClauses) { 937 Clause C = VerClause.getClause(); 938 if (FE == Frontend::Flang) { 939 OS << " Clause::" << getIdentifierName(C.getRecord(), Prefix) << ",\n"; 940 } else { 941 assert(FE == Frontend::Clang); 942 assert(DirLang.getName() == "OpenACC"); 943 OS << " OpenACCClauseKind::" << C.getClangAccSpelling() << ",\n"; 944 } 945 } 946 OS << "};\n"; 947 } 948 949 // Generate an enum set for the 4 kinds of clauses linked to a directive. 950 static void generateDirectiveClauseSets(const DirectiveLanguage &DirLang, 951 Frontend FE, raw_ostream &OS) { 952 953 std::string IfDefName{"GEN_"}; 954 IfDefName += getFESpelling(FE).upper(); 955 IfDefName += "_DIRECTIVE_CLAUSE_SETS"; 956 IfDefScope Scope(IfDefName, OS); 957 958 StringRef Namespace = 959 getFESpelling(FE == Frontend::Flang ? Frontend::LLVM : FE); 960 OS << "\n"; 961 // The namespace has to be different for clang vs flang, as 2 structs with the 962 // same name but different layout is UB. So just put the 'clang' on in the 963 // clang namespace. 964 OS << "namespace " << Namespace << " {\n"; 965 966 // Open namespaces defined in the directive language. 967 SmallVector<StringRef, 2> Namespaces; 968 SplitString(DirLang.getCppNamespace(), Namespaces, "::"); 969 for (auto Ns : Namespaces) 970 OS << "namespace " << Ns << " {\n"; 971 972 for (const Directive Dir : DirLang.getDirectives()) { 973 OS << "\n"; 974 OS << "// Sets for " << Dir.getSpellingForIdentifier() << "\n"; 975 976 generateClauseSet(Dir.getAllowedClauses(), OS, "allowedClauses_", Dir, 977 DirLang, FE); 978 generateClauseSet(Dir.getAllowedOnceClauses(), OS, "allowedOnceClauses_", 979 Dir, DirLang, FE); 980 generateClauseSet(Dir.getAllowedExclusiveClauses(), OS, 981 "allowedExclusiveClauses_", Dir, DirLang, FE); 982 generateClauseSet(Dir.getRequiredClauses(), OS, "requiredClauses_", Dir, 983 DirLang, FE); 984 } 985 986 // Closing namespaces 987 for (auto Ns : reverse(Namespaces)) 988 OS << "} // namespace " << Ns << "\n"; 989 990 OS << "} // namespace " << Namespace << "\n"; 991 } 992 993 // Generate a map of directive (key) with DirectiveClauses struct as values. 994 // The struct holds the 4 sets of enumeration for the 4 kinds of clauses 995 // allowances (allowed, allowed once, allowed exclusive and required). 996 static void generateDirectiveClauseMap(const DirectiveLanguage &DirLang, 997 Frontend FE, raw_ostream &OS) { 998 std::string IfDefName{"GEN_"}; 999 IfDefName += getFESpelling(FE).upper(); 1000 IfDefName += "_DIRECTIVE_CLAUSE_MAP"; 1001 IfDefScope Scope(IfDefName, OS); 1002 1003 OS << "\n"; 1004 OS << "{\n"; 1005 1006 // The namespace has to be different for clang vs flang, as 2 structs with the 1007 // same name but different layout is UB. So just put the 'clang' on in the 1008 // clang namespace. 1009 std::string Qual = 1010 getQualifier(DirLang, FE == Frontend::Flang ? Frontend::LLVM : FE); 1011 StringRef Prefix = DirLang.getDirectivePrefix(); 1012 1013 for (const Record *R : DirLang.getDirectives()) { 1014 Directive Dir(R); 1015 std::string Name = getIdentifierName(R, Prefix); 1016 1017 OS << " {"; 1018 if (FE == Frontend::Flang) { 1019 OS << Qual << "Directive::" << Name << ",\n"; 1020 } else { 1021 assert(FE == Frontend::Clang); 1022 assert(DirLang.getName() == "OpenACC"); 1023 OS << "clang::OpenACCDirectiveKind::" << Dir.getClangAccSpelling() 1024 << ",\n"; 1025 } 1026 1027 OS << " {\n"; 1028 OS << " " << Qual << "allowedClauses_" << Name << ",\n"; 1029 OS << " " << Qual << "allowedOnceClauses_" << Name << ",\n"; 1030 OS << " " << Qual << "allowedExclusiveClauses_" << Name << ",\n"; 1031 OS << " " << Qual << "requiredClauses_" << Name << ",\n"; 1032 OS << " }\n"; 1033 OS << " },\n"; 1034 } 1035 1036 OS << "}\n"; 1037 } 1038 1039 // Generate classes entry for Flang clauses in the Flang parse-tree 1040 // If the clause as a non-generic class, no entry is generated. 1041 // If the clause does not hold a value, an EMPTY_CLASS is used. 1042 // If the clause class is generic then a WRAPPER_CLASS is used. When the value 1043 // is optional, the value class is wrapped into a std::optional. 1044 static void generateFlangClauseParserClass(const DirectiveLanguage &DirLang, 1045 raw_ostream &OS) { 1046 1047 IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS); 1048 1049 OS << "\n"; 1050 1051 for (const Clause Clause : DirLang.getClauses()) { 1052 if (!Clause.getFlangClass().empty()) { 1053 OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName() << ", "; 1054 if (Clause.isValueOptional() && Clause.isValueList()) { 1055 OS << "std::optional<std::list<" << Clause.getFlangClass() << ">>"; 1056 } else if (Clause.isValueOptional()) { 1057 OS << "std::optional<" << Clause.getFlangClass() << ">"; 1058 } else if (Clause.isValueList()) { 1059 OS << "std::list<" << Clause.getFlangClass() << ">"; 1060 } else { 1061 OS << Clause.getFlangClass(); 1062 } 1063 } else { 1064 OS << "EMPTY_CLASS(" << Clause.getFormattedParserClassName(); 1065 } 1066 OS << ");\n"; 1067 } 1068 } 1069 1070 // Generate a list of the different clause classes for Flang. 1071 static void generateFlangClauseParserClassList(const DirectiveLanguage &DirLang, 1072 raw_ostream &OS) { 1073 1074 IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS); 1075 1076 OS << "\n"; 1077 interleaveComma(DirLang.getClauses(), OS, [&](const Record *C) { 1078 Clause Clause(C); 1079 OS << Clause.getFormattedParserClassName() << "\n"; 1080 }); 1081 } 1082 1083 // Generate dump node list for the clauses holding a generic class name. 1084 static void generateFlangClauseDump(const DirectiveLanguage &DirLang, 1085 raw_ostream &OS) { 1086 1087 IfDefScope Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS); 1088 1089 OS << "\n"; 1090 for (const Clause Clause : DirLang.getClauses()) { 1091 OS << "NODE(" << DirLang.getFlangClauseBaseClass() << ", " 1092 << Clause.getFormattedParserClassName() << ")\n"; 1093 } 1094 } 1095 1096 // Generate Unparse functions for clauses classes in the Flang parse-tree 1097 // If the clause is a non-generic class, no entry is generated. 1098 static void generateFlangClauseUnparse(const DirectiveLanguage &DirLang, 1099 raw_ostream &OS) { 1100 1101 IfDefScope Scope("GEN_FLANG_CLAUSE_UNPARSE", OS); 1102 1103 StringRef Base = DirLang.getFlangClauseBaseClass(); 1104 OS << "\n"; 1105 1106 for (const Clause Clause : DirLang.getClauses()) { 1107 if (Clause.skipFlangUnparser()) 1108 continue; 1109 // The unparser doesn't know the effective version, so just pick some 1110 // spelling. 1111 StringRef SomeSpelling = Clause.getSpellingForIdentifier(); 1112 std::string Parser = Clause.getFormattedParserClassName(); 1113 std::string Upper = SomeSpelling.upper(); 1114 1115 if (!Clause.getFlangClass().empty()) { 1116 if (Clause.isValueOptional() && Clause.getDefaultValue().empty()) { 1117 OS << "void Unparse(const " << Base << "::" << Parser << " &x) {\n"; 1118 OS << " Word(\"" << Upper << "\");\n"; 1119 1120 OS << " Walk(\"(\", x.v, \")\");\n"; 1121 OS << "}\n"; 1122 } else if (Clause.isValueOptional()) { 1123 OS << "void Unparse(const " << Base << "::" << Parser << " &x) {\n"; 1124 OS << " Word(\"" << Upper << "\");\n"; 1125 OS << " Put(\"(\");\n"; 1126 OS << " if (x.v.has_value())\n"; 1127 if (Clause.isValueList()) 1128 OS << " Walk(x.v, \",\");\n"; 1129 else 1130 OS << " Walk(x.v);\n"; 1131 OS << " else\n"; 1132 OS << " Put(\"" << Clause.getDefaultValue() << "\");\n"; 1133 OS << " Put(\")\");\n"; 1134 OS << "}\n"; 1135 } else { 1136 OS << "void Unparse(const " << Base << "::" << Parser << " &x) {\n"; 1137 OS << " Word(\"" << Upper << "\");\n"; 1138 OS << " Put(\"(\");\n"; 1139 if (Clause.isValueList()) 1140 OS << " Walk(x.v, \",\");\n"; 1141 else 1142 OS << " Walk(x.v);\n"; 1143 OS << " Put(\")\");\n"; 1144 OS << "}\n"; 1145 } 1146 } else { 1147 OS << "void Before(const " << Base << "::" << Parser << " &) { Word(\"" 1148 << Upper << "\"); }\n"; 1149 } 1150 } 1151 } 1152 1153 // Generate check in the Enter functions for clauses classes. 1154 static void generateFlangClauseCheckPrototypes(const DirectiveLanguage &DirLang, 1155 raw_ostream &OS) { 1156 1157 IfDefScope Scope("GEN_FLANG_CLAUSE_CHECK_ENTER", OS); 1158 1159 OS << "\n"; 1160 for (const Clause Clause : DirLang.getClauses()) { 1161 OS << "void Enter(const parser::" << DirLang.getFlangClauseBaseClass() 1162 << "::" << Clause.getFormattedParserClassName() << " &);\n"; 1163 } 1164 } 1165 1166 // Generate the mapping for clauses between the parser class and the 1167 // corresponding clause Kind 1168 static void generateFlangClauseParserKindMap(const DirectiveLanguage &DirLang, 1169 raw_ostream &OS) { 1170 1171 IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_KIND_MAP", OS); 1172 1173 StringRef Prefix = DirLang.getClausePrefix(); 1174 std::string Qual = getQualifier(DirLang); 1175 1176 OS << "\n"; 1177 for (const Record *R : DirLang.getClauses()) { 1178 Clause C(R); 1179 OS << "if constexpr (std::is_same_v<A, parser::" 1180 << DirLang.getFlangClauseBaseClass() 1181 << "::" << C.getFormattedParserClassName(); 1182 OS << ">)\n"; 1183 OS << " return " << Qual << "Clause::" << getIdentifierName(R, Prefix) 1184 << ";\n"; 1185 } 1186 1187 OS << "llvm_unreachable(\"Invalid " << DirLang.getName() 1188 << " Parser clause\");\n"; 1189 } 1190 1191 // Generate the parser for the clauses. 1192 static void generateFlangClausesParser(const DirectiveLanguage &DirLang, 1193 raw_ostream &OS) { 1194 std::vector<const Record *> Clauses = DirLang.getClauses(); 1195 // Sort clauses in the reverse alphabetical order with respect to their 1196 // names and aliases, so that longer names are tried before shorter ones. 1197 std::vector<RecordWithSpelling> Names = getSpellings(Clauses); 1198 llvm::sort(Names, [](const auto &A, const auto &B) { 1199 return A.second.Name > B.second.Name; 1200 }); 1201 IfDefScope Scope("GEN_FLANG_CLAUSES_PARSER", OS); 1202 StringRef Base = DirLang.getFlangClauseBaseClass(); 1203 1204 unsigned LastIndex = Names.size() - 1; 1205 OS << "\n"; 1206 OS << "TYPE_PARSER(\n"; 1207 for (auto [Index, RecSp] : llvm::enumerate(Names)) { 1208 auto [R, S] = RecSp; 1209 Clause C(R); 1210 1211 StringRef FlangClass = C.getFlangClass(); 1212 OS << " \"" << S.Name << "\" >> construct<" << Base << ">(construct<" 1213 << Base << "::" << C.getFormattedParserClassName() << ">("; 1214 if (FlangClass.empty()) { 1215 OS << "))"; 1216 if (Index != LastIndex) 1217 OS << " ||"; 1218 OS << "\n"; 1219 continue; 1220 } 1221 1222 if (C.isValueOptional()) 1223 OS << "maybe("; 1224 OS << "parenthesized("; 1225 if (C.isValueList()) 1226 OS << "nonemptyList("; 1227 1228 if (!C.getPrefix().empty()) 1229 OS << "\"" << C.getPrefix() << ":\" >> "; 1230 1231 // The common Flang parser are used directly. Their name is identical to 1232 // the Flang class with first letter as lowercase. If the Flang class is 1233 // not a common class, we assume there is a specific Parser<>{} with the 1234 // Flang class name provided. 1235 SmallString<128> Scratch; 1236 StringRef Parser = 1237 StringSwitch<StringRef>(FlangClass) 1238 .Case("Name", "name") 1239 .Case("ScalarIntConstantExpr", "scalarIntConstantExpr") 1240 .Case("ScalarIntExpr", "scalarIntExpr") 1241 .Case("ScalarExpr", "scalarExpr") 1242 .Case("ScalarLogicalExpr", "scalarLogicalExpr") 1243 .Default(("Parser<" + FlangClass + ">{}").toStringRef(Scratch)); 1244 OS << Parser; 1245 if (!C.getPrefix().empty() && C.isPrefixOptional()) 1246 OS << " || " << Parser; 1247 if (C.isValueList()) // close nonemptyList(. 1248 OS << ")"; 1249 OS << ")"; // close parenthesized(. 1250 1251 if (C.isValueOptional()) // close maybe(. 1252 OS << ")"; 1253 OS << "))"; 1254 if (Index != LastIndex) 1255 OS << " ||"; 1256 OS << "\n"; 1257 } 1258 OS << ")\n"; 1259 } 1260 1261 // Generate the implementation section for the enumeration in the directive 1262 // language 1263 static void emitDirectivesClangImpl(const DirectiveLanguage &DirLang, 1264 raw_ostream &OS) { 1265 // Currently we only have work to do for OpenACC, so skip otherwise. 1266 if (DirLang.getName() != "OpenACC") 1267 return; 1268 1269 generateDirectiveClauseSets(DirLang, Frontend::Clang, OS); 1270 generateDirectiveClauseMap(DirLang, Frontend::Clang, OS); 1271 } 1272 // Generate the implementation section for the enumeration in the directive 1273 // language 1274 static void emitDirectivesFlangImpl(const DirectiveLanguage &DirLang, 1275 raw_ostream &OS) { 1276 generateDirectiveClauseSets(DirLang, Frontend::Flang, OS); 1277 1278 generateDirectiveClauseMap(DirLang, Frontend::Flang, OS); 1279 1280 generateFlangClauseParserClass(DirLang, OS); 1281 1282 generateFlangClauseParserClassList(DirLang, OS); 1283 1284 generateFlangClauseDump(DirLang, OS); 1285 1286 generateFlangClauseUnparse(DirLang, OS); 1287 1288 generateFlangClauseCheckPrototypes(DirLang, OS); 1289 1290 generateFlangClauseParserKindMap(DirLang, OS); 1291 1292 generateFlangClausesParser(DirLang, OS); 1293 } 1294 1295 static void generateClauseClassMacro(const DirectiveLanguage &DirLang, 1296 raw_ostream &OS) { 1297 // Generate macros style information for legacy code in clang 1298 IfDefScope Scope("GEN_CLANG_CLAUSE_CLASS", OS); 1299 1300 StringRef Prefix = DirLang.getClausePrefix(); 1301 OS << "\n"; 1302 1303 OS << "#ifndef CLAUSE\n"; 1304 OS << "#define CLAUSE(Enum, Str, Implicit)\n"; 1305 OS << "#endif\n"; 1306 OS << "#ifndef CLAUSE_CLASS\n"; 1307 OS << "#define CLAUSE_CLASS(Enum, Str, Class)\n"; 1308 OS << "#endif\n"; 1309 OS << "#ifndef CLAUSE_NO_CLASS\n"; 1310 OS << "#define CLAUSE_NO_CLASS(Enum, Str)\n"; 1311 OS << "#endif\n"; 1312 OS << "\n"; 1313 OS << "#define __CLAUSE(Name, Class) \\\n"; 1314 OS << " CLAUSE(" << Prefix << "##Name, #Name, /* Implicit */ false) \\\n"; 1315 OS << " CLAUSE_CLASS(" << Prefix << "##Name, #Name, Class)\n"; 1316 OS << "#define __CLAUSE_NO_CLASS(Name) \\\n"; 1317 OS << " CLAUSE(" << Prefix << "##Name, #Name, /* Implicit */ false) \\\n"; 1318 OS << " CLAUSE_NO_CLASS(" << Prefix << "##Name, #Name)\n"; 1319 OS << "#define __IMPLICIT_CLAUSE_CLASS(Name, Str, Class) \\\n"; 1320 OS << " CLAUSE(" << Prefix << "##Name, Str, /* Implicit */ true) \\\n"; 1321 OS << " CLAUSE_CLASS(" << Prefix << "##Name, Str, Class)\n"; 1322 OS << "#define __IMPLICIT_CLAUSE_NO_CLASS(Name, Str) \\\n"; 1323 OS << " CLAUSE(" << Prefix << "##Name, Str, /* Implicit */ true) \\\n"; 1324 OS << " CLAUSE_NO_CLASS(" << Prefix << "##Name, Str)\n"; 1325 OS << "\n"; 1326 1327 for (const Clause C : DirLang.getClauses()) { 1328 std::string Name = C.getFormattedName(); 1329 if (C.getClangClass().empty()) { // NO_CLASS 1330 if (C.isImplicit()) { 1331 OS << "__IMPLICIT_CLAUSE_NO_CLASS(" << Name << ", \"" << Name 1332 << "\")\n"; 1333 } else { 1334 OS << "__CLAUSE_NO_CLASS(" << Name << ")\n"; 1335 } 1336 } else { // CLASS 1337 if (C.isImplicit()) { 1338 OS << "__IMPLICIT_CLAUSE_CLASS(" << Name << ", \"" << Name << "\", " 1339 << C.getClangClass() << ")\n"; 1340 } else { 1341 OS << "__CLAUSE(" << Name << ", " << C.getClangClass() << ")\n"; 1342 } 1343 } 1344 } 1345 1346 OS << "\n"; 1347 OS << "#undef __IMPLICIT_CLAUSE_NO_CLASS\n"; 1348 OS << "#undef __IMPLICIT_CLAUSE_CLASS\n"; 1349 OS << "#undef __CLAUSE_NO_CLASS\n"; 1350 OS << "#undef __CLAUSE\n"; 1351 OS << "#undef CLAUSE_NO_CLASS\n"; 1352 OS << "#undef CLAUSE_CLASS\n"; 1353 OS << "#undef CLAUSE\n"; 1354 } 1355 1356 // Generate the implemenation for the enumeration in the directive 1357 // language. This code can be included in library. 1358 void emitDirectivesBasicImpl(const DirectiveLanguage &DirLang, 1359 raw_ostream &OS) { 1360 IfDefScope Scope("GEN_DIRECTIVES_IMPL", OS); 1361 1362 StringRef DPrefix = DirLang.getDirectivePrefix(); 1363 StringRef CPrefix = DirLang.getClausePrefix(); 1364 1365 OS << "\n"; 1366 OS << "#include \"llvm/Frontend/Directive/Spelling.h\"\n"; 1367 OS << "#include \"llvm/Support/ErrorHandling.h\"\n"; 1368 OS << "#include <utility>\n"; 1369 1370 // getDirectiveKind(StringRef Str) 1371 generateGetKind(DirLang.getDirectives(), OS, "Directive", DirLang, DPrefix, 1372 /*ImplicitAsUnknown=*/false); 1373 1374 // getDirectiveName(Directive Kind) 1375 generateGetName(DirLang.getDirectives(), OS, "Directive", DirLang, DPrefix); 1376 1377 // getClauseKind(StringRef Str) 1378 generateGetKind(DirLang.getClauses(), OS, "Clause", DirLang, CPrefix, 1379 /*ImplicitAsUnknown=*/true); 1380 1381 // getClauseName(Clause Kind) 1382 generateGetName(DirLang.getClauses(), OS, "Clause", DirLang, CPrefix); 1383 1384 // <enumClauseValue> get<enumClauseValue>(StringRef Str) ; string -> value 1385 // StringRef get<enumClauseValue>Name(<enumClauseValue>) ; value -> string 1386 generateGetClauseVal(DirLang, OS); 1387 1388 // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version) 1389 generateIsAllowedClause(DirLang, OS); 1390 1391 // getDirectiveAssociation(Directive D) 1392 generateGetDirectiveAssociation(DirLang, OS); 1393 1394 // getDirectiveCategory(Directive D) 1395 generateGetDirectiveCategory(DirLang, OS); 1396 1397 // getDirectiveLanguages(Directive D) 1398 generateGetDirectiveLanguages(DirLang, OS); 1399 1400 // Leaf table for getLeafConstructs, etc. 1401 emitLeafTable(DirLang, OS, "LeafConstructTable"); 1402 } 1403 1404 // Generate the implemenation section for the enumeration in the directive 1405 // language. 1406 static void emitDirectivesImpl(const RecordKeeper &Records, raw_ostream &OS) { 1407 const auto DirLang = DirectiveLanguage(Records); 1408 if (DirLang.HasValidityErrors()) 1409 return; 1410 1411 emitDirectivesFlangImpl(DirLang, OS); 1412 1413 emitDirectivesClangImpl(DirLang, OS); 1414 1415 generateClauseClassMacro(DirLang, OS); 1416 1417 emitDirectivesBasicImpl(DirLang, OS); 1418 } 1419 1420 static TableGen::Emitter::Opt 1421 X("gen-directive-decl", emitDirectivesDecl, 1422 "Generate directive related declaration code (header file)"); 1423 1424 static TableGen::Emitter::Opt 1425 Y("gen-directive-impl", emitDirectivesImpl, 1426 "Generate directive related implementation code"); 1427