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 @@ -46,11 +46,17 @@ // Name of the clause string name = c; + // Alternative name + string alternativeName = ""; + // Optional class holding value of the clause in clang AST string clangClass = ?; // Is clause implicit? bit isImplicit = 0; + + // Set clause used by default when unknown. + bit isDefault = 0; } // Information about a specific directive @@ -58,6 +64,9 @@ // Name of the directive. Can be composite directive sepearted by whitespace. string name = d; + // Alternative name + string alternativeName = ""; + // List of allowed clauses for the directive. list allowedClauses = ?; @@ -66,4 +75,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,3 @@ set(LLVM_TARGET_DEFINITIONS OMP.td) -tablegen(LLVM OMP.h.inc --gen-directive-decls) +tablegen(LLVM OMP.inc --gen-directive) 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,7 +15,9 @@ #define LLVM_OPENMP_CONSTANTS_H #include "llvm/ADT/BitmaskEnum.h" -#include "llvm/Frontend/OpenMP/OMP.h.inc" + +#define GET_ENUM_DECLS +#include "llvm/Frontend/OpenMP/OMP.inc" namespace llvm { class Type; @@ -69,18 +71,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,8 @@ 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"); -} +#define GET_ENUM_IMPL +#include "llvm/Frontend/OpenMP/OMP.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,9 @@ -// RUN: llvm-tblgen -gen-directive-decls -I %p/../../include %s | FileCheck %s +// RUN: llvm-tblgen -gen-directive -I %p/../../include %s | FileCheck %s include "llvm/Frontend/Directive/DirectiveBase.td" def TestDirectiveLanguage : DirectiveLanguage { - let name = "tdl"; + let name = "Tdl"; let cppNamespace = "tdl"; let directivePrefix = "TDLD_"; @@ -13,14 +13,20 @@ } 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: #ifdef GET_ENUM_DECLS +// CHECK-NEXT: #undef GET_ENUM_DECLS + +// 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 { @@ -37,6 +43,51 @@ // 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: // Enumeration helper functions +// CHECK-NEXT: Directive getTdlDirectiveKind(llvm::StringRef Str); +// CHECK-NEXT: llvm::StringRef getTdlDirectiveName(Directive D); +// CHECK-NEXT: Clause getTdlClauseKind(llvm::StringRef Str); +// CHECK-NEXT: llvm::StringRef getTdlClauseName(Clause C); +// CHECK-NEXT: } // namespace tdl +// CHECK-NEXT: } // namespace llvm +// CHECK-NEXT: #endif // LLVM_Tdl_INC + +// CHECK: #endif // GET_ENUM_DECLS + +// CHECK: #ifdef GET_ENUM_IMPL +// CHECK-NEXT: #undef GET_ENUM_IMPL + +// CHECK: namespace llvm { +// CHECK-NEXT: namespace tdl { +// CHECK-NEXT: Directive getTdlDirectiveKind(llvm::StringRef Str) { +// CHECK-NEXT: return llvm::StringSwitch(Str) +// CHECK-NEXT: .Case("dira",TDLD_dira) +// CHECK-NEXT: .Default(TDLD_dira); +// CHECK-NEXT: } +// CHECK-NEXT: llvm::StringRef getTdlDirectiveName(Directive Kind) { +// CHECK-NEXT: switch (Kind) { +// CHECK-NEXT: case TDLD_dira: +// CHECK-NEXT: return "dira"; +// CHECK-NEXT: } +// CHECK-NEXT: llvm_unreachable("Invalid Tdl directive kind"); // CHECK-NEXT: } +// CHECK-NEXT: Clause getTdlClauseKind(llvm::StringRef Str) { +// CHECK-NEXT: return llvm::StringSwitch(Str) +// CHECK-NEXT: .Case("clausea",TDLC_clausea) +// CHECK-NEXT: .Case("clauseb",TDLC_clauseb) +// CHECK-NEXT: .Default(TDLC_clauseb); // CHECK-NEXT: } -// CHECK-NEXT: #endif +// CHECK-NEXT: llvm::StringRef getTdlClauseName(Clause Kind) { +// CHECK-NEXT: switch (Kind) { +// CHECK-NEXT: case TDLC_clausea: +// CHECK-NEXT: return "clausea"; +// CHECK-NEXT: case TDLC_clauseb: +// CHECK-NEXT: return "clauseb"; +// CHECK-NEXT: } +// CHECK-NEXT: llvm_unreachable("Invalid Tdl directive kind"); +// CHECK-NEXT: } +// CHECK-NEXT: } // namespace tdl +// CHECK-NEXT: } // namespace llvm + +// CHECK: #endif // GET_ENUM_IMPL 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,24 +1,32 @@ -// RUN: llvm-tblgen -gen-directive-decls -I %p/../../include %s | FileCheck %s +// RUN: llvm-tblgen -gen-directive -I %p/../../include %s | FileCheck %s 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: #ifdef GET_ENUM_DECLS +// CHECK-NEXT: #undef GET_ENUM_DECLS + +// CHECK: #ifndef LLVM_Tdl_INC +// CHECK-NEXT: #define LLVM_Tdl_INC // CHECK-NEXT: namespace llvm { // CHECK-NEXT: namespace tdl { // CHECK-NEXT: enum class Directive { @@ -30,6 +38,51 @@ // CHECK-NEXT: TDLC_clauseb, // CHECK-NEXT: } // CHECK-NEXT: static constexpr std::size_t Clause_enumSize = 2; + +// CHECK: // Enumeration helper functions +// CHECK-NEXT: Directive getTdlDirectiveKind(llvm::StringRef Str); +// CHECK-NEXT: llvm::StringRef getTdlDirectiveName(Directive D); +// CHECK-NEXT: Clause getTdlClauseKind(llvm::StringRef Str); +// CHECK-NEXT: llvm::StringRef getTdlClauseName(Clause C); +// CHECK-NEXT: } // namespace tdl +// CHECK-NEXT: } // namespace llvm +// CHECK-NEXT: #endif // LLVM_Tdl_INC + +// CHECK: #endif // GET_ENUM_DECLS + +// CHECK: #ifdef GET_ENUM_IMPL +// CHECK-NEXT: #undef GET_ENUM_IMPL + +// CHECK: namespace llvm { +// CHECK-NEXT: namespace tdl { +// CHECK-NEXT: Directive getTdlDirectiveKind(llvm::StringRef Str) { +// CHECK-NEXT: return llvm::StringSwitch(Str) +// CHECK-NEXT: .Case("dira",TDLD_dira) +// CHECK-NEXT: ; +// CHECK-NEXT: } +// CHECK-NEXT: llvm::StringRef getTdlDirectiveName(Directive Kind) { +// CHECK-NEXT: switch (Kind) { +// CHECK-NEXT: case TDLD_dira: +// CHECK-NEXT: return "dira"; +// CHECK-NEXT: } +// CHECK-NEXT: llvm_unreachable("Invalid Tdl directive kind"); // CHECK-NEXT: } +// CHECK-NEXT: Clause getTdlClauseKind(llvm::StringRef Str) { +// CHECK-NEXT: return llvm::StringSwitch(Str) +// CHECK-NEXT: .Case("clausea",TDLC_clauseb) +// CHECK-NEXT: .Case("clauseb",TDLC_clauseb) +// CHECK-NEXT: ; // CHECK-NEXT: } -// CHECK-NEXT: #endif +// CHECK-NEXT: llvm::StringRef getTdlClauseName(Clause Kind) { +// CHECK-NEXT: switch (Kind) { +// CHECK-NEXT: case TDLC_clausea: +// CHECK-NEXT: return "clausea"; +// CHECK-NEXT: case TDLC_clauseb: +// CHECK-NEXT: return "clauseb"; +// CHECK-NEXT: } +// CHECK-NEXT: llvm_unreachable("Invalid Tdl directive kind"); +// CHECK-NEXT: } +// CHECK-NEXT: } // namespace tdl +// CHECK-NEXT: } // namespace llvm + +// CHECK: #endif // GET_ENUM_IMPL 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,31 @@ #include "llvm/TableGen/Record.h" #include "llvm/TableGen/TableGenBackend.h" +using namespace llvm; + +namespace { +// Simple RAII helper for defining ifdef-undef-endif scopes. +class IfDefScope { +public: + IfDefScope(StringRef Name, raw_ostream &OS) : Name(Name), OS(OS) { + OS << "#ifdef " << Name << "\n" + << "#undef " << Name << "\n\n"; + } + + ~IfDefScope() { OS << "\n#endif // " << Name << "\n\n"; } + +private: + StringRef Name; + raw_ostream &OS; +}; +} // end anonymous namespace + namespace llvm { + +// Generate the declaration section for the enumeration in the directive +// language void EmitDirectivesEnums(RecordKeeper &Records, raw_ostream &OS) { + IfDefScope Scope("GET_ENUM_DECLS", OS); const auto &DirectiveLanguages = Records.getAllDerivedDefinitions("DirectiveLanguage"); @@ -30,7 +53,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,14 +63,16 @@ 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 << "namespace llvm {\n"; + OS << "class StringRef;"; + // Open namespaces defined in the directive language llvm::SmallVector Namespaces; llvm::SplitString(CppNamespace, Namespaces, "::"); @@ -76,7 +101,9 @@ const auto &Clauses = Records.getAllDerivedDefinitions("Clause"); for (const auto &C : Clauses) { const auto Name = C->getValueAsString("name"); - OS << ClausePrefix << Name << ",\n"; + std::string N = Name.str(); + std::replace(N.begin(), N.end(), ' ', '_'); + OS << ClausePrefix << N << ",\n"; } OS << "};\n"; @@ -104,12 +131,141 @@ } } + // Generic function signatures + OS << "\n"; + OS << "// Enumeration helper functions\n"; + OS << "Directive get" << LanguageName + << "DirectiveKind(llvm::StringRef Str);\n"; + OS << "llvm::StringRef get" << LanguageName + << "DirectiveName(Directive D);\n"; + + OS << "Clause get" << LanguageName << "ClauseKind(llvm::StringRef Str);\n"; + OS << "llvm::StringRef get" << LanguageName << "ClauseName(Clause C);\n"; + // Closing namespaces for (auto Ns : llvm::reverse(Namespaces)) OS << "} // namespace " << Ns << "\n"; OS << "} // namespace llvm\n"; - OS << "#endif"; + 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) { + OS << "llvm::StringRef 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 << "case " << Prefix << N << ":\n"; + OS << " return \""; + if (AlternativeName.empty()) + OS << Name; + else + OS << AlternativeName; + OS << "\";\n"; + } + OS << "}\n"; + OS << "llvm_unreachable(\"Invalid " << LanguageName + << " directive kind\");\n"; + OS << "}\n"; +} + +// Generate function implementation for getKind(StringRef Str) +void GenerateGetKind(const std::vector &Records, raw_ostream &OS, + StringRef Enum, StringRef Prefix, StringRef LanguageName, + bool ImplicitAsUnknown) { + + OS << Enum << " get" << LanguageName << Enum + << "Kind(llvm::StringRef Str) {\n"; + OS << "return llvm::StringSwitch<" << Enum << ">(Str)\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; + } + + const auto DefaultName = (*DefaultIt)->getValueAsString("name"); + std::string DefaultEnum = DefaultName.str(); + std::replace(DefaultEnum.begin(), DefaultEnum.end(), ' ', '_'); + + 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"; +} + +// Generate the implemenation section for the enumeration in the directive +// language +void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) { + IfDefScope Scope("GET_ENUM_IMPL", OS); + + const auto &DirectiveLanguages = + Records.getAllDerivedDefinitions("DirectiveLanguage"); + + 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"); + + OS << "namespace llvm {\n"; + + // Open namespaces defined in the directive language + llvm::SmallVector Namespaces; + llvm::SplitString(CppNamespace, Namespaces, "::"); + for (auto Ns : Namespaces) + OS << "namespace " << Ns << " {\n"; + + // getDirectiveKind(StringRef Str) + GenerateGetKind(Directives, OS, "Directive", DirectivePrefix, LanguageName, + false); + + // getDirectiveName(Directive Kind) + GenerateGetName(Directives, OS, "Directive", DirectivePrefix, LanguageName); + + // getClauseKind(StringRef Str) + GenerateGetKind(Clauses, OS, "Clause", ClausePrefix, LanguageName, true); + + // getClauseName(Clause Kind) + GenerateGetName(Clauses, OS, "Clause", ClausePrefix, LanguageName); + + // Closing namespaces + for (auto Ns : llvm::reverse(Namespaces)) + OS << "} // namespace " << Ns << "\n"; + + OS << "} // namespace llvm\n"; +} + +void EmitDirectives(RecordKeeper &Records, raw_ostream &OS) { + EmitDirectivesEnums(Records, OS); + EmitDirectivesImpl(Records, OS); +} + } // 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 @@ -130,7 +130,7 @@ clEnumValN(GenExegesis, "gen-exegesis", "Generate llvm-exegesis tables"), clEnumValN(GenAutomata, "gen-automata", "Generate generic automata"), - clEnumValN(GenDirectivesEnums, "gen-directive-decls", + clEnumValN(GenDirectivesEnums, "gen-directive", "Generate directive related declaration code"))); cl::OptionCategory PrintEnumsCat("Options for -print-enums"); @@ -257,7 +257,7 @@ EmitAutomata(Records, OS); break; case GenDirectivesEnums: - EmitDirectivesEnums(Records, OS); + EmitDirectives(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,7 @@ 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 EmitDirectives(RecordKeeper &RK, raw_ostream &OS); } // End llvm namespace