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" 185ffd83dbSDimitry Andric #include "llvm/TableGen/Error.h" 195ffd83dbSDimitry Andric #include "llvm/TableGen/Record.h" 205ffd83dbSDimitry Andric 215ffd83dbSDimitry Andric using namespace llvm; 225ffd83dbSDimitry Andric 235ffd83dbSDimitry Andric namespace { 245ffd83dbSDimitry Andric // Simple RAII helper for defining ifdef-undef-endif scopes. 255ffd83dbSDimitry Andric class IfDefScope { 265ffd83dbSDimitry Andric public: 275ffd83dbSDimitry Andric IfDefScope(StringRef Name, raw_ostream &OS) : Name(Name), OS(OS) { 285ffd83dbSDimitry Andric OS << "#ifdef " << Name << "\n" 295ffd83dbSDimitry Andric << "#undef " << Name << "\n"; 305ffd83dbSDimitry Andric } 315ffd83dbSDimitry Andric 325ffd83dbSDimitry Andric ~IfDefScope() { OS << "\n#endif // " << Name << "\n\n"; } 335ffd83dbSDimitry Andric 345ffd83dbSDimitry Andric private: 355ffd83dbSDimitry Andric StringRef Name; 365ffd83dbSDimitry Andric raw_ostream &OS; 375ffd83dbSDimitry Andric }; 385ffd83dbSDimitry Andric } // end anonymous namespace 395ffd83dbSDimitry Andric 405ffd83dbSDimitry Andric namespace llvm { 415ffd83dbSDimitry Andric 425ffd83dbSDimitry Andric // Generate enum class 435ffd83dbSDimitry Andric void GenerateEnumClass(const std::vector<Record *> &Records, raw_ostream &OS, 44e8d8bef9SDimitry Andric 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). 75e8d8bef9SDimitry Andric void GenerateEnumClauseVal(const std::vector<Record *> &Records, 76e8d8bef9SDimitry Andric raw_ostream &OS, const DirectiveLanguage &DirLang, 77e8d8bef9SDimitry Andric std::string &EnumHelperFuncs) { 78e8d8bef9SDimitry Andric for (const auto &R : Records) { 79e8d8bef9SDimitry Andric Clause C{R}; 80e8d8bef9SDimitry Andric const auto &ClauseVals = C.getClauseVals(); 81e8d8bef9SDimitry Andric if (ClauseVals.size() <= 0) 82e8d8bef9SDimitry Andric continue; 83e8d8bef9SDimitry Andric 84e8d8bef9SDimitry Andric const auto &EnumName = C.getEnumName(); 85e8d8bef9SDimitry Andric if (EnumName.size() == 0) { 86e8d8bef9SDimitry Andric PrintError("enumClauseValue field not set in Clause" + 87e8d8bef9SDimitry Andric C.getFormattedName() + "."); 88e8d8bef9SDimitry Andric return; 89e8d8bef9SDimitry Andric } 90e8d8bef9SDimitry Andric 91e8d8bef9SDimitry Andric OS << "\n"; 92e8d8bef9SDimitry Andric OS << "enum class " << EnumName << " {\n"; 93e8d8bef9SDimitry Andric for (const auto &CV : ClauseVals) { 94e8d8bef9SDimitry Andric ClauseVal CVal{CV}; 95e8d8bef9SDimitry Andric OS << " " << CV->getName() << "=" << CVal.getValue() << ",\n"; 96e8d8bef9SDimitry Andric } 97e8d8bef9SDimitry Andric OS << "};\n"; 98e8d8bef9SDimitry Andric 99e8d8bef9SDimitry Andric if (DirLang.hasMakeEnumAvailableInNamespace()) { 100e8d8bef9SDimitry Andric OS << "\n"; 101e8d8bef9SDimitry Andric for (const auto &CV : ClauseVals) { 102e8d8bef9SDimitry Andric OS << "constexpr auto " << CV->getName() << " = " 103e8d8bef9SDimitry Andric << "llvm::" << DirLang.getCppNamespace() << "::" << EnumName 104e8d8bef9SDimitry Andric << "::" << CV->getName() << ";\n"; 105e8d8bef9SDimitry Andric } 106e8d8bef9SDimitry Andric EnumHelperFuncs += (llvm::Twine(EnumName) + llvm::Twine(" get") + 107e8d8bef9SDimitry Andric llvm::Twine(EnumName) + llvm::Twine("(StringRef);\n")) 108e8d8bef9SDimitry Andric .str(); 109e8d8bef9SDimitry Andric 110e8d8bef9SDimitry Andric EnumHelperFuncs += 111e8d8bef9SDimitry Andric (llvm::Twine("llvm::StringRef get") + llvm::Twine(DirLang.getName()) + 112e8d8bef9SDimitry Andric llvm::Twine(EnumName) + llvm::Twine("Name(") + 113e8d8bef9SDimitry Andric llvm::Twine(EnumName) + llvm::Twine(");\n")) 114e8d8bef9SDimitry Andric .str(); 115e8d8bef9SDimitry Andric } 116e8d8bef9SDimitry Andric } 117e8d8bef9SDimitry Andric } 118e8d8bef9SDimitry Andric 119e8d8bef9SDimitry Andric bool HasDuplicateClauses(const std::vector<Record *> &Clauses, 120e8d8bef9SDimitry Andric const Directive &Directive, 121e8d8bef9SDimitry Andric llvm::StringSet<> &CrtClauses) { 122e8d8bef9SDimitry Andric bool HasError = false; 123e8d8bef9SDimitry Andric for (const auto &C : Clauses) { 124e8d8bef9SDimitry Andric VersionedClause VerClause{C}; 125e8d8bef9SDimitry Andric const auto insRes = CrtClauses.insert(VerClause.getClause().getName()); 126e8d8bef9SDimitry Andric if (!insRes.second) { 127e8d8bef9SDimitry Andric PrintError("Clause " + VerClause.getClause().getRecordName() + 128e8d8bef9SDimitry Andric " already defined on directive " + Directive.getRecordName()); 129e8d8bef9SDimitry Andric HasError = true; 130e8d8bef9SDimitry Andric } 131e8d8bef9SDimitry Andric } 132e8d8bef9SDimitry Andric return HasError; 133e8d8bef9SDimitry Andric } 134e8d8bef9SDimitry Andric 135e8d8bef9SDimitry Andric // Check for duplicate clauses in lists. Clauses cannot appear twice in the 136e8d8bef9SDimitry Andric // three allowed list. Also, since required implies allowed, clauses cannot 137e8d8bef9SDimitry Andric // appear in both the allowedClauses and requiredClauses lists. 138e8d8bef9SDimitry Andric bool HasDuplicateClausesInDirectives(const std::vector<Record *> &Directives) { 139e8d8bef9SDimitry Andric bool HasDuplicate = false; 140e8d8bef9SDimitry Andric for (const auto &D : Directives) { 141e8d8bef9SDimitry Andric Directive Dir{D}; 142e8d8bef9SDimitry Andric llvm::StringSet<> Clauses; 143e8d8bef9SDimitry Andric // Check for duplicates in the three allowed lists. 144e8d8bef9SDimitry Andric if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) || 145e8d8bef9SDimitry Andric HasDuplicateClauses(Dir.getAllowedOnceClauses(), Dir, Clauses) || 146e8d8bef9SDimitry Andric HasDuplicateClauses(Dir.getAllowedExclusiveClauses(), Dir, Clauses)) { 147e8d8bef9SDimitry Andric HasDuplicate = true; 148e8d8bef9SDimitry Andric } 149e8d8bef9SDimitry Andric // Check for duplicate between allowedClauses and required 150e8d8bef9SDimitry Andric Clauses.clear(); 151e8d8bef9SDimitry Andric if (HasDuplicateClauses(Dir.getAllowedClauses(), Dir, Clauses) || 152e8d8bef9SDimitry Andric HasDuplicateClauses(Dir.getRequiredClauses(), Dir, Clauses)) { 153e8d8bef9SDimitry Andric HasDuplicate = true; 154e8d8bef9SDimitry Andric } 155e8d8bef9SDimitry Andric if (HasDuplicate) 156e8d8bef9SDimitry Andric PrintFatalError("One or more clauses are defined multiple times on" 157e8d8bef9SDimitry Andric " directive " + 158e8d8bef9SDimitry Andric Dir.getRecordName()); 159e8d8bef9SDimitry Andric } 160e8d8bef9SDimitry Andric 161e8d8bef9SDimitry Andric return HasDuplicate; 162e8d8bef9SDimitry Andric } 163e8d8bef9SDimitry Andric 164e8d8bef9SDimitry Andric // Check consitency of records. Return true if an error has been detected. 165e8d8bef9SDimitry Andric // Return false if the records are valid. 166e8d8bef9SDimitry Andric bool DirectiveLanguage::HasValidityErrors() const { 167e8d8bef9SDimitry Andric if (getDirectiveLanguages().size() != 1) { 168e8d8bef9SDimitry Andric PrintFatalError("A single definition of DirectiveLanguage is needed."); 169e8d8bef9SDimitry Andric return true; 170e8d8bef9SDimitry Andric } 171e8d8bef9SDimitry Andric 172e8d8bef9SDimitry Andric return HasDuplicateClausesInDirectives(getDirectives()); 173e8d8bef9SDimitry Andric } 174e8d8bef9SDimitry Andric 1755ffd83dbSDimitry Andric // Generate the declaration section for the enumeration in the directive 1765ffd83dbSDimitry Andric // language 1775ffd83dbSDimitry Andric void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) { 178e8d8bef9SDimitry Andric const auto DirLang = DirectiveLanguage{Records}; 179e8d8bef9SDimitry Andric if (DirLang.HasValidityErrors()) 1805ffd83dbSDimitry Andric return; 1815ffd83dbSDimitry Andric 182e8d8bef9SDimitry Andric OS << "#ifndef LLVM_" << DirLang.getName() << "_INC\n"; 183e8d8bef9SDimitry Andric OS << "#define LLVM_" << DirLang.getName() << "_INC\n"; 1845ffd83dbSDimitry Andric 185e8d8bef9SDimitry Andric if (DirLang.hasEnableBitmaskEnumInNamespace()) 1865ffd83dbSDimitry Andric OS << "\n#include \"llvm/ADT/BitmaskEnum.h\"\n"; 1875ffd83dbSDimitry Andric 1885ffd83dbSDimitry Andric OS << "\n"; 1895ffd83dbSDimitry Andric OS << "namespace llvm {\n"; 1905ffd83dbSDimitry Andric OS << "class StringRef;\n"; 1915ffd83dbSDimitry Andric 1925ffd83dbSDimitry Andric // Open namespaces defined in the directive language 1935ffd83dbSDimitry Andric llvm::SmallVector<StringRef, 2> Namespaces; 194e8d8bef9SDimitry Andric llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::"); 1955ffd83dbSDimitry Andric for (auto Ns : Namespaces) 1965ffd83dbSDimitry Andric OS << "namespace " << Ns << " {\n"; 1975ffd83dbSDimitry Andric 198e8d8bef9SDimitry Andric if (DirLang.hasEnableBitmaskEnumInNamespace()) 1995ffd83dbSDimitry Andric OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n"; 2005ffd83dbSDimitry Andric 2015ffd83dbSDimitry Andric // Emit Directive enumeration 202e8d8bef9SDimitry Andric GenerateEnumClass(DirLang.getDirectives(), OS, "Directive", 203e8d8bef9SDimitry Andric DirLang.getDirectivePrefix(), DirLang); 2045ffd83dbSDimitry Andric 2055ffd83dbSDimitry Andric // Emit Clause enumeration 206e8d8bef9SDimitry Andric GenerateEnumClass(DirLang.getClauses(), OS, "Clause", 207e8d8bef9SDimitry Andric DirLang.getClausePrefix(), DirLang); 208e8d8bef9SDimitry Andric 209e8d8bef9SDimitry Andric // Emit ClauseVal enumeration 210e8d8bef9SDimitry Andric std::string EnumHelperFuncs; 211e8d8bef9SDimitry Andric GenerateEnumClauseVal(DirLang.getClauses(), OS, DirLang, EnumHelperFuncs); 2125ffd83dbSDimitry Andric 2135ffd83dbSDimitry Andric // Generic function signatures 2145ffd83dbSDimitry Andric OS << "\n"; 2155ffd83dbSDimitry Andric OS << "// Enumeration helper functions\n"; 216e8d8bef9SDimitry Andric OS << "Directive get" << DirLang.getName() 2175ffd83dbSDimitry Andric << "DirectiveKind(llvm::StringRef Str);\n"; 2185ffd83dbSDimitry Andric OS << "\n"; 219e8d8bef9SDimitry Andric OS << "llvm::StringRef get" << DirLang.getName() 2205ffd83dbSDimitry Andric << "DirectiveName(Directive D);\n"; 2215ffd83dbSDimitry Andric OS << "\n"; 222e8d8bef9SDimitry Andric OS << "Clause get" << DirLang.getName() 223e8d8bef9SDimitry Andric << "ClauseKind(llvm::StringRef Str);\n"; 2245ffd83dbSDimitry Andric OS << "\n"; 225e8d8bef9SDimitry Andric OS << "llvm::StringRef get" << DirLang.getName() << "ClauseName(Clause C);\n"; 2265ffd83dbSDimitry Andric OS << "\n"; 2275ffd83dbSDimitry Andric OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p " 2285ffd83dbSDimitry Andric << "Version.\n"; 2295ffd83dbSDimitry Andric OS << "bool isAllowedClauseForDirective(Directive D, " 2305ffd83dbSDimitry Andric << "Clause C, unsigned Version);\n"; 2315ffd83dbSDimitry Andric OS << "\n"; 232e8d8bef9SDimitry Andric if (EnumHelperFuncs.length() > 0) { 233e8d8bef9SDimitry Andric OS << EnumHelperFuncs; 234e8d8bef9SDimitry Andric OS << "\n"; 235e8d8bef9SDimitry Andric } 2365ffd83dbSDimitry Andric 2375ffd83dbSDimitry Andric // Closing namespaces 2385ffd83dbSDimitry Andric for (auto Ns : llvm::reverse(Namespaces)) 2395ffd83dbSDimitry Andric OS << "} // namespace " << Ns << "\n"; 2405ffd83dbSDimitry Andric 2415ffd83dbSDimitry Andric OS << "} // namespace llvm\n"; 2425ffd83dbSDimitry Andric 243e8d8bef9SDimitry Andric OS << "#endif // LLVM_" << DirLang.getName() << "_INC\n"; 2445ffd83dbSDimitry Andric } 2455ffd83dbSDimitry Andric 2465ffd83dbSDimitry Andric // Generate function implementation for get<Enum>Name(StringRef Str) 2475ffd83dbSDimitry Andric void GenerateGetName(const std::vector<Record *> &Records, raw_ostream &OS, 248e8d8bef9SDimitry Andric StringRef Enum, const DirectiveLanguage &DirLang, 249e8d8bef9SDimitry Andric StringRef Prefix) { 2505ffd83dbSDimitry Andric OS << "\n"; 251e8d8bef9SDimitry Andric OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get" 252e8d8bef9SDimitry Andric << DirLang.getName() << Enum << "Name(" << Enum << " Kind) {\n"; 2535ffd83dbSDimitry Andric OS << " switch (Kind) {\n"; 2545ffd83dbSDimitry Andric for (const auto &R : Records) { 255e8d8bef9SDimitry Andric BaseRecord Rec{R}; 256e8d8bef9SDimitry Andric OS << " case " << Prefix << Rec.getFormattedName() << ":\n"; 2575ffd83dbSDimitry Andric OS << " return \""; 258e8d8bef9SDimitry Andric if (Rec.getAlternativeName().empty()) 259e8d8bef9SDimitry Andric OS << Rec.getName(); 2605ffd83dbSDimitry Andric else 261e8d8bef9SDimitry Andric OS << Rec.getAlternativeName(); 2625ffd83dbSDimitry Andric OS << "\";\n"; 2635ffd83dbSDimitry Andric } 2645ffd83dbSDimitry Andric OS << " }\n"; // switch 265e8d8bef9SDimitry Andric OS << " llvm_unreachable(\"Invalid " << DirLang.getName() << " " << Enum 2665ffd83dbSDimitry Andric << " kind\");\n"; 2675ffd83dbSDimitry Andric OS << "}\n"; 2685ffd83dbSDimitry Andric } 2695ffd83dbSDimitry Andric 2705ffd83dbSDimitry Andric // Generate function implementation for get<Enum>Kind(StringRef Str) 2715ffd83dbSDimitry Andric void GenerateGetKind(const std::vector<Record *> &Records, raw_ostream &OS, 272e8d8bef9SDimitry Andric StringRef Enum, const DirectiveLanguage &DirLang, 273e8d8bef9SDimitry Andric StringRef Prefix, bool ImplicitAsUnknown) { 2745ffd83dbSDimitry Andric 275e8d8bef9SDimitry Andric auto DefaultIt = llvm::find_if( 276e8d8bef9SDimitry Andric Records, [](Record *R) { return R->getValueAsBit("isDefault") == true; }); 2775ffd83dbSDimitry Andric 2785ffd83dbSDimitry Andric if (DefaultIt == Records.end()) { 279e8d8bef9SDimitry Andric PrintError("At least one " + Enum + " must be defined as default."); 2805ffd83dbSDimitry Andric return; 2815ffd83dbSDimitry Andric } 2825ffd83dbSDimitry Andric 283e8d8bef9SDimitry Andric BaseRecord DefaultRec{(*DefaultIt)}; 2845ffd83dbSDimitry Andric 2855ffd83dbSDimitry Andric OS << "\n"; 286e8d8bef9SDimitry Andric OS << Enum << " llvm::" << DirLang.getCppNamespace() << "::get" 287e8d8bef9SDimitry Andric << DirLang.getName() << Enum << "Kind(llvm::StringRef Str) {\n"; 2885ffd83dbSDimitry Andric OS << " return llvm::StringSwitch<" << Enum << ">(Str)\n"; 2895ffd83dbSDimitry Andric 2905ffd83dbSDimitry Andric for (const auto &R : Records) { 291e8d8bef9SDimitry Andric BaseRecord Rec{R}; 2925ffd83dbSDimitry Andric if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) { 293e8d8bef9SDimitry Andric OS << " .Case(\"" << Rec.getName() << "\"," << Prefix 294e8d8bef9SDimitry Andric << DefaultRec.getFormattedName() << ")\n"; 2955ffd83dbSDimitry Andric } else { 296e8d8bef9SDimitry Andric OS << " .Case(\"" << Rec.getName() << "\"," << Prefix 297e8d8bef9SDimitry Andric << Rec.getFormattedName() << ")\n"; 298e8d8bef9SDimitry Andric } 299e8d8bef9SDimitry Andric } 300e8d8bef9SDimitry Andric OS << " .Default(" << Prefix << DefaultRec.getFormattedName() << ");\n"; 301e8d8bef9SDimitry Andric OS << "}\n"; 302e8d8bef9SDimitry Andric } 303e8d8bef9SDimitry Andric 304e8d8bef9SDimitry Andric // Generate function implementation for get<ClauseVal>Kind(StringRef Str) 305e8d8bef9SDimitry Andric void GenerateGetKindClauseVal(const DirectiveLanguage &DirLang, 306e8d8bef9SDimitry Andric raw_ostream &OS) { 307e8d8bef9SDimitry Andric for (const auto &R : DirLang.getClauses()) { 308e8d8bef9SDimitry Andric Clause C{R}; 309e8d8bef9SDimitry Andric const auto &ClauseVals = C.getClauseVals(); 310e8d8bef9SDimitry Andric if (ClauseVals.size() <= 0) 311e8d8bef9SDimitry Andric continue; 312e8d8bef9SDimitry Andric 313e8d8bef9SDimitry Andric auto DefaultIt = llvm::find_if(ClauseVals, [](Record *CV) { 314e8d8bef9SDimitry Andric return CV->getValueAsBit("isDefault") == true; 315e8d8bef9SDimitry Andric }); 316e8d8bef9SDimitry Andric 317e8d8bef9SDimitry Andric if (DefaultIt == ClauseVals.end()) { 318e8d8bef9SDimitry Andric PrintError("At least one val in Clause " + C.getFormattedName() + 319e8d8bef9SDimitry Andric " must be defined as default."); 320e8d8bef9SDimitry Andric return; 321e8d8bef9SDimitry Andric } 322e8d8bef9SDimitry Andric const auto DefaultName = (*DefaultIt)->getName(); 323e8d8bef9SDimitry Andric 324e8d8bef9SDimitry Andric const auto &EnumName = C.getEnumName(); 325e8d8bef9SDimitry Andric if (EnumName.size() == 0) { 326e8d8bef9SDimitry Andric PrintError("enumClauseValue field not set in Clause" + 327e8d8bef9SDimitry Andric C.getFormattedName() + "."); 328e8d8bef9SDimitry Andric return; 329e8d8bef9SDimitry Andric } 330e8d8bef9SDimitry Andric 331e8d8bef9SDimitry Andric OS << "\n"; 332e8d8bef9SDimitry Andric OS << EnumName << " llvm::" << DirLang.getCppNamespace() << "::get" 333e8d8bef9SDimitry Andric << EnumName << "(llvm::StringRef Str) {\n"; 334e8d8bef9SDimitry Andric OS << " return llvm::StringSwitch<" << EnumName << ">(Str)\n"; 335e8d8bef9SDimitry Andric for (const auto &CV : ClauseVals) { 336e8d8bef9SDimitry Andric ClauseVal CVal{CV}; 337e8d8bef9SDimitry Andric OS << " .Case(\"" << CVal.getFormattedName() << "\"," << CV->getName() 3385ffd83dbSDimitry Andric << ")\n"; 3395ffd83dbSDimitry Andric } 340e8d8bef9SDimitry Andric OS << " .Default(" << DefaultName << ");\n"; 3415ffd83dbSDimitry Andric OS << "}\n"; 342e8d8bef9SDimitry Andric 343e8d8bef9SDimitry Andric OS << "\n"; 344e8d8bef9SDimitry Andric OS << "llvm::StringRef llvm::" << DirLang.getCppNamespace() << "::get" 345e8d8bef9SDimitry Andric << DirLang.getName() << EnumName 346e8d8bef9SDimitry Andric << "Name(llvm::" << DirLang.getCppNamespace() << "::" << EnumName 347e8d8bef9SDimitry Andric << " x) {\n"; 348e8d8bef9SDimitry Andric OS << " switch (x) {\n"; 349e8d8bef9SDimitry Andric for (const auto &CV : ClauseVals) { 350e8d8bef9SDimitry Andric ClauseVal CVal{CV}; 351e8d8bef9SDimitry Andric OS << " case " << CV->getName() << ":\n"; 352e8d8bef9SDimitry Andric OS << " return \"" << CVal.getFormattedName() << "\";\n"; 353e8d8bef9SDimitry Andric } 354e8d8bef9SDimitry Andric OS << " }\n"; // switch 355e8d8bef9SDimitry Andric OS << " llvm_unreachable(\"Invalid " << DirLang.getName() << " " 356e8d8bef9SDimitry Andric << EnumName << " kind\");\n"; 357e8d8bef9SDimitry Andric OS << "}\n"; 358e8d8bef9SDimitry Andric } 3595ffd83dbSDimitry Andric } 3605ffd83dbSDimitry Andric 3615ffd83dbSDimitry Andric void GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses, 3625ffd83dbSDimitry Andric raw_ostream &OS, StringRef DirectiveName, 363e8d8bef9SDimitry Andric const DirectiveLanguage &DirLang, 3645ffd83dbSDimitry Andric llvm::StringSet<> &Cases) { 3655ffd83dbSDimitry Andric for (const auto &C : Clauses) { 366e8d8bef9SDimitry Andric VersionedClause VerClause{C}; 3675ffd83dbSDimitry Andric 368e8d8bef9SDimitry Andric const auto ClauseFormattedName = VerClause.getClause().getFormattedName(); 369e8d8bef9SDimitry Andric 370*81ad6265SDimitry Andric if (Cases.insert(ClauseFormattedName).second) { 371e8d8bef9SDimitry Andric OS << " case " << DirLang.getClausePrefix() << ClauseFormattedName 372e8d8bef9SDimitry Andric << ":\n"; 373e8d8bef9SDimitry Andric OS << " return " << VerClause.getMinVersion() 374e8d8bef9SDimitry Andric << " <= Version && " << VerClause.getMaxVersion() << " >= Version;\n"; 3755ffd83dbSDimitry Andric } 3765ffd83dbSDimitry Andric } 3775ffd83dbSDimitry Andric } 3785ffd83dbSDimitry Andric 3795ffd83dbSDimitry Andric // Generate the isAllowedClauseForDirective function implementation. 380e8d8bef9SDimitry Andric void GenerateIsAllowedClause(const DirectiveLanguage &DirLang, 381e8d8bef9SDimitry Andric raw_ostream &OS) { 3825ffd83dbSDimitry Andric OS << "\n"; 383e8d8bef9SDimitry Andric OS << "bool llvm::" << DirLang.getCppNamespace() 384e8d8bef9SDimitry Andric << "::isAllowedClauseForDirective(" 3855ffd83dbSDimitry Andric << "Directive D, Clause C, unsigned Version) {\n"; 386e8d8bef9SDimitry Andric OS << " assert(unsigned(D) <= llvm::" << DirLang.getCppNamespace() 3875ffd83dbSDimitry Andric << "::Directive_enumSize);\n"; 388e8d8bef9SDimitry Andric OS << " assert(unsigned(C) <= llvm::" << DirLang.getCppNamespace() 3895ffd83dbSDimitry Andric << "::Clause_enumSize);\n"; 3905ffd83dbSDimitry Andric 3915ffd83dbSDimitry Andric OS << " switch (D) {\n"; 3925ffd83dbSDimitry Andric 393e8d8bef9SDimitry Andric for (const auto &D : DirLang.getDirectives()) { 394e8d8bef9SDimitry Andric Directive Dir{D}; 3955ffd83dbSDimitry Andric 396e8d8bef9SDimitry Andric OS << " case " << DirLang.getDirectivePrefix() << Dir.getFormattedName() 3975ffd83dbSDimitry Andric << ":\n"; 398e8d8bef9SDimitry Andric if (Dir.getAllowedClauses().size() == 0 && 399e8d8bef9SDimitry Andric Dir.getAllowedOnceClauses().size() == 0 && 400e8d8bef9SDimitry Andric Dir.getAllowedExclusiveClauses().size() == 0 && 401e8d8bef9SDimitry Andric Dir.getRequiredClauses().size() == 0) { 4025ffd83dbSDimitry Andric OS << " return false;\n"; 4035ffd83dbSDimitry Andric } else { 4045ffd83dbSDimitry Andric OS << " switch (C) {\n"; 4055ffd83dbSDimitry Andric 4065ffd83dbSDimitry Andric llvm::StringSet<> Cases; 4075ffd83dbSDimitry Andric 408e8d8bef9SDimitry Andric GenerateCaseForVersionedClauses(Dir.getAllowedClauses(), OS, 409e8d8bef9SDimitry Andric Dir.getName(), DirLang, Cases); 4105ffd83dbSDimitry Andric 411e8d8bef9SDimitry Andric GenerateCaseForVersionedClauses(Dir.getAllowedOnceClauses(), OS, 412e8d8bef9SDimitry Andric Dir.getName(), DirLang, Cases); 4135ffd83dbSDimitry Andric 414e8d8bef9SDimitry Andric GenerateCaseForVersionedClauses(Dir.getAllowedExclusiveClauses(), OS, 415e8d8bef9SDimitry Andric Dir.getName(), DirLang, Cases); 4165ffd83dbSDimitry Andric 417e8d8bef9SDimitry Andric GenerateCaseForVersionedClauses(Dir.getRequiredClauses(), OS, 418e8d8bef9SDimitry Andric Dir.getName(), DirLang, Cases); 4195ffd83dbSDimitry Andric 4205ffd83dbSDimitry Andric OS << " default:\n"; 4215ffd83dbSDimitry Andric OS << " return false;\n"; 4225ffd83dbSDimitry Andric OS << " }\n"; // End of clauses switch 4235ffd83dbSDimitry Andric } 4245ffd83dbSDimitry Andric OS << " break;\n"; 4255ffd83dbSDimitry Andric } 4265ffd83dbSDimitry Andric 4275ffd83dbSDimitry Andric OS << " }\n"; // End of directives switch 428e8d8bef9SDimitry Andric OS << " llvm_unreachable(\"Invalid " << DirLang.getName() 4295ffd83dbSDimitry Andric << " Directive kind\");\n"; 4305ffd83dbSDimitry Andric OS << "}\n"; // End of function isAllowedClauseForDirective 4315ffd83dbSDimitry Andric } 4325ffd83dbSDimitry Andric 4335ffd83dbSDimitry Andric // Generate a simple enum set with the give clauses. 4345ffd83dbSDimitry Andric void GenerateClauseSet(const std::vector<Record *> &Clauses, raw_ostream &OS, 435e8d8bef9SDimitry Andric StringRef ClauseSetPrefix, Directive &Dir, 436e8d8bef9SDimitry Andric const DirectiveLanguage &DirLang) { 4375ffd83dbSDimitry Andric 4385ffd83dbSDimitry Andric OS << "\n"; 439e8d8bef9SDimitry Andric OS << " static " << DirLang.getClauseEnumSetClass() << " " << ClauseSetPrefix 440e8d8bef9SDimitry Andric << DirLang.getDirectivePrefix() << Dir.getFormattedName() << " {\n"; 4415ffd83dbSDimitry Andric 4425ffd83dbSDimitry Andric for (const auto &C : Clauses) { 443e8d8bef9SDimitry Andric VersionedClause VerClause{C}; 444e8d8bef9SDimitry Andric OS << " llvm::" << DirLang.getCppNamespace() 445e8d8bef9SDimitry Andric << "::Clause::" << DirLang.getClausePrefix() 446e8d8bef9SDimitry Andric << VerClause.getClause().getFormattedName() << ",\n"; 4475ffd83dbSDimitry Andric } 4485ffd83dbSDimitry Andric OS << " };\n"; 4495ffd83dbSDimitry Andric } 4505ffd83dbSDimitry Andric 4515ffd83dbSDimitry Andric // Generate an enum set for the 4 kinds of clauses linked to a directive. 452e8d8bef9SDimitry Andric void GenerateDirectiveClauseSets(const DirectiveLanguage &DirLang, 453e8d8bef9SDimitry Andric raw_ostream &OS) { 4545ffd83dbSDimitry Andric 4555ffd83dbSDimitry Andric IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_SETS", OS); 4565ffd83dbSDimitry Andric 4575ffd83dbSDimitry Andric OS << "\n"; 4585ffd83dbSDimitry Andric OS << "namespace llvm {\n"; 4595ffd83dbSDimitry Andric 4605ffd83dbSDimitry Andric // Open namespaces defined in the directive language. 4615ffd83dbSDimitry Andric llvm::SmallVector<StringRef, 2> Namespaces; 462e8d8bef9SDimitry Andric llvm::SplitString(DirLang.getCppNamespace(), Namespaces, "::"); 4635ffd83dbSDimitry Andric for (auto Ns : Namespaces) 4645ffd83dbSDimitry Andric OS << "namespace " << Ns << " {\n"; 4655ffd83dbSDimitry Andric 466e8d8bef9SDimitry Andric for (const auto &D : DirLang.getDirectives()) { 467e8d8bef9SDimitry Andric Directive Dir{D}; 4685ffd83dbSDimitry Andric 4695ffd83dbSDimitry Andric OS << "\n"; 470e8d8bef9SDimitry Andric OS << " // Sets for " << Dir.getName() << "\n"; 4715ffd83dbSDimitry Andric 472e8d8bef9SDimitry Andric GenerateClauseSet(Dir.getAllowedClauses(), OS, "allowedClauses_", Dir, 473e8d8bef9SDimitry Andric DirLang); 474e8d8bef9SDimitry Andric GenerateClauseSet(Dir.getAllowedOnceClauses(), OS, "allowedOnceClauses_", 475e8d8bef9SDimitry Andric Dir, DirLang); 476e8d8bef9SDimitry Andric GenerateClauseSet(Dir.getAllowedExclusiveClauses(), OS, 477e8d8bef9SDimitry Andric "allowedExclusiveClauses_", Dir, DirLang); 478e8d8bef9SDimitry Andric GenerateClauseSet(Dir.getRequiredClauses(), OS, "requiredClauses_", Dir, 479e8d8bef9SDimitry Andric DirLang); 4805ffd83dbSDimitry Andric } 4815ffd83dbSDimitry Andric 4825ffd83dbSDimitry Andric // Closing namespaces 4835ffd83dbSDimitry Andric for (auto Ns : llvm::reverse(Namespaces)) 4845ffd83dbSDimitry Andric OS << "} // namespace " << Ns << "\n"; 4855ffd83dbSDimitry Andric 4865ffd83dbSDimitry Andric OS << "} // namespace llvm\n"; 4875ffd83dbSDimitry Andric } 4885ffd83dbSDimitry Andric 4895ffd83dbSDimitry Andric // Generate a map of directive (key) with DirectiveClauses struct as values. 4905ffd83dbSDimitry Andric // The struct holds the 4 sets of enumeration for the 4 kinds of clauses 4915ffd83dbSDimitry Andric // allowances (allowed, allowed once, allowed exclusive and required). 492e8d8bef9SDimitry Andric void GenerateDirectiveClauseMap(const DirectiveLanguage &DirLang, 493e8d8bef9SDimitry Andric raw_ostream &OS) { 4945ffd83dbSDimitry Andric 4955ffd83dbSDimitry Andric IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_MAP", OS); 4965ffd83dbSDimitry Andric 4975ffd83dbSDimitry Andric OS << "\n"; 4985ffd83dbSDimitry Andric OS << "{\n"; 499e8d8bef9SDimitry Andric 500e8d8bef9SDimitry Andric for (const auto &D : DirLang.getDirectives()) { 501e8d8bef9SDimitry Andric Directive Dir{D}; 502e8d8bef9SDimitry Andric OS << " {llvm::" << DirLang.getCppNamespace() 503e8d8bef9SDimitry Andric << "::Directive::" << DirLang.getDirectivePrefix() 504e8d8bef9SDimitry Andric << Dir.getFormattedName() << ",\n"; 505e8d8bef9SDimitry Andric OS << " {\n"; 506e8d8bef9SDimitry Andric OS << " llvm::" << DirLang.getCppNamespace() << "::allowedClauses_" 507e8d8bef9SDimitry Andric << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n"; 508e8d8bef9SDimitry Andric OS << " llvm::" << DirLang.getCppNamespace() << "::allowedOnceClauses_" 509e8d8bef9SDimitry Andric << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n"; 510e8d8bef9SDimitry Andric OS << " llvm::" << DirLang.getCppNamespace() 511e8d8bef9SDimitry Andric << "::allowedExclusiveClauses_" << DirLang.getDirectivePrefix() 512e8d8bef9SDimitry Andric << Dir.getFormattedName() << ",\n"; 513e8d8bef9SDimitry Andric OS << " llvm::" << DirLang.getCppNamespace() << "::requiredClauses_" 514e8d8bef9SDimitry Andric << DirLang.getDirectivePrefix() << Dir.getFormattedName() << ",\n"; 5155ffd83dbSDimitry Andric OS << " }\n"; 5165ffd83dbSDimitry Andric OS << " },\n"; 5175ffd83dbSDimitry Andric } 5185ffd83dbSDimitry Andric 519e8d8bef9SDimitry Andric OS << "}\n"; 5205ffd83dbSDimitry Andric } 5215ffd83dbSDimitry Andric 522e8d8bef9SDimitry Andric // Generate classes entry for Flang clauses in the Flang parse-tree 523e8d8bef9SDimitry Andric // If the clause as a non-generic class, no entry is generated. 524e8d8bef9SDimitry Andric // If the clause does not hold a value, an EMPTY_CLASS is used. 525e8d8bef9SDimitry Andric // If the clause class is generic then a WRAPPER_CLASS is used. When the value 526e8d8bef9SDimitry Andric // is optional, the value class is wrapped into a std::optional. 527e8d8bef9SDimitry Andric void GenerateFlangClauseParserClass(const DirectiveLanguage &DirLang, 528e8d8bef9SDimitry Andric raw_ostream &OS) { 529e8d8bef9SDimitry Andric 530e8d8bef9SDimitry Andric IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES", OS); 531e8d8bef9SDimitry Andric 532e8d8bef9SDimitry Andric OS << "\n"; 533e8d8bef9SDimitry Andric 534e8d8bef9SDimitry Andric for (const auto &C : DirLang.getClauses()) { 535e8d8bef9SDimitry Andric Clause Clause{C}; 536e8d8bef9SDimitry Andric if (!Clause.getFlangClass().empty()) { 537e8d8bef9SDimitry Andric OS << "WRAPPER_CLASS(" << Clause.getFormattedParserClassName() << ", "; 538e8d8bef9SDimitry Andric if (Clause.isValueOptional() && Clause.isValueList()) { 539e8d8bef9SDimitry Andric OS << "std::optional<std::list<" << Clause.getFlangClass() << ">>"; 540e8d8bef9SDimitry Andric } else if (Clause.isValueOptional()) { 541e8d8bef9SDimitry Andric OS << "std::optional<" << Clause.getFlangClass() << ">"; 542e8d8bef9SDimitry Andric } else if (Clause.isValueList()) { 543e8d8bef9SDimitry Andric OS << "std::list<" << Clause.getFlangClass() << ">"; 544e8d8bef9SDimitry Andric } else { 545e8d8bef9SDimitry Andric OS << Clause.getFlangClass(); 546e8d8bef9SDimitry Andric } 547e8d8bef9SDimitry Andric } else { 548e8d8bef9SDimitry Andric OS << "EMPTY_CLASS(" << Clause.getFormattedParserClassName(); 549e8d8bef9SDimitry Andric } 550e8d8bef9SDimitry Andric OS << ");\n"; 551e8d8bef9SDimitry Andric } 552e8d8bef9SDimitry Andric } 553e8d8bef9SDimitry Andric 554e8d8bef9SDimitry Andric // Generate a list of the different clause classes for Flang. 555e8d8bef9SDimitry Andric void GenerateFlangClauseParserClassList(const DirectiveLanguage &DirLang, 556e8d8bef9SDimitry Andric raw_ostream &OS) { 557e8d8bef9SDimitry Andric 558e8d8bef9SDimitry Andric IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_CLASSES_LIST", OS); 559e8d8bef9SDimitry Andric 560e8d8bef9SDimitry Andric OS << "\n"; 561e8d8bef9SDimitry Andric llvm::interleaveComma(DirLang.getClauses(), OS, [&](Record *C) { 562e8d8bef9SDimitry Andric Clause Clause{C}; 563e8d8bef9SDimitry Andric OS << Clause.getFormattedParserClassName() << "\n"; 564e8d8bef9SDimitry Andric }); 565e8d8bef9SDimitry Andric } 566e8d8bef9SDimitry Andric 567e8d8bef9SDimitry Andric // Generate dump node list for the clauses holding a generic class name. 568e8d8bef9SDimitry Andric void GenerateFlangClauseDump(const DirectiveLanguage &DirLang, 569e8d8bef9SDimitry Andric raw_ostream &OS) { 570e8d8bef9SDimitry Andric 571e8d8bef9SDimitry Andric IfDefScope Scope("GEN_FLANG_DUMP_PARSE_TREE_CLAUSES", OS); 572e8d8bef9SDimitry Andric 573e8d8bef9SDimitry Andric OS << "\n"; 574e8d8bef9SDimitry Andric for (const auto &C : DirLang.getClauses()) { 575e8d8bef9SDimitry Andric Clause Clause{C}; 576e8d8bef9SDimitry Andric OS << "NODE(" << DirLang.getFlangClauseBaseClass() << ", " 577e8d8bef9SDimitry Andric << Clause.getFormattedParserClassName() << ")\n"; 578e8d8bef9SDimitry Andric } 579e8d8bef9SDimitry Andric } 580e8d8bef9SDimitry Andric 581e8d8bef9SDimitry Andric // Generate Unparse functions for clauses classes in the Flang parse-tree 582e8d8bef9SDimitry Andric // If the clause is a non-generic class, no entry is generated. 583e8d8bef9SDimitry Andric void GenerateFlangClauseUnparse(const DirectiveLanguage &DirLang, 584e8d8bef9SDimitry Andric raw_ostream &OS) { 585e8d8bef9SDimitry Andric 586e8d8bef9SDimitry Andric IfDefScope Scope("GEN_FLANG_CLAUSE_UNPARSE", OS); 587e8d8bef9SDimitry Andric 588e8d8bef9SDimitry Andric OS << "\n"; 589e8d8bef9SDimitry Andric 590e8d8bef9SDimitry Andric for (const auto &C : DirLang.getClauses()) { 591e8d8bef9SDimitry Andric Clause Clause{C}; 592e8d8bef9SDimitry Andric if (!Clause.getFlangClass().empty()) { 593e8d8bef9SDimitry Andric if (Clause.isValueOptional() && Clause.getDefaultValue().empty()) { 594e8d8bef9SDimitry Andric OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass() 595e8d8bef9SDimitry Andric << "::" << Clause.getFormattedParserClassName() << " &x) {\n"; 596e8d8bef9SDimitry Andric OS << " Word(\"" << Clause.getName().upper() << "\");\n"; 597e8d8bef9SDimitry Andric 598e8d8bef9SDimitry Andric OS << " Walk(\"(\", x.v, \")\");\n"; 599e8d8bef9SDimitry Andric OS << "}\n"; 600e8d8bef9SDimitry Andric } else if (Clause.isValueOptional()) { 601e8d8bef9SDimitry Andric OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass() 602e8d8bef9SDimitry Andric << "::" << Clause.getFormattedParserClassName() << " &x) {\n"; 603e8d8bef9SDimitry Andric OS << " Word(\"" << Clause.getName().upper() << "\");\n"; 604e8d8bef9SDimitry Andric OS << " Put(\"(\");\n"; 605e8d8bef9SDimitry Andric OS << " if (x.v.has_value())\n"; 606e8d8bef9SDimitry Andric if (Clause.isValueList()) 607e8d8bef9SDimitry Andric OS << " Walk(x.v, \",\");\n"; 608e8d8bef9SDimitry Andric else 609e8d8bef9SDimitry Andric OS << " Walk(x.v);\n"; 610e8d8bef9SDimitry Andric OS << " else\n"; 611e8d8bef9SDimitry Andric OS << " Put(\"" << Clause.getDefaultValue() << "\");\n"; 612e8d8bef9SDimitry Andric OS << " Put(\")\");\n"; 613e8d8bef9SDimitry Andric OS << "}\n"; 614e8d8bef9SDimitry Andric } else { 615e8d8bef9SDimitry Andric OS << "void Unparse(const " << DirLang.getFlangClauseBaseClass() 616e8d8bef9SDimitry Andric << "::" << Clause.getFormattedParserClassName() << " &x) {\n"; 617e8d8bef9SDimitry Andric OS << " Word(\"" << Clause.getName().upper() << "\");\n"; 618e8d8bef9SDimitry Andric OS << " Put(\"(\");\n"; 619e8d8bef9SDimitry Andric if (Clause.isValueList()) 620e8d8bef9SDimitry Andric OS << " Walk(x.v, \",\");\n"; 621e8d8bef9SDimitry Andric else 622e8d8bef9SDimitry Andric OS << " Walk(x.v);\n"; 623e8d8bef9SDimitry Andric OS << " Put(\")\");\n"; 624e8d8bef9SDimitry Andric OS << "}\n"; 625e8d8bef9SDimitry Andric } 626e8d8bef9SDimitry Andric } else { 627e8d8bef9SDimitry Andric OS << "void Before(const " << DirLang.getFlangClauseBaseClass() 628e8d8bef9SDimitry Andric << "::" << Clause.getFormattedParserClassName() << " &) { Word(\"" 629e8d8bef9SDimitry Andric << Clause.getName().upper() << "\"); }\n"; 630e8d8bef9SDimitry Andric } 631e8d8bef9SDimitry Andric } 632e8d8bef9SDimitry Andric } 633e8d8bef9SDimitry Andric 634fe6060f1SDimitry Andric // Generate check in the Enter functions for clauses classes. 635fe6060f1SDimitry Andric void GenerateFlangClauseCheckPrototypes(const DirectiveLanguage &DirLang, 636fe6060f1SDimitry Andric raw_ostream &OS) { 637fe6060f1SDimitry Andric 638fe6060f1SDimitry Andric IfDefScope Scope("GEN_FLANG_CLAUSE_CHECK_ENTER", OS); 639fe6060f1SDimitry Andric 640fe6060f1SDimitry Andric OS << "\n"; 641fe6060f1SDimitry Andric for (const auto &C : DirLang.getClauses()) { 642fe6060f1SDimitry Andric Clause Clause{C}; 643fe6060f1SDimitry Andric OS << "void Enter(const parser::" << DirLang.getFlangClauseBaseClass() 644fe6060f1SDimitry Andric << "::" << Clause.getFormattedParserClassName() << " &);\n"; 645fe6060f1SDimitry Andric } 646fe6060f1SDimitry Andric } 647fe6060f1SDimitry Andric 648fe6060f1SDimitry Andric // Generate the mapping for clauses between the parser class and the 649fe6060f1SDimitry Andric // corresponding clause Kind 650fe6060f1SDimitry Andric void GenerateFlangClauseParserKindMap(const DirectiveLanguage &DirLang, 651fe6060f1SDimitry Andric raw_ostream &OS) { 652fe6060f1SDimitry Andric 653fe6060f1SDimitry Andric IfDefScope Scope("GEN_FLANG_CLAUSE_PARSER_KIND_MAP", OS); 654fe6060f1SDimitry Andric 655fe6060f1SDimitry Andric OS << "\n"; 656fe6060f1SDimitry Andric for (const auto &C : DirLang.getClauses()) { 657fe6060f1SDimitry Andric Clause Clause{C}; 658fe6060f1SDimitry Andric OS << "if constexpr (std::is_same_v<A, parser::" 659fe6060f1SDimitry Andric << DirLang.getFlangClauseBaseClass() 660fe6060f1SDimitry Andric << "::" << Clause.getFormattedParserClassName(); 661fe6060f1SDimitry Andric OS << ">)\n"; 662fe6060f1SDimitry Andric OS << " return llvm::" << DirLang.getCppNamespace() 663fe6060f1SDimitry Andric << "::Clause::" << DirLang.getClausePrefix() << Clause.getFormattedName() 664fe6060f1SDimitry Andric << ";\n"; 665fe6060f1SDimitry Andric } 666fe6060f1SDimitry Andric 667fe6060f1SDimitry Andric OS << "llvm_unreachable(\"Invalid " << DirLang.getName() 668fe6060f1SDimitry Andric << " Parser clause\");\n"; 669fe6060f1SDimitry Andric } 670fe6060f1SDimitry Andric 671e8d8bef9SDimitry Andric // Generate the implementation section for the enumeration in the directive 6725ffd83dbSDimitry Andric // language 673e8d8bef9SDimitry Andric void EmitDirectivesFlangImpl(const DirectiveLanguage &DirLang, 674e8d8bef9SDimitry Andric raw_ostream &OS) { 6755ffd83dbSDimitry Andric 676e8d8bef9SDimitry Andric GenerateDirectiveClauseSets(DirLang, OS); 6775ffd83dbSDimitry Andric 678e8d8bef9SDimitry Andric GenerateDirectiveClauseMap(DirLang, OS); 679e8d8bef9SDimitry Andric 680e8d8bef9SDimitry Andric GenerateFlangClauseParserClass(DirLang, OS); 681e8d8bef9SDimitry Andric 682e8d8bef9SDimitry Andric GenerateFlangClauseParserClassList(DirLang, OS); 683e8d8bef9SDimitry Andric 684e8d8bef9SDimitry Andric GenerateFlangClauseDump(DirLang, OS); 685e8d8bef9SDimitry Andric 686e8d8bef9SDimitry Andric GenerateFlangClauseUnparse(DirLang, OS); 687fe6060f1SDimitry Andric 688fe6060f1SDimitry Andric GenerateFlangClauseCheckPrototypes(DirLang, OS); 689fe6060f1SDimitry Andric 690fe6060f1SDimitry Andric GenerateFlangClauseParserKindMap(DirLang, OS); 6915ffd83dbSDimitry Andric } 6925ffd83dbSDimitry Andric 693e8d8bef9SDimitry Andric void GenerateClauseClassMacro(const DirectiveLanguage &DirLang, 694e8d8bef9SDimitry Andric raw_ostream &OS) { 695e8d8bef9SDimitry Andric // Generate macros style information for legacy code in clang 696e8d8bef9SDimitry Andric IfDefScope Scope("GEN_CLANG_CLAUSE_CLASS", OS); 697e8d8bef9SDimitry Andric 698e8d8bef9SDimitry Andric OS << "\n"; 699e8d8bef9SDimitry Andric 700e8d8bef9SDimitry Andric OS << "#ifndef CLAUSE\n"; 701e8d8bef9SDimitry Andric OS << "#define CLAUSE(Enum, Str, Implicit)\n"; 702e8d8bef9SDimitry Andric OS << "#endif\n"; 703e8d8bef9SDimitry Andric OS << "#ifndef CLAUSE_CLASS\n"; 704e8d8bef9SDimitry Andric OS << "#define CLAUSE_CLASS(Enum, Str, Class)\n"; 705e8d8bef9SDimitry Andric OS << "#endif\n"; 706e8d8bef9SDimitry Andric OS << "#ifndef CLAUSE_NO_CLASS\n"; 707e8d8bef9SDimitry Andric OS << "#define CLAUSE_NO_CLASS(Enum, Str)\n"; 708e8d8bef9SDimitry Andric OS << "#endif\n"; 709e8d8bef9SDimitry Andric OS << "\n"; 710e8d8bef9SDimitry Andric OS << "#define __CLAUSE(Name, Class) \\\n"; 711e8d8bef9SDimitry Andric OS << " CLAUSE(" << DirLang.getClausePrefix() 712e8d8bef9SDimitry Andric << "##Name, #Name, /* Implicit */ false) \\\n"; 713e8d8bef9SDimitry Andric OS << " CLAUSE_CLASS(" << DirLang.getClausePrefix() 714e8d8bef9SDimitry Andric << "##Name, #Name, Class)\n"; 715e8d8bef9SDimitry Andric OS << "#define __CLAUSE_NO_CLASS(Name) \\\n"; 716e8d8bef9SDimitry Andric OS << " CLAUSE(" << DirLang.getClausePrefix() 717e8d8bef9SDimitry Andric << "##Name, #Name, /* Implicit */ false) \\\n"; 718e8d8bef9SDimitry Andric OS << " CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, #Name)\n"; 719e8d8bef9SDimitry Andric OS << "#define __IMPLICIT_CLAUSE_CLASS(Name, Str, Class) \\\n"; 720e8d8bef9SDimitry Andric OS << " CLAUSE(" << DirLang.getClausePrefix() 721e8d8bef9SDimitry Andric << "##Name, Str, /* Implicit */ true) \\\n"; 722e8d8bef9SDimitry Andric OS << " CLAUSE_CLASS(" << DirLang.getClausePrefix() 723e8d8bef9SDimitry Andric << "##Name, Str, Class)\n"; 724e8d8bef9SDimitry Andric OS << "#define __IMPLICIT_CLAUSE_NO_CLASS(Name, Str) \\\n"; 725e8d8bef9SDimitry Andric OS << " CLAUSE(" << DirLang.getClausePrefix() 726e8d8bef9SDimitry Andric << "##Name, Str, /* Implicit */ true) \\\n"; 727e8d8bef9SDimitry Andric OS << " CLAUSE_NO_CLASS(" << DirLang.getClausePrefix() << "##Name, Str)\n"; 728e8d8bef9SDimitry Andric OS << "\n"; 729e8d8bef9SDimitry Andric 730e8d8bef9SDimitry Andric for (const auto &R : DirLang.getClauses()) { 731e8d8bef9SDimitry Andric Clause C{R}; 732e8d8bef9SDimitry Andric if (C.getClangClass().empty()) { // NO_CLASS 733e8d8bef9SDimitry Andric if (C.isImplicit()) { 734e8d8bef9SDimitry Andric OS << "__IMPLICIT_CLAUSE_NO_CLASS(" << C.getFormattedName() << ", \"" 735e8d8bef9SDimitry Andric << C.getFormattedName() << "\")\n"; 736e8d8bef9SDimitry Andric } else { 737e8d8bef9SDimitry Andric OS << "__CLAUSE_NO_CLASS(" << C.getFormattedName() << ")\n"; 738e8d8bef9SDimitry Andric } 739e8d8bef9SDimitry Andric } else { // CLASS 740e8d8bef9SDimitry Andric if (C.isImplicit()) { 741e8d8bef9SDimitry Andric OS << "__IMPLICIT_CLAUSE_CLASS(" << C.getFormattedName() << ", \"" 742e8d8bef9SDimitry Andric << C.getFormattedName() << "\", " << C.getClangClass() << ")\n"; 743e8d8bef9SDimitry Andric } else { 744e8d8bef9SDimitry Andric OS << "__CLAUSE(" << C.getFormattedName() << ", " << C.getClangClass() 745e8d8bef9SDimitry Andric << ")\n"; 746e8d8bef9SDimitry Andric } 747e8d8bef9SDimitry Andric } 748e8d8bef9SDimitry Andric } 749e8d8bef9SDimitry Andric 750e8d8bef9SDimitry Andric OS << "\n"; 751e8d8bef9SDimitry Andric OS << "#undef __IMPLICIT_CLAUSE_NO_CLASS\n"; 752e8d8bef9SDimitry Andric OS << "#undef __IMPLICIT_CLAUSE_CLASS\n"; 753e8d8bef9SDimitry Andric OS << "#undef __CLAUSE\n"; 754e8d8bef9SDimitry Andric OS << "#undef CLAUSE_NO_CLASS\n"; 755e8d8bef9SDimitry Andric OS << "#undef CLAUSE_CLASS\n"; 756e8d8bef9SDimitry Andric OS << "#undef CLAUSE\n"; 757e8d8bef9SDimitry Andric } 758e8d8bef9SDimitry Andric 759fe6060f1SDimitry Andric // Generate the implemenation for the enumeration in the directive 7605ffd83dbSDimitry Andric // language. This code can be included in library. 761fe6060f1SDimitry Andric void EmitDirectivesBasicImpl(const DirectiveLanguage &DirLang, 762fe6060f1SDimitry Andric raw_ostream &OS) { 763fe6060f1SDimitry Andric IfDefScope Scope("GEN_DIRECTIVES_IMPL", OS); 7645ffd83dbSDimitry Andric 7655ffd83dbSDimitry Andric // getDirectiveKind(StringRef Str) 766e8d8bef9SDimitry Andric GenerateGetKind(DirLang.getDirectives(), OS, "Directive", DirLang, 767e8d8bef9SDimitry Andric DirLang.getDirectivePrefix(), /*ImplicitAsUnknown=*/false); 7685ffd83dbSDimitry Andric 7695ffd83dbSDimitry Andric // getDirectiveName(Directive Kind) 770e8d8bef9SDimitry Andric GenerateGetName(DirLang.getDirectives(), OS, "Directive", DirLang, 771e8d8bef9SDimitry Andric DirLang.getDirectivePrefix()); 7725ffd83dbSDimitry Andric 7735ffd83dbSDimitry Andric // getClauseKind(StringRef Str) 774e8d8bef9SDimitry Andric GenerateGetKind(DirLang.getClauses(), OS, "Clause", DirLang, 775e8d8bef9SDimitry Andric DirLang.getClausePrefix(), 776e8d8bef9SDimitry Andric /*ImplicitAsUnknown=*/true); 7775ffd83dbSDimitry Andric 7785ffd83dbSDimitry Andric // getClauseName(Clause Kind) 779e8d8bef9SDimitry Andric GenerateGetName(DirLang.getClauses(), OS, "Clause", DirLang, 780e8d8bef9SDimitry Andric DirLang.getClausePrefix()); 781e8d8bef9SDimitry Andric 782e8d8bef9SDimitry Andric // get<ClauseVal>Kind(StringRef Str) 783e8d8bef9SDimitry Andric GenerateGetKindClauseVal(DirLang, OS); 7845ffd83dbSDimitry Andric 7855ffd83dbSDimitry Andric // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version) 786e8d8bef9SDimitry Andric GenerateIsAllowedClause(DirLang, OS); 7875ffd83dbSDimitry Andric } 7885ffd83dbSDimitry Andric 789fe6060f1SDimitry Andric // Generate the implemenation section for the enumeration in the directive 790fe6060f1SDimitry Andric // language. 791fe6060f1SDimitry Andric void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) { 792fe6060f1SDimitry Andric const auto DirLang = DirectiveLanguage{Records}; 793fe6060f1SDimitry Andric if (DirLang.HasValidityErrors()) 794fe6060f1SDimitry Andric return; 795fe6060f1SDimitry Andric 796fe6060f1SDimitry Andric EmitDirectivesFlangImpl(DirLang, OS); 797fe6060f1SDimitry Andric 798fe6060f1SDimitry Andric GenerateClauseClassMacro(DirLang, OS); 799fe6060f1SDimitry Andric 800fe6060f1SDimitry Andric EmitDirectivesBasicImpl(DirLang, OS); 801fe6060f1SDimitry Andric } 802fe6060f1SDimitry Andric 8035ffd83dbSDimitry Andric } // namespace llvm 804