Skip to content

[utils][TableGen] Handle versions on clause/directive spellings #143021

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jun 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions llvm/include/llvm/Frontend/Directive/DirectiveBase.td
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ 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;

// Maximum version number where this object is valid.
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;
}
Expand Down
40 changes: 40 additions & 0 deletions llvm/include/llvm/Frontend/Directive/Spelling.h
Original file line number Diff line number Diff line change
@@ -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
25 changes: 8 additions & 17 deletions llvm/include/llvm/TableGen/DirectiveEmitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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<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;
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Frontend/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
add_subdirectory(Atomic)
add_subdirectory(Directive)
add_subdirectory(Driver)
add_subdirectory(HLSL)
add_subdirectory(OpenACC)
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/Frontend/Directive/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
add_llvm_component_library(LLVMFrontendDirective
Spelling.cpp

LINK_COMPONENTS
Support
)
38 changes: 38 additions & 0 deletions llvm/lib/Frontend/Directive/Spelling.cpp
Original file line number Diff line number Diff line change
@@ -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();
}
2 changes: 1 addition & 1 deletion llvm/lib/Frontend/OpenACC/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ add_llvm_component_library(LLVMFrontendOpenACC
acc_gen
)

target_link_libraries(LLVMFrontendOpenACC LLVMSupport)
target_link_libraries(LLVMFrontendOpenACC LLVMSupport LLVMFrontendDirective)

1 change: 1 addition & 0 deletions llvm/lib/Frontend/OpenMP/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ add_llvm_component_library(LLVMFrontendOpenMP
BitReader
FrontendOffloading
FrontendAtomic
FrontendDirective
)
34 changes: 20 additions & 14 deletions llvm/test/TableGen/directive1.td
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -320,41 +319,48 @@ 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";
// IMPL-NEXT: }
// 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: }
Expand Down
24 changes: 12 additions & 12 deletions llvm/test/TableGen/directive2.td
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,14 @@ 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>
// CHECK-EMPTY:
// 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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -267,35 +266,36 @@ 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";
// IMPL-NEXT: }
// 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})
// IMPL-NEXT: .Case("claused", {TDLC_clauseb, 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";
Expand Down
Loading