Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp
213799 views
//===- DirectiveEmitter.cpp - Directive Language Emitter ------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// DirectiveEmitter uses the descriptions of directives and clauses to construct9// common code declarations to be used in Frontends.10//11//===----------------------------------------------------------------------===//1213#include "llvm/TableGen/DirectiveEmitter.h"1415#include "llvm/ADT/DenseMap.h"16#include "llvm/ADT/DenseSet.h"17#include "llvm/ADT/STLExtras.h"18#include "llvm/ADT/SmallVector.h"19#include "llvm/ADT/StringSet.h"20#include "llvm/ADT/StringSwitch.h"21#include "llvm/TableGen/Error.h"22#include "llvm/TableGen/Record.h"23#include "llvm/TableGen/TableGenBackend.h"2425#include <numeric>26#include <string>27#include <vector>2829using namespace llvm;3031namespace {32// Simple RAII helper for defining ifdef-undef-endif scopes.33class IfDefScope {34public:35IfDefScope(StringRef Name, raw_ostream &OS) : Name(Name), OS(OS) {36OS << "#ifdef " << Name << "\n"37<< "#undef " << Name << "\n";38}3940~IfDefScope() { OS << "\n#endif // " << Name << "\n\n"; }4142private:43StringRef Name;44raw_ostream &OS;45};46} // namespace4748namespace {49enum class Frontend { LLVM, Flang, Clang };5051StringRef getFESpelling(Frontend FE) {52switch (FE) {53case Frontend::LLVM:54return "llvm";55case Frontend::Flang:56return "flang";57case Frontend::Clang:58return "clang";59}60llvm_unreachable("unknown FE kind");61}62} // namespace6364// Get the full namespace qualifier for the directive language.65static std::string getQualifier(const DirectiveLanguage &DirLang,66Frontend FE = Frontend::LLVM) {67return (Twine(getFESpelling(FE)) + "::" + DirLang.getCppNamespace().str() +68"::")69.str();70}7172// Get prefixed formatted name, e.g. for "target data", get "OMPD_target_data".73// This should work for any Record as long as BaseRecord::getFormattedName74// works.75static std::string getIdentifierName(const Record *Rec, StringRef Prefix) {76return Prefix.str() + BaseRecord(Rec).getFormattedName();77}7879using RecordWithSpelling = std::pair<const Record *, Spelling::Value>;8081static std::vector<RecordWithSpelling>82getSpellings(ArrayRef<const Record *> Records) {83std::vector<RecordWithSpelling> List;84for (const Record *R : Records) {85BaseRecord Rec(R);86llvm::transform(Rec.getSpellings(), std::back_inserter(List),87[R](Spelling::Value V) { return std::make_pair(R, V); });88}89return List;90}9192static void generateEnumExports(ArrayRef<const Record *> Records,93raw_ostream &OS, StringRef Enum,94StringRef Prefix) {95for (const Record *R : Records) {96std::string N = getIdentifierName(R, Prefix);97OS << "constexpr auto " << N << " = " << Enum << "::" << N << ";\n";98}99}100101// Generate enum class. Entries are emitted in the order in which they appear102// in the `Records` vector.103static void generateEnumClass(ArrayRef<const Record *> Records, raw_ostream &OS,104StringRef Enum, StringRef Prefix,105bool ExportEnums) {106OS << "\n";107OS << "enum class " << Enum << " {\n";108for (const Record *R : Records) {109OS << " " << getIdentifierName(R, Prefix) << ",\n";110}111OS << "};\n";112OS << "\n";113OS << "static constexpr std::size_t " << Enum114<< "_enumSize = " << Records.size() << ";\n";115116// Make the enum values available in the defined namespace. This allows us to117// write something like Enum_X if we have a `using namespace <CppNamespace>`.118// At the same time we do not loose the strong type guarantees of the enum119// class, that is we cannot pass an unsigned as Directive without an explicit120// cast.121if (ExportEnums) {122OS << "\n";123generateEnumExports(Records, OS, Enum, Prefix);124}125}126127// Generate enum class with values corresponding to different bit positions.128// Entries are emitted in the order in which they appear in the `Records`129// vector.130static void generateEnumBitmask(ArrayRef<const Record *> Records,131raw_ostream &OS, StringRef Enum,132StringRef Prefix, bool ExportEnums) {133assert(Records.size() <= 64 && "Too many values for a bitmask");134StringRef Type = Records.size() <= 32 ? "uint32_t" : "uint64_t";135StringRef TypeSuffix = Records.size() <= 32 ? "U" : "ULL";136137OS << "\n";138OS << "enum class " << Enum << " : " << Type << " {\n";139std::string LastName;140for (auto [I, R] : llvm::enumerate(Records)) {141LastName = getIdentifierName(R, Prefix);142OS << " " << LastName << " = " << (1ull << I) << TypeSuffix << ",\n";143}144OS << " LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/" << LastName << ")\n";145OS << "};\n";146OS << "\n";147OS << "static constexpr std::size_t " << Enum148<< "_enumSize = " << Records.size() << ";\n";149150// Make the enum values available in the defined namespace. This allows us to151// write something like Enum_X if we have a `using namespace <CppNamespace>`.152// At the same time we do not loose the strong type guarantees of the enum153// class, that is we cannot pass an unsigned as Directive without an explicit154// cast.155if (ExportEnums) {156OS << "\n";157generateEnumExports(Records, OS, Enum, Prefix);158}159}160161// Generate enums for values that clauses can take.162// Also generate function declarations for get<Enum>Name(StringRef Str).163static void generateClauseEnumVal(ArrayRef<const Record *> Records,164raw_ostream &OS,165const DirectiveLanguage &DirLang,166std::string &EnumHelperFuncs) {167for (const Record *R : Records) {168Clause C(R);169const auto &ClauseVals = C.getClauseVals();170if (ClauseVals.size() <= 0)171continue;172173StringRef Enum = C.getEnumName();174if (Enum.empty()) {175PrintError("enumClauseValue field not set in Clause" +176C.getFormattedName() + ".");177return;178}179180OS << "\n";181OS << "enum class " << Enum << " {\n";182for (const EnumVal Val : ClauseVals)183OS << " " << Val.getRecordName() << "=" << Val.getValue() << ",\n";184OS << "};\n";185186if (DirLang.hasMakeEnumAvailableInNamespace()) {187OS << "\n";188for (const auto &CV : ClauseVals) {189OS << "constexpr auto " << CV->getName() << " = " << Enum190<< "::" << CV->getName() << ";\n";191}192EnumHelperFuncs += (Twine("LLVM_ABI ") + Twine(Enum) + Twine(" get") +193Twine(Enum) + Twine("(StringRef Str);\n"))194.str();195196EnumHelperFuncs +=197(Twine("LLVM_ABI StringRef get") + Twine(DirLang.getName()) +198Twine(Enum) + Twine("Name(") + Twine(Enum) + Twine(" x);\n"))199.str();200}201}202}203204static bool hasDuplicateClauses(ArrayRef<const Record *> Clauses,205const Directive &Directive,206StringSet<> &CrtClauses) {207bool HasError = false;208for (const VersionedClause VerClause : Clauses) {209StringRef Name = VerClause.getClause().getRecordName();210const auto InsRes = CrtClauses.insert(Name);211if (!InsRes.second) {212PrintError("Clause " + Name + " already defined on directive " +213Directive.getRecordName());214HasError = true;215}216}217return HasError;218}219220// Check for duplicate clauses in lists. Clauses cannot appear twice in the221// three allowed list. Also, since required implies allowed, clauses cannot222// appear in both the allowedClauses and requiredClauses lists.223static bool224hasDuplicateClausesInDirectives(ArrayRef<const Record *> Directives) {225bool HasDuplicate = false;226for (const Directive Dir : Directives) {227StringSet<> Clauses;228// Check for duplicates in the three allowed lists.229if (hasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) ||230hasDuplicateClauses(Dir.getAllowedOnceClauses(), Dir, Clauses) ||231hasDuplicateClauses(Dir.getAllowedExclusiveClauses(), Dir, Clauses)) {232HasDuplicate = true;233}234// Check for duplicate between allowedClauses and required235Clauses.clear();236if (hasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) ||237hasDuplicateClauses(Dir.getRequiredClauses(), Dir, Clauses)) {238HasDuplicate = true;239}240if (HasDuplicate)241PrintFatalError("One or more clauses are defined multiple times on"242" directive " +243Dir.getRecordName());244}245246return HasDuplicate;247}248249// Check consitency of records. Return true if an error has been detected.250// Return false if the records are valid.251bool DirectiveLanguage::HasValidityErrors() const {252if (getDirectiveLanguages().size() != 1) {253PrintFatalError("A single definition of DirectiveLanguage is needed.");254return true;255}256257return hasDuplicateClausesInDirectives(getDirectives());258}259260// Count the maximum number of leaf constituents per construct.261static size_t getMaxLeafCount(const DirectiveLanguage &DirLang) {262size_t MaxCount = 0;263for (const Directive D : DirLang.getDirectives())264MaxCount = std::max(MaxCount, D.getLeafConstructs().size());265return MaxCount;266}267268// Generate the declaration section for the enumeration in the directive269// language.270static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {271const auto DirLang = DirectiveLanguage(Records);272if (DirLang.HasValidityErrors())273return;274275StringRef Lang = DirLang.getName();276277OS << "#ifndef LLVM_" << Lang << "_INC\n";278OS << "#define LLVM_" << Lang << "_INC\n";279OS << "\n#include \"llvm/ADT/ArrayRef.h\"\n";280281if (DirLang.hasEnableBitmaskEnumInNamespace())282OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n";283284OS << "#include \"llvm/ADT/StringRef.h\"\n";285OS << "#include \"llvm/Frontend/Directive/Spelling.h\"\n";286OS << "#include \"llvm/Support/Compiler.h\"\n";287OS << "#include <cstddef>\n"; // for size_t288OS << "#include <utility>\n"; // for std::pair289OS << "\n";290OS << "namespace llvm {\n";291292// Open namespaces defined in the directive language293SmallVector<StringRef, 2> Namespaces;294SplitString(DirLang.getCppNamespace(), Namespaces, "::");295for (auto Ns : Namespaces)296OS << "namespace " << Ns << " {\n";297298if (DirLang.hasEnableBitmaskEnumInNamespace())299OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n";300301// Emit Directive associations302std::vector<const Record *> Associations;303copy_if(DirLang.getAssociations(), std::back_inserter(Associations),304// Skip the "special" value305[](const Record *Def) { return Def->getName() != "AS_FromLeaves"; });306generateEnumClass(Associations, OS, "Association",307/*Prefix=*/"", /*ExportEnums=*/false);308309generateEnumClass(DirLang.getCategories(), OS, "Category", /*Prefix=*/"",310/*ExportEnums=*/false);311312generateEnumBitmask(DirLang.getSourceLanguages(), OS, "SourceLanguage",313/*Prefix=*/"", /*ExportEnums=*/false);314315// Emit Directive enumeration316generateEnumClass(DirLang.getDirectives(), OS, "Directive",317DirLang.getDirectivePrefix(),318DirLang.hasMakeEnumAvailableInNamespace());319320// Emit Clause enumeration321generateEnumClass(DirLang.getClauses(), OS, "Clause",322DirLang.getClausePrefix(),323DirLang.hasMakeEnumAvailableInNamespace());324325// Emit ClauseVals enumeration326std::string EnumHelperFuncs;327generateClauseEnumVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs);328329// Generic function signatures330OS << "\n";331OS << "// Enumeration helper functions\n";332333OS << "LLVM_ABI std::pair<Directive, directive::VersionRange> get" << Lang334<< "DirectiveKindAndVersions(StringRef Str);\n";335336OS << "inline Directive get" << Lang << "DirectiveKind(StringRef Str) {\n";337OS << " return get" << Lang << "DirectiveKindAndVersions(Str).first;\n";338OS << "}\n";339OS << "\n";340341OS << "LLVM_ABI StringRef get" << Lang342<< "DirectiveName(Directive D, unsigned Ver = 0);\n";343OS << "\n";344345OS << "LLVM_ABI std::pair<Clause, directive::VersionRange> get" << Lang346<< "ClauseKindAndVersions(StringRef Str);\n";347OS << "\n";348349OS << "inline Clause get" << Lang << "ClauseKind(StringRef Str) {\n";350OS << " return get" << Lang << "ClauseKindAndVersions(Str).first;\n";351OS << "}\n";352OS << "\n";353354OS << "LLVM_ABI StringRef get" << Lang355<< "ClauseName(Clause C, unsigned Ver = 0);\n";356OS << "\n";357358OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p "359<< "Version.\n";360OS << "LLVM_ABI bool isAllowedClauseForDirective(Directive D, "361<< "Clause C, unsigned Version);\n";362OS << "\n";363OS << "constexpr std::size_t getMaxLeafCount() { return "364<< getMaxLeafCount(DirLang) << "; }\n";365OS << "LLVM_ABI Association getDirectiveAssociation(Directive D);\n";366OS << "LLVM_ABI Category getDirectiveCategory(Directive D);\n";367OS << "LLVM_ABI SourceLanguage getDirectiveLanguages(Directive D);\n";368if (EnumHelperFuncs.length() > 0) {369OS << EnumHelperFuncs;370OS << "\n";371}372373// Closing namespaces374for (auto Ns : reverse(Namespaces))375OS << "} // namespace " << Ns << "\n";376377OS << "} // namespace llvm\n";378379OS << "#endif // LLVM_" << Lang << "_INC\n";380}381382// Given a list of spellings (for a given clause/directive), order them383// in a way that allows the use of binary search to locate a spelling384// for a specified version.385static std::vector<Spelling::Value>386orderSpellings(ArrayRef<Spelling::Value> Spellings) {387std::vector<Spelling::Value> List(Spellings.begin(), Spellings.end());388389llvm::stable_sort(List,390[](const Spelling::Value &A, const Spelling::Value &B) {391return A.Versions < B.Versions;392});393return List;394}395396// Generate function implementation for get<Enum>Name(StringRef Str)397static void generateGetName(ArrayRef<const Record *> Records, raw_ostream &OS,398StringRef Enum, const DirectiveLanguage &DirLang,399StringRef Prefix) {400StringRef Lang = DirLang.getName();401std::string Qual = getQualifier(DirLang);402OS << "\n";403OS << "llvm::StringRef " << Qual << "get" << Lang << Enum << "Name(" << Qual404<< Enum << " Kind, unsigned Version) {\n";405OS << " switch (Kind) {\n";406for (const Record *R : Records) {407BaseRecord Rec(R);408std::string Ident = getIdentifierName(R, Prefix);409OS << " case " << Ident << ":";410std::vector<Spelling::Value> Spellings(orderSpellings(Rec.getSpellings()));411assert(Spellings.size() != 0 && "No spellings for this item");412if (Spellings.size() == 1) {413OS << "\n";414OS << " return \"" << Spellings.front().Name << "\";\n";415} else {416OS << " {\n";417std::string SpellingsName = Ident + "_spellings";418OS << " static constexpr llvm::directive::Spelling " << SpellingsName419<< "[] = {\n";420for (auto &S : Spellings) {421OS << " {\"" << S.Name << "\", {" << S.Versions.Min << ", "422<< S.Versions.Max << "}},\n";423}424OS << " };\n";425OS << " return llvm::directive::FindName(" << SpellingsName426<< ", Version);\n";427OS << " }\n";428}429}430OS << " }\n"; // switch431OS << " llvm_unreachable(\"Invalid " << Lang << " " << Enum << " kind\");\n";432OS << "}\n";433}434435// Generate function implementation for get<Enum>KindAndVersions(StringRef Str)436static void generateGetKind(ArrayRef<const Record *> Records, raw_ostream &OS,437StringRef Enum, const DirectiveLanguage &DirLang,438StringRef Prefix, bool ImplicitAsUnknown) {439440const auto *DefaultIt = find_if(441Records, [](const Record *R) { return R->getValueAsBit("isDefault"); });442443if (DefaultIt == Records.end()) {444PrintError("At least one " + Enum + " must be defined as default.");445return;446}447448BaseRecord DefaultRec(*DefaultIt);449std::string Qual = getQualifier(DirLang);450std::string DefaultName = getIdentifierName(*DefaultIt, Prefix);451452// std::pair<<Enum>, VersionRange>453// get<DirLang><Enum>KindAndVersions(StringRef Str);454OS << "\n";455OS << "std::pair<" << Qual << Enum << ", llvm::directive::VersionRange> "456<< Qual << "get" << DirLang.getName() << Enum457<< "KindAndVersions(llvm::StringRef Str) {\n";458OS << " directive::VersionRange All; // Default-initialized to \"all "459"versions\"\n";460OS << " return StringSwitch<std::pair<" << Enum << ", "461<< "directive::VersionRange>>(Str)\n";462463directive::VersionRange All;464465for (const Record *R : Records) {466BaseRecord Rec(R);467std::string Ident = ImplicitAsUnknown && R->getValueAsBit("isImplicit")468? DefaultName469: getIdentifierName(R, Prefix);470471for (auto &[Name, Versions] : Rec.getSpellings()) {472OS << " .Case(\"" << Name << "\", {" << Ident << ", ";473if (Versions.Min == All.Min && Versions.Max == All.Max)474OS << "All})\n";475else476OS << "{" << Versions.Min << ", " << Versions.Max << "}})\n";477}478}479OS << " .Default({" << DefaultName << ", All});\n";480OS << "}\n";481}482483// Generate function implementations for484// <enumClauseValue> get<enumClauseValue>(StringRef Str) and485// StringRef get<enumClauseValue>Name(<enumClauseValue>)486static void generateGetClauseVal(const DirectiveLanguage &DirLang,487raw_ostream &OS) {488StringRef Lang = DirLang.getName();489std::string Qual = getQualifier(DirLang);490491for (const Clause C : DirLang.getClauses()) {492const auto &ClauseVals = C.getClauseVals();493if (ClauseVals.size() <= 0)494continue;495496auto DefaultIt = find_if(ClauseVals, [](const Record *CV) {497return CV->getValueAsBit("isDefault");498});499500if (DefaultIt == ClauseVals.end()) {501PrintError("At least one val in Clause " + C.getRecordName() +502" must be defined as default.");503return;504}505const auto DefaultName = (*DefaultIt)->getName();506507StringRef Enum = C.getEnumName();508if (Enum.empty()) {509PrintError("enumClauseValue field not set in Clause" + C.getRecordName() +510".");511return;512}513514OS << "\n";515OS << Qual << Enum << " " << Qual << "get" << Enum516<< "(llvm::StringRef Str) {\n";517OS << " return StringSwitch<" << Enum << ">(Str)\n";518for (const EnumVal Val : ClauseVals) {519OS << " .Case(\"" << Val.getFormattedName() << "\","520<< Val.getRecordName() << ")\n";521}522OS << " .Default(" << DefaultName << ");\n";523OS << "}\n";524525OS << "\n";526OS << "llvm::StringRef " << Qual << "get" << Lang << Enum << "Name(" << Qual527<< Enum << " x) {\n";528OS << " switch (x) {\n";529for (const EnumVal Val : ClauseVals) {530OS << " case " << Val.getRecordName() << ":\n";531OS << " return \"" << Val.getFormattedName() << "\";\n";532}533OS << " }\n"; // switch534OS << " llvm_unreachable(\"Invalid " << Lang << " " << Enum535<< " kind\");\n";536OS << "}\n";537}538}539540static void generateCaseForVersionedClauses(ArrayRef<const Record *> VerClauses,541raw_ostream &OS,542const DirectiveLanguage &DirLang,543StringSet<> &Cases) {544StringRef Prefix = DirLang.getClausePrefix();545for (const Record *R : VerClauses) {546VersionedClause VerClause(R);547std::string Name =548getIdentifierName(VerClause.getClause().getRecord(), Prefix);549if (Cases.insert(Name).second) {550OS << " case " << Name << ":\n";551OS << " return " << VerClause.getMinVersion()552<< " <= Version && " << VerClause.getMaxVersion() << " >= Version;\n";553}554}555}556557// Generate the isAllowedClauseForDirective function implementation.558static void generateIsAllowedClause(const DirectiveLanguage &DirLang,559raw_ostream &OS) {560std::string Qual = getQualifier(DirLang);561562OS << "\n";563OS << "bool " << Qual << "isAllowedClauseForDirective(" << Qual564<< "Directive D, " << Qual << "Clause C, unsigned Version) {\n";565OS << " assert(unsigned(D) <= Directive_enumSize);\n";566OS << " assert(unsigned(C) <= Clause_enumSize);\n";567568OS << " switch (D) {\n";569570StringRef Prefix = DirLang.getDirectivePrefix();571for (const Record *R : DirLang.getDirectives()) {572Directive Dir(R);573OS << " case " << getIdentifierName(R, Prefix) << ":\n";574if (Dir.getAllowedClauses().empty() &&575Dir.getAllowedOnceClauses().empty() &&576Dir.getAllowedExclusiveClauses().empty() &&577Dir.getRequiredClauses().empty()) {578OS << " return false;\n";579} else {580OS << " switch (C) {\n";581582StringSet<> Cases;583584generateCaseForVersionedClauses(Dir.getAllowedClauses(), OS, DirLang,585Cases);586587generateCaseForVersionedClauses(Dir.getAllowedOnceClauses(), OS, DirLang,588Cases);589590generateCaseForVersionedClauses(Dir.getAllowedExclusiveClauses(), OS,591DirLang, Cases);592593generateCaseForVersionedClauses(Dir.getRequiredClauses(), OS, DirLang,594Cases);595596OS << " default:\n";597OS << " return false;\n";598OS << " }\n"; // End of clauses switch599}600OS << " break;\n";601}602603OS << " }\n"; // End of directives switch604OS << " llvm_unreachable(\"Invalid " << DirLang.getName()605<< " Directive kind\");\n";606OS << "}\n"; // End of function isAllowedClauseForDirective607}608609static void emitLeafTable(const DirectiveLanguage &DirLang, raw_ostream &OS,610StringRef TableName) {611// The leaf constructs are emitted in a form of a 2D table, where each612// row corresponds to a directive (and there is a row for each directive).613//614// Each row consists of615// - the id of the directive itself,616// - number of leaf constructs that will follow (0 for leafs),617// - ids of the leaf constructs (none if the directive is itself a leaf).618// The total number of these entries is at most MaxLeafCount+2. If this619// number is less than that, it is padded to occupy exactly MaxLeafCount+2620// entries in memory.621//622// The rows are stored in the table in the lexicographical order. This623// is intended to enable binary search when mapping a sequence of leafs624// back to the compound directive.625// The consequence of that is that in order to find a row corresponding626// to the given directive, we'd need to scan the first element of each627// row. To avoid this, an auxiliary ordering table is created, such that628// row for Dir_A = table[auxiliary[Dir_A]].629630ArrayRef<const Record *> Directives = DirLang.getDirectives();631DenseMap<const Record *, int> DirId; // Record * -> llvm::omp::Directive632633for (auto [Idx, Rec] : enumerate(Directives))634DirId.try_emplace(Rec, Idx);635636using LeafList = std::vector<int>;637int MaxLeafCount = getMaxLeafCount(DirLang);638639// The initial leaf table, rows order is same as directive order.640std::vector<LeafList> LeafTable(Directives.size());641for (auto [Idx, Rec] : enumerate(Directives)) {642Directive Dir(Rec);643std::vector<const Record *> Leaves = Dir.getLeafConstructs();644645auto &List = LeafTable[Idx];646List.resize(MaxLeafCount + 2);647List[0] = Idx; // The id of the directive itself.648List[1] = Leaves.size(); // The number of leaves to follow.649650for (int I = 0; I != MaxLeafCount; ++I)651List[I + 2] =652static_cast<size_t>(I) < Leaves.size() ? DirId.at(Leaves[I]) : -1;653}654655// Some Fortran directives are delimited, i.e. they have the form of656// "directive"---"end directive". If "directive" is a compound construct,657// then the set of leaf constituents will be nonempty and the same for658// both directives. Given this set of leafs, looking up the corresponding659// compound directive should return "directive", and not "end directive".660// To avoid this problem, gather all "end directives" at the end of the661// leaf table, and only do the search on the initial segment of the table662// that excludes the "end directives".663// It's safe to find all directives whose names begin with "end ". The664// problem only exists for compound directives, like "end do simd".665// All existing directives with names starting with "end " are either666// "end directives" for an existing "directive", or leaf directives667// (such as "end declare target").668DenseSet<int> EndDirectives;669for (auto [Rec, Id] : DirId) {670// FIXME: This will need to recognize different spellings for different671// versions.672StringRef Name = Directive(Rec).getSpellingForIdentifier();673if (Name.starts_with_insensitive("end "))674EndDirectives.insert(Id);675}676677// Avoid sorting the vector<vector> array, instead sort an index array.678// It will also be useful later to create the auxiliary indexing array.679std::vector<int> Ordering(Directives.size());680std::iota(Ordering.begin(), Ordering.end(), 0);681682llvm::sort(Ordering, [&](int A, int B) {683auto &LeavesA = LeafTable[A];684auto &LeavesB = LeafTable[B];685int DirA = LeavesA[0], DirB = LeavesB[0];686// First of all, end directives compare greater than non-end directives.687bool IsEndA = EndDirectives.contains(DirA);688bool IsEndB = EndDirectives.contains(DirB);689if (IsEndA != IsEndB)690return IsEndA < IsEndB;691if (LeavesA[1] == 0 && LeavesB[1] == 0)692return DirA < DirB;693return std::lexicographical_compare(&LeavesA[2], &LeavesA[2] + LeavesA[1],694&LeavesB[2], &LeavesB[2] + LeavesB[1]);695});696697// Emit the table698699// The directives are emitted into a scoped enum, for which the underlying700// type is `int` (by default). The code above uses `int` to store directive701// ids, so make sure that we catch it when something changes in the702// underlying type.703StringRef Prefix = DirLang.getDirectivePrefix();704std::string Qual = getQualifier(DirLang);705std::string DirectiveType = Qual + "Directive";706OS << "\nstatic_assert(sizeof(" << DirectiveType << ") == sizeof(int));\n";707708OS << "[[maybe_unused]] static const " << DirectiveType << ' ' << TableName709<< "[][" << MaxLeafCount + 2 << "] = {\n";710for (size_t I = 0, E = Directives.size(); I != E; ++I) {711auto &Leaves = LeafTable[Ordering[I]];712OS << " {" << Qual << getIdentifierName(Directives[Leaves[0]], Prefix);713OS << ", static_cast<" << DirectiveType << ">(" << Leaves[1] << "),";714for (size_t I = 2, E = Leaves.size(); I != E; ++I) {715int Idx = Leaves[I];716if (Idx >= 0)717OS << ' ' << Qual << getIdentifierName(Directives[Leaves[I]], Prefix)718<< ',';719else720OS << " static_cast<" << DirectiveType << ">(-1),";721}722OS << "},\n";723}724OS << "};\n\n";725726// Emit a marker where the first "end directive" is.727auto FirstE = find_if(Ordering, [&](int RowIdx) {728return EndDirectives.contains(LeafTable[RowIdx][0]);729});730OS << "[[maybe_unused]] static auto " << TableName731<< "EndDirective = " << TableName << " + "732<< std::distance(Ordering.begin(), FirstE) << ";\n\n";733734// Emit the auxiliary index table: it's the inverse of the `Ordering`735// table above.736OS << "[[maybe_unused]] static const int " << TableName << "Ordering[] = {\n";737OS << " ";738std::vector<int> Reverse(Ordering.size());739for (int I = 0, E = Ordering.size(); I != E; ++I)740Reverse[Ordering[I]] = I;741for (int Idx : Reverse)742OS << ' ' << Idx << ',';743OS << "\n};\n";744}745746static void generateGetDirectiveAssociation(const DirectiveLanguage &DirLang,747raw_ostream &OS) {748enum struct Association {749None = 0, // None should be the smallest value.750Block, // The values of the rest don't matter.751Declaration,752Delimited,753Loop,754Separating,755FromLeaves,756Invalid,757};758759ArrayRef<const Record *> Associations = DirLang.getAssociations();760761auto GetAssocValue = [](StringRef Name) -> Association {762return StringSwitch<Association>(Name)763.Case("AS_Block", Association::Block)764.Case("AS_Declaration", Association::Declaration)765.Case("AS_Delimited", Association::Delimited)766.Case("AS_Loop", Association::Loop)767.Case("AS_None", Association::None)768.Case("AS_Separating", Association::Separating)769.Case("AS_FromLeaves", Association::FromLeaves)770.Default(Association::Invalid);771};772773auto GetAssocName = [&](Association A) -> StringRef {774if (A != Association::Invalid && A != Association::FromLeaves) {775const auto *F = find_if(Associations, [&](const Record *R) {776return GetAssocValue(R->getName()) == A;777});778if (F != Associations.end())779return (*F)->getValueAsString("name"); // enum name780}781llvm_unreachable("Unexpected association value");782};783784auto ErrorPrefixFor = [&](Directive D) -> std::string {785return (Twine("Directive '") + D.getRecordName() + "' in namespace '" +786DirLang.getCppNamespace() + "' ")787.str();788};789790auto Reduce = [&](Association A, Association B) -> Association {791if (A > B)792std::swap(A, B);793794// Calculate the result using the following rules:795// x + x = x796// AS_None + x = x797// AS_Block + AS_Loop = AS_Loop798if (A == Association::None || A == B)799return B;800if (A == Association::Block && B == Association::Loop)801return B;802if (A == Association::Loop && B == Association::Block)803return A;804return Association::Invalid;805};806807DenseMap<const Record *, Association> AsMap;808809auto CompAssocImpl = [&](const Record *R, auto &&Self) -> Association {810if (auto F = AsMap.find(R); F != AsMap.end())811return F->second;812813Directive D(R);814Association AS = GetAssocValue(D.getAssociation()->getName());815if (AS == Association::Invalid) {816PrintFatalError(ErrorPrefixFor(D) +817"has an unrecognized value for association: '" +818D.getAssociation()->getName() + "'");819}820if (AS != Association::FromLeaves) {821AsMap.try_emplace(R, AS);822return AS;823}824// Compute the association from leaf constructs.825std::vector<const Record *> Leaves = D.getLeafConstructs();826if (Leaves.empty()) {827PrintFatalError(ErrorPrefixFor(D) +828"requests association to be computed from leaves, "829"but it has no leaves");830}831832Association Result = Self(Leaves[0], Self);833for (int I = 1, E = Leaves.size(); I < E; ++I) {834Association A = Self(Leaves[I], Self);835Association R = Reduce(Result, A);836if (R == Association::Invalid) {837PrintFatalError(ErrorPrefixFor(D) +838"has leaves with incompatible association values: " +839GetAssocName(A) + " and " + GetAssocName(R));840}841Result = R;842}843844assert(Result != Association::Invalid);845assert(Result != Association::FromLeaves);846AsMap.try_emplace(R, Result);847return Result;848};849850for (const Record *R : DirLang.getDirectives())851CompAssocImpl(R, CompAssocImpl); // Updates AsMap.852853OS << '\n';854855StringRef Prefix = DirLang.getDirectivePrefix();856std::string Qual = getQualifier(DirLang);857858OS << Qual << "Association " << Qual << "getDirectiveAssociation(" << Qual859<< "Directive Dir) {\n";860OS << " switch (Dir) {\n";861for (const Record *R : DirLang.getDirectives()) {862if (auto F = AsMap.find(R); F != AsMap.end()) {863OS << " case " << getIdentifierName(R, Prefix) << ":\n";864OS << " return Association::" << GetAssocName(F->second) << ";\n";865}866}867OS << " } // switch (Dir)\n";868OS << " llvm_unreachable(\"Unexpected directive\");\n";869OS << "}\n";870}871872static void generateGetDirectiveCategory(const DirectiveLanguage &DirLang,873raw_ostream &OS) {874std::string Qual = getQualifier(DirLang);875876OS << '\n';877OS << Qual << "Category " << Qual << "getDirectiveCategory(" << Qual878<< "Directive Dir) {\n";879OS << " switch (Dir) {\n";880881StringRef Prefix = DirLang.getDirectivePrefix();882883for (const Record *R : DirLang.getDirectives()) {884Directive D(R);885OS << " case " << getIdentifierName(R, Prefix) << ":\n";886OS << " return Category::" << D.getCategory()->getValueAsString("name")887<< ";\n";888}889OS << " } // switch (Dir)\n";890OS << " llvm_unreachable(\"Unexpected directive\");\n";891OS << "}\n";892}893894static void generateGetDirectiveLanguages(const DirectiveLanguage &DirLang,895raw_ostream &OS) {896std::string Qual = getQualifier(DirLang);897898OS << '\n';899OS << Qual << "SourceLanguage " << Qual << "getDirectiveLanguages(" << Qual900<< "Directive D) {\n";901OS << " switch (D) {\n";902903StringRef Prefix = DirLang.getDirectivePrefix();904905for (const Record *R : DirLang.getDirectives()) {906Directive D(R);907OS << " case " << getIdentifierName(R, Prefix) << ":\n";908OS << " return ";909llvm::interleave(910D.getSourceLanguages(), OS,911[&](const Record *L) {912StringRef N = L->getValueAsString("name");913OS << "SourceLanguage::" << BaseRecord::getSnakeName(N);914},915" | ");916OS << ";\n";917}918OS << " } // switch(D)\n";919OS << " llvm_unreachable(\"Unexpected directive\");\n";920OS << "}\n";921}922923// Generate a simple enum set with the give clauses.924static void generateClauseSet(ArrayRef<const Record *> VerClauses,925raw_ostream &OS, StringRef ClauseSetPrefix,926const Directive &Dir,927const DirectiveLanguage &DirLang, Frontend FE) {928929OS << "\n";930OS << "static " << DirLang.getClauseEnumSetClass() << " " << ClauseSetPrefix931<< DirLang.getDirectivePrefix() << Dir.getFormattedName() << " {\n";932933StringRef Prefix = DirLang.getClausePrefix();934935for (const VersionedClause VerClause : VerClauses) {936Clause C = VerClause.getClause();937if (FE == Frontend::Flang) {938OS << " Clause::" << getIdentifierName(C.getRecord(), Prefix) << ",\n";939} else {940assert(FE == Frontend::Clang);941assert(DirLang.getName() == "OpenACC");942OS << " OpenACCClauseKind::" << C.getClangAccSpelling() << ",\n";943}944}945OS << "};\n";946}947948// Generate an enum set for the 4 kinds of clauses linked to a directive.949static void generateDirectiveClauseSets(const DirectiveLanguage &DirLang,950Frontend FE, raw_ostream &OS) {951952std::string IfDefName{"GEN_"};953IfDefName += getFESpelling(FE).upper();954IfDefName += "_DIRECTIVE_CLAUSE_SETS";955IfDefScope Scope(IfDefName, OS);956957StringRef Namespace =958getFESpelling(FE == Frontend::Flang ? Frontend::LLVM : FE);959OS << "\n";960// The namespace has to be different for clang vs flang, as 2 structs with the961// same name but different layout is UB. So just put the 'clang' on in the962// clang namespace.963OS << "namespace " << Namespace << " {\n";964965// Open namespaces defined in the directive language.966SmallVector<StringRef, 2> Namespaces;967SplitString(DirLang.getCppNamespace(), Namespaces, "::");968for (auto Ns : Namespaces)969OS << "namespace " << Ns << " {\n";970971for (const Directive Dir : DirLang.getDirectives()) {972OS << "\n";973OS << "// Sets for " << Dir.getSpellingForIdentifier() << "\n";974975generateClauseSet(Dir.getAllowedClauses(), OS, "allowedClauses_", Dir,976DirLang, FE);977generateClauseSet(Dir.getAllowedOnceClauses(), OS, "allowedOnceClauses_",978Dir, DirLang, FE);979generateClauseSet(Dir.getAllowedExclusiveClauses(), OS,980"allowedExclusiveClauses_", Dir, DirLang, FE);981generateClauseSet(Dir.getRequiredClauses(), OS, "requiredClauses_", Dir,982DirLang, FE);983}984985// Closing namespaces986for (auto Ns : reverse(Namespaces))987OS << "} // namespace " << Ns << "\n";988989OS << "} // namespace " << Namespace << "\n";990}991992// Generate a map of directive (key) with DirectiveClauses struct as values.993// The struct holds the 4 sets of enumeration for the 4 kinds of clauses994// allowances (allowed, allowed once, allowed exclusive and required).995static void generateDirectiveClauseMap(const DirectiveLanguage &DirLang,996Frontend FE, raw_ostream &OS) {997std::string IfDefName{"GEN_"};998IfDefName += getFESpelling(FE).upper();999IfDefName += "_DIRECTIVE_CLAUSE_MAP";1000IfDefScope Scope(IfDefName, OS);10011002OS << "\n";1003OS << "{\n";10041005// The namespace has to be different for clang vs flang, as 2 structs with the1006// same name but different layout is UB. So just put the 'clang' on in the1007// clang namespace.1008std::string Qual =1009getQualifier(DirLang, FE == Frontend::Flang ? Frontend::LLVM : FE);1010StringRef Prefix = DirLang.getDirectivePrefix();10111012for (const Record *R : DirLang.getDirectives()) {1013Directive Dir(R);1014std::string Name = getIdentifierName(R, Prefix);10151016OS << " {";1017if (FE == Frontend::Flang) {1018OS << Qual << "Directive::" << Name << ",\n";1019} else {1020assert(FE == Frontend::Clang);1021assert(DirLang.getName() == "OpenACC");1022OS << "clang::OpenACCDirectiveKind::" << Dir.getClangAccSpelling()1023<< ",\n";1024}10251026OS << " {\n";1027OS << " " << Qual << "allowedClauses_" << Name << ",\n";1028OS << " " << Qual << "allowedOnceClauses_" << Name << ",\n";1029OS << " " << Qual << "allowedExclusiveClauses_" << Name << ",\n";1030OS << " " << Qual << "requiredClauses_" << Name << ",\n";1031OS << " }\n";1032OS << " },\n";1033}10341035OS << "}\n";1036}10371038// Generate classes entry for Flang clauses in the Flang parse-tree1039// If the clause as a non-generic class, no entry is generated.1040// If the clause does not hold a value, an EMPTY_CLASS is used.1041// If the clause class is generic then a WRAPPER_CLASS is used. When the value1042// is optional, the value class is wrapped into a std::optional.1043static void generateFlangClauseParserClass(const DirectiveLanguage &DirLang,1044raw_ostream &OS) {10451046IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS);10471048OS << "\n";10491050for (const Clause Clause : DirLang.getClauses()) {1051if (!Clause.getFlangClass().empty()) {1052OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName() << ", ";1053if (Clause.isValueOptional() && Clause.isValueList()) {1054OS << "std::optional<std::list<" << Clause.getFlangClass() << ">>";1055} else if (Clause.isValueOptional()) {1056OS << "std::optional<" << Clause.getFlangClass() << ">";1057} else if (Clause.isValueList()) {1058OS << "std::list<" << Clause.getFlangClass() << ">";1059} else {1060OS << Clause.getFlangClass();1061}1062} else {1063OS << "EMPTY_CLASS(" << Clause.getFormattedParserClassName();1064}1065OS << ");\n";1066}1067}10681069// Generate a list of the different clause classes for Flang.1070static void generateFlangClauseParserClassList(const DirectiveLanguage &DirLang,1071raw_ostream &OS) {10721073IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS);10741075OS << "\n";1076interleaveComma(DirLang.getClauses(), OS, [&](const Record *C) {1077Clause Clause(C);1078OS << Clause.getFormattedParserClassName() << "\n";1079});1080}10811082// Generate dump node list for the clauses holding a generic class name.1083static void generateFlangClauseDump(const DirectiveLanguage &DirLang,1084raw_ostream &OS) {10851086IfDefScope Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS);10871088OS << "\n";1089for (const Clause Clause : DirLang.getClauses()) {1090OS << "NODE(" << DirLang.getFlangClauseBaseClass() << ", "1091<< Clause.getFormattedParserClassName() << ")\n";1092}1093}10941095// Generate Unparse functions for clauses classes in the Flang parse-tree1096// If the clause is a non-generic class, no entry is generated.1097static void generateFlangClauseUnparse(const DirectiveLanguage &DirLang,1098raw_ostream &OS) {10991100IfDefScope Scope("GEN_FLANG_CLAUSE_UNPARSE", OS);11011102StringRef Base = DirLang.getFlangClauseBaseClass();1103OS << "\n";11041105for (const Clause Clause : DirLang.getClauses()) {1106if (Clause.skipFlangUnparser())1107continue;1108// The unparser doesn't know the effective version, so just pick some1109// spelling.1110StringRef SomeSpelling = Clause.getSpellingForIdentifier();1111std::string Parser = Clause.getFormattedParserClassName();1112std::string Upper = SomeSpelling.upper();11131114if (!Clause.getFlangClass().empty()) {1115if (Clause.isValueOptional() && Clause.getDefaultValue().empty()) {1116OS << "void Unparse(const " << Base << "::" << Parser << " &x) {\n";1117OS << " Word(\"" << Upper << "\");\n";11181119OS << " Walk(\"(\", x.v, \")\");\n";1120OS << "}\n";1121} else if (Clause.isValueOptional()) {1122OS << "void Unparse(const " << Base << "::" << Parser << " &x) {\n";1123OS << " Word(\"" << Upper << "\");\n";1124OS << " Put(\"(\");\n";1125OS << " if (x.v.has_value())\n";1126if (Clause.isValueList())1127OS << " Walk(x.v, \",\");\n";1128else1129OS << " Walk(x.v);\n";1130OS << " else\n";1131OS << " Put(\"" << Clause.getDefaultValue() << "\");\n";1132OS << " Put(\")\");\n";1133OS << "}\n";1134} else {1135OS << "void Unparse(const " << Base << "::" << Parser << " &x) {\n";1136OS << " Word(\"" << Upper << "\");\n";1137OS << " Put(\"(\");\n";1138if (Clause.isValueList())1139OS << " Walk(x.v, \",\");\n";1140else1141OS << " Walk(x.v);\n";1142OS << " Put(\")\");\n";1143OS << "}\n";1144}1145} else {1146OS << "void Before(const " << Base << "::" << Parser << " &) { Word(\""1147<< Upper << "\"); }\n";1148}1149}1150}11511152// Generate check in the Enter functions for clauses classes.1153static void generateFlangClauseCheckPrototypes(const DirectiveLanguage &DirLang,1154raw_ostream &OS) {11551156IfDefScope Scope("GEN_FLANG_CLAUSE_CHECK_ENTER", OS);11571158OS << "\n";1159for (const Clause Clause : DirLang.getClauses()) {1160OS << "void Enter(const parser::" << DirLang.getFlangClauseBaseClass()1161<< "::" << Clause.getFormattedParserClassName() << " &);\n";1162}1163}11641165// Generate the mapping for clauses between the parser class and the1166// corresponding clause Kind1167static void generateFlangClauseParserKindMap(const DirectiveLanguage &DirLang,1168raw_ostream &OS) {11691170IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_KIND_MAP", OS);11711172StringRef Prefix = DirLang.getClausePrefix();1173std::string Qual = getQualifier(DirLang);11741175OS << "\n";1176for (const Record *R : DirLang.getClauses()) {1177Clause C(R);1178OS << "if constexpr (std::is_same_v<A, parser::"1179<< DirLang.getFlangClauseBaseClass()1180<< "::" << C.getFormattedParserClassName();1181OS << ">)\n";1182OS << " return " << Qual << "Clause::" << getIdentifierName(R, Prefix)1183<< ";\n";1184}11851186OS << "llvm_unreachable(\"Invalid " << DirLang.getName()1187<< " Parser clause\");\n";1188}11891190// Generate the parser for the clauses.1191static void generateFlangClausesParser(const DirectiveLanguage &DirLang,1192raw_ostream &OS) {1193std::vector<const Record *> Clauses = DirLang.getClauses();1194// Sort clauses in the reverse alphabetical order with respect to their1195// names and aliases, so that longer names are tried before shorter ones.1196std::vector<RecordWithSpelling> Names = getSpellings(Clauses);1197llvm::sort(Names, [](const auto &A, const auto &B) {1198return A.second.Name > B.second.Name;1199});1200IfDefScope Scope("GEN_FLANG_CLAUSES_PARSER", OS);1201StringRef Base = DirLang.getFlangClauseBaseClass();12021203unsigned LastIndex = Names.size() - 1;1204OS << "\n";1205OS << "TYPE_PARSER(\n";1206for (auto [Index, RecSp] : llvm::enumerate(Names)) {1207auto [R, S] = RecSp;1208Clause C(R);12091210StringRef FlangClass = C.getFlangClass();1211OS << " \"" << S.Name << "\" >> construct<" << Base << ">(construct<"1212<< Base << "::" << C.getFormattedParserClassName() << ">(";1213if (FlangClass.empty()) {1214OS << "))";1215if (Index != LastIndex)1216OS << " ||";1217OS << "\n";1218continue;1219}12201221if (C.isValueOptional())1222OS << "maybe(";1223OS << "parenthesized(";1224if (C.isValueList())1225OS << "nonemptyList(";12261227if (!C.getPrefix().empty())1228OS << "\"" << C.getPrefix() << ":\" >> ";12291230// The common Flang parser are used directly. Their name is identical to1231// the Flang class with first letter as lowercase. If the Flang class is1232// not a common class, we assume there is a specific Parser<>{} with the1233// Flang class name provided.1234SmallString<128> Scratch;1235StringRef Parser =1236StringSwitch<StringRef>(FlangClass)1237.Case("Name", "name")1238.Case("ScalarIntConstantExpr", "scalarIntConstantExpr")1239.Case("ScalarIntExpr", "scalarIntExpr")1240.Case("ScalarExpr", "scalarExpr")1241.Case("ScalarLogicalExpr", "scalarLogicalExpr")1242.Default(("Parser<" + FlangClass + ">{}").toStringRef(Scratch));1243OS << Parser;1244if (!C.getPrefix().empty() && C.isPrefixOptional())1245OS << " || " << Parser;1246if (C.isValueList()) // close nonemptyList(.1247OS << ")";1248OS << ")"; // close parenthesized(.12491250if (C.isValueOptional()) // close maybe(.1251OS << ")";1252OS << "))";1253if (Index != LastIndex)1254OS << " ||";1255OS << "\n";1256}1257OS << ")\n";1258}12591260// Generate the implementation section for the enumeration in the directive1261// language1262static void emitDirectivesClangImpl(const DirectiveLanguage &DirLang,1263raw_ostream &OS) {1264// Currently we only have work to do for OpenACC, so skip otherwise.1265if (DirLang.getName() != "OpenACC")1266return;12671268generateDirectiveClauseSets(DirLang, Frontend::Clang, OS);1269generateDirectiveClauseMap(DirLang, Frontend::Clang, OS);1270}1271// Generate the implementation section for the enumeration in the directive1272// language1273static void emitDirectivesFlangImpl(const DirectiveLanguage &DirLang,1274raw_ostream &OS) {1275generateDirectiveClauseSets(DirLang, Frontend::Flang, OS);12761277generateDirectiveClauseMap(DirLang, Frontend::Flang, OS);12781279generateFlangClauseParserClass(DirLang, OS);12801281generateFlangClauseParserClassList(DirLang, OS);12821283generateFlangClauseDump(DirLang, OS);12841285generateFlangClauseUnparse(DirLang, OS);12861287generateFlangClauseCheckPrototypes(DirLang, OS);12881289generateFlangClauseParserKindMap(DirLang, OS);12901291generateFlangClausesParser(DirLang, OS);1292}12931294static void generateClauseClassMacro(const DirectiveLanguage &DirLang,1295raw_ostream &OS) {1296// Generate macros style information for legacy code in clang1297IfDefScope Scope("GEN_CLANG_CLAUSE_CLASS", OS);12981299StringRef Prefix = DirLang.getClausePrefix();1300OS << "\n";13011302OS << "#ifndef CLAUSE\n";1303OS << "#define CLAUSE(Enum, Str, Implicit)\n";1304OS << "#endif\n";1305OS << "#ifndef CLAUSE_CLASS\n";1306OS << "#define CLAUSE_CLASS(Enum, Str, Class)\n";1307OS << "#endif\n";1308OS << "#ifndef CLAUSE_NO_CLASS\n";1309OS << "#define CLAUSE_NO_CLASS(Enum, Str)\n";1310OS << "#endif\n";1311OS << "\n";1312OS << "#define __CLAUSE(Name, Class) \\\n";1313OS << " CLAUSE(" << Prefix << "##Name, #Name, /* Implicit */ false) \\\n";1314OS << " CLAUSE_CLASS(" << Prefix << "##Name, #Name, Class)\n";1315OS << "#define __CLAUSE_NO_CLASS(Name) \\\n";1316OS << " CLAUSE(" << Prefix << "##Name, #Name, /* Implicit */ false) \\\n";1317OS << " CLAUSE_NO_CLASS(" << Prefix << "##Name, #Name)\n";1318OS << "#define __IMPLICIT_CLAUSE_CLASS(Name, Str, Class) \\\n";1319OS << " CLAUSE(" << Prefix << "##Name, Str, /* Implicit */ true) \\\n";1320OS << " CLAUSE_CLASS(" << Prefix << "##Name, Str, Class)\n";1321OS << "#define __IMPLICIT_CLAUSE_NO_CLASS(Name, Str) \\\n";1322OS << " CLAUSE(" << Prefix << "##Name, Str, /* Implicit */ true) \\\n";1323OS << " CLAUSE_NO_CLASS(" << Prefix << "##Name, Str)\n";1324OS << "\n";13251326for (const Clause C : DirLang.getClauses()) {1327std::string Name = C.getFormattedName();1328if (C.getClangClass().empty()) { // NO_CLASS1329if (C.isImplicit()) {1330OS << "__IMPLICIT_CLAUSE_NO_CLASS(" << Name << ", \"" << Name1331<< "\")\n";1332} else {1333OS << "__CLAUSE_NO_CLASS(" << Name << ")\n";1334}1335} else { // CLASS1336if (C.isImplicit()) {1337OS << "__IMPLICIT_CLAUSE_CLASS(" << Name << ", \"" << Name << "\", "1338<< C.getClangClass() << ")\n";1339} else {1340OS << "__CLAUSE(" << Name << ", " << C.getClangClass() << ")\n";1341}1342}1343}13441345OS << "\n";1346OS << "#undef __IMPLICIT_CLAUSE_NO_CLASS\n";1347OS << "#undef __IMPLICIT_CLAUSE_CLASS\n";1348OS << "#undef __CLAUSE_NO_CLASS\n";1349OS << "#undef __CLAUSE\n";1350OS << "#undef CLAUSE_NO_CLASS\n";1351OS << "#undef CLAUSE_CLASS\n";1352OS << "#undef CLAUSE\n";1353}13541355// Generate the implemenation for the enumeration in the directive1356// language. This code can be included in library.1357void emitDirectivesBasicImpl(const DirectiveLanguage &DirLang,1358raw_ostream &OS) {1359IfDefScope Scope("GEN_DIRECTIVES_IMPL", OS);13601361StringRef DPrefix = DirLang.getDirectivePrefix();1362StringRef CPrefix = DirLang.getClausePrefix();13631364OS << "\n";1365OS << "#include \"llvm/Frontend/Directive/Spelling.h\"\n";1366OS << "#include \"llvm/Support/ErrorHandling.h\"\n";1367OS << "#include <utility>\n";13681369// getDirectiveKind(StringRef Str)1370generateGetKind(DirLang.getDirectives(), OS, "Directive", DirLang, DPrefix,1371/*ImplicitAsUnknown=*/false);13721373// getDirectiveName(Directive Kind)1374generateGetName(DirLang.getDirectives(), OS, "Directive", DirLang, DPrefix);13751376// getClauseKind(StringRef Str)1377generateGetKind(DirLang.getClauses(), OS, "Clause", DirLang, CPrefix,1378/*ImplicitAsUnknown=*/true);13791380// getClauseName(Clause Kind)1381generateGetName(DirLang.getClauses(), OS, "Clause", DirLang, CPrefix);13821383// <enumClauseValue> get<enumClauseValue>(StringRef Str) ; string -> value1384// StringRef get<enumClauseValue>Name(<enumClauseValue>) ; value -> string1385generateGetClauseVal(DirLang, OS);13861387// isAllowedClauseForDirective(Directive D, Clause C, unsigned Version)1388generateIsAllowedClause(DirLang, OS);13891390// getDirectiveAssociation(Directive D)1391generateGetDirectiveAssociation(DirLang, OS);13921393// getDirectiveCategory(Directive D)1394generateGetDirectiveCategory(DirLang, OS);13951396// getDirectiveLanguages(Directive D)1397generateGetDirectiveLanguages(DirLang, OS);13981399// Leaf table for getLeafConstructs, etc.1400emitLeafTable(DirLang, OS, "LeafConstructTable");1401}14021403// Generate the implemenation section for the enumeration in the directive1404// language.1405static void emitDirectivesImpl(const RecordKeeper &Records, raw_ostream &OS) {1406const auto DirLang = DirectiveLanguage(Records);1407if (DirLang.HasValidityErrors())1408return;14091410emitDirectivesFlangImpl(DirLang, OS);14111412emitDirectivesClangImpl(DirLang, OS);14131414generateClauseClassMacro(DirLang, OS);14151416emitDirectivesBasicImpl(DirLang, OS);1417}14181419static TableGen::Emitter::Opt1420X("gen-directive-decl", emitDirectivesDecl,1421"Generate directive related declaration code (header file)");14221423static TableGen::Emitter::Opt1424Y("gen-directive-impl", emitDirectivesImpl,1425"Generate directive related implementation code");142614271428