Skip to content

Commit 2ef30aa

Browse files
committed
[utils][TableGen] Handle versions on clause/directive spellings
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
1 parent ba3c918 commit 2ef30aa

File tree

10 files changed

+212
-97
lines changed

10 files changed

+212
-97
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//===-- Spelling.h ------------------------------------------------ C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
#ifndef LLVM_FRONTEND_DIRECTIVE_SPELLING_H
9+
#define LLVM_FRONTEND_DIRECTIVE_SPELLING_H
10+
11+
#include "llvm/ADT/StringRef.h"
12+
#include "llvm/ADT/iterator_range.h"
13+
14+
#include <limits>
15+
16+
namespace llvm::directive {
17+
18+
struct VersionRange {
19+
static constexpr int MaxValue = std::numeric_limits<int>::max();
20+
int Min = 1;
21+
int Max = MaxValue;
22+
};
23+
24+
inline bool operator<(const VersionRange &A, const VersionRange &B) {
25+
if (A.Min != B.Min)
26+
return A.Min < B.Min;
27+
return A.Max < B.Max;
28+
}
29+
30+
struct Spelling {
31+
StringRef Name;
32+
VersionRange Versions;
33+
};
34+
35+
StringRef FindName(llvm::iterator_range<const Spelling *>, unsigned Version);
36+
37+
} // namespace llvm::directive
38+
39+
#endif // LLVM_FRONTEND_DIRECTIVE_SPELLING_H

llvm/include/llvm/TableGen/DirectiveEmitter.h

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "llvm/ADT/STLExtras.h"
1818
#include "llvm/ADT/StringExtras.h"
1919
#include "llvm/ADT/StringRef.h"
20+
#include "llvm/Frontend/Directive/Spelling.h"
2021
#include "llvm/Support/MathExtras.h"
2122
#include "llvm/TableGen/Record.h"
2223
#include <algorithm>
@@ -113,29 +114,19 @@ class Versioned {
113114
constexpr static int IntWidth = 8 * sizeof(int);
114115
};
115116

