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" 155ffd83dbSDimitry Andric #include "llvm/ADT/STLExtras.h" 165ffd83dbSDimitry Andric #include "llvm/ADT/SmallVector.h" 175ffd83dbSDimitry Andric #include "llvm/ADT/StringSet.h" 18fcaf7f86SDimitry Andric #include "llvm/ADT/StringSwitch.h" 195ffd83dbSDimitry Andric #include "llvm/TableGen/Error.h" 205ffd83dbSDimitry Andric #include "llvm/TableGen/Record.h" 21*06c3fb27SDimitry Andric #include "llvm/TableGen/TableGenBackend.h" 225ffd83dbSDimitry Andric 235ffd83dbSDimitry Andric using namespace llvm; 245ffd83dbSDimitry Andric 255ffd83dbSDimitry Andric namespace { 265ffd83dbSDimitry Andric // Simple RAII helper for defining ifdef-undef-endif scopes. 275ffd83dbSDimitry Andric class IfDefScope { 285ffd83dbSDimitry Andric public: 295ffd83dbSDimitry Andric IfDefScope(StringRef Name, raw_ostream &OS) : Name(Name), OS(OS) { 305ffd83dbSDimitry Andric OS << "#ifdef " << Name << "\n" 315ffd83dbSDimitry Andric << "#undef " << Name << "\n"; 325ffd83dbSDimitry Andric } 335ffd83dbSDimitry Andric 345ffd83dbSDimitry Andric ~IfDefScope() { OS << "\n#endif // " << Name << "\n\n"; } 355ffd83dbSDimitry Andric 365ffd83dbSDimitry Andric private: 375ffd83dbSDimitry Andric StringRef Name; 385ffd83dbSDimitry Andric raw_ostream &OS; 395ffd83dbSDimitry Andric }; 40*06c3fb27SDimitry Andric } // namespace 415ffd83dbSDimitry Andric 425ffd83dbSDimitry Andric // Generate enum class 43*06c3fb27SDimitry Andric static void GenerateEnumClass(const std::vector<Record *> &Records, 44*06c3fb27SDimitry Andric raw_ostream &OS, StringRef Enum, StringRef Prefix, 45e8d8bef9SDimitry Andric const DirectiveLanguage &DirLang) { 465ffd83dbSDimitry Andric OS << "\n"; 475ffd83dbSDimitry Andric OS << "enum class " << Enum << " {\n"; 485ffd83dbSDimitry Andric for (const auto &R : Records) { 49e8d8bef9SDimitry Andric BaseRecord Rec{R}; 50e8d8bef9SDimitry Andric OS << " " << Prefix << Rec.getFormattedName() << ",\n"; 515ffd83dbSDimitry Andric } 525ffd83dbSDimitry Andric OS << "};\n"; 535ffd83dbSDimitry Andric OS << "\n"; 545ffd83dbSDimitry Andric OS << "static constexpr std::size_t " << Enum 555ffd83dbSDimitry Andric << "_enumSize = " << Records.size() << ";\n"; 565ffd83dbSDimitry Andric 575ffd83dbSDimitry Andric // Make the enum values available in the defined namespace. This allows us to 585ffd83dbSDimitry Andric // write something like Enum_X if we have a `using namespace <CppNamespace>`. 595ffd83dbSDimitry Andric // At the same time we do not loose the strong type guarantees of the enum 605ffd83dbSDimitry Andric // class, that is we cannot pass an unsigned as Directive without an explicit 615ffd83dbSDimitry Andric // cast. 62e8d8bef9SDimitry Andric if (DirLang.hasMakeEnumAvailableInNamespace()) { 635ffd83dbSDimitry Andric OS << "\n"; 645ffd83dbSDimitry Andric for (const auto &R : Records) { 65e8d8bef9SDimitry Andric BaseRecord Rec{R}; 66e8d8bef9SDimitry Andric OS << "constexpr auto " << Prefix << Rec.getFormattedName() << " = " 67e8d8bef9SDimitry Andric << "llvm::" << DirLang.getCppNamespace() << "::" << Enum 68e8d8bef9SDimitry Andric << "::" << Prefix << Rec.getFormattedName() << ";\n"; 695ffd83dbSDimitry Andric } 705ffd83dbSDimitry Andric } 715ffd83dbSDimitry Andric } 725ffd83dbSDimitry Andric 73e8d8bef9SDimitry Andric // Generate enums for values that clauses can take. 74e8d8bef9SDimitry Andric // Also generate function declarations for get<Enum>Name(StringRef Str). 75*06c3fb27SDimitry Andric static void GenerateEnumClauseVal(const std::vector<Record *> &Records, 76*06c3fb27SDimitry Andric raw_ostream &OS, 77*06c3fb27SDimitry Andric const DirectiveLanguage &DirLang, 78e8d8bef9SDimitry Andric std::string &EnumHelperFuncs) { 79e8d8bef9SDimitry Andric for (const auto &R : Records) { 80e8d8bef9SDimitry Andric Clause C{R}; 81e8d8bef9SDimitry Andric const auto &ClauseVals = C.getClauseVals(); 82e8d8bef9SDimitry Andric if (ClauseVals.size() <= 0) 83e8d8bef9SDimitry Andric continue; 84e8d8bef9SDimitry Andric 85e8d8bef9SDimitry Andric const auto &EnumName = C.getEnumName(); 86e8d8bef9SDimitry Andric if (EnumName.size() == 0) { 87e8d8bef9SDimitry Andric PrintError("enumClauseValue field not set in Clause" + 88e8d8bef9SDimitry Andric C.getFormattedName() + "."); 89e8d8bef9SDimitry Andric return; 90e8d8bef9SDimitry Andric } 91e8d8bef9SDimitry Andric 92e8d8bef9SDimitry Andric OS << "\n"; 93e8d8bef9SDimitry Andric OS << "enum class " << EnumName << " {\n"; 94e8d8bef9SDimitry Andric for (const auto &CV : ClauseVals) { 95e8d8bef9SDimitry Andric ClauseVal CVal{CV}; 96e8d8bef9SDimitry Andric OS << " " << CV->getName() << "=" << CVal.getValue() << ",\n"; 97e8d8bef9SDimitry Andric } 98e8d8bef9SDimitry Andric OS << "};\n"; 99e8d8bef9SDimitry Andric 100e8d8bef9SDimitry Andric if (DirLang.hasMakeEnumAvailableInNamespace()) { 101e8d8bef9SDimitry Andric OS << "\n"; 102e8d8bef9SDimitry Andric for (const auto &CV : ClauseVals) { 103e8d8bef9SDimitry Andric OS << "constexpr auto " << CV->getName() << " = " 104e8d8bef9SDimitry Andric << "llvm::" << DirLang.getCppNamespace() << "::" << EnumName 105e8d8bef9SDimitry Andric << "::" << CV->getName() << ";\n"; 106e8d8bef9SDimitry Andric } 107e8d8bef9SDimitry Andric EnumHelperFuncs += (llvm::Twine(EnumName) + llvm::Twine(" get") + 108e8d8bef9SDimitry Andric llvm::Twine(EnumName) + llvm::Twine("(StringRef);\n")) 109e8d8bef9SDimitry Andric .str(); 110e8d8bef9SDimitry Andric 111e8d8bef9SDimitry Andric EnumHelperFuncs += 112e8d8bef9SDimitry Andric (llvm::Twine("llvm::StringRef get") + llvm::Twine(DirLang.getName()) + 113e8d8bef9SDimitry Andric llvm::Twine(EnumName) + llvm::Twine("Name(") + 114e8d8bef9SDimitry Andric llvm::Twine(EnumName) + llvm::Twine(");\n")) 115e8d8bef9SDimitry Andric .str(); 116e8d8bef9SDimitry Andric } 117e8d8bef9SDimitry Andric } 118e8d8bef9SDimitry Andric } 119e8d8bef9SDimitry Andric 120*06c3fb27SDimitry Andric static bool HasDuplicateClauses(const std::vector<Record *> &Clauses, 121e8d8bef9SDimitry Andric const Directive &Directive, 122e8d8bef9SDimitry Andric llvm::StringSet<> &CrtClauses) { 123e8d8bef9SDimitry Andric bool HasError = false; 124e8d8bef9SDimitry Andric for (const auto &C : Clauses) { 125e8d8bef9SDimitry Andric VersionedClause VerClause{C}; 126e8d8bef9SDimitry Andric const auto insRes = CrtClauses.insert(VerClause.getClause().getName()); 127e8d8bef9SDimitry Andric if (!insRes.second) { 128e8d8bef9SDimitry Andric PrintError("Clause " + VerClause.getClause().getRecordName() + 129e8d8bef9SDimitry Andric " already defined on directive " + Directive.getRecordName()); 130e8d8bef9SDimitry Andric HasError = true; 131e8d8bef9SDimitry Andric } 132e8d8bef9SDimitry Andric } 133e8d8bef9SDimitry Andric return HasError; 134e8d8bef9SDimitry Andric } 135e8d8bef9SDimitry Andric 136e8d8bef9SDimitry Andric // Check for duplicate clauses in lists. Clauses cannot appear twice in the 137e8d8bef9SDimitry Andric // three allowed list. Also, since required implies allowed, clauses cannot 138e8d8bef9SDimitry Andric // appear in both the allowedClauses and requiredClauses lists. 139*06c3fb27SDimitry Andric static bool 140*06c3fb27SDimitry Andric HasDuplicateClausesInDirectives(const std::vector<Record *> &Directives) { 141e8d8bef9SDimitry Andric bool HasDuplicate = false; 142e8d8bef9SDimitry Andric for (const auto &D : Directives) { 143e8d8bef9SDimitry Andric Directive Dir{D}; 144e8d8bef9SDimitry Andric llvm::StringSet<> Clauses; 145e8d8bef9SDimitry Andric // Check for duplicates in the three allowed lists. 146e8d8bef9SDimitry Andric if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) || 147e8d8bef9SDimitry Andric HasDuplicateClauses(Dir.getAllowedOnceClauses(), Dir, Clauses) || 148e8d8bef9SDimitry Andric HasDuplicateClauses(Dir.getAllowedExclusiveClauses(), Dir, Clauses)) { 149e8d8bef9SDimitry Andric HasDuplicate = true; 150e8d8bef9SDimitry Andric } 151e8d8bef9SDimitry Andric // Check for duplicate between allowedClauses and required 152e8d8bef9SDimitry Andric Clauses.clear(); 153e8d8bef9SDimitry Andric if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) || 154e8d8bef9SDimitry Andric HasDuplicateClauses(Dir.getRequiredClauses(), Dir, Clauses)) { 155e8d8bef9SDimitry Andric HasDuplicate = true; 156e8d8bef9SDimitry Andric } 157e8d8bef9SDimitry Andric if (HasDuplicate) 158e8d8bef9SDimitry Andric PrintFatalError("One or more clauses are defined multiple times on" 159e8d8bef9SDimitry Andric " directive " + 160e8d8bef9SDimitry Andric Dir.getRecordName()); 161e8d8bef9SDimitry Andric } 162e8d8bef9SDimitry Andric 163e8d8bef9SDimitry Andric return HasDuplicate; 164e8d8bef9SDimitry Andric } 165e8d8bef9SDimitry Andric 166e8d8bef9SDimitry Andric // Check consitency of records. Return true if an error has been detected. 167e8d8bef9SDimitry Andric // Return false if the records are valid. 168e8d8bef9SDimitry Andric bool DirectiveLanguage::HasValidityErrors() const { 169e8d8bef9SDimitry Andric if (getDirectiveLanguages().size() != 1) { 170e8d8bef9SDimitry Andric PrintFatalError("A single definition of DirectiveLanguage is needed."); 171e8d8bef9SDimitry Andric return true; 172e8d8bef9SDimitry Andric } 173e8d8bef9SDimitry Andric 174e8d8bef9SDimitry Andric return HasDuplicateClausesInDirectives(getDirectives()); 175e8d8bef9SDimitry Andric } 176e8d8bef9SDimitry Andric 1775ffd83dbSDimitry Andric // Generate the declaration section for the enumeration in the directive 1785ffd83dbSDimitry Andric // language 179*06c3fb27SDimitry Andric static void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) { 180e8d8bef9SDimitry Andric const auto DirLang = DirectiveLanguage{Records}; 181e8d8bef9SDimitry Andric if (DirLang.HasValidityErrors()) 1825ffd83dbSDimitry Andric return; 1835ffd83dbSDimitry Andric 184e8d8bef9SDimitry Andric OS << "#ifndef LLVM_" << DirLang.getName() << "_INC\n"; 185e8d8bef9SDimitry Andric OS << "#define LLVM_" << DirLang.getName() << "_INC\n"; 1865ffd83dbSDimitry Andric 187e8d8bef9SDimitry Andric if (DirLang.hasEnableBitmaskEnumInNamespace()) 1885ffd83dbSDimitry Andric OS << "\n#include \"llvm/ADT/BitmaskEnum.h\"\n"; 1895ffd83dbSDimitry Andric 1905ffd83dbSDimitry Andric OS << "\n"; 1915ffd83dbSDimitry Andric OS << "namespace llvm {\n"; 1925ffd83dbSDimitry Andric OS << "class StringRef;\n"; 1935ffd83dbSDimitry Andric 1945ffd83dbSDimitry Andric // Open namespaces defined in the directive language 1955ffd83dbSDimitry Andric llvm::SmallVector<StringRef, 2> Namespaces; 196e8d8bef9SDimitry Andric llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::"); 1975ffd83dbSDimitry Andric for (auto Ns : Namespaces) 1985ffd83dbSDimitry Andric OS << "namespace " << Ns << " {\n"; 1995ffd83dbSDimitry Andric 200e8d8bef9SDimitry Andric if (DirLang.hasEnableBitmaskEnumInNamespace()) 2015ffd83dbSDimitry Andric OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n"; 2025ffd83dbSDimitry Andric 2035ffd83dbSDimitry Andric // Emit Directive enumeration 204e8d8bef9SDimitry Andric GenerateEnumClass(DirLang.getDirectives(), OS, "Directive", 205e8d8bef9SDimitry Andric DirLang.getDirectivePrefix(), DirLang); 2065ffd83dbSDimitry Andric 2075ffd83dbSDimitry Andric // Emit Clause enumeration 208e8d8bef9SDimitry Andric GenerateEnumClass(DirLang.getClauses(), OS, "Clause", 209e8d8bef9SDimitry Andric DirLang.getClausePrefix(), DirLang); 210e8d8bef9SDimitry Andric 211e8d8bef9SDimitry Andric // Emit ClauseVal enumeration 212e8d8bef9SDimitry Andric std::string EnumHelperFuncs; 213e8d8bef9SDimitry Andric GenerateEnumClauseVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs); 2145ffd83dbSDimitry Andric 2155ffd83dbSDimitry Andric // Generic function signatures 2165ffd83dbSDimitry Andric OS << "\n"; 2175ffd83dbSDimitry Andric OS << "// Enumeration helper functions\n"; 218e8d8bef9SDimitry Andric OS << "Directive get" << DirLang.getName() 2195ffd83dbSDimitry Andric << "DirectiveKind(llvm::StringRef Str);\n"; 2205ffd83dbSDimitry Andric OS << "\n"; 221e8d8bef9SDimitry Andric OS << "llvm::StringRef get" << DirLang.getName() 2225ffd83dbSDimitry Andric << "DirectiveName(Directive D);\n"; 2235ffd83dbSDimitry Andric OS << "\n"; 224e8d8bef9SDimitry Andric OS << "Clause get" << DirLang.getName() 225e8d8bef9SDimitry Andric << "ClauseKind(llvm::StringRef Str);\n"; 2265ffd83dbSDimitry Andric OS << "\n"; 227e8d8bef9SDimitry Andric OS << "llvm::StringRef get" << DirLang.getName() << "ClauseName(Clause C);\n"; 2285ffd83dbSDimitry Andric OS << "\n"; 2295ffd83dbSDimitry Andric OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p " 2305ffd83dbSDimitry Andric << "Version.\n"; 2315ffd83dbSDimitry Andric OS << "bool isAllowedClauseForDirective(Directive D, " 2325ffd83dbSDimitry Andric << "Clause C, unsigned Version);\n"; 2335ffd83dbSDimitry Andric OS << "\n"; 234e8d8bef9SDimitry Andric if (EnumHelperFuncs.length() > 0) { 235e8d8bef9SDimitry Andric OS << EnumHelperFuncs; 236e8d8bef9SDimitry Andric OS << "\n"; 237e8d8bef9SDimitry Andric } 2385ffd83dbSDimitry Andric 2395ffd83dbSDimitry Andric // Closing namespaces 2405ffd83dbSDimitry Andric for (auto Ns : llvm::reverse(Namespaces)) 2415ffd83dbSDimitry Andric OS << "} // namespace " << Ns << "\n"; 2425ffd83dbSDimitry Andric 2435ffd83dbSDimitry Andric OS << "} // namespace llvm\n"; 2445ffd83dbSDimitry Andric 245e8d8bef9SDimitry Andric OS << "#endif // LLVM_" << DirLang.getName() << "_INC\n"; 2465ffd83dbSDimitry Andric } 2475ffd83dbSDimitry Andric 2485ffd83dbSDimitry Andric // Generate function implementation for get<Enum>Name(StringRef Str) 249*06c3fb27SDimitry Andric static void GenerateGetName(const std::vector<Record *> &Records, 250*06c3fb27SDimitry Andric raw_ostream &OS, StringRef Enum, 251*06c3fb27SDimitry Andric const DirectiveLanguage &DirLang, 252e8d8bef9SDimitry Andric StringRef Prefix) { 2535ffd83dbSDimitry Andric OS << "\n"; 254e8d8bef9SDimitry Andric OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get" 255e8d8bef9SDimitry Andric << DirLang.getName() << Enum << "Name(" << Enum << " Kind) {\n"; 2565ffd83dbSDimitry Andric OS << " switch (Kind) {\n"; 2575ffd83dbSDimitry Andric for (const auto &R : Records) { 258e8d8bef9SDimitry Andric BaseRecord Rec{R}; 259e8d8bef9SDimitry Andric OS << " case " << Prefix << Rec.getFormattedName() << ":\n"; 2605ffd83dbSDimitry Andric OS << " return \""; 261e8d8bef9SDimitry Andric if (Rec.getAlternativeName().empty()) 262e8d8bef9SDimitry Andric OS << Rec.getName(); 2635ffd83dbSDimitry Andric else 264e8d8bef9SDimitry Andric OS << Rec.getAlternativeName(); 2655ffd83dbSDimitry Andric OS << "\";\n"; 2665ffd83dbSDimitry Andric } 2675ffd83dbSDimitry Andric OS << " }\n"; // switch 268e8d8bef9SDimitry Andric OS << " llvm_unreachable(\"Invalid " << DirLang.getName() << " " << Enum 2695ffd83dbSDimitry Andric << " kind\");\n"; 2705ffd83dbSDimitry Andric OS << "}\n"; 2715ffd83dbSDimitry Andric } 2725ffd83dbSDimitry Andric 2735ffd83dbSDimitry Andric // Generate function implementation for get<Enum>Kind(StringRef Str) 274*06c3fb27SDimitry Andric static void GenerateGetKind(const std::vector<Record *> &Records, 275*06c3fb27SDimitry Andric raw_ostream &OS, StringRef Enum, 276*06c3fb27SDimitry Andric const DirectiveLanguage &DirLang, StringRef Prefix, 277*06c3fb27SDimitry Andric bool ImplicitAsUnknown) { 2785ffd83dbSDimitry Andric 279e8d8bef9SDimitry Andric auto DefaultIt = llvm::find_if( 280e8d8bef9SDimitry Andric Records, [](Record *R) { return R->getValueAsBit("isDefault") == true; }); 2815ffd83dbSDimitry Andric 2825ffd83dbSDimitry Andric if (DefaultIt == Records.end()) { 283e8d8bef9SDimitry Andric PrintError("At least one " + Enum + " must be defined as default."); 2845ffd83dbSDimitry Andric return; 2855ffd83dbSDimitry Andric } 2865ffd83dbSDimitry Andric 287e8d8bef9SDimitry Andric BaseRecord DefaultRec{(*DefaultIt)}; 2885ffd83dbSDimitry Andric 2895ffd83dbSDimitry Andric OS << "\n"; 290e8d8bef9SDimitry Andric OS << Enum << " llvm::" << DirLang.getCppNamespace() << "::get" 291e8d8bef9SDimitry Andric << DirLang.getName() << Enum << "Kind(llvm::StringRef Str) {\n"; 2925ffd83dbSDimitry Andric OS << " return llvm::StringSwitch<" << Enum << ">(Str)\n"; 2935ffd83dbSDimitry Andric 2945ffd83dbSDimitry Andric for (const auto &R : Records) { 295e8d8bef9SDimitry Andric BaseRecord Rec{R}; 2965ffd83dbSDimitry Andric if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) { 297e8d8bef9SDimitry Andric OS << " .Case(\"" << Rec.getName() << "\"," << Prefix 298e8d8bef9SDimitry Andric << DefaultRec.getFormattedName() << ")\n"; 2995ffd83dbSDimitry Andric } else { 300e8d8bef9SDimitry Andric OS << " .Case(\"" << Rec.getName() << "\"," << Prefix 301e8d8bef9SDimitry Andric << Rec.getFormattedName() << ")\n"; 302e8d8bef9SDimitry Andric } 303e8d8bef9SDimitry Andric } 304e8d8bef9SDimitry Andric OS << " .Default(" << Prefix << DefaultRec.getFormattedName() << ");\n"; 305e8d8bef9SDimitry Andric OS << "}\n"; 306e8d8bef9SDimitry Andric } 307e8d8bef9SDimitry Andric 308e8d8bef9SDimitry Andric // Generate function implementation for get<ClauseVal>Kind(StringRef Str) 309*06c3fb27SDimitry Andric static void GenerateGetKindClauseVal(const DirectiveLanguage &DirLang, 310e8d8bef9SDimitry Andric raw_ostream &OS) { 311e8d8bef9SDimitry Andric for (const auto &R : DirLang.getClauses()) { 312e8d8bef9SDimitry Andric Clause C{R}; 313e8d8bef9SDimitry Andric const auto &ClauseVals = C.getClauseVals(); 314e8d8bef9SDimitry Andric if (ClauseVals.size() <= 0) 315e8d8bef9SDimitry Andric continue; 316e8d8bef9SDimitry Andric 317e8d8bef9SDimitry Andric auto DefaultIt = llvm::find_if(ClauseVals, [](Record *CV) { 318e8d8bef9SDimitry Andric return CV->getValueAsBit("isDefault") == true; 319e8d8bef9SDimitry Andric }); 320e8d8bef9SDimitry Andric 321e8d8bef9SDimitry Andric if (DefaultIt == ClauseVals.end()) { 322e8d8bef9SDimitry Andric PrintError("At least one val in Clause " + C.getFormattedName() + 323e8d8bef9SDimitry Andric " must be defined as default."); 324e8d8bef9SDimitry Andric return; 325e8d8bef9SDimitry Andric } 326e8d8bef9SDimitry Andric const auto DefaultName = (*DefaultIt)->getName(); 327e8d8bef9SDimitry Andric 328e8d8bef9SDimitry Andric const auto &EnumName = C.getEnumName(); 329e8d8bef9SDimitry Andric if (EnumName.size() == 0) { 330e8d8bef9SDimitry Andric PrintError("enumClauseValue field not set in Clause" + 331e8d8bef9SDimitry Andric C.getFormattedName() + "."); 332e8d8bef9SDimitry Andric return; 333e8d8bef9SDimitry Andric } 334e8d8bef9SDimitry Andric 335e8d8bef9SDimitry Andric OS << "\n"; 336e8d8bef9SDimitry Andric OS << EnumName << " llvm::" << DirLang.getCppNamespace() << "::get" 337e8d8bef9SDimitry Andric << EnumName << "(llvm::StringRef Str) {\n"; 338e8d8bef9SDimitry Andric OS << " return llvm::StringSwitch<" << EnumName << ">(Str)\n"; 339e8d8bef9SDimitry Andric for (const auto &CV : ClauseVals) { 340e8d8bef9SDimitry Andric ClauseVal CVal{CV}; 341e8d8bef9SDimitry Andric OS << " .Case(\"" << CVal.getFormattedName() << "\"," << CV->getName() 3425ffd83dbSDimitry Andric << ")\n"; 3435ffd83dbSDimitry Andric } 344e8d8bef9SDimitry Andric OS << " .Default(" << DefaultName << ");\n"; 3455ffd83dbSDimitry Andric OS << "}\n"; 346e8d8bef9SDimitry Andric 347e8d8bef9SDimitry Andric OS << "\n"; 348e8d8bef9SDimitry Andric OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get" 349e8d8bef9SDimitry Andric << DirLang.getName() << EnumName 350e8d8bef9SDimitry Andric << "Name(llvm::" << DirLang.getCppNamespace() << "::" << EnumName 351e8d8bef9SDimitry Andric << " x) {\n"; 352e8d8bef9SDimitry Andric OS << " switch (x) {\n"; 353e8d8bef9SDimitry Andric for (const auto &CV : ClauseVals) { 354e8d8bef9SDimitry Andric ClauseVal CVal{CV}; 355e8d8bef9SDimitry Andric OS << " case " << CV->getName() << ":\n"; 356e8d8bef9SDimitry Andric OS << " return \"" << CVal.getFormattedName() << "\";\n"; 357e8d8bef9SDimitry Andric } 358e8d8bef9SDimitry Andric OS << " }\n"; // switch 359e8d8bef9SDimitry Andric OS << " llvm_unreachable(\"Invalid " << DirLang.getName() << " " 360e8d8bef9SDimitry Andric << EnumName << " kind\");\n"; 361e8d8bef9SDimitry Andric OS << "}\n"; 362e8d8bef9SDimitry Andric } 3635ffd83dbSDimitry Andric } 3645ffd83dbSDimitry Andric 365*06c3fb27SDimitry Andric static void 366*06c3fb27SDimitry Andric GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses, 3675ffd83dbSDimitry Andric raw_ostream &OS, StringRef DirectiveName, 368e8d8bef9SDimitry Andric const DirectiveLanguage &DirLang, 3695ffd83dbSDimitry Andric llvm::StringSet<> &Cases) { 3705ffd83dbSDimitry Andric for (const auto &C : Clauses) { 371e8d8bef9SDimitry Andric VersionedClause VerClause{C}; 3725ffd83dbSDimitry Andric 373e8d8bef9SDimitry Andric const auto ClauseFormattedName = VerClause.getClause().getFormattedName(); 374e8d8bef9SDimitry Andric 37581ad6265SDimitry Andric if (Cases.insert(ClauseFormattedName).second) { 376e8d8bef9SDimitry Andric OS << " case " << DirLang.getClausePrefix() << ClauseFormattedName 377e8d8bef9SDimitry Andric << ":\n"; 378e8d8bef9SDimitry Andric OS << " return " << VerClause.getMinVersion() 379e8d8bef9SDimitry Andric << " <= Version && " << VerClause.getMaxVersion() << " >= Version;\n"; 3805ffd83dbSDimitry Andric } 3815ffd83dbSDimitry Andric } 3825ffd83dbSDimitry Andric } 3835ffd83dbSDimitry Andric 3845ffd83dbSDimitry Andric // Generate the isAllowedClauseForDirective function implementation. 385*06c3fb27SDimitry Andric static void GenerateIsAllowedClause(const DirectiveLanguage &DirLang, 386e8d8bef9SDimitry Andric raw_ostream &OS) { 3875ffd83dbSDimitry Andric OS << "\n"; 388e8d8bef9SDimitry Andric OS << "bool llvm::" << DirLang.getCppNamespace() 389e8d8bef9SDimitry Andric << "::isAllowedClauseForDirective(" 3905ffd83dbSDimitry Andric << "Directive D, Clause C, unsigned Version) {\n"; 391e8d8bef9SDimitry Andric OS << " assert(unsigned(D) <= llvm::" << DirLang.getCppNamespace() 3925ffd83dbSDimitry Andric << "::Directive_enumSize);\n"; 393e8d8bef9SDimitry Andric OS << " assert(unsigned(C) <= llvm::" << DirLang.getCppNamespace() 3945ffd83dbSDimitry Andric << "::Clause_enumSize);\n"; 3955ffd83dbSDimitry Andric 3965ffd83dbSDimitry Andric OS << " switch (D) {\n"; 3975ffd83dbSDimitry Andric 398e8d8bef9SDimitry Andric for (const auto &D : DirLang.getDirectives()) { 399e8d8bef9SDimitry Andric Directive Dir{D}; 4005ffd83dbSDimitry Andric 401e8d8bef9SDimitry Andric OS << " case " << DirLang.getDirectivePrefix() << Dir.getFormattedName() 4025ffd83dbSDimitry Andric << ":\n"; 403e8d8bef9SDimitry Andric if (Dir.getAllowedClauses().size() == 0 && 404e8d8bef9SDimitry Andric Dir.getAllowedOnceClauses().size() == 0 && 405e8d8bef9SDimitry Andric Dir.getAllowedExclusiveClauses().size() == 0 && 406e8d8bef9SDimitry Andric Dir.getRequiredClauses().size() == 0) { 4075ffd83dbSDimitry Andric OS << " return false;\n"; 4085ffd83dbSDimitry Andric } else { 4095ffd83dbSDimitry Andric OS << " switch (C) {\n"; 4105ffd83dbSDimitry Andric 4115ffd83dbSDimitry Andric llvm::StringSet<> Cases; 4125ffd83dbSDimitry Andric 413e8d8bef9SDimitry Andric GenerateCaseForVersionedClauses(Dir.getAllowedClauses(), OS, 414e8d8bef9SDimitry Andric Dir.getName(), DirLang, Cases); 4155ffd83dbSDimitry Andric 416e8d8bef9SDimitry Andric GenerateCaseForVersionedClauses(Dir.getAllowedOnceClauses(), OS, 417e8d8bef9SDimitry Andric Dir.getName(), DirLang, Cases); 4185ffd83dbSDimitry Andric 419e8d8bef9SDimitry Andric GenerateCaseForVersionedClauses(Dir.getAllowedExclusiveClauses(), OS, 420e8d8bef9SDimitry Andric Dir.getName(), DirLang, Cases); 4215ffd83dbSDimitry Andric 422e8d8bef9SDimitry Andric GenerateCaseForVersionedClauses(Dir.getRequiredClauses(), OS, 423e8d8bef9SDimitry Andric Dir.getName(), DirLang, Cases); 4245ffd83dbSDimitry Andric 4255ffd83dbSDimitry Andric OS << " default:\n"; 4265ffd83dbSDimitry Andric OS << " return false;\n"; 4275ffd83dbSDimitry Andric OS << " }\n"; // End of clauses switch 4285ffd83dbSDimitry Andric } 4295ffd83dbSDimitry Andric OS << " break;\n"; 4305ffd83dbSDimitry Andric } 4315ffd83dbSDimitry Andric 4325ffd83dbSDimitry Andric OS << " }\n"; // End of directives switch 433e8d8bef9SDimitry Andric OS << " llvm_unreachable(\"Invalid " << DirLang.getName() 4345ffd83dbSDimitry Andric << " Directive kind\");\n"; 4355ffd83dbSDimitry Andric OS << "}\n"; // End of function isAllowedClauseForDirective 4365ffd83dbSDimitry Andric } 4375ffd83dbSDimitry Andric 4385ffd83dbSDimitry Andric // Generate a simple enum set with the give clauses. 439*06c3fb27SDimitry Andric static void GenerateClauseSet(const std::vector<Record *> &Clauses, 440*06c3fb27SDimitry Andric raw_ostream &OS, StringRef ClauseSetPrefix, 441*06c3fb27SDimitry Andric Directive &Dir, 442e8d8bef9SDimitry Andric const DirectiveLanguage &DirLang) { 4435ffd83dbSDimitry Andric 4445ffd83dbSDimitry Andric OS << "\n"; 445e8d8bef9SDimitry Andric OS << " static " << DirLang.getClauseEnumSetClass() << " " << ClauseSetPrefix 446e8d8bef9SDimitry Andric << DirLang.getDirectivePrefix() << Dir.getFormattedName() << " {\n"; 4475ffd83dbSDimitry Andric 4485ffd83dbSDimitry Andric for (const auto &C : Clauses) { 449e8d8bef9SDimitry Andric VersionedClause VerClause{C}; 450e8d8bef9SDimitry Andric OS << " llvm::" << DirLang.getCppNamespace() 451e8d8bef9SDimitry Andric << "::Clause::" << DirLang.getClausePrefix() 452e8d8bef9SDimitry Andric << VerClause.getClause().getFormattedName() << ",\n"; 4535ffd83dbSDimitry Andric } 4545ffd83dbSDimitry Andric OS << " };\n"; 4555ffd83dbSDimitry Andric } 4565ffd83dbSDimitry Andric 4575ffd83dbSDimitry Andric // Generate an enum set for the 4 kinds of clauses linked to a directive. 458*06c3fb27SDimitry Andric static void GenerateDirectiveClauseSets(const DirectiveLanguage &DirLang, 459e8d8bef9SDimitry Andric raw_ostream &OS) { 4605ffd83dbSDimitry Andric 4615ffd83dbSDimitry Andric IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_SETS", OS); 4625ffd83dbSDimitry Andric 4635ffd83dbSDimitry Andric OS << "\n"; 4645ffd83dbSDimitry Andric OS << "namespace llvm {\n"; 4655ffd83dbSDimitry Andric 4665ffd83dbSDimitry Andric // Open namespaces defined in the directive language. 4675ffd83dbSDimitry Andric llvm::SmallVector<StringRef, 2> Namespaces; 468e8d8bef9SDimitry Andric llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::"); 4695ffd83dbSDimitry Andric for (auto Ns : Namespaces) 4705ffd83dbSDimitry Andric OS << "namespace " << Ns << " {\n"; 4715ffd83dbSDimitry Andric 472e8d8bef9SDimitry Andric for (const auto &D : DirLang.getDirectives()) { 473e8d8bef9SDimitry Andric Directive Dir{D}; 4745ffd83dbSDimitry Andric 4755ffd83dbSDimitry Andric OS << "\n"; 476e8d8bef9SDimitry Andric OS << " // Sets for " << Dir.getName() << "\n"; 4775ffd83dbSDimitry Andric 478e8d8bef9SDimitry Andric GenerateClauseSet(Dir.getAllowedClauses(), OS, "allowedClauses_", Dir, 479e8d8bef9SDimitry Andric DirLang); 480e8d8bef9SDimitry Andric GenerateClauseSet(Dir.getAllowedOnceClauses(), OS, "allowedOnceClauses_", 481e8d8bef9SDimitry Andric Dir, DirLang); 482e8d8bef9SDimitry Andric GenerateClauseSet(Dir.getAllowedExclusiveClauses(), OS, 483e8d8bef9SDimitry Andric "allowedExclusiveClauses_", Dir, DirLang); 484e8d8bef9SDimitry Andric GenerateClauseSet(Dir.getRequiredClauses(), OS, "requiredClauses_", Dir, 485e8d8bef9SDimitry Andric DirLang); 4865ffd83dbSDimitry Andric } 4875ffd83dbSDimitry Andric 4885ffd83dbSDimitry Andric // Closing namespaces 4895ffd83dbSDimitry Andric for (auto Ns : llvm::reverse(Namespaces)) 4905ffd83dbSDimitry Andric OS << "} // namespace " << Ns << "\n"; 4915ffd83dbSDimitry Andric 4925ffd83dbSDimitry Andric OS << "} // namespace llvm\n"; 4935ffd83dbSDimitry Andric } 4945ffd83dbSDimitry Andric 4955ffd83dbSDimitry Andric // Generate a map of directive (key) with DirectiveClauses struct as values. 4965ffd83dbSDimitry Andric // The struct holds the 4 sets of enumeration for the 4 kinds of clauses 4975ffd83dbSDimitry Andric // allowances (allowed, allowed once, allowed exclusive and required). 498*06c3fb27SDimitry Andric static void GenerateDirectiveClauseMap(const DirectiveLanguage &DirLang, 499e8d8bef9SDimitry Andric raw_ostream &OS) { 5005ffd83dbSDimitry Andric 5015ffd83dbSDimitry Andric IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_MAP", OS); 5025ffd83dbSDimitry Andric 5035ffd83dbSDimitry Andric OS << "\n"; 5045ffd83dbSDimitry Andric OS << "{\n"; 505e8d8bef9SDimitry Andric 506e8d8bef9SDimitry Andric for (const auto &D : DirLang.getDirectives()) { 507e8d8bef9SDimitry Andric Directive Dir{D}; 508e8d8bef9SDimitry Andric OS << " {llvm::" << DirLang.getCppNamespace() 509e8d8bef9SDimitry Andric << "::Directive::" << DirLang.getDirectivePrefix() 510e8d8bef9SDimitry Andric << Dir.getFormattedName() << ",\n"; 511e8d8bef9SDimitry Andric OS << " {\n"; 512e8d8bef9SDimitry Andric OS << " llvm::" << DirLang.getCppNamespace() << "::allowedClauses_" 513e8d8bef9SDimitry Andric << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n"; 514e8d8bef9SDimitry Andric OS << " llvm::" << DirLang.getCppNamespace() << "::allowedOnceClauses_" 515e8d8bef9SDimitry Andric << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n"; 516e8d8bef9SDimitry Andric OS << " llvm::" << DirLang.getCppNamespace() 517e8d8bef9SDimitry Andric << "::allowedExclusiveClauses_" << DirLang.getDirectivePrefix() 518e8d8bef9SDimitry Andric << Dir.getFormattedName() << ",\n"; 519e8d8bef9SDimitry Andric OS << " llvm::" << DirLang.getCppNamespace() << "::requiredClauses_" 520e8d8bef9SDimitry Andric << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n"; 5215ffd83dbSDimitry Andric OS << " }\n"; 5225ffd83dbSDimitry Andric OS << " },\n"; 5235ffd83dbSDimitry Andric } 5245ffd83dbSDimitry Andric 525e8d8bef9SDimitry Andric OS << "}\n"; 5265ffd83dbSDimitry Andric } 5275ffd83dbSDimitry Andric 528e8d8bef9SDimitry Andric // Generate classes entry for Flang clauses in the Flang parse-tree 529e8d8bef9SDimitry Andric // If the clause as a non-generic class, no entry is generated. 530e8d8bef9SDimitry Andric // If the clause does not hold a value, an EMPTY_CLASS is used. 531e8d8bef9SDimitry Andric // If the clause class is generic then a WRAPPER_CLASS is used. When the value 532e8d8bef9SDimitry Andric // is optional, the value class is wrapped into a std::optional. 533*06c3fb27SDimitry Andric static void GenerateFlangClauseParserClass(const DirectiveLanguage &DirLang, 534e8d8bef9SDimitry Andric raw_ostream &OS) { 535e8d8bef9SDimitry Andric 536e8d8bef9SDimitry Andric IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS); 537e8d8bef9SDimitry Andric 538e8d8bef9SDimitry Andric OS << "\n"; 539e8d8bef9SDimitry Andric 540e8d8bef9SDimitry Andric for (const auto &C : DirLang.getClauses()) { 541e8d8bef9SDimitry Andric Clause Clause{C}; 542e8d8bef9SDimitry Andric if (!Clause.getFlangClass().empty()) { 543e8d8bef9SDimitry Andric OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName() << ", "; 544e8d8bef9SDimitry Andric if (Clause.isValueOptional() && Clause.isValueList()) { 545e8d8bef9SDimitry Andric OS << "std::optional<std::list<" << Clause.getFlangClass() << ">>"; 546e8d8bef9SDimitry Andric } else if (Clause.isValueOptional()) { 547e8d8bef9SDimitry Andric OS << "std::optional<" << Clause.getFlangClass() << ">"; 548e8d8bef9SDimitry Andric } else if (Clause.isValueList()) { 549e8d8bef9SDimitry Andric OS << "std::list<" << Clause.getFlangClass() << ">"; 550e8d8bef9SDimitry Andric } else { 551e8d8bef9SDimitry Andric OS << Clause.getFlangClass(); 552e8d8bef9SDimitry Andric } 553e8d8bef9SDimitry Andric } else { 554e8d8bef9SDimitry Andric OS << "EMPTY_CLASS(" << Clause.getFormattedParserClassName(); 555e8d8bef9SDimitry Andric } 556e8d8bef9SDimitry Andric OS << ");\n"; 557e8d8bef9SDimitry Andric } 558e8d8bef9SDimitry Andric } 559e8d8bef9SDimitry Andric 560e8d8bef9SDimitry Andric // Generate a list of the different clause classes for Flang. 561*06c3fb27SDimitry Andric static void GenerateFlangClauseParserClassList(const DirectiveLanguage &DirLang, 562e8d8bef9SDimitry Andric raw_ostream &OS) { 563e8d8bef9SDimitry Andric 564e8d8bef9SDimitry Andric IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS); 565e8d8bef9SDimitry Andric 566e8d8bef9SDimitry Andric OS << "\n"; 567e8d8bef9SDimitry Andric llvm::interleaveComma(DirLang.getClauses(), OS, [&](Record *C) { 568e8d8bef9SDimitry Andric Clause Clause{C}; 569e8d8bef9SDimitry Andric OS << Clause.getFormattedParserClassName() << "\n"; 570e8d8bef9SDimitry Andric }); 571e8d8bef9SDimitry Andric } 572e8d8bef9SDimitry Andric 573e8d8bef9SDimitry Andric // Generate dump node list for the clauses holding a generic class name. 574*06c3fb27SDimitry Andric static void GenerateFlangClauseDump(const DirectiveLanguage &DirLang, 575e8d8bef9SDimitry Andric raw_ostream &OS) { 576e8d8bef9SDimitry Andric 577e8d8bef9SDimitry Andric IfDefScope Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS); 578e8d8bef9SDimitry Andric 579e8d8bef9SDimitry Andric OS << "\n"; 580e8d8bef9SDimitry Andric for (const auto &C : DirLang.getClauses()) { 581e8d8bef9SDimitry Andric Clause Clause{C}; 582e8d8bef9SDimitry Andric OS << "NODE(" << DirLang.getFlangClauseBaseClass() << ", " 583e8d8bef9SDimitry Andric << Clause.getFormattedParserClassName() << ")\n"; 584e8d8bef9SDimitry Andric } 585e8d8bef9SDimitry Andric } 586e8d8bef9SDimitry Andric 587e8d8bef9SDimitry Andric // Generate Unparse functions for clauses classes in the Flang parse-tree 588e8d8bef9SDimitry Andric // If the clause is a non-generic class, no entry is generated. 589*06c3fb27SDimitry Andric static void GenerateFlangClauseUnparse(const DirectiveLanguage &DirLang, 590e8d8bef9SDimitry Andric raw_ostream &OS) { 591e8d8bef9SDimitry Andric 592e8d8bef9SDimitry Andric IfDefScope Scope("GEN_FLANG_CLAUSE_UNPARSE", OS); 593e8d8bef9SDimitry Andric 594e8d8bef9SDimitry Andric OS << "\n"; 595e8d8bef9SDimitry Andric 596e8d8bef9SDimitry Andric for (const auto &C : DirLang.getClauses()) { 597e8d8bef9SDimitry Andric Clause Clause{C}; 598e8d8bef9SDimitry Andric if (!Clause.getFlangClass().empty()) { 599e8d8bef9SDimitry Andric if (Clause.isValueOptional() && Clause.getDefaultValue().empty()) { 600e8d8bef9SDimitry Andric OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass() 601e8d8bef9SDimitry Andric << "::" << Clause.getFormattedParserClassName() << " &x) {\n"; 602e8d8bef9SDimitry Andric OS << " Word(\"" << Clause.getName().upper() << "\");\n"; 603e8d8bef9SDimitry Andric 604e8d8bef9SDimitry Andric OS << " Walk(\"(\", x.v, \")\");\n"; 605e8d8bef9SDimitry Andric OS << "}\n"; 606e8d8bef9SDimitry Andric } else if (Clause.isValueOptional()) { 607e8d8bef9SDimitry Andric OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass() 608e8d8bef9SDimitry Andric << "::" << Clause.getFormattedParserClassName() << " &x) {\n"; 609e8d8bef9SDimitry Andric OS << " Word(\"" << Clause.getName().upper() << "\");\n"; 610e8d8bef9SDimitry Andric OS << " Put(\"(\");\n"; 611e8d8bef9SDimitry Andric OS << " if (x.v.has_value())\n"; 612e8d8bef9SDimitry Andric if (Clause.isValueList()) 613e8d8bef9SDimitry Andric OS << " Walk(x.v, \",\");\n"; 614e8d8bef9SDimitry Andric else 615e8d8bef9SDimitry Andric OS << " Walk(x.v);\n"; 616e8d8bef9SDimitry Andric OS << " else\n"; 617e8d8bef9SDimitry Andric OS << " Put(\"" << Clause.getDefaultValue() << "\");\n"; 618e8d8bef9SDimitry Andric OS << " Put(\")\");\n"; 619e8d8bef9SDimitry Andric OS << "}\n"; 620e8d8bef9SDimitry Andric } else { 621e8d8bef9SDimitry Andric OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass() 622e8d8bef9SDimitry Andric << "::" << Clause.getFormattedParserClassName() << " &x) {\n"; 623e8d8bef9SDimitry Andric OS << " Word(\"" << Clause.getName().upper() << "\");\n"; 624e8d8bef9SDimitry Andric OS << " Put(\"(\");\n"; 625e8d8bef9SDimitry Andric if (Clause.isValueList()) 626e8d8bef9SDimitry Andric OS << " Walk(x.v, \",\");\n"; 627e8d8bef9SDimitry Andric else 628e8d8bef9SDimitry Andric OS << " Walk(x.v);\n"; 629e8d8bef9SDimitry Andric OS << " Put(\")\");\n"; 630e8d8bef9SDimitry Andric OS << "}\n"; 631e8d8bef9SDimitry Andric } 632e8d8bef9SDimitry Andric } else { 633e8d8bef9SDimitry Andric OS << "void Before(const " << DirLang.getFlangClauseBaseClass() 634e8d8bef9SDimitry Andric << "::" << Clause.getFormattedParserClassName() << " &) { Word(\"" 635e8d8bef9SDimitry Andric << Clause.getName().upper() << "\"); }\n"; 636e8d8bef9SDimitry Andric } 637e8d8bef9SDimitry Andric } 638e8d8bef9SDimitry Andric } 639e8d8bef9SDimitry Andric 640fe6060f1SDimitry Andric // Generate check in the Enter functions for clauses classes. 641*06c3fb27SDimitry Andric static void GenerateFlangClauseCheckPrototypes(const DirectiveLanguage &DirLang, 642fe6060f1SDimitry Andric raw_ostream &OS) { 643fe6060f1SDimitry Andric 644fe6060f1SDimitry Andric IfDefScope Scope("GEN_FLANG_CLAUSE_CHECK_ENTER", OS); 645fe6060f1SDimitry Andric 646fe6060f1SDimitry Andric OS << "\n"; 647fe6060f1SDimitry Andric for (const auto &C : DirLang.getClauses()) { 648fe6060f1SDimitry Andric Clause Clause{C}; 649fe6060f1SDimitry Andric OS << "void Enter(const parser::" << DirLang.getFlangClauseBaseClass() 650fe6060f1SDimitry Andric << "::" << Clause.getFormattedParserClassName() << " &);\n"; 651fe6060f1SDimitry Andric } 652fe6060f1SDimitry Andric } 653fe6060f1SDimitry Andric 654fe6060f1SDimitry Andric // Generate the mapping for clauses between the parser class and the 655fe6060f1SDimitry Andric // corresponding clause Kind 656*06c3fb27SDimitry Andric static void GenerateFlangClauseParserKindMap(const DirectiveLanguage &DirLang, 657fe6060f1SDimitry Andric raw_ostream &OS) { 658fe6060f1SDimitry Andric 659fe6060f1SDimitry Andric IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_KIND_MAP", OS); 660fe6060f1SDimitry Andric 661fe6060f1SDimitry Andric OS << "\n"; 662fe6060f1SDimitry Andric for (const auto &C : DirLang.getClauses()) { 663fe6060f1SDimitry Andric Clause Clause{C}; 664fe6060f1SDimitry Andric OS << "if constexpr (std::is_same_v<A, parser::" 665fe6060f1SDimitry Andric << DirLang.getFlangClauseBaseClass() 666fe6060f1SDimitry Andric << "::" << Clause.getFormattedParserClassName(); 667fe6060f1SDimitry Andric OS << ">)\n"; 668fe6060f1SDimitry Andric OS << " return llvm::" << DirLang.getCppNamespace() 669fe6060f1SDimitry Andric << "::Clause::" << DirLang.getClausePrefix() << Clause.getFormattedName() 670fe6060f1SDimitry Andric << ";\n"; 671fe6060f1SDimitry Andric } 672fe6060f1SDimitry Andric 673fe6060f1SDimitry Andric OS << "llvm_unreachable(\"Invalid " << DirLang.getName() 674fe6060f1SDimitry Andric << " Parser clause\");\n"; 675fe6060f1SDimitry Andric } 676fe6060f1SDimitry Andric 677*06c3fb27SDimitry Andric static bool compareClauseName(Record *R1, Record *R2) { 678fcaf7f86SDimitry Andric Clause C1{R1}; 679fcaf7f86SDimitry Andric Clause C2{R2}; 680fcaf7f86SDimitry Andric return (C1.getName() > C2.getName()); 681fcaf7f86SDimitry Andric } 682fcaf7f86SDimitry Andric 683fcaf7f86SDimitry Andric // Generate the parser for the clauses. 684*06c3fb27SDimitry Andric static void GenerateFlangClausesParser(const DirectiveLanguage &DirLang, 685fcaf7f86SDimitry Andric raw_ostream &OS) { 686fcaf7f86SDimitry Andric std::vector<Record *> Clauses = DirLang.getClauses(); 687fcaf7f86SDimitry Andric // Sort clauses in reverse alphabetical order so with clauses with same 688fcaf7f86SDimitry Andric // beginning, the longer option is tried before. 689fcaf7f86SDimitry Andric llvm::sort(Clauses, compareClauseName); 690fcaf7f86SDimitry Andric IfDefScope Scope("GEN_FLANG_CLAUSES_PARSER", OS); 691fcaf7f86SDimitry Andric OS << "\n"; 692fcaf7f86SDimitry Andric unsigned index = 0; 693fcaf7f86SDimitry Andric unsigned lastClauseIndex = DirLang.getClauses().size() - 1; 694fcaf7f86SDimitry Andric OS << "TYPE_PARSER(\n"; 695fcaf7f86SDimitry Andric for (const auto &C : Clauses) { 696fcaf7f86SDimitry Andric Clause Clause{C}; 697fcaf7f86SDimitry Andric if (Clause.getAliases().empty()) { 698fcaf7f86SDimitry Andric OS << " \"" << Clause.getName() << "\""; 699fcaf7f86SDimitry Andric } else { 700fcaf7f86SDimitry Andric OS << " (" 701fcaf7f86SDimitry Andric << "\"" << Clause.getName() << "\"_tok"; 702fcaf7f86SDimitry Andric for (StringRef alias : Clause.getAliases()) { 703fcaf7f86SDimitry Andric OS << " || \"" << alias << "\"_tok"; 704fcaf7f86SDimitry Andric } 705fcaf7f86SDimitry Andric OS << ")"; 706fcaf7f86SDimitry Andric } 707fcaf7f86SDimitry Andric 708fcaf7f86SDimitry Andric OS << " >> construct<" << DirLang.getFlangClauseBaseClass() 709fcaf7f86SDimitry Andric << ">(construct<" << DirLang.getFlangClauseBaseClass() 710fcaf7f86SDimitry Andric << "::" << Clause.getFormattedParserClassName() << ">("; 711fcaf7f86SDimitry Andric if (Clause.getFlangClass().empty()) { 712fcaf7f86SDimitry Andric OS << "))"; 713fcaf7f86SDimitry Andric if (index != lastClauseIndex) 714fcaf7f86SDimitry Andric OS << " ||"; 715fcaf7f86SDimitry Andric OS << "\n"; 716fcaf7f86SDimitry Andric ++index; 717fcaf7f86SDimitry Andric continue; 718fcaf7f86SDimitry Andric } 719fcaf7f86SDimitry Andric 720fcaf7f86SDimitry Andric if (Clause.isValueOptional()) 721fcaf7f86SDimitry Andric OS << "maybe("; 722fcaf7f86SDimitry Andric OS << "parenthesized("; 723*06c3fb27SDimitry Andric if (Clause.isValueList()) 724*06c3fb27SDimitry Andric OS << "nonemptyList("; 725fcaf7f86SDimitry Andric 726fcaf7f86SDimitry Andric if (!Clause.getPrefix().empty()) 727fcaf7f86SDimitry Andric OS << "\"" << Clause.getPrefix() << ":\" >> "; 728fcaf7f86SDimitry Andric 729fcaf7f86SDimitry Andric // The common Flang parser are used directly. Their name is identical to 730fcaf7f86SDimitry Andric // the Flang class with first letter as lowercase. If the Flang class is 731fcaf7f86SDimitry Andric // not a common class, we assume there is a specific Parser<>{} with the 732fcaf7f86SDimitry Andric // Flang class name provided. 733fcaf7f86SDimitry Andric llvm::SmallString<128> Scratch; 734fcaf7f86SDimitry Andric StringRef Parser = 735fcaf7f86SDimitry Andric llvm::StringSwitch<StringRef>(Clause.getFlangClass()) 736fcaf7f86SDimitry Andric .Case("Name", "name") 737fcaf7f86SDimitry Andric .Case("ScalarIntConstantExpr", "scalarIntConstantExpr") 738fcaf7f86SDimitry Andric .Case("ScalarIntExpr", "scalarIntExpr") 739fcaf7f86SDimitry Andric .Case("ScalarLogicalExpr", "scalarLogicalExpr") 740fcaf7f86SDimitry Andric .Default(("Parser<" + Clause.getFlangClass() + ">{}") 741fcaf7f86SDimitry Andric .toStringRef(Scratch)); 742fcaf7f86SDimitry Andric OS << Parser; 743fcaf7f86SDimitry Andric if (!Clause.getPrefix().empty() && Clause.isPrefixOptional()) 744fcaf7f86SDimitry Andric OS << " || " << Parser; 745*06c3fb27SDimitry Andric if (Clause.isValueList()) // close nonemptyList(. 746*06c3fb27SDimitry Andric OS << ")"; 747fcaf7f86SDimitry Andric OS << ")"; // close parenthesized(. 748fcaf7f86SDimitry Andric 749fcaf7f86SDimitry Andric if (Clause.isValueOptional()) // close maybe(. 750fcaf7f86SDimitry Andric OS << ")"; 751fcaf7f86SDimitry Andric OS << "))"; 752fcaf7f86SDimitry Andric if (index != lastClauseIndex) 753fcaf7f86SDimitry Andric OS << " ||"; 754fcaf7f86SDimitry Andric OS << "\n"; 755fcaf7f86SDimitry Andric ++index; 756fcaf7f86SDimitry Andric } 757fcaf7f86SDimitry Andric OS << ")\n"; 758fcaf7f86SDimitry Andric } 759fcaf7f86SDimitry Andric 760e8d8bef9SDimitry Andric // Generate the implementation section for the enumeration in the directive 7615ffd83dbSDimitry Andric // language 762*06c3fb27SDimitry Andric static void EmitDirectivesFlangImpl(const DirectiveLanguage &DirLang, 763e8d8bef9SDimitry Andric raw_ostream &OS) { 7645ffd83dbSDimitry Andric 765e8d8bef9SDimitry Andric GenerateDirectiveClauseSets(DirLang, OS); 7665ffd83dbSDimitry Andric 767e8d8bef9SDimitry Andric GenerateDirectiveClauseMap(DirLang, OS); 768e8d8bef9SDimitry Andric 769e8d8bef9SDimitry Andric GenerateFlangClauseParserClass(DirLang, OS); 770e8d8bef9SDimitry Andric 771e8d8bef9SDimitry Andric GenerateFlangClauseParserClassList(DirLang, OS); 772e8d8bef9SDimitry Andric 773e8d8bef9SDimitry Andric GenerateFlangClauseDump(DirLang, OS); 774e8d8bef9SDimitry Andric 775e8d8bef9SDimitry Andric GenerateFlangClauseUnparse(DirLang, OS); 776fe6060f1SDimitry Andric 777fe6060f1SDimitry Andric GenerateFlangClauseCheckPrototypes(DirLang, OS); 778fe6060f1SDimitry Andric 779fe6060f1SDimitry Andric GenerateFlangClauseParserKindMap(DirLang, OS); 780fcaf7f86SDimitry Andric 781fcaf7f86SDimitry Andric GenerateFlangClausesParser(DirLang, OS); 7825ffd83dbSDimitry Andric } 7835ffd83dbSDimitry Andric 784*06c3fb27SDimitry Andric static void GenerateClauseClassMacro(const DirectiveLanguage &DirLang, 785e8d8bef9SDimitry Andric raw_ostream &OS) { 786e8d8bef9SDimitry Andric // Generate macros style information for legacy code in clang 787e8d8bef9SDimitry Andric IfDefScope Scope("GEN_CLANG_CLAUSE_CLASS", OS); 788e8d8bef9SDimitry Andric 789e8d8bef9SDimitry Andric OS << "\n"; 790e8d8bef9SDimitry Andric 791e8d8bef9SDimitry Andric OS << "#ifndef CLAUSE\n"; 792e8d8bef9SDimitry Andric OS << "#define CLAUSE(Enum, Str, Implicit)\n"; 793e8d8bef9SDimitry Andric OS << "#endif\n"; 794e8d8bef9SDimitry Andric OS << "#ifndef CLAUSE_CLASS\n"; 795e8d8bef9SDimitry Andric OS << "#define CLAUSE_CLASS(Enum, Str, Class)\n"; 796e8d8bef9SDimitry Andric OS << "#endif\n"; 797e8d8bef9SDimitry Andric OS << "#ifndef CLAUSE_NO_CLASS\n"; 798e8d8bef9SDimitry Andric OS << "#define CLAUSE_NO_CLASS(Enum, Str)\n"; 799e8d8bef9SDimitry Andric OS << "#endif\n"; 800e8d8bef9SDimitry Andric OS << "\n"; 801e8d8bef9SDimitry Andric OS << "#define __CLAUSE(Name, Class) \\\n"; 802e8d8bef9SDimitry Andric OS << " CLAUSE(" << DirLang.getClausePrefix() 803e8d8bef9SDimitry Andric << "##Name, #Name, /* Implicit */ false) \\\n"; 804e8d8bef9SDimitry Andric OS << " CLAUSE_CLASS(" << DirLang.getClausePrefix() 805e8d8bef9SDimitry Andric << "##Name, #Name, Class)\n"; 806e8d8bef9SDimitry Andric OS << "#define __CLAUSE_NO_CLASS(Name) \\\n"; 807e8d8bef9SDimitry Andric OS << " CLAUSE(" << DirLang.getClausePrefix() 808e8d8bef9SDimitry Andric << "##Name, #Name, /* Implicit */ false) \\\n"; 809e8d8bef9SDimitry Andric OS << " CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, #Name)\n"; 810e8d8bef9SDimitry Andric OS << "#define __IMPLICIT_CLAUSE_CLASS(Name, Str, Class) \\\n"; 811e8d8bef9SDimitry Andric OS << " CLAUSE(" << DirLang.getClausePrefix() 812e8d8bef9SDimitry Andric << "##Name, Str, /* Implicit */ true) \\\n"; 813e8d8bef9SDimitry Andric OS << " CLAUSE_CLASS(" << DirLang.getClausePrefix() 814e8d8bef9SDimitry Andric << "##Name, Str, Class)\n"; 815e8d8bef9SDimitry Andric OS << "#define __IMPLICIT_CLAUSE_NO_CLASS(Name, Str) \\\n"; 816e8d8bef9SDimitry Andric OS << " CLAUSE(" << DirLang.getClausePrefix() 817e8d8bef9SDimitry Andric << "##Name, Str, /* Implicit */ true) \\\n"; 818e8d8bef9SDimitry Andric OS << " CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, Str)\n"; 819e8d8bef9SDimitry Andric OS << "\n"; 820e8d8bef9SDimitry Andric 821e8d8bef9SDimitry Andric for (const auto &R : DirLang.getClauses()) { 822e8d8bef9SDimitry Andric Clause C{R}; 823e8d8bef9SDimitry Andric if (C.getClangClass().empty()) { // NO_CLASS 824e8d8bef9SDimitry Andric if (C.isImplicit()) { 825e8d8bef9SDimitry Andric OS << "__IMPLICIT_CLAUSE_NO_CLASS(" << C.getFormattedName() << ", \"" 826e8d8bef9SDimitry Andric << C.getFormattedName() << "\")\n"; 827e8d8bef9SDimitry Andric } else { 828e8d8bef9SDimitry Andric OS << "__CLAUSE_NO_CLASS(" << C.getFormattedName() << ")\n"; 829e8d8bef9SDimitry Andric } 830e8d8bef9SDimitry Andric } else { // CLASS 831e8d8bef9SDimitry Andric if (C.isImplicit()) { 832e8d8bef9SDimitry Andric OS << "__IMPLICIT_CLAUSE_CLASS(" << C.getFormattedName() << ", \"" 833e8d8bef9SDimitry Andric << C.getFormattedName() << "\", " << C.getClangClass() << ")\n"; 834e8d8bef9SDimitry Andric } else { 835e8d8bef9SDimitry Andric OS << "__CLAUSE(" << C.getFormattedName() << ", " << C.getClangClass() 836e8d8bef9SDimitry Andric << ")\n"; 837e8d8bef9SDimitry Andric } 838e8d8bef9SDimitry Andric } 839e8d8bef9SDimitry Andric } 840e8d8bef9SDimitry Andric 841e8d8bef9SDimitry Andric OS << "\n"; 842e8d8bef9SDimitry Andric OS << "#undef __IMPLICIT_CLAUSE_NO_CLASS\n"; 843e8d8bef9SDimitry Andric OS << "#undef __IMPLICIT_CLAUSE_CLASS\n"; 844e8d8bef9SDimitry Andric OS << "#undef __CLAUSE\n"; 845e8d8bef9SDimitry Andric OS << "#undef CLAUSE_NO_CLASS\n"; 846e8d8bef9SDimitry Andric OS << "#undef CLAUSE_CLASS\n"; 847e8d8bef9SDimitry Andric OS << "#undef CLAUSE\n"; 848e8d8bef9SDimitry Andric } 849e8d8bef9SDimitry Andric 850fe6060f1SDimitry Andric // Generate the implemenation for the enumeration in the directive 8515ffd83dbSDimitry Andric // language. This code can be included in library. 852fe6060f1SDimitry Andric void EmitDirectivesBasicImpl(const DirectiveLanguage &DirLang, 853fe6060f1SDimitry Andric raw_ostream &OS) { 854fe6060f1SDimitry Andric IfDefScope Scope("GEN_DIRECTIVES_IMPL", OS); 8555ffd83dbSDimitry Andric 8565ffd83dbSDimitry Andric // getDirectiveKind(StringRef Str) 857e8d8bef9SDimitry Andric GenerateGetKind(DirLang.getDirectives(), OS, "Directive", DirLang, 858e8d8bef9SDimitry Andric DirLang.getDirectivePrefix(), /*ImplicitAsUnknown=*/false); 8595ffd83dbSDimitry Andric 8605ffd83dbSDimitry Andric // getDirectiveName(Directive Kind) 861e8d8bef9SDimitry Andric GenerateGetName(DirLang.getDirectives(), OS, "Directive", DirLang, 862e8d8bef9SDimitry Andric DirLang.getDirectivePrefix()); 8635ffd83dbSDimitry Andric 8645ffd83dbSDimitry Andric // getClauseKind(StringRef Str) 865e8d8bef9SDimitry Andric GenerateGetKind(DirLang.getClauses(), OS, "Clause", DirLang, 866e8d8bef9SDimitry Andric DirLang.getClausePrefix(), 867e8d8bef9SDimitry Andric /*ImplicitAsUnknown=*/true); 8685ffd83dbSDimitry Andric 8695ffd83dbSDimitry Andric // getClauseName(Clause Kind) 870e8d8bef9SDimitry Andric GenerateGetName(DirLang.getClauses(), OS, "Clause", DirLang, 871e8d8bef9SDimitry Andric DirLang.getClausePrefix()); 872e8d8bef9SDimitry Andric 873e8d8bef9SDimitry Andric // get<ClauseVal>Kind(StringRef Str) 874e8d8bef9SDimitry Andric GenerateGetKindClauseVal(DirLang, OS); 8755ffd83dbSDimitry Andric 8765ffd83dbSDimitry Andric // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version) 877e8d8bef9SDimitry Andric GenerateIsAllowedClause(DirLang, OS); 8785ffd83dbSDimitry Andric } 8795ffd83dbSDimitry Andric 880fe6060f1SDimitry Andric // Generate the implemenation section for the enumeration in the directive 881fe6060f1SDimitry Andric // language. 882*06c3fb27SDimitry Andric static void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) { 883fe6060f1SDimitry Andric const auto DirLang = DirectiveLanguage{Records}; 884fe6060f1SDimitry Andric if (DirLang.HasValidityErrors()) 885fe6060f1SDimitry Andric return; 886fe6060f1SDimitry Andric 887fe6060f1SDimitry Andric EmitDirectivesFlangImpl(DirLang, OS); 888fe6060f1SDimitry Andric 889fe6060f1SDimitry Andric GenerateClauseClassMacro(DirLang, OS); 890fe6060f1SDimitry Andric 891fe6060f1SDimitry Andric EmitDirectivesBasicImpl(DirLang, OS); 892fe6060f1SDimitry Andric } 893fe6060f1SDimitry Andric 894*06c3fb27SDimitry Andric static TableGen::Emitter::Opt 895*06c3fb27SDimitry Andric X("gen-directive-decl", EmitDirectivesDecl, 896*06c3fb27SDimitry Andric "Generate directive related declaration code (header file)"); 897*06c3fb27SDimitry Andric 898*06c3fb27SDimitry Andric static TableGen::Emitter::Opt 899*06c3fb27SDimitry Andric Y("gen-directive-impl", EmitDirectivesImpl, 900*06c3fb27SDimitry Andric "Generate directive related implementation code"); 901