brintos

brintos / llvm-project-archived public Read only

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