15ffd83dbSDimitry Andric //===- DirectiveEmitter.cpp - Directive Language Emitter ------------------===// 25ffd83dbSDimitry Andric // 35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ffd83dbSDimitry Andric // 75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 85ffd83dbSDimitry Andric // 95ffd83dbSDimitry Andric // DirectiveEmitter uses the descriptions of directives and clauses to construct 105ffd83dbSDimitry Andric // common code declarations to be used in Frontends. 115ffd83dbSDimitry Andric // 125ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 135ffd83dbSDimitry Andric 14e8d8bef9SDimitry Andric #include "llvm/TableGen/DirectiveEmitter.h" 15*0fca6ea1SDimitry Andric #include "llvm/ADT/DenseMap.h" 16*0fca6ea1SDimitry Andric #include "llvm/ADT/DenseSet.h" 175ffd83dbSDimitry Andric #include "llvm/ADT/STLExtras.h" 185ffd83dbSDimitry Andric #include "llvm/ADT/SmallVector.h" 195ffd83dbSDimitry Andric #include "llvm/ADT/StringSet.h" 20fcaf7f86SDimitry Andric #include "llvm/ADT/StringSwitch.h" 215ffd83dbSDimitry Andric #include "llvm/TableGen/Error.h" 225ffd83dbSDimitry Andric #include "llvm/TableGen/Record.h" 2306c3fb27SDimitry Andric #include "llvm/TableGen/TableGenBackend.h" 245ffd83dbSDimitry Andric 25*0fca6ea1SDimitry Andric #include <numeric> 26*0fca6ea1SDimitry Andric #include <vector> 27*0fca6ea1SDimitry Andric 285ffd83dbSDimitry Andric using namespace llvm; 295ffd83dbSDimitry Andric 305ffd83dbSDimitry Andric namespace { 315ffd83dbSDimitry Andric // Simple RAII helper for defining ifdef-undef-endif scopes. 325ffd83dbSDimitry Andric class IfDefScope { 335ffd83dbSDimitry Andric public: 345ffd83dbSDimitry Andric IfDefScope(StringRef Name, raw_ostream &OS) : Name(Name), OS(OS) { 355ffd83dbSDimitry Andric OS << "#ifdef " << Name << "\n" 365ffd83dbSDimitry Andric << "#undef " << Name << "\n"; 375ffd83dbSDimitry Andric } 385ffd83dbSDimitry Andric 395ffd83dbSDimitry Andric ~IfDefScope() { OS << "\n#endif // " << Name << "\n\n"; } 405ffd83dbSDimitry Andric 415ffd83dbSDimitry Andric private: 425ffd83dbSDimitry Andric StringRef Name; 435ffd83dbSDimitry Andric raw_ostream &OS; 445ffd83dbSDimitry Andric }; 4506c3fb27SDimitry Andric } // namespace 465ffd83dbSDimitry Andric 47*0fca6ea1SDimitry Andric // Generate enum class. Entries are emitted in the order in which they appear 48*0fca6ea1SDimitry Andric // in the `Records` vector. 4906c3fb27SDimitry Andric static void GenerateEnumClass(const std::vector<Record *> &Records, 5006c3fb27SDimitry Andric raw_ostream &OS, StringRef Enum, StringRef Prefix, 51*0fca6ea1SDimitry Andric const DirectiveLanguage &DirLang, 52*0fca6ea1SDimitry Andric bool ExportEnums) { 535ffd83dbSDimitry Andric OS << "\n"; 545ffd83dbSDimitry Andric OS << "enum class " << Enum << " {\n"; 555ffd83dbSDimitry Andric for (const auto &R : Records) { 56e8d8bef9SDimitry Andric BaseRecord Rec{R}; 57e8d8bef9SDimitry Andric OS << " " << Prefix << Rec.getFormattedName() << ",\n"; 585ffd83dbSDimitry Andric } 595ffd83dbSDimitry Andric OS << "};\n"; 605ffd83dbSDimitry Andric OS << "\n"; 615ffd83dbSDimitry Andric OS << "static constexpr std::size_t " << Enum 625ffd83dbSDimitry Andric << "_enumSize = " << Records.size() << ";\n"; 635ffd83dbSDimitry Andric 645ffd83dbSDimitry Andric // Make the enum values available in the defined namespace. This allows us to 655ffd83dbSDimitry Andric // write something like Enum_X if we have a `using namespace <CppNamespace>`. 665ffd83dbSDimitry Andric // At the same time we do not loose the strong type guarantees of the enum 675ffd83dbSDimitry Andric // class, that is we cannot pass an unsigned as Directive without an explicit 685ffd83dbSDimitry Andric // cast. 69*0fca6ea1SDimitry Andric if (ExportEnums) { 705ffd83dbSDimitry Andric OS << "\n"; 715ffd83dbSDimitry Andric for (const auto &R : Records) { 72e8d8bef9SDimitry Andric BaseRecord Rec{R}; 73e8d8bef9SDimitry Andric OS << "constexpr auto " << Prefix << Rec.getFormattedName() << " = " 74e8d8bef9SDimitry Andric << "llvm::" << DirLang.getCppNamespace() << "::" << Enum 75e8d8bef9SDimitry Andric << "::" << Prefix << Rec.getFormattedName() << ";\n"; 765ffd83dbSDimitry Andric } 775ffd83dbSDimitry Andric } 785ffd83dbSDimitry Andric } 795ffd83dbSDimitry Andric 80e8d8bef9SDimitry Andric // Generate enums for values that clauses can take. 81e8d8bef9SDimitry Andric // Also generate function declarations for get<Enum>Name(StringRef Str). 8206c3fb27SDimitry Andric static void GenerateEnumClauseVal(const std::vector<Record *> &Records, 8306c3fb27SDimitry Andric raw_ostream &OS, 8406c3fb27SDimitry Andric const DirectiveLanguage &DirLang, 85e8d8bef9SDimitry Andric std::string &EnumHelperFuncs) { 86e8d8bef9SDimitry Andric for (const auto &R : Records) { 87e8d8bef9SDimitry Andric Clause C{R}; 88e8d8bef9SDimitry Andric const auto &ClauseVals = C.getClauseVals(); 89e8d8bef9SDimitry Andric if (ClauseVals.size() <= 0) 90e8d8bef9SDimitry Andric continue; 91e8d8bef9SDimitry Andric 92e8d8bef9SDimitry Andric const auto &EnumName = C.getEnumName(); 93e8d8bef9SDimitry Andric if (EnumName.size() == 0) { 94e8d8bef9SDimitry Andric PrintError("enumClauseValue field not set in Clause" + 95e8d8bef9SDimitry Andric C.getFormattedName() + "."); 96e8d8bef9SDimitry Andric return; 97e8d8bef9SDimitry Andric } 98e8d8bef9SDimitry Andric 99e8d8bef9SDimitry Andric OS << "\n"; 100e8d8bef9SDimitry Andric OS << "enum class " << EnumName << " {\n"; 101e8d8bef9SDimitry Andric for (const auto &CV : ClauseVals) { 102e8d8bef9SDimitry Andric ClauseVal CVal{CV}; 103e8d8bef9SDimitry Andric OS << " " << CV->getName() << "=" << CVal.getValue() << ",\n"; 104e8d8bef9SDimitry Andric } 105e8d8bef9SDimitry Andric OS << "};\n"; 106e8d8bef9SDimitry Andric 107e8d8bef9SDimitry Andric if (DirLang.hasMakeEnumAvailableInNamespace()) { 108e8d8bef9SDimitry Andric OS << "\n"; 109e8d8bef9SDimitry Andric for (const auto &CV : ClauseVals) { 110e8d8bef9SDimitry Andric OS << "constexpr auto " << CV->getName() << " = " 111e8d8bef9SDimitry Andric << "llvm::" << DirLang.getCppNamespace() << "::" << EnumName 112e8d8bef9SDimitry Andric << "::" << CV->getName() << ";\n"; 113e8d8bef9SDimitry Andric } 114e8d8bef9SDimitry Andric EnumHelperFuncs += (llvm::Twine(EnumName) + llvm::Twine(" get") + 115e8d8bef9SDimitry Andric llvm::Twine(EnumName) + llvm::Twine("(StringRef);\n")) 116e8d8bef9SDimitry Andric .str(); 117e8d8bef9SDimitry Andric 118e8d8bef9SDimitry Andric EnumHelperFuncs += 119e8d8bef9SDimitry Andric (llvm::Twine("llvm::StringRef get") + llvm::Twine(DirLang.getName()) + 120e8d8bef9SDimitry Andric llvm::Twine(EnumName) + llvm::Twine("Name(") + 121e8d8bef9SDimitry Andric llvm::Twine(EnumName) + llvm::Twine(");\n")) 122e8d8bef9SDimitry Andric .str(); 123e8d8bef9SDimitry Andric } 124e8d8bef9SDimitry Andric } 125e8d8bef9SDimitry Andric } 126e8d8bef9SDimitry Andric 12706c3fb27SDimitry Andric static bool HasDuplicateClauses(const std::vector<Record *> &Clauses, 128e8d8bef9SDimitry Andric const Directive &Directive, 129e8d8bef9SDimitry Andric llvm::StringSet<> &CrtClauses) { 130e8d8bef9SDimitry Andric bool HasError = false; 131e8d8bef9SDimitry Andric for (const auto &C : Clauses) { 132e8d8bef9SDimitry Andric VersionedClause VerClause{C}; 133e8d8bef9SDimitry Andric const auto insRes = CrtClauses.insert(VerClause.getClause().getName()); 134e8d8bef9SDimitry Andric if (!insRes.second) { 135e8d8bef9SDimitry Andric PrintError("Clause " + VerClause.getClause().getRecordName() + 136e8d8bef9SDimitry Andric " already defined on directive " + Directive.getRecordName()); 137e8d8bef9SDimitry Andric HasError = true; 138e8d8bef9SDimitry Andric } 139e8d8bef9SDimitry Andric } 140e8d8bef9SDimitry Andric return HasError; 141e8d8bef9SDimitry Andric } 142e8d8bef9SDimitry Andric 143e8d8bef9SDimitry Andric // Check for duplicate clauses in lists. Clauses cannot appear twice in the 144e8d8bef9SDimitry Andric // three allowed list. Also, since required implies allowed, clauses cannot 145e8d8bef9SDimitry Andric // appear in both the allowedClauses and requiredClauses lists. 14606c3fb27SDimitry Andric static bool 14706c3fb27SDimitry Andric HasDuplicateClausesInDirectives(const std::vector<Record *> &Directives) { 148e8d8bef9SDimitry Andric bool HasDuplicate = false; 149e8d8bef9SDimitry Andric for (const auto &D : Directives) { 150e8d8bef9SDimitry Andric Directive Dir{D}; 151e8d8bef9SDimitry Andric llvm::StringSet<> Clauses; 152e8d8bef9SDimitry Andric // Check for duplicates in the three allowed lists. 153e8d8bef9SDimitry Andric if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) || 154e8d8bef9SDimitry Andric HasDuplicateClauses(Dir.getAllowedOnceClauses(), Dir, Clauses) || 155e8d8bef9SDimitry Andric HasDuplicateClauses(Dir.getAllowedExclusiveClauses(), Dir, Clauses)) { 156e8d8bef9SDimitry Andric HasDuplicate = true; 157e8d8bef9SDimitry Andric } 158e8d8bef9SDimitry Andric // Check for duplicate between allowedClauses and required 159e8d8bef9SDimitry Andric Clauses.clear(); 160e8d8bef9SDimitry Andric if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) || 161e8d8bef9SDimitry Andric HasDuplicateClauses(Dir.getRequiredClauses(), Dir, Clauses)) { 162e8d8bef9SDimitry Andric HasDuplicate = true; 163e8d8bef9SDimitry Andric } 164e8d8bef9SDimitry Andric if (HasDuplicate) 165e8d8bef9SDimitry Andric PrintFatalError("One or more clauses are defined multiple times on" 166e8d8bef9SDimitry Andric " directive " + 167e8d8bef9SDimitry Andric Dir.getRecordName()); 168e8d8bef9SDimitry Andric } 169e8d8bef9SDimitry Andric 170e8d8bef9SDimitry Andric return HasDuplicate; 171e8d8bef9SDimitry Andric } 172e8d8bef9SDimitry Andric 173e8d8bef9SDimitry Andric // Check consitency of records. Return true if an error has been detected. 174e8d8bef9SDimitry Andric // Return false if the records are valid. 175e8d8bef9SDimitry Andric bool DirectiveLanguage::HasValidityErrors() const { 176e8d8bef9SDimitry Andric if (getDirectiveLanguages().size() != 1) { 177e8d8bef9SDimitry Andric PrintFatalError("A single definition of DirectiveLanguage is needed."); 178e8d8bef9SDimitry Andric return true; 179e8d8bef9SDimitry Andric } 180e8d8bef9SDimitry Andric 181e8d8bef9SDimitry Andric return HasDuplicateClausesInDirectives(getDirectives()); 182e8d8bef9SDimitry Andric } 183e8d8bef9SDimitry Andric 184*0fca6ea1SDimitry Andric // Count the maximum number of leaf constituents per construct. 185*0fca6ea1SDimitry Andric static size_t GetMaxLeafCount(const DirectiveLanguage &DirLang) { 186*0fca6ea1SDimitry Andric size_t MaxCount = 0; 187*0fca6ea1SDimitry Andric for (Record *R : DirLang.getDirectives()) { 188*0fca6ea1SDimitry Andric size_t Count = Directive{R}.getLeafConstructs().size(); 189*0fca6ea1SDimitry Andric MaxCount = std::max(MaxCount, Count); 190*0fca6ea1SDimitry Andric } 191*0fca6ea1SDimitry Andric return MaxCount; 192*0fca6ea1SDimitry Andric } 193*0fca6ea1SDimitry Andric 1945ffd83dbSDimitry Andric // Generate the declaration section for the enumeration in the directive 1955ffd83dbSDimitry Andric // language 19606c3fb27SDimitry Andric static void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) { 197e8d8bef9SDimitry Andric const auto DirLang = DirectiveLanguage{Records}; 198e8d8bef9SDimitry Andric if (DirLang.HasValidityErrors()) 1995ffd83dbSDimitry Andric return; 2005ffd83dbSDimitry Andric 201e8d8bef9SDimitry Andric OS << "#ifndef LLVM_" << DirLang.getName() << "_INC\n"; 202e8d8bef9SDimitry Andric OS << "#define LLVM_" << DirLang.getName() << "_INC\n"; 203*0fca6ea1SDimitry Andric OS << "\n#include \"llvm/ADT/ArrayRef.h\"\n"; 2045ffd83dbSDimitry Andric 205e8d8bef9SDimitry Andric if (DirLang.hasEnableBitmaskEnumInNamespace()) 206*0fca6ea1SDimitry Andric OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n"; 2075ffd83dbSDimitry Andric 208*0fca6ea1SDimitry Andric OS << "#include <cstddef>\n"; // for size_t 2095ffd83dbSDimitry Andric OS << "\n"; 2105ffd83dbSDimitry Andric OS << "namespace llvm {\n"; 2115ffd83dbSDimitry Andric OS << "class StringRef;\n"; 2125ffd83dbSDimitry Andric 2135ffd83dbSDimitry Andric // Open namespaces defined in the directive language 2145ffd83dbSDimitry Andric llvm::SmallVector<StringRef, 2> Namespaces; 215e8d8bef9SDimitry Andric llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::"); 2165ffd83dbSDimitry Andric for (auto Ns : Namespaces) 2175ffd83dbSDimitry Andric OS << "namespace " << Ns << " {\n"; 2185ffd83dbSDimitry Andric 219e8d8bef9SDimitry Andric if (DirLang.hasEnableBitmaskEnumInNamespace()) 2205ffd83dbSDimitry Andric OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n"; 2215ffd83dbSDimitry Andric 222*0fca6ea1SDimitry Andric // Emit Directive associations 223*0fca6ea1SDimitry Andric std::vector<Record *> associations; 224*0fca6ea1SDimitry Andric llvm::copy_if( 225*0fca6ea1SDimitry Andric DirLang.getAssociations(), std::back_inserter(associations), 226*0fca6ea1SDimitry Andric // Skip the "special" value 227*0fca6ea1SDimitry Andric [](const Record *Def) { return Def->getName() != "AS_FromLeaves"; }); 228*0fca6ea1SDimitry Andric GenerateEnumClass(associations, OS, "Association", 229*0fca6ea1SDimitry Andric /*Prefix=*/"", DirLang, /*ExportEnums=*/false); 230*0fca6ea1SDimitry Andric 231*0fca6ea1SDimitry Andric GenerateEnumClass(DirLang.getCategories(), OS, "Category", /*Prefix=*/"", 232*0fca6ea1SDimitry Andric DirLang, /*ExportEnums=*/false); 233*0fca6ea1SDimitry Andric 2345ffd83dbSDimitry Andric // Emit Directive enumeration 235e8d8bef9SDimitry Andric GenerateEnumClass(DirLang.getDirectives(), OS, "Directive", 236*0fca6ea1SDimitry Andric DirLang.getDirectivePrefix(), DirLang, 237*0fca6ea1SDimitry Andric DirLang.hasMakeEnumAvailableInNamespace()); 2385ffd83dbSDimitry Andric 2395ffd83dbSDimitry Andric // Emit Clause enumeration 240e8d8bef9SDimitry Andric GenerateEnumClass(DirLang.getClauses(), OS, "Clause", 241*0fca6ea1SDimitry Andric DirLang.getClausePrefix(), DirLang, 242*0fca6ea1SDimitry Andric DirLang.hasMakeEnumAvailableInNamespace()); 243e8d8bef9SDimitry Andric 244e8d8bef9SDimitry Andric // Emit ClauseVal enumeration 245e8d8bef9SDimitry Andric std::string EnumHelperFuncs; 246e8d8bef9SDimitry Andric GenerateEnumClauseVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs); 2475ffd83dbSDimitry Andric 2485ffd83dbSDimitry Andric // Generic function signatures 2495ffd83dbSDimitry Andric OS << "\n"; 2505ffd83dbSDimitry Andric OS << "// Enumeration helper functions\n"; 251e8d8bef9SDimitry Andric OS << "Directive get" << DirLang.getName() 2525ffd83dbSDimitry Andric << "DirectiveKind(llvm::StringRef Str);\n"; 2535ffd83dbSDimitry Andric OS << "\n"; 254e8d8bef9SDimitry Andric OS << "llvm::StringRef get" << DirLang.getName() 2555ffd83dbSDimitry Andric << "DirectiveName(Directive D);\n"; 2565ffd83dbSDimitry Andric OS << "\n"; 257e8d8bef9SDimitry Andric OS << "Clause get" << DirLang.getName() 258e8d8bef9SDimitry Andric << "ClauseKind(llvm::StringRef Str);\n"; 2595ffd83dbSDimitry Andric OS << "\n"; 260e8d8bef9SDimitry Andric OS << "llvm::StringRef get" << DirLang.getName() << "ClauseName(Clause C);\n"; 2615ffd83dbSDimitry Andric OS << "\n"; 2625ffd83dbSDimitry Andric OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p " 2635ffd83dbSDimitry Andric << "Version.\n"; 2645ffd83dbSDimitry Andric OS << "bool isAllowedClauseForDirective(Directive D, " 2655ffd83dbSDimitry Andric << "Clause C, unsigned Version);\n"; 2665ffd83dbSDimitry Andric OS << "\n"; 267*0fca6ea1SDimitry Andric OS << "constexpr std::size_t getMaxLeafCount() { return " 268*0fca6ea1SDimitry Andric << GetMaxLeafCount(DirLang) << "; }\n"; 269*0fca6ea1SDimitry Andric OS << "Association getDirectiveAssociation(Directive D);\n"; 270*0fca6ea1SDimitry Andric OS << "Category getDirectiveCategory(Directive D);\n"; 271e8d8bef9SDimitry Andric if (EnumHelperFuncs.length() > 0) { 272e8d8bef9SDimitry Andric OS << EnumHelperFuncs; 273e8d8bef9SDimitry Andric OS << "\n"; 274e8d8bef9SDimitry Andric } 2755ffd83dbSDimitry Andric 2765ffd83dbSDimitry Andric // Closing namespaces 2775ffd83dbSDimitry Andric for (auto Ns : llvm::reverse(Namespaces)) 2785ffd83dbSDimitry Andric OS << "} // namespace " << Ns << "\n"; 2795ffd83dbSDimitry Andric 2805ffd83dbSDimitry Andric OS << "} // namespace llvm\n"; 2815ffd83dbSDimitry Andric 282e8d8bef9SDimitry Andric OS << "#endif // LLVM_" << DirLang.getName() << "_INC\n"; 2835ffd83dbSDimitry Andric } 2845ffd83dbSDimitry Andric 2855ffd83dbSDimitry Andric // Generate function implementation for get<Enum>Name(StringRef Str) 28606c3fb27SDimitry Andric static void GenerateGetName(const std::vector<Record *> &Records, 28706c3fb27SDimitry Andric raw_ostream &OS, StringRef Enum, 28806c3fb27SDimitry Andric const DirectiveLanguage &DirLang, 289e8d8bef9SDimitry Andric StringRef Prefix) { 2905ffd83dbSDimitry Andric OS << "\n"; 291e8d8bef9SDimitry Andric OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get" 292e8d8bef9SDimitry Andric << DirLang.getName() << Enum << "Name(" << Enum << " Kind) {\n"; 2935ffd83dbSDimitry Andric OS << " switch (Kind) {\n"; 2945ffd83dbSDimitry Andric for (const auto &R : Records) { 295e8d8bef9SDimitry Andric BaseRecord Rec{R}; 296e8d8bef9SDimitry Andric OS << " case " << Prefix << Rec.getFormattedName() << ":\n"; 2975ffd83dbSDimitry Andric OS << " return \""; 298e8d8bef9SDimitry Andric if (Rec.getAlternativeName().empty()) 299e8d8bef9SDimitry Andric OS << Rec.getName(); 3005ffd83dbSDimitry Andric else 301e8d8bef9SDimitry Andric OS << Rec.getAlternativeName(); 3025ffd83dbSDimitry Andric OS << "\";\n"; 3035ffd83dbSDimitry Andric } 3045ffd83dbSDimitry Andric OS << " }\n"; // switch 305e8d8bef9SDimitry Andric OS << " llvm_unreachable(\"Invalid " << DirLang.getName() << " " << Enum 3065ffd83dbSDimitry Andric << " kind\");\n"; 3075ffd83dbSDimitry Andric OS << "}\n"; 3085ffd83dbSDimitry Andric } 3095ffd83dbSDimitry Andric 3105ffd83dbSDimitry Andric // Generate function implementation for get<Enum>Kind(StringRef Str) 31106c3fb27SDimitry Andric static void GenerateGetKind(const std::vector<Record *> &Records, 31206c3fb27SDimitry Andric raw_ostream &OS, StringRef Enum, 31306c3fb27SDimitry Andric const DirectiveLanguage &DirLang, StringRef Prefix, 31406c3fb27SDimitry Andric bool ImplicitAsUnknown) { 3155ffd83dbSDimitry Andric 316e8d8bef9SDimitry Andric auto DefaultIt = llvm::find_if( 317e8d8bef9SDimitry Andric Records, [](Record *R) { return R->getValueAsBit("isDefault") == true; }); 3185ffd83dbSDimitry Andric 3195ffd83dbSDimitry Andric if (DefaultIt == Records.end()) { 320e8d8bef9SDimitry Andric PrintError("At least one " + Enum + " must be defined as default."); 3215ffd83dbSDimitry Andric return; 3225ffd83dbSDimitry Andric } 3235ffd83dbSDimitry Andric 324e8d8bef9SDimitry Andric BaseRecord DefaultRec{(*DefaultIt)}; 3255ffd83dbSDimitry Andric 3265ffd83dbSDimitry Andric OS << "\n"; 327e8d8bef9SDimitry Andric OS << Enum << " llvm::" << DirLang.getCppNamespace() << "::get" 328e8d8bef9SDimitry Andric << DirLang.getName() << Enum << "Kind(llvm::StringRef Str) {\n"; 3295ffd83dbSDimitry Andric OS << " return llvm::StringSwitch<" << Enum << ">(Str)\n"; 3305ffd83dbSDimitry Andric 3315ffd83dbSDimitry Andric for (const auto &R : Records) { 332e8d8bef9SDimitry Andric BaseRecord Rec{R}; 3335ffd83dbSDimitry Andric if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) { 334e8d8bef9SDimitry Andric OS << " .Case(\"" << Rec.getName() << "\"," << Prefix 335e8d8bef9SDimitry Andric << DefaultRec.getFormattedName() << ")\n"; 3365ffd83dbSDimitry Andric } else { 337e8d8bef9SDimitry Andric OS << " .Case(\"" << Rec.getName() << "\"," << Prefix 338e8d8bef9SDimitry Andric << Rec.getFormattedName() << ")\n"; 339e8d8bef9SDimitry Andric } 340e8d8bef9SDimitry Andric } 341e8d8bef9SDimitry Andric OS << " .Default(" << Prefix << DefaultRec.getFormattedName() << ");\n"; 342e8d8bef9SDimitry Andric OS << "}\n"; 343e8d8bef9SDimitry Andric } 344e8d8bef9SDimitry Andric 345e8d8bef9SDimitry Andric // Generate function implementation for get<ClauseVal>Kind(StringRef Str) 34606c3fb27SDimitry Andric static void GenerateGetKindClauseVal(const DirectiveLanguage &DirLang, 347e8d8bef9SDimitry Andric raw_ostream &OS) { 348e8d8bef9SDimitry Andric for (const auto &R : DirLang.getClauses()) { 349e8d8bef9SDimitry Andric Clause C{R}; 350e8d8bef9SDimitry Andric const auto &ClauseVals = C.getClauseVals(); 351e8d8bef9SDimitry Andric if (ClauseVals.size() <= 0) 352e8d8bef9SDimitry Andric continue; 353e8d8bef9SDimitry Andric 354e8d8bef9SDimitry Andric auto DefaultIt = llvm::find_if(ClauseVals, [](Record *CV) { 355e8d8bef9SDimitry Andric return CV->getValueAsBit("isDefault") == true; 356e8d8bef9SDimitry Andric }); 357e8d8bef9SDimitry Andric 358e8d8bef9SDimitry Andric if (DefaultIt == ClauseVals.end()) { 359e8d8bef9SDimitry Andric PrintError("At least one val in Clause " + C.getFormattedName() + 360e8d8bef9SDimitry Andric " must be defined as default."); 361e8d8bef9SDimitry Andric return; 362e8d8bef9SDimitry Andric } 363e8d8bef9SDimitry Andric const auto DefaultName = (*DefaultIt)->getName(); 364e8d8bef9SDimitry Andric 365e8d8bef9SDimitry Andric const auto &EnumName = C.getEnumName(); 366e8d8bef9SDimitry Andric if (EnumName.size() == 0) { 367e8d8bef9SDimitry Andric PrintError("enumClauseValue field not set in Clause" + 368e8d8bef9SDimitry Andric C.getFormattedName() + "."); 369e8d8bef9SDimitry Andric return; 370e8d8bef9SDimitry Andric } 371e8d8bef9SDimitry Andric 372e8d8bef9SDimitry Andric OS << "\n"; 373e8d8bef9SDimitry Andric OS << EnumName << " llvm::" << DirLang.getCppNamespace() << "::get" 374e8d8bef9SDimitry Andric << EnumName << "(llvm::StringRef Str) {\n"; 375e8d8bef9SDimitry Andric OS << " return llvm::StringSwitch<" << EnumName << ">(Str)\n"; 376e8d8bef9SDimitry Andric for (const auto &CV : ClauseVals) { 377e8d8bef9SDimitry Andric ClauseVal CVal{CV}; 378e8d8bef9SDimitry Andric OS << " .Case(\"" << CVal.getFormattedName() << "\"," << CV->getName() 3795ffd83dbSDimitry Andric << ")\n"; 3805ffd83dbSDimitry Andric } 381e8d8bef9SDimitry Andric OS << " .Default(" << DefaultName << ");\n"; 3825ffd83dbSDimitry Andric OS << "}\n"; 383e8d8bef9SDimitry Andric 384e8d8bef9SDimitry Andric OS << "\n"; 385e8d8bef9SDimitry Andric OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get" 386e8d8bef9SDimitry Andric << DirLang.getName() << EnumName 387e8d8bef9SDimitry Andric << "Name(llvm::" << DirLang.getCppNamespace() << "::" << EnumName 388e8d8bef9SDimitry Andric << " x) {\n"; 389e8d8bef9SDimitry Andric OS << " switch (x) {\n"; 390e8d8bef9SDimitry Andric for (const auto &CV : ClauseVals) { 391e8d8bef9SDimitry Andric ClauseVal CVal{CV}; 392e8d8bef9SDimitry Andric OS << " case " << CV->getName() << ":\n"; 393e8d8bef9SDimitry Andric OS << " return \"" << CVal.getFormattedName() << "\";\n"; 394e8d8bef9SDimitry Andric } 395e8d8bef9SDimitry Andric OS << " }\n"; // switch 396e8d8bef9SDimitry Andric OS << " llvm_unreachable(\"Invalid " << DirLang.getName() << " " 397e8d8bef9SDimitry Andric << EnumName << " kind\");\n"; 398e8d8bef9SDimitry Andric OS << "}\n"; 399e8d8bef9SDimitry Andric } 4005ffd83dbSDimitry Andric } 4015ffd83dbSDimitry Andric 40206c3fb27SDimitry Andric static void 40306c3fb27SDimitry Andric GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses, 4045ffd83dbSDimitry Andric raw_ostream &OS, StringRef DirectiveName, 405e8d8bef9SDimitry Andric const DirectiveLanguage &DirLang, 4065ffd83dbSDimitry Andric llvm::StringSet<> &Cases) { 4075ffd83dbSDimitry Andric for (const auto &C : Clauses) { 408e8d8bef9SDimitry Andric VersionedClause VerClause{C}; 4095ffd83dbSDimitry Andric 410e8d8bef9SDimitry Andric const auto ClauseFormattedName = VerClause.getClause().getFormattedName(); 411e8d8bef9SDimitry Andric 41281ad6265SDimitry Andric if (Cases.insert(ClauseFormattedName).second) { 413e8d8bef9SDimitry Andric OS << " case " << DirLang.getClausePrefix() << ClauseFormattedName 414e8d8bef9SDimitry Andric << ":\n"; 415e8d8bef9SDimitry Andric OS << " return " << VerClause.getMinVersion() 416e8d8bef9SDimitry Andric << " <= Version && " << VerClause.getMaxVersion() << " >= Version;\n"; 4175ffd83dbSDimitry Andric } 4185ffd83dbSDimitry Andric } 4195ffd83dbSDimitry Andric } 4205ffd83dbSDimitry Andric 421*0fca6ea1SDimitry Andric static std::string GetDirectiveName(const DirectiveLanguage &DirLang, 422*0fca6ea1SDimitry Andric const Record *Rec) { 423*0fca6ea1SDimitry Andric Directive Dir{Rec}; 424*0fca6ea1SDimitry Andric return (llvm::Twine("llvm::") + DirLang.getCppNamespace() + 425*0fca6ea1SDimitry Andric "::" + DirLang.getDirectivePrefix() + Dir.getFormattedName()) 426*0fca6ea1SDimitry Andric .str(); 427*0fca6ea1SDimitry Andric } 428*0fca6ea1SDimitry Andric 429*0fca6ea1SDimitry Andric static std::string GetDirectiveType(const DirectiveLanguage &DirLang) { 430*0fca6ea1SDimitry Andric return (llvm::Twine("llvm::") + DirLang.getCppNamespace() + "::Directive") 431*0fca6ea1SDimitry Andric .str(); 432*0fca6ea1SDimitry Andric } 433*0fca6ea1SDimitry Andric 4345ffd83dbSDimitry Andric // Generate the isAllowedClauseForDirective function implementation. 43506c3fb27SDimitry Andric static void GenerateIsAllowedClause(const DirectiveLanguage &DirLang, 436e8d8bef9SDimitry Andric raw_ostream &OS) { 4375ffd83dbSDimitry Andric OS << "\n"; 438e8d8bef9SDimitry Andric OS << "bool llvm::" << DirLang.getCppNamespace() 439e8d8bef9SDimitry Andric << "::isAllowedClauseForDirective(" 4405ffd83dbSDimitry Andric << "Directive D, Clause C, unsigned Version) {\n"; 441e8d8bef9SDimitry Andric OS << " assert(unsigned(D) <= llvm::" << DirLang.getCppNamespace() 4425ffd83dbSDimitry Andric << "::Directive_enumSize);\n"; 443e8d8bef9SDimitry Andric OS << " assert(unsigned(C) <= llvm::" << DirLang.getCppNamespace() 4445ffd83dbSDimitry Andric << "::Clause_enumSize);\n"; 4455ffd83dbSDimitry Andric 4465ffd83dbSDimitry Andric OS << " switch (D) {\n"; 4475ffd83dbSDimitry Andric 448e8d8bef9SDimitry Andric for (const auto &D : DirLang.getDirectives()) { 449e8d8bef9SDimitry Andric Directive Dir{D}; 4505ffd83dbSDimitry Andric 451e8d8bef9SDimitry Andric OS << " case " << DirLang.getDirectivePrefix() << Dir.getFormattedName() 4525ffd83dbSDimitry Andric << ":\n"; 453e8d8bef9SDimitry Andric if (Dir.getAllowedClauses().size() == 0 && 454e8d8bef9SDimitry Andric Dir.getAllowedOnceClauses().size() == 0 && 455e8d8bef9SDimitry Andric Dir.getAllowedExclusiveClauses().size() == 0 && 456e8d8bef9SDimitry Andric Dir.getRequiredClauses().size() == 0) { 4575ffd83dbSDimitry Andric OS << " return false;\n"; 4585ffd83dbSDimitry Andric } else { 4595ffd83dbSDimitry Andric OS << " switch (C) {\n"; 4605ffd83dbSDimitry Andric 4615ffd83dbSDimitry Andric llvm::StringSet<> Cases; 4625ffd83dbSDimitry Andric 463e8d8bef9SDimitry Andric GenerateCaseForVersionedClauses(Dir.getAllowedClauses(), OS, 464e8d8bef9SDimitry Andric Dir.getName(), DirLang, Cases); 4655ffd83dbSDimitry Andric 466e8d8bef9SDimitry Andric GenerateCaseForVersionedClauses(Dir.getAllowedOnceClauses(), OS, 467e8d8bef9SDimitry Andric Dir.getName(), DirLang, Cases); 4685ffd83dbSDimitry Andric 469e8d8bef9SDimitry Andric GenerateCaseForVersionedClauses(Dir.getAllowedExclusiveClauses(), OS, 470e8d8bef9SDimitry Andric Dir.getName(), DirLang, Cases); 4715ffd83dbSDimitry Andric 472e8d8bef9SDimitry Andric GenerateCaseForVersionedClauses(Dir.getRequiredClauses(), OS, 473e8d8bef9SDimitry Andric Dir.getName(), DirLang, Cases); 4745ffd83dbSDimitry Andric 4755ffd83dbSDimitry Andric OS << " default:\n"; 4765ffd83dbSDimitry Andric OS << " return false;\n"; 4775ffd83dbSDimitry Andric OS << " }\n"; // End of clauses switch 4785ffd83dbSDimitry Andric } 4795ffd83dbSDimitry Andric OS << " break;\n"; 4805ffd83dbSDimitry Andric } 4815ffd83dbSDimitry Andric 4825ffd83dbSDimitry Andric OS << " }\n"; // End of directives switch 483e8d8bef9SDimitry Andric OS << " llvm_unreachable(\"Invalid " << DirLang.getName() 4845ffd83dbSDimitry Andric << " Directive kind\");\n"; 4855ffd83dbSDimitry Andric OS << "}\n"; // End of function isAllowedClauseForDirective 4865ffd83dbSDimitry Andric } 4875ffd83dbSDimitry Andric 488*0fca6ea1SDimitry Andric static void EmitLeafTable(const DirectiveLanguage &DirLang, raw_ostream &OS, 489*0fca6ea1SDimitry Andric StringRef TableName) { 490*0fca6ea1SDimitry Andric // The leaf constructs are emitted in a form of a 2D table, where each 491*0fca6ea1SDimitry Andric // row corresponds to a directive (and there is a row for each directive). 492*0fca6ea1SDimitry Andric // 493*0fca6ea1SDimitry Andric // Each row consists of 494*0fca6ea1SDimitry Andric // - the id of the directive itself, 495*0fca6ea1SDimitry Andric // - number of leaf constructs that will follow (0 for leafs), 496*0fca6ea1SDimitry Andric // - ids of the leaf constructs (none if the directive is itself a leaf). 497*0fca6ea1SDimitry Andric // The total number of these entries is at most MaxLeafCount+2. If this 498*0fca6ea1SDimitry Andric // number is less than that, it is padded to occupy exactly MaxLeafCount+2 499*0fca6ea1SDimitry Andric // entries in memory. 500*0fca6ea1SDimitry Andric // 501*0fca6ea1SDimitry Andric // The rows are stored in the table in the lexicographical order. This 502*0fca6ea1SDimitry Andric // is intended to enable binary search when mapping a sequence of leafs 503*0fca6ea1SDimitry Andric // back to the compound directive. 504*0fca6ea1SDimitry Andric // The consequence of that is that in order to find a row corresponding 505*0fca6ea1SDimitry Andric // to the given directive, we'd need to scan the first element of each 506*0fca6ea1SDimitry Andric // row. To avoid this, an auxiliary ordering table is created, such that 507*0fca6ea1SDimitry Andric // row for Dir_A = table[auxiliary[Dir_A]]. 508*0fca6ea1SDimitry Andric 509*0fca6ea1SDimitry Andric std::vector<Record *> Directives = DirLang.getDirectives(); 510*0fca6ea1SDimitry Andric DenseMap<Record *, int> DirId; // Record * -> llvm::omp::Directive 511*0fca6ea1SDimitry Andric 512*0fca6ea1SDimitry Andric for (auto [Idx, Rec] : llvm::enumerate(Directives)) 513*0fca6ea1SDimitry Andric DirId.insert(std::make_pair(Rec, Idx)); 514*0fca6ea1SDimitry Andric 515*0fca6ea1SDimitry Andric using LeafList = std::vector<int>; 516*0fca6ea1SDimitry Andric int MaxLeafCount = GetMaxLeafCount(DirLang); 517*0fca6ea1SDimitry Andric 518*0fca6ea1SDimitry Andric // The initial leaf table, rows order is same as directive order. 519*0fca6ea1SDimitry Andric std::vector<LeafList> LeafTable(Directives.size()); 520*0fca6ea1SDimitry Andric for (auto [Idx, Rec] : llvm::enumerate(Directives)) { 521*0fca6ea1SDimitry Andric Directive Dir{Rec}; 522*0fca6ea1SDimitry Andric std::vector<Record *> Leaves = Dir.getLeafConstructs(); 523*0fca6ea1SDimitry Andric 524*0fca6ea1SDimitry Andric auto &List = LeafTable[Idx]; 525*0fca6ea1SDimitry Andric List.resize(MaxLeafCount + 2); 526*0fca6ea1SDimitry Andric List[0] = Idx; // The id of the directive itself. 527*0fca6ea1SDimitry Andric List[1] = Leaves.size(); // The number of leaves to follow. 528*0fca6ea1SDimitry Andric 529*0fca6ea1SDimitry Andric for (int I = 0; I != MaxLeafCount; ++I) 530*0fca6ea1SDimitry Andric List[I + 2] = 531*0fca6ea1SDimitry Andric static_cast<size_t>(I) < Leaves.size() ? DirId.at(Leaves[I]) : -1; 532*0fca6ea1SDimitry Andric } 533*0fca6ea1SDimitry Andric 534*0fca6ea1SDimitry Andric // Some Fortran directives are delimited, i.e. they have the form of 535*0fca6ea1SDimitry Andric // "directive"---"end directive". If "directive" is a compound construct, 536*0fca6ea1SDimitry Andric // then the set of leaf constituents will be nonempty and the same for 537*0fca6ea1SDimitry Andric // both directives. Given this set of leafs, looking up the corresponding 538*0fca6ea1SDimitry Andric // compound directive should return "directive", and not "end directive". 539*0fca6ea1SDimitry Andric // To avoid this problem, gather all "end directives" at the end of the 540*0fca6ea1SDimitry Andric // leaf table, and only do the search on the initial segment of the table 541*0fca6ea1SDimitry Andric // that excludes the "end directives". 542*0fca6ea1SDimitry Andric // It's safe to find all directives whose names begin with "end ". The 543*0fca6ea1SDimitry Andric // problem only exists for compound directives, like "end do simd". 544*0fca6ea1SDimitry Andric // All existing directives with names starting with "end " are either 545*0fca6ea1SDimitry Andric // "end directives" for an existing "directive", or leaf directives 546*0fca6ea1SDimitry Andric // (such as "end declare target"). 547*0fca6ea1SDimitry Andric DenseSet<int> EndDirectives; 548*0fca6ea1SDimitry Andric for (auto [Rec, Id] : DirId) { 549*0fca6ea1SDimitry Andric if (Directive{Rec}.getName().starts_with_insensitive("end ")) 550*0fca6ea1SDimitry Andric EndDirectives.insert(Id); 551*0fca6ea1SDimitry Andric } 552*0fca6ea1SDimitry Andric 553*0fca6ea1SDimitry Andric // Avoid sorting the vector<vector> array, instead sort an index array. 554*0fca6ea1SDimitry Andric // It will also be useful later to create the auxiliary indexing array. 555*0fca6ea1SDimitry Andric std::vector<int> Ordering(Directives.size()); 556*0fca6ea1SDimitry Andric std::iota(Ordering.begin(), Ordering.end(), 0); 557*0fca6ea1SDimitry Andric 558*0fca6ea1SDimitry Andric llvm::sort(Ordering, [&](int A, int B) { 559*0fca6ea1SDimitry Andric auto &LeavesA = LeafTable[A]; 560*0fca6ea1SDimitry Andric auto &LeavesB = LeafTable[B]; 561*0fca6ea1SDimitry Andric int DirA = LeavesA[0], DirB = LeavesB[0]; 562*0fca6ea1SDimitry Andric // First of all, end directives compare greater than non-end directives. 563*0fca6ea1SDimitry Andric int IsEndA = EndDirectives.count(DirA), IsEndB = EndDirectives.count(DirB); 564*0fca6ea1SDimitry Andric if (IsEndA != IsEndB) 565*0fca6ea1SDimitry Andric return IsEndA < IsEndB; 566*0fca6ea1SDimitry Andric if (LeavesA[1] == 0 && LeavesB[1] == 0) 567*0fca6ea1SDimitry Andric return DirA < DirB; 568*0fca6ea1SDimitry Andric return std::lexicographical_compare(&LeavesA[2], &LeavesA[2] + LeavesA[1], 569*0fca6ea1SDimitry Andric &LeavesB[2], &LeavesB[2] + LeavesB[1]); 570*0fca6ea1SDimitry Andric }); 571*0fca6ea1SDimitry Andric 572*0fca6ea1SDimitry Andric // Emit the table 573*0fca6ea1SDimitry Andric 574*0fca6ea1SDimitry Andric // The directives are emitted into a scoped enum, for which the underlying 575*0fca6ea1SDimitry Andric // type is `int` (by default). The code above uses `int` to store directive 576*0fca6ea1SDimitry Andric // ids, so make sure that we catch it when something changes in the 577*0fca6ea1SDimitry Andric // underlying type. 578*0fca6ea1SDimitry Andric std::string DirectiveType = GetDirectiveType(DirLang); 579*0fca6ea1SDimitry Andric OS << "\nstatic_assert(sizeof(" << DirectiveType << ") == sizeof(int));\n"; 580*0fca6ea1SDimitry Andric 581*0fca6ea1SDimitry Andric OS << "[[maybe_unused]] static const " << DirectiveType << ' ' << TableName 582*0fca6ea1SDimitry Andric << "[][" << MaxLeafCount + 2 << "] = {\n"; 583*0fca6ea1SDimitry Andric for (size_t I = 0, E = Directives.size(); I != E; ++I) { 584*0fca6ea1SDimitry Andric auto &Leaves = LeafTable[Ordering[I]]; 585*0fca6ea1SDimitry Andric OS << " {" << GetDirectiveName(DirLang, Directives[Leaves[0]]); 586*0fca6ea1SDimitry Andric OS << ", static_cast<" << DirectiveType << ">(" << Leaves[1] << "),"; 587*0fca6ea1SDimitry Andric for (size_t I = 2, E = Leaves.size(); I != E; ++I) { 588*0fca6ea1SDimitry Andric int Idx = Leaves[I]; 589*0fca6ea1SDimitry Andric if (Idx >= 0) 590*0fca6ea1SDimitry Andric OS << ' ' << GetDirectiveName(DirLang, Directives[Leaves[I]]) << ','; 591*0fca6ea1SDimitry Andric else 592*0fca6ea1SDimitry Andric OS << " static_cast<" << DirectiveType << ">(-1),"; 593*0fca6ea1SDimitry Andric } 594*0fca6ea1SDimitry Andric OS << "},\n"; 595*0fca6ea1SDimitry Andric } 596*0fca6ea1SDimitry Andric OS << "};\n\n"; 597*0fca6ea1SDimitry Andric 598*0fca6ea1SDimitry Andric // Emit a marker where the first "end directive" is. 599*0fca6ea1SDimitry Andric auto FirstE = llvm::find_if(Ordering, [&](int RowIdx) { 600*0fca6ea1SDimitry Andric return EndDirectives.count(LeafTable[RowIdx][0]); 601*0fca6ea1SDimitry Andric }); 602*0fca6ea1SDimitry Andric OS << "[[maybe_unused]] static auto " << TableName 603*0fca6ea1SDimitry Andric << "EndDirective = " << TableName << " + " 604*0fca6ea1SDimitry Andric << std::distance(Ordering.begin(), FirstE) << ";\n\n"; 605*0fca6ea1SDimitry Andric 606*0fca6ea1SDimitry Andric // Emit the auxiliary index table: it's the inverse of the `Ordering` 607*0fca6ea1SDimitry Andric // table above. 608*0fca6ea1SDimitry Andric OS << "[[maybe_unused]] static const int " << TableName << "Ordering[] = {\n"; 609*0fca6ea1SDimitry Andric OS << " "; 610*0fca6ea1SDimitry Andric std::vector<int> Reverse(Ordering.size()); 611*0fca6ea1SDimitry Andric for (int I = 0, E = Ordering.size(); I != E; ++I) 612*0fca6ea1SDimitry Andric Reverse[Ordering[I]] = I; 613*0fca6ea1SDimitry Andric for (int Idx : Reverse) 614*0fca6ea1SDimitry Andric OS << ' ' << Idx << ','; 615*0fca6ea1SDimitry Andric OS << "\n};\n"; 616*0fca6ea1SDimitry Andric } 617*0fca6ea1SDimitry Andric 618*0fca6ea1SDimitry Andric static void GenerateGetDirectiveAssociation(const DirectiveLanguage &DirLang, 619*0fca6ea1SDimitry Andric raw_ostream &OS) { 620*0fca6ea1SDimitry Andric enum struct Association { 621*0fca6ea1SDimitry Andric None = 0, // None should be the smallest value. 622*0fca6ea1SDimitry Andric Block, // The values of the rest don't matter. 623*0fca6ea1SDimitry Andric Declaration, 624*0fca6ea1SDimitry Andric Delimited, 625*0fca6ea1SDimitry Andric Loop, 626*0fca6ea1SDimitry Andric Separating, 627*0fca6ea1SDimitry Andric FromLeaves, 628*0fca6ea1SDimitry Andric Invalid, 629*0fca6ea1SDimitry Andric }; 630*0fca6ea1SDimitry Andric 631*0fca6ea1SDimitry Andric std::vector<Record *> associations = DirLang.getAssociations(); 632*0fca6ea1SDimitry Andric 633*0fca6ea1SDimitry Andric auto getAssocValue = [](StringRef name) -> Association { 634*0fca6ea1SDimitry Andric return StringSwitch<Association>(name) 635*0fca6ea1SDimitry Andric .Case("AS_Block", Association::Block) 636*0fca6ea1SDimitry Andric .Case("AS_Declaration", Association::Declaration) 637*0fca6ea1SDimitry Andric .Case("AS_Delimited", Association::Delimited) 638*0fca6ea1SDimitry Andric .Case("AS_Loop", Association::Loop) 639*0fca6ea1SDimitry Andric .Case("AS_None", Association::None) 640*0fca6ea1SDimitry Andric .Case("AS_Separating", Association::Separating) 641*0fca6ea1SDimitry Andric .Case("AS_FromLeaves", Association::FromLeaves) 642*0fca6ea1SDimitry Andric .Default(Association::Invalid); 643*0fca6ea1SDimitry Andric }; 644*0fca6ea1SDimitry Andric 645*0fca6ea1SDimitry Andric auto getAssocName = [&](Association A) -> StringRef { 646*0fca6ea1SDimitry Andric if (A != Association::Invalid && A != Association::FromLeaves) { 647*0fca6ea1SDimitry Andric auto F = llvm::find_if(associations, [&](const Record *R) { 648*0fca6ea1SDimitry Andric return getAssocValue(R->getName()) == A; 649*0fca6ea1SDimitry Andric }); 650*0fca6ea1SDimitry Andric if (F != associations.end()) 651*0fca6ea1SDimitry Andric return (*F)->getValueAsString("name"); // enum name 652*0fca6ea1SDimitry Andric } 653*0fca6ea1SDimitry Andric llvm_unreachable("Unexpected association value"); 654*0fca6ea1SDimitry Andric }; 655*0fca6ea1SDimitry Andric 656*0fca6ea1SDimitry Andric auto errorPrefixFor = [&](Directive D) -> std::string { 657*0fca6ea1SDimitry Andric return (Twine("Directive '") + D.getName() + "' in namespace '" + 658*0fca6ea1SDimitry Andric DirLang.getCppNamespace() + "' ") 659*0fca6ea1SDimitry Andric .str(); 660*0fca6ea1SDimitry Andric }; 661*0fca6ea1SDimitry Andric 662*0fca6ea1SDimitry Andric auto reduce = [&](Association A, Association B) -> Association { 663*0fca6ea1SDimitry Andric if (A > B) 664*0fca6ea1SDimitry Andric std::swap(A, B); 665*0fca6ea1SDimitry Andric 666*0fca6ea1SDimitry Andric // Calculate the result using the following rules: 667*0fca6ea1SDimitry Andric // x + x = x 668*0fca6ea1SDimitry Andric // AS_None + x = x 669*0fca6ea1SDimitry Andric // AS_Block + AS_Loop = AS_Loop 670*0fca6ea1SDimitry Andric if (A == Association::None || A == B) 671*0fca6ea1SDimitry Andric return B; 672*0fca6ea1SDimitry Andric if (A == Association::Block && B == Association::Loop) 673*0fca6ea1SDimitry Andric return B; 674*0fca6ea1SDimitry Andric if (A == Association::Loop && B == Association::Block) 675*0fca6ea1SDimitry Andric return A; 676*0fca6ea1SDimitry Andric return Association::Invalid; 677*0fca6ea1SDimitry Andric }; 678*0fca6ea1SDimitry Andric 679*0fca6ea1SDimitry Andric llvm::DenseMap<const Record *, Association> AsMap; 680*0fca6ea1SDimitry Andric 681*0fca6ea1SDimitry Andric auto compAssocImpl = [&](const Record *R, auto &&Self) -> Association { 682*0fca6ea1SDimitry Andric if (auto F = AsMap.find(R); F != AsMap.end()) 683*0fca6ea1SDimitry Andric return F->second; 684*0fca6ea1SDimitry Andric 685*0fca6ea1SDimitry Andric Directive D{R}; 686*0fca6ea1SDimitry Andric Association AS = getAssocValue(D.getAssociation()->getName()); 687*0fca6ea1SDimitry Andric if (AS == Association::Invalid) { 688*0fca6ea1SDimitry Andric PrintFatalError(errorPrefixFor(D) + 689*0fca6ea1SDimitry Andric "has an unrecognized value for association: '" + 690*0fca6ea1SDimitry Andric D.getAssociation()->getName() + "'"); 691*0fca6ea1SDimitry Andric } 692*0fca6ea1SDimitry Andric if (AS != Association::FromLeaves) { 693*0fca6ea1SDimitry Andric AsMap.insert(std::make_pair(R, AS)); 694*0fca6ea1SDimitry Andric return AS; 695*0fca6ea1SDimitry Andric } 696*0fca6ea1SDimitry Andric // Compute the association from leaf constructs. 697*0fca6ea1SDimitry Andric std::vector<Record *> leaves = D.getLeafConstructs(); 698*0fca6ea1SDimitry Andric if (leaves.empty()) { 699*0fca6ea1SDimitry Andric llvm::errs() << D.getName() << '\n'; 700*0fca6ea1SDimitry Andric PrintFatalError(errorPrefixFor(D) + 701*0fca6ea1SDimitry Andric "requests association to be computed from leaves, " 702*0fca6ea1SDimitry Andric "but it has no leaves"); 703*0fca6ea1SDimitry Andric } 704*0fca6ea1SDimitry Andric 705*0fca6ea1SDimitry Andric Association Result = Self(leaves[0], Self); 706*0fca6ea1SDimitry Andric for (int I = 1, E = leaves.size(); I < E; ++I) { 707*0fca6ea1SDimitry Andric Association A = Self(leaves[I], Self); 708*0fca6ea1SDimitry Andric Association R = reduce(Result, A); 709*0fca6ea1SDimitry Andric if (R == Association::Invalid) { 710*0fca6ea1SDimitry Andric PrintFatalError(errorPrefixFor(D) + 711*0fca6ea1SDimitry Andric "has leaves with incompatible association values: " + 712*0fca6ea1SDimitry Andric getAssocName(A) + " and " + getAssocName(R)); 713*0fca6ea1SDimitry Andric } 714*0fca6ea1SDimitry Andric Result = R; 715*0fca6ea1SDimitry Andric } 716*0fca6ea1SDimitry Andric 717*0fca6ea1SDimitry Andric assert(Result != Association::Invalid); 718*0fca6ea1SDimitry Andric assert(Result != Association::FromLeaves); 719*0fca6ea1SDimitry Andric AsMap.insert(std::make_pair(R, Result)); 720*0fca6ea1SDimitry Andric return Result; 721*0fca6ea1SDimitry Andric }; 722*0fca6ea1SDimitry Andric 723*0fca6ea1SDimitry Andric for (Record *R : DirLang.getDirectives()) 724*0fca6ea1SDimitry Andric compAssocImpl(R, compAssocImpl); // Updates AsMap. 725*0fca6ea1SDimitry Andric 726*0fca6ea1SDimitry Andric OS << '\n'; 727*0fca6ea1SDimitry Andric 728*0fca6ea1SDimitry Andric auto getQualifiedName = [&](StringRef Formatted) -> std::string { 729*0fca6ea1SDimitry Andric return (llvm::Twine("llvm::") + DirLang.getCppNamespace() + 730*0fca6ea1SDimitry Andric "::Directive::" + DirLang.getDirectivePrefix() + Formatted) 731*0fca6ea1SDimitry Andric .str(); 732*0fca6ea1SDimitry Andric }; 733*0fca6ea1SDimitry Andric 734*0fca6ea1SDimitry Andric std::string DirectiveTypeName = 735*0fca6ea1SDimitry Andric std::string("llvm::") + DirLang.getCppNamespace().str() + "::Directive"; 736*0fca6ea1SDimitry Andric std::string AssociationTypeName = 737*0fca6ea1SDimitry Andric std::string("llvm::") + DirLang.getCppNamespace().str() + "::Association"; 738*0fca6ea1SDimitry Andric 739*0fca6ea1SDimitry Andric OS << AssociationTypeName << " llvm::" << DirLang.getCppNamespace() 740*0fca6ea1SDimitry Andric << "::getDirectiveAssociation(" << DirectiveTypeName << " Dir) {\n"; 741*0fca6ea1SDimitry Andric OS << " switch (Dir) {\n"; 742*0fca6ea1SDimitry Andric for (Record *R : DirLang.getDirectives()) { 743*0fca6ea1SDimitry Andric if (auto F = AsMap.find(R); F != AsMap.end()) { 744*0fca6ea1SDimitry Andric Directive Dir{R}; 745*0fca6ea1SDimitry Andric OS << " case " << getQualifiedName(Dir.getFormattedName()) << ":\n"; 746*0fca6ea1SDimitry Andric OS << " return " << AssociationTypeName 747*0fca6ea1SDimitry Andric << "::" << getAssocName(F->second) << ";\n"; 748*0fca6ea1SDimitry Andric } 749*0fca6ea1SDimitry Andric } 750*0fca6ea1SDimitry Andric OS << " } // switch (Dir)\n"; 751*0fca6ea1SDimitry Andric OS << " llvm_unreachable(\"Unexpected directive\");\n"; 752*0fca6ea1SDimitry Andric OS << "}\n"; 753*0fca6ea1SDimitry Andric } 754*0fca6ea1SDimitry Andric 755*0fca6ea1SDimitry Andric static void GenerateGetDirectiveCategory(const DirectiveLanguage &DirLang, 756*0fca6ea1SDimitry Andric raw_ostream &OS) { 757*0fca6ea1SDimitry Andric std::string LangNamespace = "llvm::" + DirLang.getCppNamespace().str(); 758*0fca6ea1SDimitry Andric std::string CategoryTypeName = LangNamespace + "::Category"; 759*0fca6ea1SDimitry Andric std::string CategoryNamespace = CategoryTypeName + "::"; 760*0fca6ea1SDimitry Andric 761*0fca6ea1SDimitry Andric OS << '\n'; 762*0fca6ea1SDimitry Andric OS << CategoryTypeName << ' ' << LangNamespace << "::getDirectiveCategory(" 763*0fca6ea1SDimitry Andric << GetDirectiveType(DirLang) << " Dir) {\n"; 764*0fca6ea1SDimitry Andric OS << " switch (Dir) {\n"; 765*0fca6ea1SDimitry Andric 766*0fca6ea1SDimitry Andric for (Record *R : DirLang.getDirectives()) { 767*0fca6ea1SDimitry Andric Directive D{R}; 768*0fca6ea1SDimitry Andric OS << " case " << GetDirectiveName(DirLang, R) << ":\n"; 769*0fca6ea1SDimitry Andric OS << " return " << CategoryNamespace 770*0fca6ea1SDimitry Andric << D.getCategory()->getValueAsString("name") << ";\n"; 771*0fca6ea1SDimitry Andric } 772*0fca6ea1SDimitry Andric OS << " } // switch (Dir)\n"; 773*0fca6ea1SDimitry Andric OS << " llvm_unreachable(\"Unexpected directive\");\n"; 774*0fca6ea1SDimitry Andric OS << "}\n"; 775*0fca6ea1SDimitry Andric } 776*0fca6ea1SDimitry Andric 7775ffd83dbSDimitry Andric // Generate a simple enum set with the give clauses. 77806c3fb27SDimitry Andric static void GenerateClauseSet(const std::vector<Record *> &Clauses, 77906c3fb27SDimitry Andric raw_ostream &OS, StringRef ClauseSetPrefix, 78006c3fb27SDimitry Andric Directive &Dir, 781e8d8bef9SDimitry Andric const DirectiveLanguage &DirLang) { 7825ffd83dbSDimitry Andric 7835ffd83dbSDimitry Andric OS << "\n"; 784e8d8bef9SDimitry Andric OS << " static " << DirLang.getClauseEnumSetClass() << " " << ClauseSetPrefix 785e8d8bef9SDimitry Andric << DirLang.getDirectivePrefix() << Dir.getFormattedName() << " {\n"; 7865ffd83dbSDimitry Andric 7875ffd83dbSDimitry Andric for (const auto &C : Clauses) { 788e8d8bef9SDimitry Andric VersionedClause VerClause{C}; 789e8d8bef9SDimitry Andric OS << " llvm::" << DirLang.getCppNamespace() 790e8d8bef9SDimitry Andric << "::Clause::" << DirLang.getClausePrefix() 791e8d8bef9SDimitry Andric << VerClause.getClause().getFormattedName() << ",\n"; 7925ffd83dbSDimitry Andric } 7935ffd83dbSDimitry Andric OS << " };\n"; 7945ffd83dbSDimitry Andric } 7955ffd83dbSDimitry Andric 7965ffd83dbSDimitry Andric // Generate an enum set for the 4 kinds of clauses linked to a directive. 79706c3fb27SDimitry Andric static void GenerateDirectiveClauseSets(const DirectiveLanguage &DirLang, 798e8d8bef9SDimitry Andric raw_ostream &OS) { 7995ffd83dbSDimitry Andric 8005ffd83dbSDimitry Andric IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_SETS", OS); 8015ffd83dbSDimitry Andric 8025ffd83dbSDimitry Andric OS << "\n"; 8035ffd83dbSDimitry Andric OS << "namespace llvm {\n"; 8045ffd83dbSDimitry Andric 8055ffd83dbSDimitry Andric // Open namespaces defined in the directive language. 8065ffd83dbSDimitry Andric llvm::SmallVector<StringRef, 2> Namespaces; 807e8d8bef9SDimitry Andric llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::"); 8085ffd83dbSDimitry Andric for (auto Ns : Namespaces) 8095ffd83dbSDimitry Andric OS << "namespace " << Ns << " {\n"; 8105ffd83dbSDimitry Andric 811e8d8bef9SDimitry Andric for (const auto &D : DirLang.getDirectives()) { 812e8d8bef9SDimitry Andric Directive Dir{D}; 8135ffd83dbSDimitry Andric 8145ffd83dbSDimitry Andric OS << "\n"; 815e8d8bef9SDimitry Andric OS << " // Sets for " << Dir.getName() << "\n"; 8165ffd83dbSDimitry Andric 817e8d8bef9SDimitry Andric GenerateClauseSet(Dir.getAllowedClauses(), OS, "allowedClauses_", Dir, 818e8d8bef9SDimitry Andric DirLang); 819e8d8bef9SDimitry Andric GenerateClauseSet(Dir.getAllowedOnceClauses(), OS, "allowedOnceClauses_", 820e8d8bef9SDimitry Andric Dir, DirLang); 821e8d8bef9SDimitry Andric GenerateClauseSet(Dir.getAllowedExclusiveClauses(), OS, 822e8d8bef9SDimitry Andric "allowedExclusiveClauses_", Dir, DirLang); 823e8d8bef9SDimitry Andric GenerateClauseSet(Dir.getRequiredClauses(), OS, "requiredClauses_", Dir, 824e8d8bef9SDimitry Andric DirLang); 8255ffd83dbSDimitry Andric } 8265ffd83dbSDimitry Andric 8275ffd83dbSDimitry Andric // Closing namespaces 8285ffd83dbSDimitry Andric for (auto Ns : llvm::reverse(Namespaces)) 8295ffd83dbSDimitry Andric OS << "} // namespace " << Ns << "\n"; 8305ffd83dbSDimitry Andric 8315ffd83dbSDimitry Andric OS << "} // namespace llvm\n"; 8325ffd83dbSDimitry Andric } 8335ffd83dbSDimitry Andric 8345ffd83dbSDimitry Andric // Generate a map of directive (key) with DirectiveClauses struct as values. 8355ffd83dbSDimitry Andric // The struct holds the 4 sets of enumeration for the 4 kinds of clauses 8365ffd83dbSDimitry Andric // allowances (allowed, allowed once, allowed exclusive and required). 83706c3fb27SDimitry Andric static void GenerateDirectiveClauseMap(const DirectiveLanguage &DirLang, 838e8d8bef9SDimitry Andric raw_ostream &OS) { 8395ffd83dbSDimitry Andric 8405ffd83dbSDimitry Andric IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_MAP", OS); 8415ffd83dbSDimitry Andric 8425ffd83dbSDimitry Andric OS << "\n"; 8435ffd83dbSDimitry Andric OS << "{\n"; 844e8d8bef9SDimitry Andric 845e8d8bef9SDimitry Andric for (const auto &D : DirLang.getDirectives()) { 846e8d8bef9SDimitry Andric Directive Dir{D}; 847e8d8bef9SDimitry Andric OS << " {llvm::" << DirLang.getCppNamespace() 848e8d8bef9SDimitry Andric << "::Directive::" << DirLang.getDirectivePrefix() 849e8d8bef9SDimitry Andric << Dir.getFormattedName() << ",\n"; 850e8d8bef9SDimitry Andric OS << " {\n"; 851e8d8bef9SDimitry Andric OS << " llvm::" << DirLang.getCppNamespace() << "::allowedClauses_" 852e8d8bef9SDimitry Andric << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n"; 853e8d8bef9SDimitry Andric OS << " llvm::" << DirLang.getCppNamespace() << "::allowedOnceClauses_" 854e8d8bef9SDimitry Andric << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n"; 855e8d8bef9SDimitry Andric OS << " llvm::" << DirLang.getCppNamespace() 856e8d8bef9SDimitry Andric << "::allowedExclusiveClauses_" << DirLang.getDirectivePrefix() 857e8d8bef9SDimitry Andric << Dir.getFormattedName() << ",\n"; 858e8d8bef9SDimitry Andric OS << " llvm::" << DirLang.getCppNamespace() << "::requiredClauses_" 859e8d8bef9SDimitry Andric << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n"; 8605ffd83dbSDimitry Andric OS << " }\n"; 8615ffd83dbSDimitry Andric OS << " },\n"; 8625ffd83dbSDimitry Andric } 8635ffd83dbSDimitry Andric 864e8d8bef9SDimitry Andric OS << "}\n"; 8655ffd83dbSDimitry Andric } 8665ffd83dbSDimitry Andric 867e8d8bef9SDimitry Andric // Generate classes entry for Flang clauses in the Flang parse-tree 868e8d8bef9SDimitry Andric // If the clause as a non-generic class, no entry is generated. 869e8d8bef9SDimitry Andric // If the clause does not hold a value, an EMPTY_CLASS is used. 870e8d8bef9SDimitry Andric // If the clause class is generic then a WRAPPER_CLASS is used. When the value 871e8d8bef9SDimitry Andric // is optional, the value class is wrapped into a std::optional. 87206c3fb27SDimitry Andric static void GenerateFlangClauseParserClass(const DirectiveLanguage &DirLang, 873e8d8bef9SDimitry Andric raw_ostream &OS) { 874e8d8bef9SDimitry Andric 875e8d8bef9SDimitry Andric IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS); 876e8d8bef9SDimitry Andric 877e8d8bef9SDimitry Andric OS << "\n"; 878e8d8bef9SDimitry Andric 879e8d8bef9SDimitry Andric for (const auto &C : DirLang.getClauses()) { 880e8d8bef9SDimitry Andric Clause Clause{C}; 881e8d8bef9SDimitry Andric if (!Clause.getFlangClass().empty()) { 882e8d8bef9SDimitry Andric OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName() << ", "; 883e8d8bef9SDimitry Andric if (Clause.isValueOptional() && Clause.isValueList()) { 884e8d8bef9SDimitry Andric OS << "std::optional<std::list<" << Clause.getFlangClass() << ">>"; 885e8d8bef9SDimitry Andric } else if (Clause.isValueOptional()) { 886e8d8bef9SDimitry Andric OS << "std::optional<" << Clause.getFlangClass() << ">"; 887e8d8bef9SDimitry Andric } else if (Clause.isValueList()) { 888e8d8bef9SDimitry Andric OS << "std::list<" << Clause.getFlangClass() << ">"; 889e8d8bef9SDimitry Andric } else { 890e8d8bef9SDimitry Andric OS << Clause.getFlangClass(); 891e8d8bef9SDimitry Andric } 892e8d8bef9SDimitry Andric } else { 893e8d8bef9SDimitry Andric OS << "EMPTY_CLASS(" << Clause.getFormattedParserClassName(); 894e8d8bef9SDimitry Andric } 895e8d8bef9SDimitry Andric OS << ");\n"; 896e8d8bef9SDimitry Andric } 897e8d8bef9SDimitry Andric } 898e8d8bef9SDimitry Andric 899e8d8bef9SDimitry Andric // Generate a list of the different clause classes for Flang. 90006c3fb27SDimitry Andric static void GenerateFlangClauseParserClassList(const DirectiveLanguage &DirLang, 901e8d8bef9SDimitry Andric raw_ostream &OS) { 902e8d8bef9SDimitry Andric 903e8d8bef9SDimitry Andric IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS); 904e8d8bef9SDimitry Andric 905e8d8bef9SDimitry Andric OS << "\n"; 906e8d8bef9SDimitry Andric llvm::interleaveComma(DirLang.getClauses(), OS, [&](Record *C) { 907e8d8bef9SDimitry Andric Clause Clause{C}; 908e8d8bef9SDimitry Andric OS << Clause.getFormattedParserClassName() << "\n"; 909e8d8bef9SDimitry Andric }); 910e8d8bef9SDimitry Andric } 911e8d8bef9SDimitry Andric 912e8d8bef9SDimitry Andric // Generate dump node list for the clauses holding a generic class name. 91306c3fb27SDimitry Andric static void GenerateFlangClauseDump(const DirectiveLanguage &DirLang, 914e8d8bef9SDimitry Andric raw_ostream &OS) { 915e8d8bef9SDimitry Andric 916e8d8bef9SDimitry Andric IfDefScope Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS); 917e8d8bef9SDimitry Andric 918e8d8bef9SDimitry Andric OS << "\n"; 919e8d8bef9SDimitry Andric for (const auto &C : DirLang.getClauses()) { 920e8d8bef9SDimitry Andric Clause Clause{C}; 921e8d8bef9SDimitry Andric OS << "NODE(" << DirLang.getFlangClauseBaseClass() << ", " 922e8d8bef9SDimitry Andric << Clause.getFormattedParserClassName() << ")\n"; 923e8d8bef9SDimitry Andric } 924e8d8bef9SDimitry Andric } 925e8d8bef9SDimitry Andric 926e8d8bef9SDimitry Andric // Generate Unparse functions for clauses classes in the Flang parse-tree 927e8d8bef9SDimitry Andric // If the clause is a non-generic class, no entry is generated. 92806c3fb27SDimitry Andric static void GenerateFlangClauseUnparse(const DirectiveLanguage &DirLang, 929e8d8bef9SDimitry Andric raw_ostream &OS) { 930e8d8bef9SDimitry Andric 931e8d8bef9SDimitry Andric IfDefScope Scope("GEN_FLANG_CLAUSE_UNPARSE", OS); 932e8d8bef9SDimitry Andric 933e8d8bef9SDimitry Andric OS << "\n"; 934e8d8bef9SDimitry Andric 935e8d8bef9SDimitry Andric for (const auto &C : DirLang.getClauses()) { 936e8d8bef9SDimitry Andric Clause Clause{C}; 937e8d8bef9SDimitry Andric if (!Clause.getFlangClass().empty()) { 938e8d8bef9SDimitry Andric if (Clause.isValueOptional() && Clause.getDefaultValue().empty()) { 939e8d8bef9SDimitry Andric OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass() 940e8d8bef9SDimitry Andric << "::" << Clause.getFormattedParserClassName() << " &x) {\n"; 941e8d8bef9SDimitry Andric OS << " Word(\"" << Clause.getName().upper() << "\");\n"; 942e8d8bef9SDimitry Andric 943e8d8bef9SDimitry Andric OS << " Walk(\"(\", x.v, \")\");\n"; 944e8d8bef9SDimitry Andric OS << "}\n"; 945e8d8bef9SDimitry Andric } else if (Clause.isValueOptional()) { 946e8d8bef9SDimitry Andric OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass() 947e8d8bef9SDimitry Andric << "::" << Clause.getFormattedParserClassName() << " &x) {\n"; 948e8d8bef9SDimitry Andric OS << " Word(\"" << Clause.getName().upper() << "\");\n"; 949e8d8bef9SDimitry Andric OS << " Put(\"(\");\n"; 950e8d8bef9SDimitry Andric OS << " if (x.v.has_value())\n"; 951e8d8bef9SDimitry Andric if (Clause.isValueList()) 952e8d8bef9SDimitry Andric OS << " Walk(x.v, \",\");\n"; 953e8d8bef9SDimitry Andric else 954e8d8bef9SDimitry Andric OS << " Walk(x.v);\n"; 955e8d8bef9SDimitry Andric OS << " else\n"; 956e8d8bef9SDimitry Andric OS << " Put(\"" << Clause.getDefaultValue() << "\");\n"; 957e8d8bef9SDimitry Andric OS << " Put(\")\");\n"; 958e8d8bef9SDimitry Andric OS << "}\n"; 959e8d8bef9SDimitry Andric } else { 960e8d8bef9SDimitry Andric OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass() 961e8d8bef9SDimitry Andric << "::" << Clause.getFormattedParserClassName() << " &x) {\n"; 962e8d8bef9SDimitry Andric OS << " Word(\"" << Clause.getName().upper() << "\");\n"; 963e8d8bef9SDimitry Andric OS << " Put(\"(\");\n"; 964e8d8bef9SDimitry Andric if (Clause.isValueList()) 965e8d8bef9SDimitry Andric OS << " Walk(x.v, \",\");\n"; 966e8d8bef9SDimitry Andric else 967e8d8bef9SDimitry Andric OS << " Walk(x.v);\n"; 968e8d8bef9SDimitry Andric OS << " Put(\")\");\n"; 969e8d8bef9SDimitry Andric OS << "}\n"; 970e8d8bef9SDimitry Andric } 971e8d8bef9SDimitry Andric } else { 972e8d8bef9SDimitry Andric OS << "void Before(const " << DirLang.getFlangClauseBaseClass() 973e8d8bef9SDimitry Andric << "::" << Clause.getFormattedParserClassName() << " &) { Word(\"" 974e8d8bef9SDimitry Andric << Clause.getName().upper() << "\"); }\n"; 975e8d8bef9SDimitry Andric } 976e8d8bef9SDimitry Andric } 977e8d8bef9SDimitry Andric } 978e8d8bef9SDimitry Andric 979fe6060f1SDimitry Andric // Generate check in the Enter functions for clauses classes. 98006c3fb27SDimitry Andric static void GenerateFlangClauseCheckPrototypes(const DirectiveLanguage &DirLang, 981fe6060f1SDimitry Andric raw_ostream &OS) { 982fe6060f1SDimitry Andric 983fe6060f1SDimitry Andric IfDefScope Scope("GEN_FLANG_CLAUSE_CHECK_ENTER", OS); 984fe6060f1SDimitry Andric 985fe6060f1SDimitry Andric OS << "\n"; 986fe6060f1SDimitry Andric for (const auto &C : DirLang.getClauses()) { 987fe6060f1SDimitry Andric Clause Clause{C}; 988fe6060f1SDimitry Andric OS << "void Enter(const parser::" << DirLang.getFlangClauseBaseClass() 989fe6060f1SDimitry Andric << "::" << Clause.getFormattedParserClassName() << " &);\n"; 990fe6060f1SDimitry Andric } 991fe6060f1SDimitry Andric } 992fe6060f1SDimitry Andric 993fe6060f1SDimitry Andric // Generate the mapping for clauses between the parser class and the 994fe6060f1SDimitry Andric // corresponding clause Kind 99506c3fb27SDimitry Andric static void GenerateFlangClauseParserKindMap(const DirectiveLanguage &DirLang, 996fe6060f1SDimitry Andric raw_ostream &OS) { 997fe6060f1SDimitry Andric 998fe6060f1SDimitry Andric IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_KIND_MAP", OS); 999fe6060f1SDimitry Andric 1000fe6060f1SDimitry Andric OS << "\n"; 1001fe6060f1SDimitry Andric for (const auto &C : DirLang.getClauses()) { 1002fe6060f1SDimitry Andric Clause Clause{C}; 1003fe6060f1SDimitry Andric OS << "if constexpr (std::is_same_v<A, parser::" 1004fe6060f1SDimitry Andric << DirLang.getFlangClauseBaseClass() 1005fe6060f1SDimitry Andric << "::" << Clause.getFormattedParserClassName(); 1006fe6060f1SDimitry Andric OS << ">)\n"; 1007fe6060f1SDimitry Andric OS << " return llvm::" << DirLang.getCppNamespace() 1008fe6060f1SDimitry Andric << "::Clause::" << DirLang.getClausePrefix() << Clause.getFormattedName() 1009fe6060f1SDimitry Andric << ";\n"; 1010fe6060f1SDimitry Andric } 1011fe6060f1SDimitry Andric 1012fe6060f1SDimitry Andric OS << "llvm_unreachable(\"Invalid " << DirLang.getName() 1013fe6060f1SDimitry Andric << " Parser clause\");\n"; 1014fe6060f1SDimitry Andric } 1015fe6060f1SDimitry Andric 101606c3fb27SDimitry Andric static bool compareClauseName(Record *R1, Record *R2) { 1017fcaf7f86SDimitry Andric Clause C1{R1}; 1018fcaf7f86SDimitry Andric Clause C2{R2}; 1019fcaf7f86SDimitry Andric return (C1.getName() > C2.getName()); 1020fcaf7f86SDimitry Andric } 1021fcaf7f86SDimitry Andric 1022fcaf7f86SDimitry Andric // Generate the parser for the clauses. 102306c3fb27SDimitry Andric static void GenerateFlangClausesParser(const DirectiveLanguage &DirLang, 1024fcaf7f86SDimitry Andric raw_ostream &OS) { 1025fcaf7f86SDimitry Andric std::vector<Record *> Clauses = DirLang.getClauses(); 1026fcaf7f86SDimitry Andric // Sort clauses in reverse alphabetical order so with clauses with same 1027fcaf7f86SDimitry Andric // beginning, the longer option is tried before. 1028fcaf7f86SDimitry Andric llvm::sort(Clauses, compareClauseName); 1029fcaf7f86SDimitry Andric IfDefScope Scope("GEN_FLANG_CLAUSES_PARSER", OS); 1030fcaf7f86SDimitry Andric OS << "\n"; 1031fcaf7f86SDimitry Andric unsigned index = 0; 1032fcaf7f86SDimitry Andric unsigned lastClauseIndex = DirLang.getClauses().size() - 1; 1033fcaf7f86SDimitry Andric OS << "TYPE_PARSER(\n"; 1034fcaf7f86SDimitry Andric for (const auto &C : Clauses) { 1035fcaf7f86SDimitry Andric Clause Clause{C}; 1036fcaf7f86SDimitry Andric if (Clause.getAliases().empty()) { 1037fcaf7f86SDimitry Andric OS << " \"" << Clause.getName() << "\""; 1038fcaf7f86SDimitry Andric } else { 1039fcaf7f86SDimitry Andric OS << " (" 1040fcaf7f86SDimitry Andric << "\"" << Clause.getName() << "\"_tok"; 1041fcaf7f86SDimitry Andric for (StringRef alias : Clause.getAliases()) { 1042fcaf7f86SDimitry Andric OS << " || \"" << alias << "\"_tok"; 1043fcaf7f86SDimitry Andric } 1044fcaf7f86SDimitry Andric OS << ")"; 1045fcaf7f86SDimitry Andric } 1046fcaf7f86SDimitry Andric 1047fcaf7f86SDimitry Andric OS << " >> construct<" << DirLang.getFlangClauseBaseClass() 1048fcaf7f86SDimitry Andric << ">(construct<" << DirLang.getFlangClauseBaseClass() 1049fcaf7f86SDimitry Andric << "::" << Clause.getFormattedParserClassName() << ">("; 1050fcaf7f86SDimitry Andric if (Clause.getFlangClass().empty()) { 1051fcaf7f86SDimitry Andric OS << "))"; 1052fcaf7f86SDimitry Andric if (index != lastClauseIndex) 1053fcaf7f86SDimitry Andric OS << " ||"; 1054fcaf7f86SDimitry Andric OS << "\n"; 1055fcaf7f86SDimitry Andric ++index; 1056fcaf7f86SDimitry Andric continue; 1057fcaf7f86SDimitry Andric } 1058fcaf7f86SDimitry Andric 1059fcaf7f86SDimitry Andric if (Clause.isValueOptional()) 1060fcaf7f86SDimitry Andric OS << "maybe("; 1061fcaf7f86SDimitry Andric OS << "parenthesized("; 106206c3fb27SDimitry Andric if (Clause.isValueList()) 106306c3fb27SDimitry Andric OS << "nonemptyList("; 1064fcaf7f86SDimitry Andric 1065fcaf7f86SDimitry Andric if (!Clause.getPrefix().empty()) 1066fcaf7f86SDimitry Andric OS << "\"" << Clause.getPrefix() << ":\" >> "; 1067fcaf7f86SDimitry Andric 1068fcaf7f86SDimitry Andric // The common Flang parser are used directly. Their name is identical to 1069fcaf7f86SDimitry Andric // the Flang class with first letter as lowercase. If the Flang class is 1070fcaf7f86SDimitry Andric // not a common class, we assume there is a specific Parser<>{} with the 1071fcaf7f86SDimitry Andric // Flang class name provided. 1072fcaf7f86SDimitry Andric llvm::SmallString<128> Scratch; 1073fcaf7f86SDimitry Andric StringRef Parser = 1074fcaf7f86SDimitry Andric llvm::StringSwitch<StringRef>(Clause.getFlangClass()) 1075fcaf7f86SDimitry Andric .Case("Name", "name") 1076fcaf7f86SDimitry Andric .Case("ScalarIntConstantExpr", "scalarIntConstantExpr") 1077fcaf7f86SDimitry Andric .Case("ScalarIntExpr", "scalarIntExpr") 10785f757f3fSDimitry Andric .Case("ScalarExpr", "scalarExpr") 1079fcaf7f86SDimitry Andric .Case("ScalarLogicalExpr", "scalarLogicalExpr") 1080fcaf7f86SDimitry Andric .Default(("Parser<" + Clause.getFlangClass() + ">{}") 1081fcaf7f86SDimitry Andric .toStringRef(Scratch)); 1082fcaf7f86SDimitry Andric OS << Parser; 1083fcaf7f86SDimitry Andric if (!Clause.getPrefix().empty() && Clause.isPrefixOptional()) 1084fcaf7f86SDimitry Andric OS << " || " << Parser; 108506c3fb27SDimitry Andric if (Clause.isValueList()) // close nonemptyList(. 108606c3fb27SDimitry Andric OS << ")"; 1087fcaf7f86SDimitry Andric OS << ")"; // close parenthesized(. 1088fcaf7f86SDimitry Andric 1089fcaf7f86SDimitry Andric if (Clause.isValueOptional()) // close maybe(. 1090fcaf7f86SDimitry Andric OS << ")"; 1091fcaf7f86SDimitry Andric OS << "))"; 1092fcaf7f86SDimitry Andric if (index != lastClauseIndex) 1093fcaf7f86SDimitry Andric OS << " ||"; 1094fcaf7f86SDimitry Andric OS << "\n"; 1095fcaf7f86SDimitry Andric ++index; 1096fcaf7f86SDimitry Andric } 1097fcaf7f86SDimitry Andric OS << ")\n"; 1098fcaf7f86SDimitry Andric } 1099fcaf7f86SDimitry Andric 1100e8d8bef9SDimitry Andric // Generate the implementation section for the enumeration in the directive 11015ffd83dbSDimitry Andric // language 110206c3fb27SDimitry Andric static void EmitDirectivesFlangImpl(const DirectiveLanguage &DirLang, 1103e8d8bef9SDimitry Andric raw_ostream &OS) { 11045ffd83dbSDimitry Andric 1105e8d8bef9SDimitry Andric GenerateDirectiveClauseSets(DirLang, OS); 11065ffd83dbSDimitry Andric 1107e8d8bef9SDimitry Andric GenerateDirectiveClauseMap(DirLang, OS); 1108e8d8bef9SDimitry Andric 1109e8d8bef9SDimitry Andric GenerateFlangClauseParserClass(DirLang, OS); 1110e8d8bef9SDimitry Andric 1111e8d8bef9SDimitry Andric GenerateFlangClauseParserClassList(DirLang, OS); 1112e8d8bef9SDimitry Andric 1113e8d8bef9SDimitry Andric GenerateFlangClauseDump(DirLang, OS); 1114e8d8bef9SDimitry Andric 1115e8d8bef9SDimitry Andric GenerateFlangClauseUnparse(DirLang, OS); 1116fe6060f1SDimitry Andric 1117fe6060f1SDimitry Andric GenerateFlangClauseCheckPrototypes(DirLang, OS); 1118fe6060f1SDimitry Andric 1119fe6060f1SDimitry Andric GenerateFlangClauseParserKindMap(DirLang, OS); 1120fcaf7f86SDimitry Andric 1121fcaf7f86SDimitry Andric GenerateFlangClausesParser(DirLang, OS); 11225ffd83dbSDimitry Andric } 11235ffd83dbSDimitry Andric 112406c3fb27SDimitry Andric static void GenerateClauseClassMacro(const DirectiveLanguage &DirLang, 1125e8d8bef9SDimitry Andric raw_ostream &OS) { 1126e8d8bef9SDimitry Andric // Generate macros style information for legacy code in clang 1127e8d8bef9SDimitry Andric IfDefScope Scope("GEN_CLANG_CLAUSE_CLASS", OS); 1128e8d8bef9SDimitry Andric 1129e8d8bef9SDimitry Andric OS << "\n"; 1130e8d8bef9SDimitry Andric 1131e8d8bef9SDimitry Andric OS << "#ifndef CLAUSE\n"; 1132e8d8bef9SDimitry Andric OS << "#define CLAUSE(Enum, Str, Implicit)\n"; 1133e8d8bef9SDimitry Andric OS << "#endif\n"; 1134e8d8bef9SDimitry Andric OS << "#ifndef CLAUSE_CLASS\n"; 1135e8d8bef9SDimitry Andric OS << "#define CLAUSE_CLASS(Enum, Str, Class)\n"; 1136e8d8bef9SDimitry Andric OS << "#endif\n"; 1137e8d8bef9SDimitry Andric OS << "#ifndef CLAUSE_NO_CLASS\n"; 1138e8d8bef9SDimitry Andric OS << "#define CLAUSE_NO_CLASS(Enum, Str)\n"; 1139e8d8bef9SDimitry Andric OS << "#endif\n"; 1140e8d8bef9SDimitry Andric OS << "\n"; 1141e8d8bef9SDimitry Andric OS << "#define __CLAUSE(Name, Class) \\\n"; 1142e8d8bef9SDimitry Andric OS << " CLAUSE(" << DirLang.getClausePrefix() 1143e8d8bef9SDimitry Andric << "##Name, #Name, /* Implicit */ false) \\\n"; 1144e8d8bef9SDimitry Andric OS << " CLAUSE_CLASS(" << DirLang.getClausePrefix() 1145e8d8bef9SDimitry Andric << "##Name, #Name, Class)\n"; 1146e8d8bef9SDimitry Andric OS << "#define __CLAUSE_NO_CLASS(Name) \\\n"; 1147e8d8bef9SDimitry Andric OS << " CLAUSE(" << DirLang.getClausePrefix() 1148e8d8bef9SDimitry Andric << "##Name, #Name, /* Implicit */ false) \\\n"; 1149e8d8bef9SDimitry Andric OS << " CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, #Name)\n"; 1150e8d8bef9SDimitry Andric OS << "#define __IMPLICIT_CLAUSE_CLASS(Name, Str, Class) \\\n"; 1151e8d8bef9SDimitry Andric OS << " CLAUSE(" << DirLang.getClausePrefix() 1152e8d8bef9SDimitry Andric << "##Name, Str, /* Implicit */ true) \\\n"; 1153e8d8bef9SDimitry Andric OS << " CLAUSE_CLASS(" << DirLang.getClausePrefix() 1154e8d8bef9SDimitry Andric << "##Name, Str, Class)\n"; 1155e8d8bef9SDimitry Andric OS << "#define __IMPLICIT_CLAUSE_NO_CLASS(Name, Str) \\\n"; 1156e8d8bef9SDimitry Andric OS << " CLAUSE(" << DirLang.getClausePrefix() 1157e8d8bef9SDimitry Andric << "##Name, Str, /* Implicit */ true) \\\n"; 1158e8d8bef9SDimitry Andric OS << " CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, Str)\n"; 1159e8d8bef9SDimitry Andric OS << "\n"; 1160e8d8bef9SDimitry Andric 1161e8d8bef9SDimitry Andric for (const auto &R : DirLang.getClauses()) { 1162e8d8bef9SDimitry Andric Clause C{R}; 1163e8d8bef9SDimitry Andric if (C.getClangClass().empty()) { // NO_CLASS 1164e8d8bef9SDimitry Andric if (C.isImplicit()) { 1165e8d8bef9SDimitry Andric OS << "__IMPLICIT_CLAUSE_NO_CLASS(" << C.getFormattedName() << ", \"" 1166e8d8bef9SDimitry Andric << C.getFormattedName() << "\")\n"; 1167e8d8bef9SDimitry Andric } else { 1168e8d8bef9SDimitry Andric OS << "__CLAUSE_NO_CLASS(" << C.getFormattedName() << ")\n"; 1169e8d8bef9SDimitry Andric } 1170e8d8bef9SDimitry Andric } else { // CLASS 1171e8d8bef9SDimitry Andric if (C.isImplicit()) { 1172e8d8bef9SDimitry Andric OS << "__IMPLICIT_CLAUSE_CLASS(" << C.getFormattedName() << ", \"" 1173e8d8bef9SDimitry Andric << C.getFormattedName() << "\", " << C.getClangClass() << ")\n"; 1174e8d8bef9SDimitry Andric } else { 1175e8d8bef9SDimitry Andric OS << "__CLAUSE(" << C.getFormattedName() << ", " << C.getClangClass() 1176e8d8bef9SDimitry Andric << ")\n"; 1177e8d8bef9SDimitry Andric } 1178e8d8bef9SDimitry Andric } 1179e8d8bef9SDimitry Andric } 1180e8d8bef9SDimitry Andric 1181e8d8bef9SDimitry Andric OS << "\n"; 1182e8d8bef9SDimitry Andric OS << "#undef __IMPLICIT_CLAUSE_NO_CLASS\n"; 1183e8d8bef9SDimitry Andric OS << "#undef __IMPLICIT_CLAUSE_CLASS\n"; 1184*0fca6ea1SDimitry Andric OS << "#undef __CLAUSE_NO_CLASS\n"; 1185e8d8bef9SDimitry Andric OS << "#undef __CLAUSE\n"; 1186e8d8bef9SDimitry Andric OS << "#undef CLAUSE_NO_CLASS\n"; 1187e8d8bef9SDimitry Andric OS << "#undef CLAUSE_CLASS\n"; 1188e8d8bef9SDimitry Andric OS << "#undef CLAUSE\n"; 1189e8d8bef9SDimitry Andric } 1190e8d8bef9SDimitry Andric 1191fe6060f1SDimitry Andric // Generate the implemenation for the enumeration in the directive 11925ffd83dbSDimitry Andric // language. This code can be included in library. 1193fe6060f1SDimitry Andric void EmitDirectivesBasicImpl(const DirectiveLanguage &DirLang, 1194fe6060f1SDimitry Andric raw_ostream &OS) { 1195fe6060f1SDimitry Andric IfDefScope Scope("GEN_DIRECTIVES_IMPL", OS); 11965ffd83dbSDimitry Andric 1197*0fca6ea1SDimitry Andric OS << "\n#include \"llvm/Support/ErrorHandling.h\"\n"; 1198*0fca6ea1SDimitry Andric 11995ffd83dbSDimitry Andric // getDirectiveKind(StringRef Str) 1200e8d8bef9SDimitry Andric GenerateGetKind(DirLang.getDirectives(), OS, "Directive", DirLang, 1201e8d8bef9SDimitry Andric DirLang.getDirectivePrefix(), /*ImplicitAsUnknown=*/false); 12025ffd83dbSDimitry Andric 12035ffd83dbSDimitry Andric // getDirectiveName(Directive Kind) 1204e8d8bef9SDimitry Andric GenerateGetName(DirLang.getDirectives(), OS, "Directive", DirLang, 1205e8d8bef9SDimitry Andric DirLang.getDirectivePrefix()); 12065ffd83dbSDimitry Andric 12075ffd83dbSDimitry Andric // getClauseKind(StringRef Str) 1208e8d8bef9SDimitry Andric GenerateGetKind(DirLang.getClauses(), OS, "Clause", DirLang, 1209e8d8bef9SDimitry Andric DirLang.getClausePrefix(), 1210e8d8bef9SDimitry Andric /*ImplicitAsUnknown=*/true); 12115ffd83dbSDimitry Andric 12125ffd83dbSDimitry Andric // getClauseName(Clause Kind) 1213e8d8bef9SDimitry Andric GenerateGetName(DirLang.getClauses(), OS, "Clause", DirLang, 1214e8d8bef9SDimitry Andric DirLang.getClausePrefix()); 1215e8d8bef9SDimitry Andric 1216e8d8bef9SDimitry Andric // get<ClauseVal>Kind(StringRef Str) 1217e8d8bef9SDimitry Andric GenerateGetKindClauseVal(DirLang, OS); 12185ffd83dbSDimitry Andric 12195ffd83dbSDimitry Andric // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version) 1220e8d8bef9SDimitry Andric GenerateIsAllowedClause(DirLang, OS); 1221*0fca6ea1SDimitry Andric 1222*0fca6ea1SDimitry Andric // getDirectiveAssociation(Directive D) 1223*0fca6ea1SDimitry Andric GenerateGetDirectiveAssociation(DirLang, OS); 1224*0fca6ea1SDimitry Andric 1225*0fca6ea1SDimitry Andric // getDirectiveCategory(Directive D) 1226*0fca6ea1SDimitry Andric GenerateGetDirectiveCategory(DirLang, OS); 1227*0fca6ea1SDimitry Andric 1228*0fca6ea1SDimitry Andric // Leaf table for getLeafConstructs, etc. 1229*0fca6ea1SDimitry Andric EmitLeafTable(DirLang, OS, "LeafConstructTable"); 12305ffd83dbSDimitry Andric } 12315ffd83dbSDimitry Andric 1232fe6060f1SDimitry Andric // Generate the implemenation section for the enumeration in the directive 1233fe6060f1SDimitry Andric // language. 123406c3fb27SDimitry Andric static void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) { 1235fe6060f1SDimitry Andric const auto DirLang = DirectiveLanguage{Records}; 1236fe6060f1SDimitry Andric if (DirLang.HasValidityErrors()) 1237fe6060f1SDimitry Andric return; 1238fe6060f1SDimitry Andric 1239fe6060f1SDimitry Andric EmitDirectivesFlangImpl(DirLang, OS); 1240fe6060f1SDimitry Andric 1241fe6060f1SDimitry Andric GenerateClauseClassMacro(DirLang, OS); 1242fe6060f1SDimitry Andric 1243fe6060f1SDimitry Andric EmitDirectivesBasicImpl(DirLang, OS); 1244fe6060f1SDimitry Andric } 1245fe6060f1SDimitry Andric 124606c3fb27SDimitry Andric static TableGen::Emitter::Opt 124706c3fb27SDimitry Andric X("gen-directive-decl", EmitDirectivesDecl, 124806c3fb27SDimitry Andric "Generate directive related declaration code (header file)"); 124906c3fb27SDimitry Andric 125006c3fb27SDimitry Andric static TableGen::Emitter::Opt 125106c3fb27SDimitry Andric Y("gen-directive-impl", EmitDirectivesImpl, 125206c3fb27SDimitry Andric "Generate directive related implementation code"); 1253