1*5ffd83dbSDimitry Andric //===- DirectiveEmitter.cpp - Directive Language Emitter ------------------===// 2*5ffd83dbSDimitry Andric // 3*5ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*5ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5ffd83dbSDimitry Andric // 7*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 8*5ffd83dbSDimitry Andric // 9*5ffd83dbSDimitry Andric // DirectiveEmitter uses the descriptions of directives and clauses to construct 10*5ffd83dbSDimitry Andric // common code declarations to be used in Frontends. 11*5ffd83dbSDimitry Andric // 12*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 13*5ffd83dbSDimitry Andric 14*5ffd83dbSDimitry Andric #include "llvm/ADT/STLExtras.h" 15*5ffd83dbSDimitry Andric #include "llvm/ADT/SmallVector.h" 16*5ffd83dbSDimitry Andric #include "llvm/ADT/StringExtras.h" 17*5ffd83dbSDimitry Andric #include "llvm/ADT/StringSet.h" 18*5ffd83dbSDimitry Andric #include "llvm/TableGen/Error.h" 19*5ffd83dbSDimitry Andric #include "llvm/TableGen/Record.h" 20*5ffd83dbSDimitry Andric #include "llvm/TableGen/TableGenBackend.h" 21*5ffd83dbSDimitry Andric 22*5ffd83dbSDimitry Andric using namespace llvm; 23*5ffd83dbSDimitry Andric 24*5ffd83dbSDimitry Andric namespace { 25*5ffd83dbSDimitry Andric // Simple RAII helper for defining ifdef-undef-endif scopes. 26*5ffd83dbSDimitry Andric class IfDefScope { 27*5ffd83dbSDimitry Andric public: 28*5ffd83dbSDimitry Andric IfDefScope(StringRef Name, raw_ostream &OS) : Name(Name), OS(OS) { 29*5ffd83dbSDimitry Andric OS << "#ifdef " << Name << "\n" 30*5ffd83dbSDimitry Andric << "#undef " << Name << "\n"; 31*5ffd83dbSDimitry Andric } 32*5ffd83dbSDimitry Andric 33*5ffd83dbSDimitry Andric ~IfDefScope() { OS << "\n#endif // " << Name << "\n\n"; } 34*5ffd83dbSDimitry Andric 35*5ffd83dbSDimitry Andric private: 36*5ffd83dbSDimitry Andric StringRef Name; 37*5ffd83dbSDimitry Andric raw_ostream &OS; 38*5ffd83dbSDimitry Andric }; 39*5ffd83dbSDimitry Andric } // end anonymous namespace 40*5ffd83dbSDimitry Andric 41*5ffd83dbSDimitry Andric namespace llvm { 42*5ffd83dbSDimitry Andric 43*5ffd83dbSDimitry Andric // Get Directive or Clause name formatted by replacing whitespaces with 44*5ffd83dbSDimitry Andric // underscores. 45*5ffd83dbSDimitry Andric std::string getFormattedName(StringRef Name) { 46*5ffd83dbSDimitry Andric std::string N = Name.str(); 47*5ffd83dbSDimitry Andric std::replace(N.begin(), N.end(), ' ', '_'); 48*5ffd83dbSDimitry Andric return N; 49*5ffd83dbSDimitry Andric } 50*5ffd83dbSDimitry Andric 51*5ffd83dbSDimitry Andric // Generate enum class 52*5ffd83dbSDimitry Andric void GenerateEnumClass(const std::vector<Record *> &Records, raw_ostream &OS, 53*5ffd83dbSDimitry Andric StringRef Enum, StringRef Prefix, StringRef CppNamespace, 54*5ffd83dbSDimitry Andric bool MakeEnumAvailableInNamespace) { 55*5ffd83dbSDimitry Andric OS << "\n"; 56*5ffd83dbSDimitry Andric OS << "enum class " << Enum << " {\n"; 57*5ffd83dbSDimitry Andric for (const auto &R : Records) { 58*5ffd83dbSDimitry Andric const auto Name = R->getValueAsString("name"); 59*5ffd83dbSDimitry Andric OS << " " << Prefix << getFormattedName(Name) << ",\n"; 60*5ffd83dbSDimitry Andric } 61*5ffd83dbSDimitry Andric OS << "};\n"; 62*5ffd83dbSDimitry Andric OS << "\n"; 63*5ffd83dbSDimitry Andric OS << "static constexpr std::size_t " << Enum 64*5ffd83dbSDimitry Andric << "_enumSize = " << Records.size() << ";\n"; 65*5ffd83dbSDimitry Andric 66*5ffd83dbSDimitry Andric // Make the enum values available in the defined namespace. This allows us to 67*5ffd83dbSDimitry Andric // write something like Enum_X if we have a `using namespace <CppNamespace>`. 68*5ffd83dbSDimitry Andric // At the same time we do not loose the strong type guarantees of the enum 69*5ffd83dbSDimitry Andric // class, that is we cannot pass an unsigned as Directive without an explicit 70*5ffd83dbSDimitry Andric // cast. 71*5ffd83dbSDimitry Andric if (MakeEnumAvailableInNamespace) { 72*5ffd83dbSDimitry Andric OS << "\n"; 73*5ffd83dbSDimitry Andric for (const auto &R : Records) { 74*5ffd83dbSDimitry Andric const auto FormattedName = getFormattedName(R->getValueAsString("name")); 75*5ffd83dbSDimitry Andric OS << "constexpr auto " << Prefix << FormattedName << " = " 76*5ffd83dbSDimitry Andric << "llvm::" << CppNamespace << "::" << Enum << "::" << Prefix 77*5ffd83dbSDimitry Andric << FormattedName << ";\n"; 78*5ffd83dbSDimitry Andric } 79*5ffd83dbSDimitry Andric } 80*5ffd83dbSDimitry Andric } 81*5ffd83dbSDimitry Andric 82*5ffd83dbSDimitry Andric // Generate the declaration section for the enumeration in the directive 83*5ffd83dbSDimitry Andric // language 84*5ffd83dbSDimitry Andric void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) { 85*5ffd83dbSDimitry Andric 86*5ffd83dbSDimitry Andric const auto &DirectiveLanguages = 87*5ffd83dbSDimitry Andric Records.getAllDerivedDefinitions("DirectiveLanguage"); 88*5ffd83dbSDimitry Andric 89*5ffd83dbSDimitry Andric if (DirectiveLanguages.size() != 1) { 90*5ffd83dbSDimitry Andric PrintError("A single definition of DirectiveLanguage is needed."); 91*5ffd83dbSDimitry Andric return; 92*5ffd83dbSDimitry Andric } 93*5ffd83dbSDimitry Andric 94*5ffd83dbSDimitry Andric const auto &DirectiveLanguage = DirectiveLanguages[0]; 95*5ffd83dbSDimitry Andric StringRef LanguageName = DirectiveLanguage->getValueAsString("name"); 96*5ffd83dbSDimitry Andric StringRef DirectivePrefix = 97*5ffd83dbSDimitry Andric DirectiveLanguage->getValueAsString("directivePrefix"); 98*5ffd83dbSDimitry Andric StringRef ClausePrefix = DirectiveLanguage->getValueAsString("clausePrefix"); 99*5ffd83dbSDimitry Andric StringRef CppNamespace = DirectiveLanguage->getValueAsString("cppNamespace"); 100*5ffd83dbSDimitry Andric bool MakeEnumAvailableInNamespace = 101*5ffd83dbSDimitry Andric DirectiveLanguage->getValueAsBit("makeEnumAvailableInNamespace"); 102*5ffd83dbSDimitry Andric bool EnableBitmaskEnumInNamespace = 103*5ffd83dbSDimitry Andric DirectiveLanguage->getValueAsBit("enableBitmaskEnumInNamespace"); 104*5ffd83dbSDimitry Andric 105*5ffd83dbSDimitry Andric OS << "#ifndef LLVM_" << LanguageName << "_INC\n"; 106*5ffd83dbSDimitry Andric OS << "#define LLVM_" << LanguageName << "_INC\n"; 107*5ffd83dbSDimitry Andric 108*5ffd83dbSDimitry Andric if (EnableBitmaskEnumInNamespace) 109*5ffd83dbSDimitry Andric OS << "\n#include \"llvm/ADT/BitmaskEnum.h\"\n"; 110*5ffd83dbSDimitry Andric 111*5ffd83dbSDimitry Andric OS << "\n"; 112*5ffd83dbSDimitry Andric OS << "namespace llvm {\n"; 113*5ffd83dbSDimitry Andric OS << "class StringRef;\n"; 114*5ffd83dbSDimitry Andric 115*5ffd83dbSDimitry Andric // Open namespaces defined in the directive language 116*5ffd83dbSDimitry Andric llvm::SmallVector<StringRef, 2> Namespaces; 117*5ffd83dbSDimitry Andric llvm::SplitString(CppNamespace, Namespaces, "::"); 118*5ffd83dbSDimitry Andric for (auto Ns : Namespaces) 119*5ffd83dbSDimitry Andric OS << "namespace " << Ns << " {\n"; 120*5ffd83dbSDimitry Andric 121*5ffd83dbSDimitry Andric if (EnableBitmaskEnumInNamespace) 122*5ffd83dbSDimitry Andric OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n"; 123*5ffd83dbSDimitry Andric 124*5ffd83dbSDimitry Andric // Emit Directive enumeration 125*5ffd83dbSDimitry Andric const auto &Directives = Records.getAllDerivedDefinitions("Directive"); 126*5ffd83dbSDimitry Andric GenerateEnumClass(Directives, OS, "Directive", DirectivePrefix, CppNamespace, 127*5ffd83dbSDimitry Andric MakeEnumAvailableInNamespace); 128*5ffd83dbSDimitry Andric 129*5ffd83dbSDimitry Andric // Emit Clause enumeration 130*5ffd83dbSDimitry Andric const auto &Clauses = Records.getAllDerivedDefinitions("Clause"); 131*5ffd83dbSDimitry Andric GenerateEnumClass(Clauses, OS, "Clause", ClausePrefix, CppNamespace, 132*5ffd83dbSDimitry Andric MakeEnumAvailableInNamespace); 133*5ffd83dbSDimitry Andric 134*5ffd83dbSDimitry Andric // Generic function signatures 135*5ffd83dbSDimitry Andric OS << "\n"; 136*5ffd83dbSDimitry Andric OS << "// Enumeration helper functions\n"; 137*5ffd83dbSDimitry Andric OS << "Directive get" << LanguageName 138*5ffd83dbSDimitry Andric << "DirectiveKind(llvm::StringRef Str);\n"; 139*5ffd83dbSDimitry Andric OS << "\n"; 140*5ffd83dbSDimitry Andric OS << "llvm::StringRef get" << LanguageName 141*5ffd83dbSDimitry Andric << "DirectiveName(Directive D);\n"; 142*5ffd83dbSDimitry Andric OS << "\n"; 143*5ffd83dbSDimitry Andric OS << "Clause get" << LanguageName << "ClauseKind(llvm::StringRef Str);\n"; 144*5ffd83dbSDimitry Andric OS << "\n"; 145*5ffd83dbSDimitry Andric OS << "llvm::StringRef get" << LanguageName << "ClauseName(Clause C);\n"; 146*5ffd83dbSDimitry Andric OS << "\n"; 147*5ffd83dbSDimitry Andric OS << "/// Return true if \\p C is a valid clause for \\p D in version \\p " 148*5ffd83dbSDimitry Andric << "Version.\n"; 149*5ffd83dbSDimitry Andric OS << "bool isAllowedClauseForDirective(Directive D, " 150*5ffd83dbSDimitry Andric << "Clause C, unsigned Version);\n"; 151*5ffd83dbSDimitry Andric OS << "\n"; 152*5ffd83dbSDimitry Andric 153*5ffd83dbSDimitry Andric // Closing namespaces 154*5ffd83dbSDimitry Andric for (auto Ns : llvm::reverse(Namespaces)) 155*5ffd83dbSDimitry Andric OS << "} // namespace " << Ns << "\n"; 156*5ffd83dbSDimitry Andric 157*5ffd83dbSDimitry Andric OS << "} // namespace llvm\n"; 158*5ffd83dbSDimitry Andric 159*5ffd83dbSDimitry Andric OS << "#endif // LLVM_" << LanguageName << "_INC\n"; 160*5ffd83dbSDimitry Andric } 161*5ffd83dbSDimitry Andric 162*5ffd83dbSDimitry Andric // Generate function implementation for get<Enum>Name(StringRef Str) 163*5ffd83dbSDimitry Andric void GenerateGetName(const std::vector<Record *> &Records, raw_ostream &OS, 164*5ffd83dbSDimitry Andric StringRef Enum, StringRef Prefix, StringRef LanguageName, 165*5ffd83dbSDimitry Andric StringRef Namespace) { 166*5ffd83dbSDimitry Andric OS << "\n"; 167*5ffd83dbSDimitry Andric OS << "llvm::StringRef llvm::" << Namespace << "::get" << LanguageName << Enum 168*5ffd83dbSDimitry Andric << "Name(" << Enum << " Kind) {\n"; 169*5ffd83dbSDimitry Andric OS << " switch (Kind) {\n"; 170*5ffd83dbSDimitry Andric for (const auto &R : Records) { 171*5ffd83dbSDimitry Andric const auto Name = R->getValueAsString("name"); 172*5ffd83dbSDimitry Andric const auto AlternativeName = R->getValueAsString("alternativeName"); 173*5ffd83dbSDimitry Andric OS << " case " << Prefix << getFormattedName(Name) << ":\n"; 174*5ffd83dbSDimitry Andric OS << " return \""; 175*5ffd83dbSDimitry Andric if (AlternativeName.empty()) 176*5ffd83dbSDimitry Andric OS << Name; 177*5ffd83dbSDimitry Andric else 178*5ffd83dbSDimitry Andric OS << AlternativeName; 179*5ffd83dbSDimitry Andric OS << "\";\n"; 180*5ffd83dbSDimitry Andric } 181*5ffd83dbSDimitry Andric OS << " }\n"; // switch 182*5ffd83dbSDimitry Andric OS << " llvm_unreachable(\"Invalid " << LanguageName << " " << Enum 183*5ffd83dbSDimitry Andric << " kind\");\n"; 184*5ffd83dbSDimitry Andric OS << "}\n"; 185*5ffd83dbSDimitry Andric } 186*5ffd83dbSDimitry Andric 187*5ffd83dbSDimitry Andric // Generate function implementation for get<Enum>Kind(StringRef Str) 188*5ffd83dbSDimitry Andric void GenerateGetKind(const std::vector<Record *> &Records, raw_ostream &OS, 189*5ffd83dbSDimitry Andric StringRef Enum, StringRef Prefix, StringRef LanguageName, 190*5ffd83dbSDimitry Andric StringRef Namespace, bool ImplicitAsUnknown) { 191*5ffd83dbSDimitry Andric 192*5ffd83dbSDimitry Andric auto DefaultIt = std::find_if(Records.begin(), Records.end(), [](Record *R) { 193*5ffd83dbSDimitry Andric return R->getValueAsBit("isDefault") == true; 194*5ffd83dbSDimitry Andric }); 195*5ffd83dbSDimitry Andric 196*5ffd83dbSDimitry Andric if (DefaultIt == Records.end()) { 197*5ffd83dbSDimitry Andric PrintError("A least one " + Enum + " must be defined as default."); 198*5ffd83dbSDimitry Andric return; 199*5ffd83dbSDimitry Andric } 200*5ffd83dbSDimitry Andric 201*5ffd83dbSDimitry Andric const auto FormattedDefaultName = 202*5ffd83dbSDimitry Andric getFormattedName((*DefaultIt)->getValueAsString("name")); 203*5ffd83dbSDimitry Andric 204*5ffd83dbSDimitry Andric OS << "\n"; 205*5ffd83dbSDimitry Andric OS << Enum << " llvm::" << Namespace << "::get" << LanguageName << Enum 206*5ffd83dbSDimitry Andric << "Kind(llvm::StringRef Str) {\n"; 207*5ffd83dbSDimitry Andric OS << " return llvm::StringSwitch<" << Enum << ">(Str)\n"; 208*5ffd83dbSDimitry Andric 209*5ffd83dbSDimitry Andric for (const auto &R : Records) { 210*5ffd83dbSDimitry Andric const auto Name = R->getValueAsString("name"); 211*5ffd83dbSDimitry Andric if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) { 212*5ffd83dbSDimitry Andric OS << " .Case(\"" << Name << "\"," << Prefix << FormattedDefaultName 213*5ffd83dbSDimitry Andric << ")\n"; 214*5ffd83dbSDimitry Andric } else { 215*5ffd83dbSDimitry Andric OS << " .Case(\"" << Name << "\"," << Prefix << getFormattedName(Name) 216*5ffd83dbSDimitry Andric << ")\n"; 217*5ffd83dbSDimitry Andric } 218*5ffd83dbSDimitry Andric } 219*5ffd83dbSDimitry Andric OS << " .Default(" << Prefix << FormattedDefaultName << ");\n"; 220*5ffd83dbSDimitry Andric OS << "}\n"; 221*5ffd83dbSDimitry Andric } 222*5ffd83dbSDimitry Andric 223*5ffd83dbSDimitry Andric void GenerateCaseForVersionedClauses(const std::vector<Record *> &Clauses, 224*5ffd83dbSDimitry Andric raw_ostream &OS, StringRef DirectiveName, 225*5ffd83dbSDimitry Andric StringRef DirectivePrefix, 226*5ffd83dbSDimitry Andric StringRef ClausePrefix, 227*5ffd83dbSDimitry Andric llvm::StringSet<> &Cases) { 228*5ffd83dbSDimitry Andric for (const auto &C : Clauses) { 229*5ffd83dbSDimitry Andric const auto MinVersion = C->getValueAsInt("minVersion"); 230*5ffd83dbSDimitry Andric const auto MaxVersion = C->getValueAsInt("maxVersion"); 231*5ffd83dbSDimitry Andric const auto SpecificClause = C->getValueAsDef("clause"); 232*5ffd83dbSDimitry Andric const auto ClauseName = 233*5ffd83dbSDimitry Andric getFormattedName(SpecificClause->getValueAsString("name")); 234*5ffd83dbSDimitry Andric 235*5ffd83dbSDimitry Andric if (Cases.find(ClauseName) == Cases.end()) { 236*5ffd83dbSDimitry Andric Cases.insert(ClauseName); 237*5ffd83dbSDimitry Andric OS << " case " << ClausePrefix << ClauseName << ":\n"; 238*5ffd83dbSDimitry Andric OS << " return " << MinVersion << " <= Version && " << MaxVersion 239*5ffd83dbSDimitry Andric << " >= Version;\n"; 240*5ffd83dbSDimitry Andric } 241*5ffd83dbSDimitry Andric } 242*5ffd83dbSDimitry Andric } 243*5ffd83dbSDimitry Andric 244*5ffd83dbSDimitry Andric // Generate the isAllowedClauseForDirective function implementation. 245*5ffd83dbSDimitry Andric void GenerateIsAllowedClause(const std::vector<Record *> &Directives, 246*5ffd83dbSDimitry Andric raw_ostream &OS, StringRef LanguageName, 247*5ffd83dbSDimitry Andric StringRef DirectivePrefix, StringRef ClausePrefix, 248*5ffd83dbSDimitry Andric StringRef CppNamespace) { 249*5ffd83dbSDimitry Andric OS << "\n"; 250*5ffd83dbSDimitry Andric OS << "bool llvm::" << CppNamespace << "::isAllowedClauseForDirective(" 251*5ffd83dbSDimitry Andric << "Directive D, Clause C, unsigned Version) {\n"; 252*5ffd83dbSDimitry Andric OS << " assert(unsigned(D) <= llvm::" << CppNamespace 253*5ffd83dbSDimitry Andric << "::Directive_enumSize);\n"; 254*5ffd83dbSDimitry Andric OS << " assert(unsigned(C) <= llvm::" << CppNamespace 255*5ffd83dbSDimitry Andric << "::Clause_enumSize);\n"; 256*5ffd83dbSDimitry Andric 257*5ffd83dbSDimitry Andric OS << " switch (D) {\n"; 258*5ffd83dbSDimitry Andric 259*5ffd83dbSDimitry Andric for (const auto &D : Directives) { 260*5ffd83dbSDimitry Andric 261*5ffd83dbSDimitry Andric const auto DirectiveName = D->getValueAsString("name"); 262*5ffd83dbSDimitry Andric const auto &AllowedClauses = D->getValueAsListOfDefs("allowedClauses"); 263*5ffd83dbSDimitry Andric const auto &AllowedOnceClauses = 264*5ffd83dbSDimitry Andric D->getValueAsListOfDefs("allowedOnceClauses"); 265*5ffd83dbSDimitry Andric const auto &AllowedExclusiveClauses = 266*5ffd83dbSDimitry Andric D->getValueAsListOfDefs("allowedExclusiveClauses"); 267*5ffd83dbSDimitry Andric const auto &RequiredClauses = D->getValueAsListOfDefs("requiredClauses"); 268*5ffd83dbSDimitry Andric 269*5ffd83dbSDimitry Andric OS << " case " << DirectivePrefix << getFormattedName(DirectiveName) 270*5ffd83dbSDimitry Andric << ":\n"; 271*5ffd83dbSDimitry Andric if (AllowedClauses.size() == 0 && AllowedOnceClauses.size() == 0 && 272*5ffd83dbSDimitry Andric AllowedExclusiveClauses.size() == 0 && RequiredClauses.size() == 0) { 273*5ffd83dbSDimitry Andric OS << " return false;\n"; 274*5ffd83dbSDimitry Andric } else { 275*5ffd83dbSDimitry Andric OS << " switch (C) {\n"; 276*5ffd83dbSDimitry Andric 277*5ffd83dbSDimitry Andric llvm::StringSet<> Cases; 278*5ffd83dbSDimitry Andric 279*5ffd83dbSDimitry Andric GenerateCaseForVersionedClauses(AllowedClauses, OS, DirectiveName, 280*5ffd83dbSDimitry Andric DirectivePrefix, ClausePrefix, Cases); 281*5ffd83dbSDimitry Andric 282*5ffd83dbSDimitry Andric GenerateCaseForVersionedClauses(AllowedOnceClauses, OS, DirectiveName, 283*5ffd83dbSDimitry Andric DirectivePrefix, ClausePrefix, Cases); 284*5ffd83dbSDimitry Andric 285*5ffd83dbSDimitry Andric GenerateCaseForVersionedClauses(AllowedExclusiveClauses, OS, 286*5ffd83dbSDimitry Andric DirectiveName, DirectivePrefix, 287*5ffd83dbSDimitry Andric ClausePrefix, Cases); 288*5ffd83dbSDimitry Andric 289*5ffd83dbSDimitry Andric GenerateCaseForVersionedClauses(RequiredClauses, OS, DirectiveName, 290*5ffd83dbSDimitry Andric DirectivePrefix, ClausePrefix, Cases); 291*5ffd83dbSDimitry Andric 292*5ffd83dbSDimitry Andric OS << " default:\n"; 293*5ffd83dbSDimitry Andric OS << " return false;\n"; 294*5ffd83dbSDimitry Andric OS << " }\n"; // End of clauses switch 295*5ffd83dbSDimitry Andric } 296*5ffd83dbSDimitry Andric OS << " break;\n"; 297*5ffd83dbSDimitry Andric } 298*5ffd83dbSDimitry Andric 299*5ffd83dbSDimitry Andric OS << " }\n"; // End of directives switch 300*5ffd83dbSDimitry Andric OS << " llvm_unreachable(\"Invalid " << LanguageName 301*5ffd83dbSDimitry Andric << " Directive kind\");\n"; 302*5ffd83dbSDimitry Andric OS << "}\n"; // End of function isAllowedClauseForDirective 303*5ffd83dbSDimitry Andric } 304*5ffd83dbSDimitry Andric 305*5ffd83dbSDimitry Andric // Generate a simple enum set with the give clauses. 306*5ffd83dbSDimitry Andric void GenerateClauseSet(const std::vector<Record *> &Clauses, raw_ostream &OS, 307*5ffd83dbSDimitry Andric StringRef ClauseEnumSetClass, StringRef ClauseSetPrefix, 308*5ffd83dbSDimitry Andric StringRef DirectiveName, StringRef DirectivePrefix, 309*5ffd83dbSDimitry Andric StringRef ClausePrefix, StringRef CppNamespace) { 310*5ffd83dbSDimitry Andric 311*5ffd83dbSDimitry Andric OS << "\n"; 312*5ffd83dbSDimitry Andric OS << " static " << ClauseEnumSetClass << " " << ClauseSetPrefix 313*5ffd83dbSDimitry Andric << DirectivePrefix << getFormattedName(DirectiveName) << " {\n"; 314*5ffd83dbSDimitry Andric 315*5ffd83dbSDimitry Andric for (const auto &C : Clauses) { 316*5ffd83dbSDimitry Andric const auto SpecificClause = C->getValueAsDef("clause"); 317*5ffd83dbSDimitry Andric const auto ClauseName = SpecificClause->getValueAsString("name"); 318*5ffd83dbSDimitry Andric OS << " llvm::" << CppNamespace << "::Clause::" << ClausePrefix 319*5ffd83dbSDimitry Andric << getFormattedName(ClauseName) << ",\n"; 320*5ffd83dbSDimitry Andric } 321*5ffd83dbSDimitry Andric OS << " };\n"; 322*5ffd83dbSDimitry Andric } 323*5ffd83dbSDimitry Andric 324*5ffd83dbSDimitry Andric // Generate an enum set for the 4 kinds of clauses linked to a directive. 325*5ffd83dbSDimitry Andric void GenerateDirectiveClauseSets(const std::vector<Record *> &Directives, 326*5ffd83dbSDimitry Andric raw_ostream &OS, StringRef LanguageName, 327*5ffd83dbSDimitry Andric StringRef ClauseEnumSetClass, 328*5ffd83dbSDimitry Andric StringRef DirectivePrefix, 329*5ffd83dbSDimitry Andric StringRef ClausePrefix, 330*5ffd83dbSDimitry Andric StringRef CppNamespace) { 331*5ffd83dbSDimitry Andric 332*5ffd83dbSDimitry Andric IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_SETS", OS); 333*5ffd83dbSDimitry Andric 334*5ffd83dbSDimitry Andric OS << "\n"; 335*5ffd83dbSDimitry Andric OS << "namespace llvm {\n"; 336*5ffd83dbSDimitry Andric 337*5ffd83dbSDimitry Andric // Open namespaces defined in the directive language. 338*5ffd83dbSDimitry Andric llvm::SmallVector<StringRef, 2> Namespaces; 339*5ffd83dbSDimitry Andric llvm::SplitString(CppNamespace, Namespaces, "::"); 340*5ffd83dbSDimitry Andric for (auto Ns : Namespaces) 341*5ffd83dbSDimitry Andric OS << "namespace " << Ns << " {\n"; 342*5ffd83dbSDimitry Andric 343*5ffd83dbSDimitry Andric for (const auto &D : Directives) { 344*5ffd83dbSDimitry Andric const auto DirectiveName = D->getValueAsString("name"); 345*5ffd83dbSDimitry Andric 346*5ffd83dbSDimitry Andric const auto &AllowedClauses = D->getValueAsListOfDefs("allowedClauses"); 347*5ffd83dbSDimitry Andric const auto &AllowedOnceClauses = 348*5ffd83dbSDimitry Andric D->getValueAsListOfDefs("allowedOnceClauses"); 349*5ffd83dbSDimitry Andric const auto &AllowedExclusiveClauses = 350*5ffd83dbSDimitry Andric D->getValueAsListOfDefs("allowedExclusiveClauses"); 351*5ffd83dbSDimitry Andric const auto &RequiredClauses = D->getValueAsListOfDefs("requiredClauses"); 352*5ffd83dbSDimitry Andric 353*5ffd83dbSDimitry Andric OS << "\n"; 354*5ffd83dbSDimitry Andric OS << " // Sets for " << DirectiveName << "\n"; 355*5ffd83dbSDimitry Andric 356*5ffd83dbSDimitry Andric GenerateClauseSet(AllowedClauses, OS, ClauseEnumSetClass, "allowedClauses_", 357*5ffd83dbSDimitry Andric DirectiveName, DirectivePrefix, ClausePrefix, 358*5ffd83dbSDimitry Andric CppNamespace); 359*5ffd83dbSDimitry Andric GenerateClauseSet(AllowedOnceClauses, OS, ClauseEnumSetClass, 360*5ffd83dbSDimitry Andric "allowedOnceClauses_", DirectiveName, DirectivePrefix, 361*5ffd83dbSDimitry Andric ClausePrefix, CppNamespace); 362*5ffd83dbSDimitry Andric GenerateClauseSet(AllowedExclusiveClauses, OS, ClauseEnumSetClass, 363*5ffd83dbSDimitry Andric "allowedExclusiveClauses_", DirectiveName, 364*5ffd83dbSDimitry Andric DirectivePrefix, ClausePrefix, CppNamespace); 365*5ffd83dbSDimitry Andric GenerateClauseSet(RequiredClauses, OS, ClauseEnumSetClass, 366*5ffd83dbSDimitry Andric "requiredClauses_", DirectiveName, DirectivePrefix, 367*5ffd83dbSDimitry Andric ClausePrefix, CppNamespace); 368*5ffd83dbSDimitry Andric } 369*5ffd83dbSDimitry Andric 370*5ffd83dbSDimitry Andric // Closing namespaces 371*5ffd83dbSDimitry Andric for (auto Ns : llvm::reverse(Namespaces)) 372*5ffd83dbSDimitry Andric OS << "} // namespace " << Ns << "\n"; 373*5ffd83dbSDimitry Andric 374*5ffd83dbSDimitry Andric OS << "} // namespace llvm\n"; 375*5ffd83dbSDimitry Andric } 376*5ffd83dbSDimitry Andric 377*5ffd83dbSDimitry Andric // Generate a map of directive (key) with DirectiveClauses struct as values. 378*5ffd83dbSDimitry Andric // The struct holds the 4 sets of enumeration for the 4 kinds of clauses 379*5ffd83dbSDimitry Andric // allowances (allowed, allowed once, allowed exclusive and required). 380*5ffd83dbSDimitry Andric void GenerateDirectiveClauseMap(const std::vector<Record *> &Directives, 381*5ffd83dbSDimitry Andric raw_ostream &OS, StringRef LanguageName, 382*5ffd83dbSDimitry Andric StringRef ClauseEnumSetClass, 383*5ffd83dbSDimitry Andric StringRef DirectivePrefix, 384*5ffd83dbSDimitry Andric StringRef ClausePrefix, 385*5ffd83dbSDimitry Andric StringRef CppNamespace) { 386*5ffd83dbSDimitry Andric 387*5ffd83dbSDimitry Andric IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_MAP", OS); 388*5ffd83dbSDimitry Andric 389*5ffd83dbSDimitry Andric OS << "\n"; 390*5ffd83dbSDimitry Andric OS << "struct " << LanguageName << "DirectiveClauses {\n"; 391*5ffd83dbSDimitry Andric OS << " const " << ClauseEnumSetClass << " allowed;\n"; 392*5ffd83dbSDimitry Andric OS << " const " << ClauseEnumSetClass << " allowedOnce;\n"; 393*5ffd83dbSDimitry Andric OS << " const " << ClauseEnumSetClass << " allowedExclusive;\n"; 394*5ffd83dbSDimitry Andric OS << " const " << ClauseEnumSetClass << " requiredOneOf;\n"; 395*5ffd83dbSDimitry Andric OS << "};\n"; 396*5ffd83dbSDimitry Andric 397*5ffd83dbSDimitry Andric OS << "\n"; 398*5ffd83dbSDimitry Andric 399*5ffd83dbSDimitry Andric OS << "std::unordered_map<llvm::" << CppNamespace << "::Directive, " 400*5ffd83dbSDimitry Andric << LanguageName << "DirectiveClauses>\n"; 401*5ffd83dbSDimitry Andric OS << " directiveClausesTable = {\n"; 402*5ffd83dbSDimitry Andric 403*5ffd83dbSDimitry Andric for (const auto &D : Directives) { 404*5ffd83dbSDimitry Andric const auto FormattedDirectiveName = 405*5ffd83dbSDimitry Andric getFormattedName(D->getValueAsString("name")); 406*5ffd83dbSDimitry Andric OS << " {llvm::" << CppNamespace << "::Directive::" << DirectivePrefix 407*5ffd83dbSDimitry Andric << FormattedDirectiveName << ",\n"; 408*5ffd83dbSDimitry Andric OS << " {\n"; 409*5ffd83dbSDimitry Andric OS << " llvm::" << CppNamespace << "::allowedClauses_" 410*5ffd83dbSDimitry Andric << DirectivePrefix << FormattedDirectiveName << ",\n"; 411*5ffd83dbSDimitry Andric OS << " llvm::" << CppNamespace << "::allowedOnceClauses_" 412*5ffd83dbSDimitry Andric << DirectivePrefix << FormattedDirectiveName << ",\n"; 413*5ffd83dbSDimitry Andric OS << " llvm::" << CppNamespace << "::allowedExclusiveClauses_" 414*5ffd83dbSDimitry Andric << DirectivePrefix << FormattedDirectiveName << ",\n"; 415*5ffd83dbSDimitry Andric OS << " llvm::" << CppNamespace << "::requiredClauses_" 416*5ffd83dbSDimitry Andric << DirectivePrefix << FormattedDirectiveName << ",\n"; 417*5ffd83dbSDimitry Andric OS << " }\n"; 418*5ffd83dbSDimitry Andric OS << " },\n"; 419*5ffd83dbSDimitry Andric } 420*5ffd83dbSDimitry Andric 421*5ffd83dbSDimitry Andric OS << "};\n"; 422*5ffd83dbSDimitry Andric } 423*5ffd83dbSDimitry Andric 424*5ffd83dbSDimitry Andric // Generate the implemenation section for the enumeration in the directive 425*5ffd83dbSDimitry Andric // language 426*5ffd83dbSDimitry Andric void EmitDirectivesFlangImpl(const std::vector<Record *> &Directives, 427*5ffd83dbSDimitry Andric raw_ostream &OS, StringRef LanguageName, 428*5ffd83dbSDimitry Andric StringRef ClauseEnumSetClass, 429*5ffd83dbSDimitry Andric StringRef DirectivePrefix, StringRef ClausePrefix, 430*5ffd83dbSDimitry Andric StringRef CppNamespace) { 431*5ffd83dbSDimitry Andric 432*5ffd83dbSDimitry Andric GenerateDirectiveClauseSets(Directives, OS, LanguageName, ClauseEnumSetClass, 433*5ffd83dbSDimitry Andric DirectivePrefix, ClausePrefix, CppNamespace); 434*5ffd83dbSDimitry Andric 435*5ffd83dbSDimitry Andric GenerateDirectiveClauseMap(Directives, OS, LanguageName, ClauseEnumSetClass, 436*5ffd83dbSDimitry Andric DirectivePrefix, ClausePrefix, CppNamespace); 437*5ffd83dbSDimitry Andric } 438*5ffd83dbSDimitry Andric 439*5ffd83dbSDimitry Andric // Generate the implemenation section for the enumeration in the directive 440*5ffd83dbSDimitry Andric // language. 441*5ffd83dbSDimitry Andric void EmitDirectivesGen(RecordKeeper &Records, raw_ostream &OS) { 442*5ffd83dbSDimitry Andric 443*5ffd83dbSDimitry Andric const auto &DirectiveLanguages = 444*5ffd83dbSDimitry Andric Records.getAllDerivedDefinitions("DirectiveLanguage"); 445*5ffd83dbSDimitry Andric 446*5ffd83dbSDimitry Andric if (DirectiveLanguages.size() != 1) { 447*5ffd83dbSDimitry Andric PrintError("A single definition of DirectiveLanguage is needed."); 448*5ffd83dbSDimitry Andric return; 449*5ffd83dbSDimitry Andric } 450*5ffd83dbSDimitry Andric 451*5ffd83dbSDimitry Andric const auto &DirectiveLanguage = DirectiveLanguages[0]; 452*5ffd83dbSDimitry Andric StringRef DirectivePrefix = 453*5ffd83dbSDimitry Andric DirectiveLanguage->getValueAsString("directivePrefix"); 454*5ffd83dbSDimitry Andric StringRef LanguageName = DirectiveLanguage->getValueAsString("name"); 455*5ffd83dbSDimitry Andric StringRef ClausePrefix = DirectiveLanguage->getValueAsString("clausePrefix"); 456*5ffd83dbSDimitry Andric StringRef CppNamespace = DirectiveLanguage->getValueAsString("cppNamespace"); 457*5ffd83dbSDimitry Andric StringRef ClauseEnumSetClass = 458*5ffd83dbSDimitry Andric DirectiveLanguage->getValueAsString("clauseEnumSetClass"); 459*5ffd83dbSDimitry Andric 460*5ffd83dbSDimitry Andric const auto &Directives = Records.getAllDerivedDefinitions("Directive"); 461*5ffd83dbSDimitry Andric 462*5ffd83dbSDimitry Andric EmitDirectivesFlangImpl(Directives, OS, LanguageName, ClauseEnumSetClass, 463*5ffd83dbSDimitry Andric DirectivePrefix, ClausePrefix, CppNamespace); 464*5ffd83dbSDimitry Andric } 465*5ffd83dbSDimitry Andric 466*5ffd83dbSDimitry Andric // Generate the implemenation for the enumeration in the directive 467*5ffd83dbSDimitry Andric // language. This code can be included in library. 468*5ffd83dbSDimitry Andric void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) { 469*5ffd83dbSDimitry Andric 470*5ffd83dbSDimitry Andric const auto &DirectiveLanguages = 471*5ffd83dbSDimitry Andric Records.getAllDerivedDefinitions("DirectiveLanguage"); 472*5ffd83dbSDimitry Andric 473*5ffd83dbSDimitry Andric if (DirectiveLanguages.size() != 1) { 474*5ffd83dbSDimitry Andric PrintError("A single definition of DirectiveLanguage is needed."); 475*5ffd83dbSDimitry Andric return; 476*5ffd83dbSDimitry Andric } 477*5ffd83dbSDimitry Andric 478*5ffd83dbSDimitry Andric const auto &DirectiveLanguage = DirectiveLanguages[0]; 479*5ffd83dbSDimitry Andric StringRef DirectivePrefix = 480*5ffd83dbSDimitry Andric DirectiveLanguage->getValueAsString("directivePrefix"); 481*5ffd83dbSDimitry Andric StringRef LanguageName = DirectiveLanguage->getValueAsString("name"); 482*5ffd83dbSDimitry Andric StringRef ClausePrefix = DirectiveLanguage->getValueAsString("clausePrefix"); 483*5ffd83dbSDimitry Andric StringRef CppNamespace = DirectiveLanguage->getValueAsString("cppNamespace"); 484*5ffd83dbSDimitry Andric const auto &Directives = Records.getAllDerivedDefinitions("Directive"); 485*5ffd83dbSDimitry Andric const auto &Clauses = Records.getAllDerivedDefinitions("Clause"); 486*5ffd83dbSDimitry Andric 487*5ffd83dbSDimitry Andric StringRef IncludeHeader = 488*5ffd83dbSDimitry Andric DirectiveLanguage->getValueAsString("includeHeader"); 489*5ffd83dbSDimitry Andric 490*5ffd83dbSDimitry Andric if (!IncludeHeader.empty()) 491*5ffd83dbSDimitry Andric OS << "#include \"" << IncludeHeader << "\"\n\n"; 492*5ffd83dbSDimitry Andric 493*5ffd83dbSDimitry Andric OS << "#include \"llvm/ADT/StringRef.h\"\n"; 494*5ffd83dbSDimitry Andric OS << "#include \"llvm/ADT/StringSwitch.h\"\n"; 495*5ffd83dbSDimitry Andric OS << "#include \"llvm/Support/ErrorHandling.h\"\n"; 496*5ffd83dbSDimitry Andric OS << "\n"; 497*5ffd83dbSDimitry Andric OS << "using namespace llvm;\n"; 498*5ffd83dbSDimitry Andric llvm::SmallVector<StringRef, 2> Namespaces; 499*5ffd83dbSDimitry Andric llvm::SplitString(CppNamespace, Namespaces, "::"); 500*5ffd83dbSDimitry Andric for (auto Ns : Namespaces) 501*5ffd83dbSDimitry Andric OS << "using namespace " << Ns << ";\n"; 502*5ffd83dbSDimitry Andric 503*5ffd83dbSDimitry Andric // getDirectiveKind(StringRef Str) 504*5ffd83dbSDimitry Andric GenerateGetKind(Directives, OS, "Directive", DirectivePrefix, LanguageName, 505*5ffd83dbSDimitry Andric CppNamespace, /*ImplicitAsUnknown=*/false); 506*5ffd83dbSDimitry Andric 507*5ffd83dbSDimitry Andric // getDirectiveName(Directive Kind) 508*5ffd83dbSDimitry Andric GenerateGetName(Directives, OS, "Directive", DirectivePrefix, LanguageName, 509*5ffd83dbSDimitry Andric CppNamespace); 510*5ffd83dbSDimitry Andric 511*5ffd83dbSDimitry Andric // getClauseKind(StringRef Str) 512*5ffd83dbSDimitry Andric GenerateGetKind(Clauses, OS, "Clause", ClausePrefix, LanguageName, 513*5ffd83dbSDimitry Andric CppNamespace, /*ImplicitAsUnknown=*/true); 514*5ffd83dbSDimitry Andric 515*5ffd83dbSDimitry Andric // getClauseName(Clause Kind) 516*5ffd83dbSDimitry Andric GenerateGetName(Clauses, OS, "Clause", ClausePrefix, LanguageName, 517*5ffd83dbSDimitry Andric CppNamespace); 518*5ffd83dbSDimitry Andric 519*5ffd83dbSDimitry Andric // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version) 520*5ffd83dbSDimitry Andric GenerateIsAllowedClause(Directives, OS, LanguageName, DirectivePrefix, 521*5ffd83dbSDimitry Andric ClausePrefix, CppNamespace); 522*5ffd83dbSDimitry Andric } 523*5ffd83dbSDimitry Andric 524*5ffd83dbSDimitry Andric } // namespace llvm 525