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