diff --git a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td index 142ba0423f251..301a7cce59627 100644 --- a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td +++ b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td @@ -52,7 +52,7 @@ class DirectiveLanguage { } // Base class for versioned entities. -class Versioned { +class Versioned { // Mininum version number where this object is valid. int minVersion = min; @@ -60,7 +60,7 @@ class Versioned { int maxVersion = max; } -class Spelling +class Spelling : Versioned { string spelling = s; } diff --git a/llvm/include/llvm/Frontend/Directive/Spelling.h b/llvm/include/llvm/Frontend/Directive/Spelling.h new file mode 100644 index 0000000000000..a101489603254 --- /dev/null +++ b/llvm/include/llvm/Frontend/Directive/Spelling.h @@ -0,0 +1,40 @@ +//===-------------------------------------------------------------- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_FRONTEND_DIRECTIVE_SPELLING_H +#define LLVM_FRONTEND_DIRECTIVE_SPELLING_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" + +#include +#include + +namespace llvm::directive { + +struct VersionRange { + static constexpr int MaxValue = std::numeric_limits::max(); + // The default "Version" value in getName() is 0, include that + // in the maximum range. + int Min = 0; + int Max = MaxValue; + + bool operator<(const VersionRange &R) const { + return std::tie(Min, Max) < std::tie(R.Min, R.Max); + } +}; + +struct Spelling { + StringRef Name; + VersionRange Versions; +}; + +StringRef FindName(llvm::iterator_range, unsigned Version); + +} // namespace llvm::directive + +#endif // LLVM_FRONTEND_DIRECTIVE_SPELLING_H diff --git a/llvm/include/llvm/TableGen/DirectiveEmitter.h b/llvm/include/llvm/TableGen/DirectiveEmitter.h index dc2f75083ec0d..ce3e87e470b9d 100644 --- a/llvm/include/llvm/TableGen/DirectiveEmitter.h +++ b/llvm/include/llvm/TableGen/DirectiveEmitter.h @@ -17,6 +17,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Frontend/Directive/Spelling.h" #include "llvm/Support/MathExtras.h" #include "llvm/TableGen/Record.h" #include @@ -113,29 +114,19 @@ class Versioned { constexpr static int IntWidth = 8 * sizeof(int); }; -// Range of specification versions: [Min, Max] -// Default value: all possible versions. -// This is the same structure as the one emitted into the generated sources. -#define STRUCT_VERSION_RANGE \ - struct VersionRange { \ - int Min = 1; \ - int Max = 0x7fffffff; \ - } - -STRUCT_VERSION_RANGE; - class Spelling : public Versioned { public: - using Value = std::pair; + using Value = directive::Spelling; Spelling(const Record *Def) : Def(Def) {} StringRef getText() const { return Def->getValueAsString("spelling"); } - VersionRange getVersions() const { - return VersionRange{getMinVersion(Def), getMaxVersion(Def)}; + llvm::directive::VersionRange getVersions() const { + return llvm::directive::VersionRange{getMinVersion(Def), + getMaxVersion(Def)}; } - Value get() const { return std::make_pair(getText(), getVersions()); } + Value get() const { return Value{getText(), getVersions()}; } private: const Record *Def; @@ -177,9 +168,9 @@ class BaseRecord { // are added. Spelling::Value Oldest{"not found", {/*Min=*/INT_MAX, 0}}; for (auto V : getSpellings()) - if (V.second.Min < Oldest.second.Min) + if (V.Versions.Min < Oldest.Versions.Min) Oldest = V; - return Oldest.first; + return Oldest.Name; } // Returns the name of the directive formatted for output. Whitespace are diff --git a/llvm/lib/Frontend/CMakeLists.txt b/llvm/lib/Frontend/CMakeLists.txt index b305ce7d771ce..3b31e6f8dec96 100644 --- a/llvm/lib/Frontend/CMakeLists.txt +++ b/llvm/lib/Frontend/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(Atomic) +add_subdirectory(Directive) add_subdirectory(Driver) add_subdirectory(HLSL) add_subdirectory(OpenACC) diff --git a/llvm/lib/Frontend/Directive/CMakeLists.txt b/llvm/lib/Frontend/Directive/CMakeLists.txt new file mode 100644 index 0000000000000..a567e1affb171 --- /dev/null +++ b/llvm/lib/Frontend/Directive/CMakeLists.txt @@ -0,0 +1,6 @@ +add_llvm_component_library(LLVMFrontendDirective + Spelling.cpp + + LINK_COMPONENTS + Support +) diff --git a/llvm/lib/Frontend/Directive/Spelling.cpp b/llvm/lib/Frontend/Directive/Spelling.cpp new file mode 100644 index 0000000000000..4992268f2e677 --- /dev/null +++ b/llvm/lib/Frontend/Directive/Spelling.cpp @@ -0,0 +1,38 @@ +//===-------------------------------------------------------------- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Frontend/Directive/Spelling.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/MathExtras.h" + +#include + +using namespace llvm; + +static bool Contains(directive::VersionRange V, int P) { + return V.Min <= P && P <= V.Max; +} + +llvm::StringRef llvm::directive::FindName( + llvm::iterator_range Range, unsigned Version) { + assert(llvm::isInt<8 * sizeof(int)>(Version) && "Version value out of range"); + + int V = Version; + // Do a linear search to find the first Spelling that contains Version. + // The condition "contains(S, Version)" does not partition the list of + // spellings, so std::[lower|upper]_bound cannot be used. + // In practice the list of spellings is expected to be very short, so + // linear search seems appropriate. In general, an interval tree may be + // a better choice, but in this case it may be an overkill. + for (auto &S : Range) { + if (Contains(S.Versions, V)) + return S.Name; + } + return StringRef(); +} diff --git a/llvm/lib/Frontend/OpenACC/CMakeLists.txt b/llvm/lib/Frontend/OpenACC/CMakeLists.txt index f352014978690..4664b71407c48 100644 --- a/llvm/lib/Frontend/OpenACC/CMakeLists.txt +++ b/llvm/lib/Frontend/OpenACC/CMakeLists.txt @@ -9,5 +9,5 @@ add_llvm_component_library(LLVMFrontendOpenACC acc_gen ) -target_link_libraries(LLVMFrontendOpenACC LLVMSupport) +target_link_libraries(LLVMFrontendOpenACC LLVMSupport LLVMFrontendDirective) diff --git a/llvm/lib/Frontend/OpenMP/CMakeLists.txt b/llvm/lib/Frontend/OpenMP/CMakeLists.txt index 35c607866a94e..5bf15ca3a8991 100644 --- a/llvm/lib/Frontend/OpenMP/CMakeLists.txt +++ b/llvm/lib/Frontend/OpenMP/CMakeLists.txt @@ -23,4 +23,5 @@ add_llvm_component_library(LLVMFrontendOpenMP BitReader FrontendOffloading FrontendAtomic + FrontendDirective ) diff --git a/llvm/test/TableGen/directive1.td b/llvm/test/TableGen/directive1.td index 8196a30d03df4..1d2bd51204e4f 100644 --- a/llvm/test/TableGen/directive1.td +++ b/llvm/test/TableGen/directive1.td @@ -54,6 +54,7 @@ def TDL_DirA : Directive<[Spelling<"dira">]> { // CHECK-NEXT: #include "llvm/ADT/ArrayRef.h" // CHECK-NEXT: #include "llvm/ADT/BitmaskEnum.h" // CHECK-NEXT: #include "llvm/ADT/StringRef.h" +// CHECK-NEXT: #include "llvm/Frontend/Directive/Spelling.h" // CHECK-NEXT: #include "llvm/Support/Compiler.h" // CHECK-NEXT: #include // CHECK-NEXT: #include @@ -63,8 +64,6 @@ def TDL_DirA : Directive<[Spelling<"dira">]> { // CHECK-EMPTY: // CHECK-NEXT: LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); // CHECK-EMPTY: -// CHECK-NEXT: struct VersionRange { int Min = 1; int Max = 0x7fffffff; }; -// CHECK-EMPTY: // CHECK-NEXT: enum class Association { // CHECK-NEXT: Block, // CHECK-NEXT: Declaration, @@ -126,14 +125,14 @@ def TDL_DirA : Directive<[Spelling<"dira">]> { // CHECK-NEXT: constexpr auto TDLCV_valc = AKind::TDLCV_valc; // CHECK-EMPTY: // CHECK-NEXT: // Enumeration helper functions -// CHECK-NEXT: LLVM_ABI std::pair getTdlDirectiveKindAndVersions(StringRef Str); +// CHECK-NEXT: LLVM_ABI std::pair getTdlDirectiveKindAndVersions(StringRef Str); // CHECK-NEXT: inline Directive getTdlDirectiveKind(StringRef Str) { // CHECK-NEXT: return getTdlDirectiveKindAndVersions(Str).first; // CHECK-NEXT: } // CHECK-EMPTY: // CHECK-NEXT: LLVM_ABI StringRef getTdlDirectiveName(Directive D, unsigned Ver = 0); // CHECK-EMPTY: -// CHECK-NEXT: LLVM_ABI std::pair getTdlClauseKindAndVersions(StringRef Str); +// CHECK-NEXT: LLVM_ABI std::pair getTdlClauseKindAndVersions(StringRef Str); // CHECK-EMPTY: // CHECK-NEXT: inline Clause getTdlClauseKind(StringRef Str) { // CHECK-NEXT: return getTdlClauseKindAndVersions(Str).first; @@ -320,17 +319,18 @@ def TDL_DirA : Directive<[Spelling<"dira">]> { // IMPL: #ifdef GEN_DIRECTIVES_IMPL // IMPL-NEXT: #undef GEN_DIRECTIVES_IMPL // IMPL-EMPTY: +// IMPL-NEXT: #include "llvm/Frontend/Directive/Spelling.h" // IMPL-NEXT: #include "llvm/Support/ErrorHandling.h" // IMPL-NEXT: #include // IMPL-EMPTY: -// IMPL-NEXT: std::pair llvm::tdl::getTdlDirectiveKindAndVersions(llvm::StringRef Str) { -// IMPL-NEXT: VersionRange All{}; // Default-initialized to "all-versions" -// IMPL-NEXT: return StringSwitch>(Str) +// IMPL-NEXT: std::pair llvm::tdl::getTdlDirectiveKindAndVersions(llvm::StringRef Str) { +// IMPL-NEXT: directive::VersionRange All; // Default-initialized to "all versions" +// IMPL-NEXT: return StringSwitch>(Str) // IMPL-NEXT: .Case("dira", {TDLD_dira, All}) // IMPL-NEXT: .Default({TDLD_dira, All}); // IMPL-NEXT: } // IMPL-EMPTY: -// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlDirectiveName(llvm::tdl::Directive Kind, unsigned) { +// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlDirectiveName(llvm::tdl::Directive Kind, unsigned Version) { // IMPL-NEXT: switch (Kind) { // IMPL-NEXT: case TDLD_dira: // IMPL-NEXT: return "dira"; @@ -338,23 +338,29 @@ def TDL_DirA : Directive<[Spelling<"dira">]> { // IMPL-NEXT: llvm_unreachable("Invalid Tdl Directive kind"); // IMPL-NEXT: } // IMPL-EMPTY: -// IMPL-NEXT: std::pair llvm::tdl::getTdlClauseKindAndVersions(llvm::StringRef Str) { -// IMPL-NEXT: VersionRange All{}; // Default-initialized to "all-versions" -// IMPL-NEXT: return StringSwitch>(Str) +// IMPL-NEXT: std::pair llvm::tdl::getTdlClauseKindAndVersions(llvm::StringRef Str) { +// IMPL-NEXT: directive::VersionRange All; // Default-initialized to "all versions" +// IMPL-NEXT: return StringSwitch>(Str) // IMPL-NEXT: .Case("clausea", {TDLC_clausea, All}) // IMPL-NEXT: .Case("clauseb", {TDLC_clauseb, All}) // IMPL-NEXT: .Case("clausec", {TDLC_clausec, All}) +// IMPL-NEXT: .Case("ccccccc", {TDLC_clausec, All}) // IMPL-NEXT: .Default({TDLC_clauseb, All}); // IMPL-NEXT: } // IMPL-EMPTY: -// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlClauseName(llvm::tdl::Clause Kind, unsigned) { +// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlClauseName(llvm::tdl::Clause Kind, unsigned Version) { // IMPL-NEXT: switch (Kind) { // IMPL-NEXT: case TDLC_clausea: // IMPL-NEXT: return "clausea"; // IMPL-NEXT: case TDLC_clauseb: // IMPL-NEXT: return "clauseb"; -// IMPL-NEXT: case TDLC_clausec: -// IMPL-NEXT: return "clausec"; +// IMPL-NEXT: case TDLC_clausec: { +// IMPL-NEXT: static constexpr llvm::directive::Spelling TDLC_clausec_spellings[] = { +// IMPL-NEXT: {"clausec", {0, 2147483647}}, +// IMPL-NEXT: {"ccccccc", {0, 2147483647}}, +// IMPL-NEXT: }; +// IMPL-NEXT: return llvm::directive::FindName(TDLC_clausec_spellings, Version); +// IMPL-NEXT: } // 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 index ead6aa2637b76..3a64bb3900a31 100644 --- a/llvm/test/TableGen/directive2.td +++ b/llvm/test/TableGen/directive2.td @@ -47,6 +47,7 @@ def TDL_DirA : Directive<[Spelling<"dira">]> { // CHECK-EMPTY: // CHECK-NEXT: #include "llvm/ADT/ArrayRef.h" // CHECK-NEXT: #include "llvm/ADT/StringRef.h" +// CHECK-NEXT: #include "llvm/Frontend/Directive/Spelling.h" // CHECK-NEXT: #include "llvm/Support/Compiler.h" // CHECK-NEXT: #include // CHECK-NEXT: #include @@ -54,8 +55,6 @@ def TDL_DirA : Directive<[Spelling<"dira">]> { // CHECK-NEXT: namespace llvm { // CHECK-NEXT: namespace tdl { // CHECK-EMPTY: -// CHECK-NEXT: struct VersionRange { int Min = 1; int Max = 0x7fffffff; }; -// CHECK-EMPTY: // CHECK-NEXT: enum class Association { // CHECK-NEXT: Block, // CHECK-NEXT: Declaration, @@ -102,14 +101,14 @@ def TDL_DirA : Directive<[Spelling<"dira">]> { // CHECK-NEXT: static constexpr std::size_t Clause_enumSize = 4; // CHECK-EMPTY: // CHECK-NEXT: // Enumeration helper functions -// CHECK-NEXT: LLVM_ABI std::pair getTdlDirectiveKindAndVersions(StringRef Str); +// CHECK-NEXT: LLVM_ABI std::pair getTdlDirectiveKindAndVersions(StringRef Str); // CHECK-NEXT: inline Directive getTdlDirectiveKind(StringRef Str) { // CHECK-NEXT: return getTdlDirectiveKindAndVersions(Str).first; // CHECK-NEXT: } // CHECK-EMPTY: // CHECK-NEXT: LLVM_ABI StringRef getTdlDirectiveName(Directive D, unsigned Ver = 0); // CHECK-EMPTY: -// CHECK-NEXT: LLVM_ABI std::pair getTdlClauseKindAndVersions(StringRef Str); +// CHECK-NEXT: LLVM_ABI std::pair getTdlClauseKindAndVersions(StringRef Str); // CHECK-EMPTY: // CHECK-NEXT: inline Clause getTdlClauseKind(StringRef Str) { // CHECK-NEXT: return getTdlClauseKindAndVersions(Str).first; @@ -267,17 +266,18 @@ def TDL_DirA : Directive<[Spelling<"dira">]> { // IMPL: #ifdef GEN_DIRECTIVES_IMPL // IMPL-NEXT: #undef GEN_DIRECTIVES_IMPL // IMPL-EMPTY: +// IMPL-NEXT: #include "llvm/Frontend/Directive/Spelling.h" // IMPL-NEXT: #include "llvm/Support/ErrorHandling.h" // IMPL-NEXT: #include // IMPL-EMPTY: -// IMPL-NEXT: std::pair llvm::tdl::getTdlDirectiveKindAndVersions(llvm::StringRef Str) { -// IMPL-NEXT: VersionRange All{}; // Default-initialized to "all-versions" -// IMPL-NEXT: return StringSwitch>(Str) +// IMPL-NEXT: std::pair llvm::tdl::getTdlDirectiveKindAndVersions(llvm::StringRef Str) { +// IMPL-NEXT: directive::VersionRange All; // Default-initialized to "all versions" +// IMPL-NEXT: return StringSwitch>(Str) // IMPL-NEXT: .Case("dira", {TDLD_dira, All}) // IMPL-NEXT: .Default({TDLD_dira, All}); // IMPL-NEXT: } // IMPL-EMPTY: -// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlDirectiveName(llvm::tdl::Directive Kind, unsigned) { +// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlDirectiveName(llvm::tdl::Directive Kind, unsigned Version) { // IMPL-NEXT: switch (Kind) { // IMPL-NEXT: case TDLD_dira: // IMPL-NEXT: return "dira"; @@ -285,9 +285,9 @@ def TDL_DirA : Directive<[Spelling<"dira">]> { // IMPL-NEXT: llvm_unreachable("Invalid Tdl Directive kind"); // IMPL-NEXT: } // IMPL-EMPTY: -// IMPL-NEXT: std::pair llvm::tdl::getTdlClauseKindAndVersions(llvm::StringRef Str) { -// IMPL-NEXT: VersionRange All{}; // Default-initialized to "all-versions" -// IMPL-NEXT: return StringSwitch>(Str) +// IMPL-NEXT: std::pair llvm::tdl::getTdlClauseKindAndVersions(llvm::StringRef Str) { +// IMPL-NEXT: directive::VersionRange All; // Default-initialized to "all versions" +// IMPL-NEXT: return StringSwitch>(Str) // IMPL-NEXT: .Case("clausea", {TDLC_clauseb, All}) // IMPL-NEXT: .Case("clauseb", {TDLC_clauseb, All}) // IMPL-NEXT: .Case("clausec", {TDLC_clausec, All}) @@ -295,7 +295,7 @@ def TDL_DirA : Directive<[Spelling<"dira">]> { // IMPL-NEXT: .Default({TDLC_clauseb, All}); // IMPL-NEXT: } // IMPL-EMPTY: -// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlClauseName(llvm::tdl::Clause Kind, unsigned) { +// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlClauseName(llvm::tdl::Clause Kind, unsigned Version) { // IMPL-NEXT: switch (Kind) { // IMPL-NEXT: case TDLC_clausea: // IMPL-NEXT: return "clausea"; diff --git a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp index 75f796abb7ce6..ac166a1db4aff 100644 --- a/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp +++ b/llvm/utils/TableGen/Basic/DirectiveEmitter.cpp @@ -77,6 +77,19 @@ static std::string getIdentifierName(const Record *Rec, StringRef Prefix) { return Prefix.str() + BaseRecord(Rec).getFormattedName(); } +using RecordWithSpelling = std::pair; + +static std::vector +getSpellings(ArrayRef Records) { + std::vector List; + for (const Record *R : Records) { + BaseRecord Rec(R); + llvm::transform(Rec.getSpellings(), std::back_inserter(List), + [R](Spelling::Value V) { return std::make_pair(R, V); }); + } + return List; +} + static void generateEnumExports(ArrayRef Records, raw_ostream &OS, StringRef Enum, StringRef Prefix) { @@ -270,6 +283,7 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) { OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n"; OS << "#include \"llvm/ADT/StringRef.h\"\n"; + OS << "#include \"llvm/Frontend/Directive/Spelling.h\"\n"; OS << "#include \"llvm/Support/Compiler.h\"\n"; OS << "#include \n"; // for size_t OS << "#include \n"; // for std::pair @@ -285,13 +299,6 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) { if (DirLang.hasEnableBitmaskEnumInNamespace()) OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n"; -#define AS_STRING_HELPER_TO_GET_THE_ARGUMENT_MACRO_EXPANDED(x) #x -#define AS_STRING(x) AS_STRING_HELPER_TO_GET_THE_ARGUMENT_MACRO_EXPANDED(x) - OS << "\n"; - OS << AS_STRING(STRUCT_VERSION_RANGE) << ";\n"; -#undef AS_STRING -#undef AS_STRING_HELPER_TO_GET_THE_ARGUMENT_MACRO_EXPANDED - // Emit Directive associations std::vector Associations; copy_if(DirLang.getAssociations(), std::back_inserter(Associations), @@ -324,7 +331,7 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) { OS << "\n"; OS << "// Enumeration helper functions\n"; - OS << "LLVM_ABI std::pair get" << Lang + OS << "LLVM_ABI std::pair get" << Lang << "DirectiveKindAndVersions(StringRef Str);\n"; OS << "inline Directive get" << Lang << "DirectiveKind(StringRef Str) {\n"; @@ -336,7 +343,7 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) { << "DirectiveName(Directive D, unsigned Ver = 0);\n"; OS << "\n"; - OS << "LLVM_ABI std::pair get" << Lang + OS << "LLVM_ABI std::pair get" << Lang << "ClauseKindAndVersions(StringRef Str);\n"; OS << "\n"; @@ -373,6 +380,20 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) { OS << "#endif // LLVM_" << Lang << "_INC\n"; } +// Given a list of spellings (for a given clause/directive), order them +// in a way that allows the use of binary search to locate a spelling +// for a specified version. +static std::vector +orderSpellings(ArrayRef Spellings) { + std::vector List(Spellings.begin(), Spellings.end()); + + llvm::stable_sort(List, + [](const Spelling::Value &A, const Spelling::Value &B) { + return A.Versions < B.Versions; + }); + return List; +} + // Generate function implementation for getName(StringRef Str) static void generateGetName(ArrayRef Records, raw_ostream &OS, StringRef Enum, const DirectiveLanguage &DirLang, @@ -381,14 +402,31 @@ static void generateGetName(ArrayRef Records, raw_ostream &OS, std::string Qual = getQualifier(DirLang); OS << "\n"; OS << "llvm::StringRef " << Qual << "get" << Lang << Enum << "Name(" << Qual - << Enum << " Kind, unsigned) {\n"; + << Enum << " Kind, unsigned Version) {\n"; OS << " switch (Kind) {\n"; for (const Record *R : Records) { - OS << " case " << getIdentifierName(R, Prefix) << ":\n"; - // FIXME: This will need to recognize different spellings for different - // versions. - OS << " return \"" << BaseRecord(R).getSpellingForIdentifier() - << "\";\n"; + BaseRecord Rec(R); + std::string Ident = getIdentifierName(R, Prefix); + OS << " case " << Ident << ":"; + std::vector Spellings(orderSpellings(Rec.getSpellings())); + assert(Spellings.size() != 0 && "No spellings for this item"); + if (Spellings.size() == 1) { + OS << "\n"; + OS << " return \"" << Spellings.front().Name << "\";\n"; + } else { + OS << " {\n"; + std::string SpellingsName = Ident + "_spellings"; + OS << " static constexpr llvm::directive::Spelling " << SpellingsName + << "[] = {\n"; + for (auto &S : Spellings) { + OS << " {\"" << S.Name << "\", {" << S.Versions.Min << ", " + << S.Versions.Max << "}},\n"; + } + OS << " };\n"; + OS << " return llvm::directive::FindName(" << SpellingsName + << ", Version);\n"; + OS << " }\n"; + } } OS << " }\n"; // switch OS << " llvm_unreachable(\"Invalid " << Lang << " " << Enum << " kind\");\n"; @@ -415,23 +453,28 @@ static void generateGetKind(ArrayRef Records, raw_ostream &OS, // std::pair<, VersionRange> // getKindAndVersions(StringRef Str); OS << "\n"; - OS << "std::pair<" << Qual << Enum << ", " << Qual << "VersionRange> " << Qual - << "get" << DirLang.getName() << Enum + OS << "std::pair<" << Qual << Enum << ", llvm::directive::VersionRange> " + << Qual << "get" << DirLang.getName() << Enum << "KindAndVersions(llvm::StringRef Str) {\n"; - OS << " VersionRange All{}; // Default-initialized to \"all-versions\"\n"; + OS << " directive::VersionRange All; // Default-initialized to \"all " + "versions\"\n"; OS << " return StringSwitch>(Str)\n"; + << "directive::VersionRange>>(Str)\n"; + + directive::VersionRange All; for (const Record *R : Records) { BaseRecord Rec(R); - // FIXME: This will need to recognize different spellings for different - // versions. - StringRef Name = Rec.getSpellingForIdentifier(); - if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) { - OS << " .Case(\"" << Name << "\", {" << DefaultName << ", All})\n"; - } else { - OS << " .Case(\"" << Name << "\", {" << getIdentifierName(R, Prefix) - << ", All})\n"; + std::string Ident = ImplicitAsUnknown && R->getValueAsBit("isImplicit") + ? DefaultName + : getIdentifierName(R, Prefix); + + for (auto &[Name, Versions] : Rec.getSpellings()) { + OS << " .Case(\"" << Name << "\", {" << Ident << ", "; + if (Versions.Min == All.Min && Versions.Max == All.Max) + OS << "All})\n"; + else + OS << "{" << Versions.Min << ", " << Versions.Max << "}})\n"; } } OS << " .Default({" << DefaultName << ", All});\n"; @@ -1144,47 +1187,29 @@ static void generateFlangClauseParserKindMap(const DirectiveLanguage &DirLang, << " Parser clause\");\n"; } -using RecordWithText = std::pair; - -static bool compareRecordText(const RecordWithText &A, - const RecordWithText &B) { - return A.second > B.second; -} - -static std::vector -getSpellingTexts(ArrayRef Records) { - std::vector List; - for (const Record *R : Records) { - Clause C(R); - llvm::transform( - C.getSpellings(), std::back_inserter(List), - [R](Spelling::Value V) { return std::make_pair(R, V.first); }); - } - return List; -} - // Generate the parser for the clauses. static void generateFlangClausesParser(const DirectiveLanguage &DirLang, raw_ostream &OS) { std::vector Clauses = DirLang.getClauses(); // Sort clauses in the reverse alphabetical order with respect to their // names and aliases, so that longer names are tried before shorter ones. - std::vector> Names = - getSpellingTexts(Clauses); - llvm::sort(Names, compareRecordText); + std::vector Names = getSpellings(Clauses); + llvm::sort(Names, [](const auto &A, const auto &B) { + return A.second.Name > B.second.Name; + }); IfDefScope Scope("GEN_FLANG_CLAUSES_PARSER", OS); StringRef Base = DirLang.getFlangClauseBaseClass(); unsigned LastIndex = Names.size() - 1; OS << "\n"; OS << "TYPE_PARSER(\n"; - for (auto [Index, RecTxt] : llvm::enumerate(Names)) { - auto [R, N] = RecTxt; + for (auto [Index, RecSp] : llvm::enumerate(Names)) { + auto [R, S] = RecSp; Clause C(R); StringRef FlangClass = C.getFlangClass(); - OS << " \"" << N << "\" >> construct<" << Base << ">(construct<" << Base - << "::" << C.getFormattedParserClassName() << ">("; + OS << " \"" << S.Name << "\" >> construct<" << Base << ">(construct<" + << Base << "::" << C.getFormattedParserClassName() << ">("; if (FlangClass.empty()) { OS << "))"; if (Index != LastIndex) @@ -1337,6 +1362,7 @@ void emitDirectivesBasicImpl(const DirectiveLanguage &DirLang, StringRef CPrefix = DirLang.getClausePrefix(); OS << "\n"; + OS << "#include \"llvm/Frontend/Directive/Spelling.h\"\n"; OS << "#include \"llvm/Support/ErrorHandling.h\"\n"; OS << "#include \n";