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