[utils][TableGen] Handle versions on clause/directive spellings (#143021)
In "get<lang>DirectiveName(Kind, Version)", return the spelling that
corresponds to Version, and in "get<lang>DirectiveKindAndVersions(Name)"
return the pair {Kind, VersionRange}, where VersionRange contains the
minimum and the maximum versions that allow "Name" as a spelling. This
applies to clauses as well. In general it applies to classes that have
spellings (defined via TableGen class "Spelling").
Given a Kind and a Version, getting the corresponding spelling requires
a runtime search (which can fail in a general case). To avoid generating
the search function inline, a small additional component of
llvm/Frontent was added: LLVMFrontendDirective. The corresponding header
file also defines C++ classes "Spelling" and "VersionRange", which are
used in TableGen/DirectiveEmitter as well.
For background information see
https://discourse.llvm.org/t/rfc-alternative-spellings-of-openmp-directives/85507
This commit is contained in:
committed by
GitHub
parent
428afa62b0
commit
7b2aa02a33
@@ -52,7 +52,7 @@ class DirectiveLanguage {
|
||||
}
|
||||
|
||||
// Base class for versioned entities.
|
||||
class Versioned<int min = 1, int max = 0x7FFFFFFF> {
|
||||
class Versioned<int min = 0, int max = 0x7FFFFFFF> {
|
||||
// Mininum version number where this object is valid.
|
||||
int minVersion = min;
|
||||
|
||||
@@ -60,7 +60,7 @@ class Versioned<int min = 1, int max = 0x7FFFFFFF> {
|
||||
int maxVersion = max;
|
||||
}
|
||||
|
||||
class Spelling<string s, int min = 1, int max = 0x7FFFFFFF>
|
||||
class Spelling<string s, int min = 0, int max = 0x7FFFFFFF>
|
||||
: Versioned<min, max> {
|
||||
string spelling = s;
|
||||
}
|
||||
|
||||
40
llvm/include/llvm/Frontend/Directive/Spelling.h
Normal file
40
llvm/include/llvm/Frontend/Directive/Spelling.h
Normal file
@@ -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 <limits>
|
||||
#include <tuple>
|
||||
|
||||
namespace llvm::directive {
|
||||
|
||||
struct VersionRange {
|
||||
static constexpr int MaxValue = std::numeric_limits<int>::max();
|
||||
// The default "Version" value in get<Lang><Enum>Name() 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<const Spelling *>, unsigned Version);
|
||||
|
||||
} // namespace llvm::directive
|
||||
|
||||
#endif // LLVM_FRONTEND_DIRECTIVE_SPELLING_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 <algorithm>
|
||||
@@ -113,29 +114,19 @@ private:
|
||||
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<StringRef, VersionRange>;
|
||||
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 @@ public:
|
||||
// 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
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
add_subdirectory(Atomic)
|
||||
add_subdirectory(Directive)
|
||||
add_subdirectory(Driver)
|
||||
add_subdirectory(HLSL)
|
||||
add_subdirectory(OpenACC)
|
||||
|
||||
6
llvm/lib/Frontend/Directive/CMakeLists.txt
Normal file
6
llvm/lib/Frontend/Directive/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
add_llvm_component_library(LLVMFrontendDirective
|
||||
Spelling.cpp
|
||||
|
||||
LINK_COMPONENTS
|
||||
Support
|
||||
)
|
||||
38
llvm/lib/Frontend/Directive/Spelling.cpp
Normal file
38
llvm/lib/Frontend/Directive/Spelling.cpp
Normal file
@@ -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 <cassert>
|
||||
|
||||
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<const directive::Spelling *> 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();
|
||||
}
|
||||
@@ -9,5 +9,5 @@ add_llvm_component_library(LLVMFrontendOpenACC
|
||||
acc_gen
|
||||
)
|
||||
|
||||
target_link_libraries(LLVMFrontendOpenACC LLVMSupport)
|
||||
target_link_libraries(LLVMFrontendOpenACC LLVMSupport LLVMFrontendDirective)
|
||||
|
||||
|
||||
@@ -23,4 +23,5 @@ add_llvm_component_library(LLVMFrontendOpenMP
|
||||
BitReader
|
||||
FrontendOffloading
|
||||
FrontendAtomic
|
||||
FrontendDirective
|
||||
)
|
||||
|
||||
@@ -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 <cstddef>
|
||||
// CHECK-NEXT: #include <utility>
|
||||
@@ -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<Directive, VersionRange> getTdlDirectiveKindAndVersions(StringRef Str);
|
||||
// CHECK-NEXT: LLVM_ABI std::pair<Directive, directive::VersionRange> 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<Clause, VersionRange> getTdlClauseKindAndVersions(StringRef Str);
|
||||
// CHECK-NEXT: LLVM_ABI std::pair<Clause, directive::VersionRange> 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 <utility>
|
||||
// IMPL-EMPTY:
|
||||
// IMPL-NEXT: std::pair<llvm::tdl::Directive, llvm::tdl::VersionRange> llvm::tdl::getTdlDirectiveKindAndVersions(llvm::StringRef Str) {
|
||||
// IMPL-NEXT: VersionRange All{}; // Default-initialized to "all-versions"
|
||||
// IMPL-NEXT: return StringSwitch<std::pair<Directive, VersionRange>>(Str)
|
||||
// IMPL-NEXT: std::pair<llvm::tdl::Directive, llvm::directive::VersionRange> llvm::tdl::getTdlDirectiveKindAndVersions(llvm::StringRef Str) {
|
||||
// IMPL-NEXT: directive::VersionRange All; // Default-initialized to "all versions"
|
||||
// IMPL-NEXT: return StringSwitch<std::pair<Directive, directive::VersionRange>>(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::Clause, llvm::tdl::VersionRange> llvm::tdl::getTdlClauseKindAndVersions(llvm::StringRef Str) {
|
||||
// IMPL-NEXT: VersionRange All{}; // Default-initialized to "all-versions"
|
||||
// IMPL-NEXT: return StringSwitch<std::pair<Clause, VersionRange>>(Str)
|
||||
// IMPL-NEXT: std::pair<llvm::tdl::Clause, llvm::directive::VersionRange> llvm::tdl::getTdlClauseKindAndVersions(llvm::StringRef Str) {
|
||||
// IMPL-NEXT: directive::VersionRange All; // Default-initialized to "all versions"
|
||||
// IMPL-NEXT: return StringSwitch<std::pair<Clause, directive::VersionRange>>(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: }
|
||||
|
||||
@@ -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 <cstddef>
|
||||
// CHECK-NEXT: #include <utility>
|
||||
@@ -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<Directive, VersionRange> getTdlDirectiveKindAndVersions(StringRef Str);
|
||||
// CHECK-NEXT: LLVM_ABI std::pair<Directive, directive::VersionRange> 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<Clause, VersionRange> getTdlClauseKindAndVersions(StringRef Str);
|
||||
// CHECK-NEXT: LLVM_ABI std::pair<Clause, directive::VersionRange> 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 <utility>
|
||||
// IMPL-EMPTY:
|
||||
// IMPL-NEXT: std::pair<llvm::tdl::Directive, llvm::tdl::VersionRange> llvm::tdl::getTdlDirectiveKindAndVersions(llvm::StringRef Str) {
|
||||
// IMPL-NEXT: VersionRange All{}; // Default-initialized to "all-versions"
|
||||
// IMPL-NEXT: return StringSwitch<std::pair<Directive, VersionRange>>(Str)
|
||||
// IMPL-NEXT: std::pair<llvm::tdl::Directive, llvm::directive::VersionRange> llvm::tdl::getTdlDirectiveKindAndVersions(llvm::StringRef Str) {
|
||||
// IMPL-NEXT: directive::VersionRange All; // Default-initialized to "all versions"
|
||||
// IMPL-NEXT: return StringSwitch<std::pair<Directive, directive::VersionRange>>(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::Clause, llvm::tdl::VersionRange> llvm::tdl::getTdlClauseKindAndVersions(llvm::StringRef Str) {
|
||||
// IMPL-NEXT: VersionRange All{}; // Default-initialized to "all-versions"
|
||||
// IMPL-NEXT: return StringSwitch<std::pair<Clause, VersionRange>>(Str)
|
||||
// IMPL-NEXT: std::pair<llvm::tdl::Clause, llvm::directive::VersionRange> llvm::tdl::getTdlClauseKindAndVersions(llvm::StringRef Str) {
|
||||
// IMPL-NEXT: directive::VersionRange All; // Default-initialized to "all versions"
|
||||
// IMPL-NEXT: return StringSwitch<std::pair<Clause, directive::VersionRange>>(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";
|
||||
|
||||
@@ -77,6 +77,19 @@ static std::string getIdentifierName(const Record *Rec, StringRef Prefix) {
|
||||
return Prefix.str() + BaseRecord(Rec).getFormattedName();
|
||||
}
|
||||
|
||||
using RecordWithSpelling = std::pair<const Record *, Spelling::Value>;
|
||||
|
||||
static std::vector<RecordWithSpelling>
|
||||
getSpellings(ArrayRef<const Record *> Records) {
|
||||
std::vector<RecordWithSpelling> 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<const Record *> 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 <cstddef>\n"; // for size_t
|
||||
OS << "#include <utility>\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<const Record *> 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<Directive, VersionRange> get" << Lang
|
||||
OS << "LLVM_ABI std::pair<Directive, directive::VersionRange> 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<Clause, VersionRange> get" << Lang
|
||||
OS << "LLVM_ABI std::pair<Clause, directive::VersionRange> 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<Spelling::Value>
|
||||
orderSpellings(ArrayRef<Spelling::Value> Spellings) {
|
||||
std::vector<Spelling::Value> 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 get<Enum>Name(StringRef Str)
|
||||
static void generateGetName(ArrayRef<const Record *> Records, raw_ostream &OS,
|
||||
StringRef Enum, const DirectiveLanguage &DirLang,
|
||||
@@ -381,14 +402,31 @@ static void generateGetName(ArrayRef<const Record *> 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<Spelling::Value> 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<const Record *> Records, raw_ostream &OS,
|
||||
// std::pair<<Enum>, VersionRange>
|
||||
// get<DirLang><Enum>KindAndVersions(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<std::pair<" << Enum << ", "
|
||||
<< "VersionRange>>(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<const Record *, StringRef>;
|
||||
|
||||
static bool compareRecordText(const RecordWithText &A,
|
||||
const RecordWithText &B) {
|
||||
return A.second > B.second;
|
||||
}
|
||||
|
||||
static std::vector<RecordWithText>
|
||||
getSpellingTexts(ArrayRef<const Record *> Records) {
|
||||
std::vector<RecordWithText> 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<const Record *> 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<std::pair<const Record *, StringRef>> Names =
|
||||
getSpellingTexts(Clauses);
|
||||
llvm::sort(Names, compareRecordText);
|
||||
std::vector<RecordWithSpelling> 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 <utility>\n";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user