diff --git a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td --- a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td +++ b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// -// General information about the directive language +// General information about the directive language. class DirectiveLanguage { // Name of the directive language such as omp or acc. string name = ?; @@ -37,20 +37,28 @@ // write something like Enum_X if we have a `using namespace cppNamespace`. bit makeEnumAvailableInNamespace = 0; - // Generate include and macro to enable LLVM BitmaskEnum + // Generate include and macro to enable LLVM BitmaskEnum. bit enableBitmaskEnumInNamespace = 0; } -// Information about a specific clause +// Information about a specific clause. class Clause { - // Name of the clause + // Name of the clause. string name = c; - // Optional class holding value of the clause in clang AST + // Define an alternative name return in getClauseName function. + string alternativeName = ""; + + // Optional class holding value of the clause in clang AST. string clangClass = ?; - // Is clause implicit? + // Is clause implicit? If clause is set as implicit, the default kind will + // be return in getClauseKind instead of their own kind. bit isImplicit = 0; + + // Set directive used by default when unknown. Function returning the kind + // of enumeration will use this clause as the default. + bit isDefault = 0; } // Information about a specific directive @@ -58,6 +66,10 @@ // Name of the directive. Can be composite directive sepearted by whitespace. string name = d; + // Define an alternative name return in getDirectiveName + // function. + string alternativeName = ""; + // List of allowed clauses for the directive. list allowedClauses = ?; @@ -66,4 +78,7 @@ // List of clauses that are required. list requiredClauses = ?; + + // Set directive used by default when unknown. + bit isDefault = 0; } diff --git a/llvm/include/llvm/Frontend/OpenMP/CMakeLists.txt b/llvm/include/llvm/Frontend/OpenMP/CMakeLists.txt --- a/llvm/include/llvm/Frontend/OpenMP/CMakeLists.txt +++ b/llvm/include/llvm/Frontend/OpenMP/CMakeLists.txt @@ -1,3 +1,4 @@ set(LLVM_TARGET_DEFINITIONS OMP.td) -tablegen(LLVM OMP.h.inc --gen-directive-decls) +tablegen(LLVM OMP.h.inc --gen-directive-decl) +tablegen(LLVM OMP.cpp.inc --gen-directive-impl) add_public_tablegen_target(omp_gen) diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -182,11 +182,12 @@ let isImplicit = 1; } def OMPC_ThreadPrivate : Clause<"threadprivate"> { - // threadprivate or thread local + let alternativeName = "threadprivate or thread local"; let isImplicit = 1; } def OMPC_Unknown : Clause<"unknown"> { let isImplicit = 1; + let isDefault = 1; } //===----------------------------------------------------------------------===// @@ -493,4 +494,6 @@ } def OMP_BeginDeclareVariant : Directive<"begin declare variant"> {} def OMP_EndDeclareVariant : Directive<"end declare variant"> {} -def OMP_Unknown : Directive<"unknown"> {} +def OMP_Unknown : Directive<"unknown"> { + let isDefault = 1; +} diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPConstants.h b/llvm/include/llvm/Frontend/OpenMP/OMPConstants.h --- a/llvm/include/llvm/Frontend/OpenMP/OMPConstants.h +++ b/llvm/include/llvm/Frontend/OpenMP/OMPConstants.h @@ -15,6 +15,7 @@ #define LLVM_OPENMP_CONSTANTS_H #include "llvm/ADT/BitmaskEnum.h" + #include "llvm/Frontend/OpenMP/OMP.h.inc" namespace llvm { @@ -88,18 +89,6 @@ #define OMP_IDENT_FLAG(Enum, ...) constexpr auto Enum = omp::IdentFlag::Enum; #include "llvm/Frontend/OpenMP/OMPKinds.def" -/// Parse \p Str and return the directive it matches or OMPD_unknown if none. -Directive getOpenMPDirectiveKind(StringRef Str); - -/// Return a textual representation of the directive \p D. -StringRef getOpenMPDirectiveName(Directive D); - -/// Parse \p Str and return the clause it matches or OMPC_unknown if none. -Clause getOpenMPClauseKind(StringRef Str); - -/// Return a textual representation of the clause \p C. -StringRef getOpenMPClauseName(Clause C); - /// Return true if \p C is a valid clause for \p D in version \p Version. bool isAllowedClauseForDirective(Directive D, Clause C, unsigned Version); diff --git a/llvm/lib/Frontend/OpenMP/OMPConstants.cpp b/llvm/lib/Frontend/OpenMP/OMPConstants.cpp --- a/llvm/lib/Frontend/OpenMP/OMPConstants.cpp +++ b/llvm/lib/Frontend/OpenMP/OMPConstants.cpp @@ -19,40 +19,7 @@ using namespace omp; using namespace types; -Directive llvm::omp::getOpenMPDirectiveKind(StringRef Str) { - return llvm::StringSwitch(Str) -#define OMP_DIRECTIVE(Enum, Str) .Case(Str, Enum) -#include "llvm/Frontend/OpenMP/OMPKinds.def" - .Default(OMPD_unknown); -} - -StringRef llvm::omp::getOpenMPDirectiveName(Directive Kind) { - switch (Kind) { -#define OMP_DIRECTIVE(Enum, Str) \ - case Enum: \ - return Str; -#include "llvm/Frontend/OpenMP/OMPKinds.def" - } - llvm_unreachable("Invalid OpenMP directive kind"); -} - -Clause llvm::omp::getOpenMPClauseKind(StringRef Str) { - return llvm::StringSwitch(Str) -#define OMP_CLAUSE(Enum, Str, Implicit) \ - .Case(Str, Implicit ? OMPC_unknown : Enum) -#include "llvm/Frontend/OpenMP/OMPKinds.def" - .Default(OMPC_unknown); -} - -StringRef llvm::omp::getOpenMPClauseName(Clause C) { - switch (C) { -#define OMP_CLAUSE(Enum, Str, ...) \ - case Enum: \ - return Str; -#include "llvm/Frontend/OpenMP/OMPKinds.def" - } - llvm_unreachable("Invalid OpenMP clause kind"); -} +#include "llvm/Frontend/OpenMP/OMP.cpp.inc" bool llvm::omp::isAllowedClauseForDirective(Directive D, Clause C, unsigned Version) { diff --git a/llvm/test/TableGen/directive1.td b/llvm/test/TableGen/directive1.td --- a/llvm/test/TableGen/directive1.td +++ b/llvm/test/TableGen/directive1.td @@ -1,9 +1,10 @@ -// RUN: llvm-tblgen -gen-directive-decls -I %p/../../include %s | FileCheck %s +// RUN: llvm-tblgen -gen-directive-decl -I %p/../../include %s | FileCheck -match-full-lines %s +// RUN: llvm-tblgen -gen-directive-impl -I %p/../../include %s | FileCheck -match-full-lines %s -check-prefix=IMPL include "llvm/Frontend/Directive/DirectiveBase.td" def TestDirectiveLanguage : DirectiveLanguage { - let name = "tdl"; + let name = "Tdl"; let cppNamespace = "tdl"; let directivePrefix = "TDLD_"; @@ -13,30 +14,85 @@ } def TDLC_ClauseA : Clause<"clausea"> {} -def TDLC_ClauseB : Clause<"clauseb"> {} +def TDLC_ClauseB : Clause<"clauseb"> { + let isDefault = 1; +} def TDL_DirA : Directive<"dira"> { let allowedClauses = [TDLC_ClauseA, TDLC_ClauseB]; + let isDefault = 1; } -// CHECK: #ifndef LLVM_tdl_INC -// CHECK-NEXT: #define LLVM_tdl_INC -// CHECK-NEXT: #include "llvm/ADT/BitmaskEnum.h" -// CHECK-NEXT: namespace llvm { -// CHECK-NEXT: namespace tdl { -// CHECK-NEXT: LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); -// CHECK-NEXT: enum class Directive { -// CHECK-NEXT: TDLD_dira, -// CHECK-NEXT: } -// CHECK-NEXT: static constexpr std::size_t Directive_enumSize = 1; -// CHECK-NEXT: enum class Clause { -// CHECK-NEXT: TDLC_clausea, -// CHECK-NEXT: TDLC_clauseb, -// CHECK-NEXT: } -// CHECK-NEXT: static constexpr std::size_t Clause_enumSize = 2; -// CHECK-NEXT: constexpr auto TDLD_dira = tdl::Directive::TDLD_dira; -// CHECK-NEXT: constexpr auto TDLC_clausea = tdl::Clause::TDLC_clausea; -// CHECK-NEXT: constexpr auto TDLC_clauseb = tdl::Clause::TDLC_clauseb; -// CHECK-NEXT: } -// CHECK-NEXT: } -// CHECK-NEXT: #endif +// CHECK: #ifndef LLVM_Tdl_INC +// CHECK-NEXT: #define LLVM_Tdl_INC +// CHECK-EMPTY: +// CHECK-NEXT: #include "llvm/ADT/BitmaskEnum.h" +// CHECK-EMPTY: +// CHECK-NEXT: namespace llvm { +// CHECK-NEXT: class StringRef; +// CHECK-NEXT: namespace tdl { +// CHECK-EMPTY: +// CHECK-NEXT: LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); +// CHECK-EMPTY: +// CHECK-NEXT: enum class Directive { +// CHECK-NEXT: TDLD_dira, +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static constexpr std::size_t Directive_enumSize = 1; +// CHECK-EMPTY: +// CHECK-NEXT: constexpr auto TDLD_dira = llvm::tdl::Directive::TDLD_dira; +// CHECK-EMPTY: +// CHECK-NEXT: enum class Clause { +// CHECK-NEXT: TDLC_clausea, +// CHECK-NEXT: TDLC_clauseb, +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static constexpr std::size_t Clause_enumSize = 2; +// CHECK-EMPTY: +// CHECK-NEXT: constexpr auto TDLC_clausea = llvm::tdl::Clause::TDLC_clausea; +// CHECK-NEXT: constexpr auto TDLC_clauseb = llvm::tdl::Clause::TDLC_clauseb; +// CHECK-EMPTY: +// CHECK-NEXT: // Enumeration helper functions +// CHECK-NEXT: Directive getTdlDirectiveKind(llvm::StringRef Str); +// CHECK-EMPTY: +// CHECK-NEXT: llvm::StringRef getTdlDirectiveName(Directive D); +// CHECK-EMPTY: +// CHECK-NEXT: Clause getTdlClauseKind(llvm::StringRef Str); +// CHECK-EMPTY: +// CHECK-NEXT: llvm::StringRef getTdlClauseName(Clause C); +// CHECK-EMPTY: +// CHECK-NEXT: } // namespace tdl +// CHECK-NEXT: } // namespace llvm +// CHECK-NEXT: #endif // LLVM_Tdl_INC + + +// IMPL: Directive llvm::tdl::getTdlDirectiveKind(llvm::StringRef Str) { +// IMPL-NEXT: return llvm::StringSwitch(Str) +// IMPL-NEXT: .Case("dira",TDLD_dira) +// IMPL-NEXT: .Default(TDLD_dira); +// IMPL-NEXT: } +// IMPL-EMPTY: +// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlDirectiveName(Directive Kind) { +// IMPL-NEXT: switch (Kind) { +// IMPL-NEXT: case TDLD_dira: +// IMPL-NEXT: return "dira"; +// IMPL-NEXT: } +// IMPL-NEXT: llvm_unreachable("Invalid Tdl Directive kind"); +// IMPL-NEXT: } +// IMPL-EMPTY: +// IMPL-NEXT: Clause llvm::tdl::getTdlClauseKind(llvm::StringRef Str) { +// IMPL-NEXT: return llvm::StringSwitch(Str) +// IMPL-NEXT: .Case("clausea",TDLC_clausea) +// IMPL-NEXT: .Case("clauseb",TDLC_clauseb) +// IMPL-NEXT: .Default(TDLC_clauseb); +// IMPL-NEXT: } +// IMPL-EMPTY: +// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlClauseName(Clause Kind) { +// IMPL-NEXT: switch (Kind) { +// IMPL-NEXT: case TDLC_clausea: +// IMPL-NEXT: return "clausea"; +// IMPL-NEXT: case TDLC_clauseb: +// IMPL-NEXT: return "clauseb"; +// IMPL-NEXT: } +// IMPL-NEXT: llvm_unreachable("Invalid Tdl Clause kind"); +// IMPL-NEXT: } diff --git a/llvm/test/TableGen/directive2.td b/llvm/test/TableGen/directive2.td --- a/llvm/test/TableGen/directive2.td +++ b/llvm/test/TableGen/directive2.td @@ -1,35 +1,89 @@ -// RUN: llvm-tblgen -gen-directive-decls -I %p/../../include %s | FileCheck %s +// RUN: llvm-tblgen -gen-directive-decl -I %p/../../include %s | FileCheck -match-full-lines %s +// RUN: llvm-tblgen -gen-directive-impl -I %p/../../include %s | FileCheck -match-full-lines %s -check-prefix=IMPL include "llvm/Frontend/Directive/DirectiveBase.td" def TestDirectiveLanguage : DirectiveLanguage { - let name = "tdl"; + let name = "Tdl"; let cppNamespace = "tdl"; let directivePrefix = "TDLD_"; let clausePrefix = "TDLC_"; } -def TDLC_ClauseA : Clause<"clausea"> {} -def TDLC_ClauseB : Clause<"clauseb"> {} +def TDLC_ClauseA : Clause<"clausea"> { + let isImplicit = 1; +} +def TDLC_ClauseB : Clause<"clauseb"> { + let isDefault = 1; +} def TDL_DirA : Directive<"dira"> { let allowedClauses = [TDLC_ClauseA, TDLC_ClauseB]; + let isDefault = 1; } -// CHECK: #ifndef LLVM_tdl_INC -// CHECK-NEXT: #define LLVM_tdl_INC -// CHECK-NEXT: namespace llvm { -// CHECK-NEXT: namespace tdl { -// CHECK-NEXT: enum class Directive { -// CHECK-NEXT: TDLD_dira, -// CHECK-NEXT: } -// CHECK-NEXT: static constexpr std::size_t Directive_enumSize = 1; -// CHECK-NEXT: enum class Clause { -// CHECK-NEXT: TDLC_clausea, -// CHECK-NEXT: TDLC_clauseb, -// CHECK-NEXT: } -// CHECK-NEXT: static constexpr std::size_t Clause_enumSize = 2; -// CHECK-NEXT: } -// CHECK-NEXT: } -// CHECK-NEXT: #endif +// CHECK: #ifndef LLVM_Tdl_INC +// CHECK-NEXT: #define LLVM_Tdl_INC +// CHECK-EMPTY: +// CHECK-NEXT: namespace llvm { +// CHECK-NEXT: class StringRef; +// CHECK-NEXT: namespace tdl { +// CHECK-EMPTY: +// CHECK-NEXT: enum class Directive { +// CHECK-NEXT: TDLD_dira, +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static constexpr std::size_t Directive_enumSize = 1; +// CHECK-EMPTY: +// CHECK-NEXT: enum class Clause { +// CHECK-NEXT: TDLC_clausea, +// CHECK-NEXT: TDLC_clauseb, +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static constexpr std::size_t Clause_enumSize = 2; +// CHECK-EMPTY: +// CHECK-NEXT: // Enumeration helper functions +// CHECK-NEXT: Directive getTdlDirectiveKind(llvm::StringRef Str); +// CHECK-EMPTY: +// CHECK-NEXT: llvm::StringRef getTdlDirectiveName(Directive D); +// CHECK-EMPTY: +// CHECK-NEXT: Clause getTdlClauseKind(llvm::StringRef Str); +// CHECK-EMPTY: +// CHECK-NEXT: llvm::StringRef getTdlClauseName(Clause C); +// CHECK-EMPTY: +// CHECK-NEXT: } // namespace tdl +// CHECK-NEXT: } // namespace llvm +// CHECK-NEXT: #endif // LLVM_Tdl_INC + + +// IMPL: Directive llvm::tdl::getTdlDirectiveKind(llvm::StringRef Str) { +// IMPL-NEXT: return llvm::StringSwitch(Str) +// IMPL-NEXT: .Case("dira",TDLD_dira) +// IMPL-NEXT: .Default(TDLD_dira); +// IMPL-NEXT: } +// IMPL-EMPTY: +// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlDirectiveName(Directive Kind) { +// IMPL-NEXT: switch (Kind) { +// IMPL-NEXT: case TDLD_dira: +// IMPL-NEXT: return "dira"; +// IMPL-NEXT: } +// IMPL-NEXT: llvm_unreachable("Invalid Tdl Directive kind"); +// IMPL-NEXT: } +// IMPL-EMPTY: +// IMPL-NEXT: Clause llvm::tdl::getTdlClauseKind(llvm::StringRef Str) { +// IMPL-NEXT: return llvm::StringSwitch(Str) +// IMPL-NEXT: .Case("clausea",TDLC_clauseb) +// IMPL-NEXT: .Case("clauseb",TDLC_clauseb) +// IMPL-NEXT: .Default(TDLC_clauseb); +// IMPL-NEXT: } +// IMPL-EMPTY: +// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlClauseName(Clause Kind) { +// IMPL-NEXT: switch (Kind) { +// IMPL-NEXT: case TDLC_clausea: +// IMPL-NEXT: return "clausea"; +// IMPL-NEXT: case TDLC_clauseb: +// IMPL-NEXT: return "clauseb"; +// IMPL-NEXT: } +// IMPL-NEXT: llvm_unreachable("Invalid Tdl Clause kind"); +// IMPL-NEXT: } \ No newline at end of file diff --git a/llvm/utils/TableGen/DirectiveEmitter.cpp b/llvm/utils/TableGen/DirectiveEmitter.cpp --- a/llvm/utils/TableGen/DirectiveEmitter.cpp +++ b/llvm/utils/TableGen/DirectiveEmitter.cpp @@ -18,8 +18,48 @@ #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" +using namespace llvm; + namespace llvm { -void EmitDirectivesEnums(RecordKeeper &Records, raw_ostream &OS) { + +// Generate enum class +void GenerateEnumClass(const std::vector &Records, raw_ostream &OS, + StringRef Enum, StringRef Prefix, StringRef CppNamespace, + bool MakeEnumAvailableInNamespace) { + OS << "\n"; + OS << "enum class " << Enum << " {\n"; + for (const auto &R : Records) { + const auto Name = R->getValueAsString("name"); + std::string N = Name.str(); + std::replace(N.begin(), N.end(), ' ', '_'); + OS << " " << Prefix << N << ",\n"; + } + OS << "};\n"; + OS << "\n"; + OS << "static constexpr std::size_t " << Enum + << "_enumSize = " << Records.size() << ";\n"; + + // Make the enum values available in the defined namespace. This allows us to + // write something like Enum_X if we have a `using namespace `. + // At the same time we do not loose the strong type guarantees of the enum + // class, that is we cannot pass an unsigned as Directive without an explicit + // cast. + if (MakeEnumAvailableInNamespace) { + OS << "\n"; + for (const auto &R : Records) { + const auto Name = R->getValueAsString("name"); + std::string N = Name.str(); + std::replace(N.begin(), N.end(), ' ', '_'); + OS << "constexpr auto " << Prefix << N << " = " + << "llvm::" << CppNamespace << "::" << Enum << "::" << Prefix << N + << ";\n"; + } + } +} + +// Generate the declaration section for the enumeration in the directive +// language +void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) { const auto &DirectiveLanguages = Records.getAllDerivedDefinitions("DirectiveLanguage"); @@ -30,7 +70,7 @@ } const auto &DirectiveLanguage = DirectiveLanguages[0]; - StringRef languageName = DirectiveLanguage->getValueAsString("name"); + StringRef LanguageName = DirectiveLanguage->getValueAsString("name"); StringRef DirectivePrefix = DirectiveLanguage->getValueAsString("directivePrefix"); StringRef ClausePrefix = DirectiveLanguage->getValueAsString("clausePrefix"); @@ -40,13 +80,15 @@ bool EnableBitmaskEnumInNamespace = DirectiveLanguage->getValueAsBit("enableBitmaskEnumInNamespace"); - OS << "#ifndef LLVM_" << languageName << "_INC\n"; - OS << "#define LLVM_" << languageName << "_INC\n"; + OS << "#ifndef LLVM_" << LanguageName << "_INC\n"; + OS << "#define LLVM_" << LanguageName << "_INC\n"; if (EnableBitmaskEnumInNamespace) - OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n"; + OS << "\n#include \"llvm/ADT/BitmaskEnum.h\"\n"; + OS << "\n"; OS << "namespace llvm {\n"; + OS << "class StringRef;\n"; // Open namespaces defined in the directive language llvm::SmallVector Namespaces; @@ -55,61 +97,142 @@ OS << "namespace " << Ns << " {\n"; if (EnableBitmaskEnumInNamespace) - OS << "LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n"; + OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n"; // Emit Directive enumeration - OS << "enum class Directive {\n"; const auto &Directives = Records.getAllDerivedDefinitions("Directive"); - for (const auto &D : Directives) { - const auto Name = D->getValueAsString("name"); + GenerateEnumClass(Directives, OS, "Directive", DirectivePrefix, CppNamespace, + MakeEnumAvailableInNamespace); + + // Emit Clause enumeration + const auto &Clauses = Records.getAllDerivedDefinitions("Clause"); + GenerateEnumClass(Clauses, OS, "Clause", ClausePrefix, CppNamespace, + MakeEnumAvailableInNamespace); + + // Generic function signatures + OS << "\n"; + OS << "// Enumeration helper functions\n"; + OS << "Directive get" << LanguageName + << "DirectiveKind(llvm::StringRef Str);\n"; + OS << "\n"; + OS << "llvm::StringRef get" << LanguageName + << "DirectiveName(Directive D);\n"; + OS << "\n"; + OS << "Clause get" << LanguageName << "ClauseKind(llvm::StringRef Str);\n"; + OS << "\n"; + OS << "llvm::StringRef get" << LanguageName << "ClauseName(Clause C);\n"; + OS << "\n"; + + // Closing namespaces + for (auto Ns : llvm::reverse(Namespaces)) + OS << "} // namespace " << Ns << "\n"; + + OS << "} // namespace llvm\n"; + + OS << "#endif // LLVM_" << LanguageName << "_INC\n"; +} + +// Generate function implementation for getName(StringRef Str) +void GenerateGetName(const std::vector &Records, raw_ostream &OS, + StringRef Enum, StringRef Prefix, StringRef LanguageName, + StringRef Namespace) { + OS << "\n"; + OS << "llvm::StringRef llvm::" << Namespace << "::get" << LanguageName << Enum + << "Name(" << Enum << " Kind) {\n"; + OS << " switch (Kind) {\n"; + for (const auto &R : Records) { + const auto Name = R->getValueAsString("name"); + const auto AlternativeName = R->getValueAsString("alternativeName"); std::string N = Name.str(); std::replace(N.begin(), N.end(), ' ', '_'); - OS << DirectivePrefix << N << ",\n"; + OS << " case " << Prefix << N << ":\n"; + OS << " return \""; + if (AlternativeName.empty()) + OS << Name; + else + OS << AlternativeName; + OS << "\";\n"; } - OS << "};\n"; + OS << " }\n"; // switch + OS << " llvm_unreachable(\"Invalid " << LanguageName << " " << Enum + << " kind\");\n"; + OS << "}\n"; +} - OS << "static constexpr std::size_t Directive_enumSize = " - << Directives.size() << ";\n"; +// Generate function implementation for getKind(StringRef Str) +void GenerateGetKind(const std::vector &Records, raw_ostream &OS, + StringRef Enum, StringRef Prefix, StringRef LanguageName, + StringRef Namespace, bool ImplicitAsUnknown) { - // Emit Clause enumeration - OS << "enum class Clause {\n"; - const auto &Clauses = Records.getAllDerivedDefinitions("Clause"); - for (const auto &C : Clauses) { - const auto Name = C->getValueAsString("name"); - OS << ClausePrefix << Name << ",\n"; + auto DefaultIt = std::find_if(Records.begin(), Records.end(), [](Record *R) { + return R->getValueAsBit("isDefault") == true; + }); + + if (DefaultIt == Records.end()) { + PrintError("A least one " + Enum + " must be defined as default."); + return; } - OS << "};\n"; - OS << "static constexpr std::size_t Clause_enumSize = " << Clauses.size() - << ";\n"; + const auto DefaultName = (*DefaultIt)->getValueAsString("name"); + std::string DefaultEnum = DefaultName.str(); + std::replace(DefaultEnum.begin(), DefaultEnum.end(), ' ', '_'); - // Make the enum values available in the defined namespace. This allows us to - // write something like Enum_X if we have a `using namespace `. - // At the same time we do not loose the strong type guarantees of the enum - // class, that is we cannot pass an unsigned as Directive without an explicit - // cast. - if (MakeEnumAvailableInNamespace) { - for (const auto &D : Directives) { - const auto Name = D->getValueAsString("name"); - std::string N = Name.str(); - std::replace(N.begin(), N.end(), ' ', '_'); - OS << "constexpr auto " << DirectivePrefix << N << " = " << CppNamespace - << "::Directive::" << DirectivePrefix << N << ";\n"; - } + OS << "\n"; + OS << Enum << " llvm::" << Namespace << "::get" << LanguageName << Enum + << "Kind(llvm::StringRef Str) {\n"; + OS << " return llvm::StringSwitch<" << Enum << ">(Str)\n"; - for (const auto &C : Clauses) { - const auto Name = C->getValueAsString("name"); - OS << "constexpr auto " << ClausePrefix << Name << " = " << CppNamespace - << "::Clause::" << ClausePrefix << Name << ";\n"; + for (const auto &R : Records) { + const auto Name = R->getValueAsString("name"); + std::string N = Name.str(); + std::replace(N.begin(), N.end(), ' ', '_'); + if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) { + OS << " .Case(\"" << Name << "\"," << Prefix << DefaultEnum << ")\n"; + } else { + OS << " .Case(\"" << Name << "\"," << Prefix << N << ")\n"; } } + OS << " .Default(" << Prefix << DefaultEnum << ");\n"; + OS << "}\n"; +} - // Closing namespaces - for (auto Ns : llvm::reverse(Namespaces)) - OS << "} // namespace " << Ns << "\n"; +// Generate the implemenation section for the enumeration in the directive +// language +void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) { - OS << "} // namespace llvm\n"; + const auto &DirectiveLanguages = + Records.getAllDerivedDefinitions("DirectiveLanguage"); - OS << "#endif"; + if (DirectiveLanguages.size() != 1) { + PrintError("A single definition of DirectiveLanguage is needed."); + return; + } + + const auto &DirectiveLanguage = DirectiveLanguages[0]; + StringRef DirectivePrefix = + DirectiveLanguage->getValueAsString("directivePrefix"); + StringRef LanguageName = DirectiveLanguage->getValueAsString("name"); + StringRef ClausePrefix = DirectiveLanguage->getValueAsString("clausePrefix"); + StringRef CppNamespace = DirectiveLanguage->getValueAsString("cppNamespace"); + + const auto &Directives = Records.getAllDerivedDefinitions("Directive"); + const auto &Clauses = Records.getAllDerivedDefinitions("Clause"); + + // getDirectiveKind(StringRef Str) + GenerateGetKind(Directives, OS, "Directive", DirectivePrefix, LanguageName, + CppNamespace, /*ImplicitAsUnknown=*/false); + + // getDirectiveName(Directive Kind) + GenerateGetName(Directives, OS, "Directive", DirectivePrefix, LanguageName, + CppNamespace); + + // getClauseKind(StringRef Str) + GenerateGetKind(Clauses, OS, "Clause", ClausePrefix, LanguageName, + CppNamespace, /*ImplicitAsUnknown=*/true); + + // getClauseName(Clause Kind) + GenerateGetName(Clauses, OS, "Clause", ClausePrefix, LanguageName, + CppNamespace); } + } // namespace llvm diff --git a/llvm/utils/TableGen/TableGen.cpp b/llvm/utils/TableGen/TableGen.cpp --- a/llvm/utils/TableGen/TableGen.cpp +++ b/llvm/utils/TableGen/TableGen.cpp @@ -54,7 +54,8 @@ GenRegisterBank, GenExegesis, GenAutomata, - GenDirectivesEnums, + GenDirectivesEnumDecl, + GenDirectivesEnumImpl, }; namespace llvm { @@ -130,8 +131,10 @@ clEnumValN(GenExegesis, "gen-exegesis", "Generate llvm-exegesis tables"), clEnumValN(GenAutomata, "gen-automata", "Generate generic automata"), - clEnumValN(GenDirectivesEnums, "gen-directive-decls", - "Generate directive related declaration code"))); + clEnumValN(GenDirectivesEnumDecl, "gen-directive-decl", + "Generate directive related declaration code"), + clEnumValN(GenDirectivesEnumImpl, "gen-directive-impl", + "Generate directive related implementation code"))); cl::OptionCategory PrintEnumsCat("Options for -print-enums"); cl::opt Class("class", cl::desc("Print Enum list for this class"), @@ -256,8 +259,11 @@ case GenAutomata: EmitAutomata(Records, OS); break; - case GenDirectivesEnums: - EmitDirectivesEnums(Records, OS); + case GenDirectivesEnumDecl: + EmitDirectivesDecl(Records, OS); + break; + case GenDirectivesEnumImpl: + EmitDirectivesImpl(Records, OS); break; } diff --git a/llvm/utils/TableGen/TableGenBackends.h b/llvm/utils/TableGen/TableGenBackends.h --- a/llvm/utils/TableGen/TableGenBackends.h +++ b/llvm/utils/TableGen/TableGenBackends.h @@ -90,7 +90,8 @@ void EmitRegisterBank(RecordKeeper &RK, raw_ostream &OS); void EmitExegesis(RecordKeeper &RK, raw_ostream &OS); void EmitAutomata(RecordKeeper &RK, raw_ostream &OS); -void EmitDirectivesEnums(RecordKeeper &RK, raw_ostream &OS); +void EmitDirectivesDecl(RecordKeeper &RK, raw_ostream &OS); +void EmitDirectivesImpl(RecordKeeper &RK, raw_ostream &OS); } // End llvm namespace