116-
// Range of specification versions: [Min, Max]
117-
// Default value: all possible versions.
118-
// This is the same structure as the one emitted into the generated sources.
119-
#define STRUCT_VERSION_RANGE \
120-
struct VersionRange { \
121-
int Min = 1; \
122-
int Max = INT_MAX; \
123-
}
124-
125-
STRUCT_VERSION_RANGE;
126-
127117
class Spelling : public Versioned {
128118
public:
129-
using Value = std::pair<StringRef, VersionRange>;
119+
using Value = llvm::directive::Spelling;
130120

131121
Spelling(const Record *Def) : Def(Def) {}
132122

133123
StringRef getText() const { return Def->getValueAsString("spelling"); }
134-
VersionRange getVersions() const {
135-
return VersionRange{getMinVersion(Def), getMaxVersion(Def)};
124+
llvm::directive::VersionRange getVersions() const {
125+
return llvm::directive::VersionRange{getMinVersion(Def),
126+
getMaxVersion(Def)};
136127
}
137128

138-
Value get() const { return std::make_pair(getText(), getVersions()); }
129+
Value get() const { return Value{getText(), getVersions()}; }
139130

140131
private:
141132
const Record *Def;
@@ -177,11 +168,11 @@ class BaseRecord {
177168
// are added.
178169
Spelling::Value Oldest{"not found", {/*Min=*/INT_MAX, 0}};
179170
for (auto V : getSpellings()) {
180-
if (V.second.Min < Oldest.second.Min) {
171+
if (V.Versions.Min < Oldest.Versions.Min) {
181172
Oldest = V;
182173
}
183174
}
184-
return Oldest.first;
175+
return Oldest.Name;
185176
}
186177

187178
// Returns the name of the directive formatted for output. Whitespace are

llvm/lib/Frontend/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
add_subdirectory(Atomic)
2+
add_subdirectory(Directive)
23
add_subdirectory(Driver)
34
add_subdirectory(HLSL)
45
add_subdirectory(OpenACC)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
add_llvm_component_library(LLVMFrontendDirective
2+
Spelling.cpp
3+
4+
LINK_COMPONENTS
5+
Support
6+
)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//===-- Spelling.cpp ---------------------------------------------- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "llvm/Frontend/Directive/Spelling.h"
10+
11+
#include "llvm/ADT/STLExtras.h"
12+
#include "llvm/ADT/StringRef.h"
13+
#include "llvm/Support/MathExtras.h"
14+
15+
#include <cassert>
16+
17+
llvm::StringRef llvm::directive::FindName(
18+
llvm::iterator_range<const llvm::directive::Spelling *> Range,
19+
unsigned Version) {
20+
assert(llvm::isInt<8 * sizeof(int)>(Version) && "Version value out of range");
21+
22+
int V = Version;
23+
Spelling Tmp{StringRef(), {V, V}};
24+
auto F =
25+
llvm::lower_bound(Range, Tmp, [](const Spelling &A, const Spelling &B) {
26+
return A.Versions < B.Versions;
27+
});
28+
if (F != Range.end())
29+
return F->Name;
30+
return StringRef();
31+
}

llvm/lib/Frontend/OpenACC/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ add_llvm_component_library(LLVMFrontendOpenACC
99
acc_gen
1010
)
1111

12-
target_link_libraries(LLVMFrontendOpenACC LLVMSupport)
12+
target_link_libraries(LLVMFrontendOpenACC LLVMSupport LLVMFrontendDirective)
1313

llvm/lib/Frontend/OpenMP/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ add_llvm_component_library(LLVMFrontendOpenMP
2323
BitReader
2424
FrontendOffloading
2525
FrontendAtomic
26+
FrontendDirective
2627
)

llvm/test/TableGen/directive1.td

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
5454
// CHECK-NEXT: #include "llvm/ADT/ArrayRef.h"
5555
// CHECK-NEXT: #include "llvm/ADT/BitmaskEnum.h"
5656
// CHECK-NEXT: #include "llvm/ADT/StringRef.h"
57+
// CHECK-NEXT: #include "llvm/Frontend/Directive/Spelling.h"
5758
// CHECK-NEXT: #include "llvm/Support/Compiler.h"
5859
// CHECK-NEXT: #include <cstddef>
5960
// CHECK-NEXT: #include <utility>
@@ -63,8 +64,6 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
6364
// CHECK-EMPTY:
6465
// CHECK-NEXT: LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
6566
// CHECK-EMPTY:
66-
// CHECK-NEXT: struct VersionRange { int Min = 1; int Max = 0x7fffffff; };
67-
// CHECK-EMPTY:
6867
// CHECK-NEXT: enum class Association {
6968
// CHECK-NEXT: Block,
7069
// CHECK-NEXT: Declaration,
@@ -126,14 +125,14 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
126125
// CHECK-NEXT: constexpr auto TDLCV_valc = AKind::TDLCV_valc;
127126
// CHECK-EMPTY:
128127
// CHECK-NEXT: // Enumeration helper functions
129-
// CHECK-NEXT: LLVM_ABI std::pair<Directive, VersionRange> getTdlDirectiveKindAndVersions(StringRef Str);
128+
// CHECK-NEXT: LLVM_ABI std::pair<Directive, directive::VersionRange> getTdlDirectiveKindAndVersions(StringRef Str);
130129
// CHECK-NEXT: inline Directive getTdlDirectiveKind(StringRef Str) {
131130
// CHECK-NEXT: return getTdlDirectiveKindAndVersions(Str).first;
132131
// CHECK-NEXT: }
133132
// CHECK-EMPTY:
134133
// CHECK-NEXT: LLVM_ABI StringRef getTdlDirectiveName(Directive D, unsigned Ver = 0);
135134
// CHECK-EMPTY:
136-
// CHECK-NEXT: LLVM_ABI std::pair<Clause, VersionRange> getTdlClauseKindAndVersions(StringRef Str);
135+
// CHECK-NEXT: LLVM_ABI std::pair<Clause, directive::VersionRange> getTdlClauseKindAndVersions(StringRef Str);
137136
// CHECK-EMPTY:
138137
// CHECK-NEXT: inline Clause getTdlClauseKind(StringRef Str) {
139138
// CHECK-NEXT: return getTdlClauseKindAndVersions(Str).first;
@@ -320,41 +319,48 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
320319
// IMPL: #ifdef GEN_DIRECTIVES_IMPL
321320
// IMPL-NEXT: #undef GEN_DIRECTIVES_IMPL
322321
// IMPL-EMPTY:
322+
// IMPL-NEXT: #include "llvm/Frontend/Directive/Spelling.h"
323323
// IMPL-NEXT: #include "llvm/Support/ErrorHandling.h"
324324
// IMPL-NEXT: #include <utility>
325325
// IMPL-EMPTY:
326-
// IMPL-NEXT: std::pair<llvm::tdl::Directive, llvm::tdl::VersionRange> llvm::tdl::getTdlDirectiveKindAndVersions(llvm::StringRef Str) {
327-
// IMPL-NEXT: VersionRange All{}; // Default-initialized to "all-versions"
328-
// IMPL-NEXT: return StringSwitch<std::pair<Directive, VersionRange>>(Str)
326+
// IMPL-NEXT: std::pair<llvm::tdl::Directive, llvm::directive::VersionRange> llvm::tdl::getTdlDirectiveKindAndVersions(llvm::StringRef Str) {
327+
// IMPL-NEXT: directive::VersionRange All; // Default-initialized to "all versions"
328+
// IMPL-NEXT: return StringSwitch<std::pair<Directive, directive::VersionRange>>(Str)
329329
// IMPL-NEXT: .Case("dira", {TDLD_dira, All})
330330
// IMPL-NEXT: .Default({TDLD_dira, All});
331331
// IMPL-NEXT: }
332332
// IMPL-EMPTY:
333-
// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlDirectiveName(llvm::tdl::Directive Kind, unsigned) {
333+
// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlDirectiveName(llvm::tdl::Directive Kind, unsigned Version) {
334334
// IMPL-NEXT: switch (Kind) {
335335
// IMPL-NEXT: case TDLD_dira:
336336
// IMPL-NEXT: return "dira";
337337
// IMPL-NEXT: }
338338
// IMPL-NEXT: llvm_unreachable("Invalid Tdl Directive kind");
339339
// IMPL-NEXT: }
340340
// IMPL-EMPTY:
341-
// IMPL-NEXT: std::pair<llvm::tdl::Clause, llvm::tdl::VersionRange> llvm::tdl::getTdlClauseKindAndVersions(llvm::StringRef Str) {
342-
// IMPL-NEXT: VersionRange All{}; // Default-initialized to "all-versions"
343-
// IMPL-NEXT: return StringSwitch<std::pair<Clause, VersionRange>>(Str)
341+
// IMPL-NEXT: std::pair<llvm::tdl::Clause, llvm::directive::VersionRange> llvm::tdl::getTdlClauseKindAndVersions(llvm::StringRef Str) {
342+
// IMPL-NEXT: directive::VersionRange All; // Default-initialized to "all versions"
343+
// IMPL-NEXT: return StringSwitch<std::pair<Clause, directive::VersionRange>>(Str)
344344
// IMPL-NEXT: .Case("clausea", {TDLC_clausea, All})
345345
// IMPL-NEXT: .Case("clauseb", {TDLC_clauseb, All})
346346
// IMPL-NEXT: .Case("clausec", {TDLC_clausec, All})
347+
// IMPL-NEXT: .Case("ccccccc", {TDLC_clausec, All})
347348
// IMPL-NEXT: .Default({TDLC_clauseb, All});
348349
// IMPL-NEXT: }
349350
// IMPL-EMPTY:
350-
// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlClauseName(llvm::tdl::Clause Kind, unsigned) {
351+
// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlClauseName(llvm::tdl::Clause Kind, unsigned Version) {
351352
// IMPL-NEXT: switch (Kind) {
352353
// IMPL-NEXT: case TDLC_clausea:
353354
// IMPL-NEXT: return "clausea";
354355
// IMPL-NEXT: case TDLC_clauseb:
355356
// IMPL-NEXT: return "clauseb";
356-
// IMPL-NEXT: case TDLC_clausec:
357-
// IMPL-NEXT: return "clausec";
357+
// IMPL-NEXT: case TDLC_clausec: {
358+
// IMPL-NEXT: static const llvm::directive::Spelling TDLC_clausec_spellings[] = {
359+
// IMPL-NEXT: {"clausec", {1, 2147483647}},
360+
// IMPL-NEXT: {"ccccccc", {1, 2147483647}},
361+
// IMPL-NEXT: };
362+
// IMPL-NEXT: return llvm::directive::FindName(TDLC_clausec_spellings, Version);
363+
// IMPL-NEXT: }
358364
// IMPL-NEXT: }
359365
// IMPL-NEXT: llvm_unreachable("Invalid Tdl Clause kind");
360366
// IMPL-NEXT: }

llvm/test/TableGen/directive2.td

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,14 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
4747
// CHECK-EMPTY:
4848
// CHECK-NEXT: #include "llvm/ADT/ArrayRef.h"
4949
// CHECK-NEXT: #include "llvm/ADT/StringRef.h"
50+
// CHECK-NEXT: #include "llvm/Frontend/Directive/Spelling.h"
5051
// CHECK-NEXT: #include "llvm/Support/Compiler.h"
5152
// CHECK-NEXT: #include <cstddef>
5253
// CHECK-NEXT: #include <utility>
5354
// CHECK-EMPTY:
5455
// CHECK-NEXT: namespace llvm {
5556
// CHECK-NEXT: namespace tdl {
5657
// CHECK-EMPTY:
57-
// CHECK-NEXT: struct VersionRange { int Min = 1; int Max = 0x7fffffff; };
58-
// CHECK-EMPTY:
5958
// CHECK-NEXT: enum class Association {
6059
// CHECK-NEXT: Block,
6160
// CHECK-NEXT: Declaration,
@@ -102,14 +101,14 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
102101
// CHECK-NEXT: static constexpr std::size_t Clause_enumSize = 4;
103102
// CHECK-EMPTY:
104103
// CHECK-NEXT: // Enumeration helper functions
105-
// CHECK-NEXT: LLVM_ABI std::pair<Directive, VersionRange> getTdlDirectiveKindAndVersions(StringRef Str);
104+
// CHECK-NEXT: LLVM_ABI std::pair<Directive, directive::VersionRange> getTdlDirectiveKindAndVersions(StringRef Str);
106105
// CHECK-NEXT: inline Directive getTdlDirectiveKind(StringRef Str) {
107106
// CHECK-NEXT: return getTdlDirectiveKindAndVersions(Str).first;
108107
// CHECK-NEXT: }
109108
// CHECK-EMPTY:
110109
// CHECK-NEXT: LLVM_ABI StringRef getTdlDirectiveName(Directive D, unsigned Ver = 0);
111110
// CHECK-EMPTY:
112-
// CHECK-NEXT: LLVM_ABI std::pair<Clause, VersionRange> getTdlClauseKindAndVersions(StringRef Str);
111+
// CHECK-NEXT: LLVM_ABI std::pair<Clause, directive::VersionRange> getTdlClauseKindAndVersions(StringRef Str);
113112
// CHECK-EMPTY:
114113
// CHECK-NEXT: inline Clause getTdlClauseKind(StringRef Str) {
115114
// CHECK-NEXT: return getTdlClauseKindAndVersions(Str).first;
@@ -267,35 +266,36 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
267266
// IMPL: #ifdef GEN_DIRECTIVES_IMPL
268267
// IMPL-NEXT: #undef GEN_DIRECTIVES_IMPL
269268
// IMPL-EMPTY:
269+
// IMPL-NEXT: #include "llvm/Frontend/Directive/Spelling.h"
270270
// IMPL-NEXT: #include "llvm/Support/ErrorHandling.h"
271271
// IMPL-NEXT: #include <utility>
272272
// IMPL-EMPTY:
273-
// IMPL-NEXT: std::pair<llvm::tdl::Directive, llvm::tdl::VersionRange> llvm::tdl::getTdlDirectiveKindAndVersions(llvm::StringRef Str) {
274-
// IMPL-NEXT: VersionRange All{}; // Default-initialized to "all-versions"
275-
// IMPL-NEXT: return StringSwitch<std::pair<Directive, VersionRange>>(Str)
273+
// IMPL-NEXT: std::pair<llvm::tdl::Directive, llvm::directive::VersionRange> llvm::tdl::getTdlDirectiveKindAndVersions(llvm::StringRef Str) {
274+
// IMPL-NEXT: directive::VersionRange All; // Default-initialized to "all versions"
275+
// IMPL-NEXT: return StringSwitch<std::pair<Directive, directive::VersionRange>>(Str)
276276
// IMPL-NEXT: .Case("dira", {TDLD_dira, All})
277277
// IMPL-NEXT: .Default({TDLD_dira, All});
278278
// IMPL-NEXT: }
279279
// IMPL-EMPTY:
280-
// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlDirectiveName(llvm::tdl::Directive Kind, unsigned) {
280+
// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlDirectiveName(llvm::tdl::Directive Kind, unsigned Version) {
281281
// IMPL-NEXT: switch (Kind) {
282282
// IMPL-NEXT: case TDLD_dira:
283283
// IMPL-NEXT: return "dira";
284284
// IMPL-NEXT: }
285285
// IMPL-NEXT: llvm_unreachable("Invalid Tdl Directive kind");
286286
// IMPL-NEXT: }
287287
// IMPL-EMPTY:
288-
// IMPL-NEXT: std::pair<llvm::tdl::Clause, llvm::tdl::VersionRange> llvm::tdl::getTdlClauseKindAndVersions(llvm::StringRef Str) {
289-
// IMPL-NEXT: VersionRange All{}; // Default-initialized to "all-versions"
290-
// IMPL-NEXT: return StringSwitch<std::pair<Clause, VersionRange>>(Str)
288+
// IMPL-NEXT: std::pair<llvm::tdl::Clause, llvm::directive::VersionRange> llvm::tdl::getTdlClauseKindAndVersions(llvm::StringRef Str) {
289+
// IMPL-NEXT: directive::VersionRange All; // Default-initialized to "all versions"
290+
// IMPL-NEXT: return StringSwitch<std::pair<Clause, directive::VersionRange>>(Str)
291291
// IMPL-NEXT: .Case("clausea", {TDLC_clauseb, All})
292292
// IMPL-NEXT: .Case("clauseb", {TDLC_clauseb, All})
293293
// IMPL-NEXT: .Case("clausec", {TDLC_clausec, All})
294294
// IMPL-NEXT: .Case("claused", {TDLC_clauseb, All})
295295
// IMPL-NEXT: .Default({TDLC_clauseb, All});
296296
// IMPL-NEXT: }
297297
// IMPL-EMPTY:
298-
// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlClauseName(llvm::tdl::Clause Kind, unsigned) {
298+
// IMPL-NEXT: llvm::StringRef llvm::tdl::getTdlClauseName(llvm::tdl::Clause Kind, unsigned Version) {
299299
// IMPL-NEXT: switch (Kind) {
300300
// IMPL-NEXT: case TDLC_clausea:
301301
// IMPL-NEXT: return "clausea";

0 commit comments

Comments
 (0)