Skip to content

Commit af83ed2

Browse files
kparzyszrorth
authored andcommitted
[utils][TableGen] Handle versions on clause/directive spellings (llvm#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
1 parent d17ade9 commit af83ed2

File tree

11 files changed

+208
-99
lines changed

11 files changed

+208
-99
lines changed

llvm/include/llvm/Frontend/Directive/DirectiveBase.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,15 @@ class DirectiveLanguage {
5252
}
5353

5454
// Base class for versioned entities.
55-
class Versioned<int min = 1, int max = 0x7FFFFFFF> {
55+
class Versioned<int min = 0, int max = 0x7FFFFFFF> {
5656
// Mininum version number where this object is valid.
5757
int minVersion = min;
5858

5959
// Maximum version number where this object is valid.
6060
int maxVersion = max;
6161
}
6262

63-
class Spelling<string s, int min = 1, int max = 0x7FFFFFFF>
63+
class Spelling<string s, int min = 0, int max = 0x7FFFFFFF>
6464
: Versioned<min, max> {
6565
string spelling = s;
6666
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//===-------------------------------------------------------------- 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+
#include <tuple>
16+
17+
namespace llvm::directive {
18+
19+
struct VersionRange {
20+
static constexpr int MaxValue = std::numeric_limits<int>::max();
21+
// The default "Version" value in get<Lang><Enum>Name() is 0, include that
22+
// in the maximum range.
23+
int Min = 0;
24+
int Max = MaxValue;
25+
26+
bool operator<(const VersionRange &R) const {
27+
return std::tie(Min, Max) < std::tie(R.Min, R.Max);
28+
}
29+
};
30+
31+
struct Spelling {
32+
StringRef Name;
33+
VersionRange Versions;
34+
};
35+
36+
StringRef FindName(llvm::iterator_range<const Spelling *>, unsigned Version);
37+
38+
} // namespace llvm::directive
39+
40+
#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 = 0x7fffffff; \
123-
}
124-
125-
STRUCT_VERSION_RANGE;
126-
127117
class Spelling : public Versioned {
128118
public:
129-
using Value = std::pair<StringRef, VersionRange>;
119+
using Value = 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,9 +168,9 @@ 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;
182-
return Oldest.first;
173+
return Oldest.Name;
183174
}
184175

185176
// 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: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//===-------------------------------------------------------------- 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/StringRef.h"
12+
#include "llvm/Support/MathExtras.h"
13+
14+
#include <cassert>
15+
16+
using namespace llvm;
17+
18+
static bool Contains(directive::VersionRange V, int P) {
19+
return V.Min <= P && P <= V.Max;
20+
}
21+
22+
llvm::StringRef llvm::directive::FindName(
23+
llvm::iterator_range<const directive::Spelling *> Range, unsigned Version) {
24+
assert(llvm::isInt<8 * sizeof(int)>(Version) && "Version value out of range");
25+
26+
int V = Version;
27+
// Do a linear search to find the first Spelling that contains Version.
28+
// The condition "contains(S, Version)" does not partition the list of
29+
// spellings, so std::[lower|upper]_bound cannot be used.
30+
// In practice the list of spellings is expected to be very short, so
31+
// linear search seems appropriate. In general, an interval tree may be
32+
// a better choice, but in this case it may be an overkill.
33+
for (auto &S : Range) {
34+
if (Contains(S.Versions, V))
35+
return S.Name;
36+
}
37+
return StringRef();
38+
}

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 constexpr llvm::directive::Spelling TDLC_clausec_spellings[] = {
359+
// IMPL-NEXT: {"clausec", {0, 2147483647}},
360+
// IMPL-NEXT: {"ccccccc", {0, 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)