Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 2ef30aa

Browse files
committedMay 28, 2025·
[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";

‎llvm/utils/TableGen/Basic/DirectiveEmitter.cpp

Lines changed: 93 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,19 @@ static std::string getIdentifierName(const Record *Rec, StringRef Prefix) {
7777
return Prefix.str() + BaseRecord(Rec).getFormattedName();
7878
}
7979

80+
using RecordWithSpelling = std::pair<const Record *, Spelling::Value>;
81+
82+
static std::vector<RecordWithSpelling>
83+
getSpellings(ArrayRef<const Record *> Records) {
84+
std::vector<RecordWithSpelling> List;
85+
for (const Record *R : Records) {
86+
Clause C(R);
87+
llvm::transform(C.getSpellings(), std::back_inserter(List),
88+
[R](Spelling::Value V) { return std::make_pair(R, V); });
89+
}
90+
return List;
91+
}
92+
8093
static void generateEnumExports(ArrayRef<const Record *> Records,
8194
raw_ostream &OS, StringRef Enum,
8295
StringRef Prefix) {
@@ -270,6 +283,7 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
270283
OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n";
271284

272285
OS << "#include \"llvm/ADT/StringRef.h\"\n";
286+
OS << "#include \"llvm/Frontend/Directive/Spelling.h\"\n";
273287
OS << "#include \"llvm/Support/Compiler.h\"\n";
274288
OS << "#include <cstddef>\n"; // for size_t
275289
OS << "#include <utility>\n"; // for std::pair
@@ -285,13 +299,6 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
285299
if (DirLang.hasEnableBitmaskEnumInNamespace())
286300
OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n";
287301

288-
#define AS_STRING_HELPER_TO_GET_THE_ARGUMENT_MACRO_EXPANDED(x) #x
289-
#define AS_STRING(x) AS_STRING_HELPER_TO_GET_THE_ARGUMENT_MACRO_EXPANDED(x)
290-
OS << "\n";
291-
OS << AS_STRING(STRUCT_VERSION_RANGE) << ";\n";
292-
#undef AS_STRING
293-
#undef AS_STRING_HELPER_TO_GET_THE_ARGUMENT_MACRO_EXPANDED
294-
295302
// Emit Directive associations
296303
std::vector<const Record *> Associations;
297304
copy_if(DirLang.getAssociations(), std::back_inserter(Associations),
@@ -324,7 +331,7 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
324331
OS << "\n";
325332
OS << "// Enumeration helper functions\n";
326333

327-
OS << "LLVM_ABI std::pair<Directive, VersionRange> get" << Lang
334+
OS << "LLVM_ABI std::pair<Directive, directive::VersionRange> get" << Lang
328335
<< "DirectiveKindAndVersions(StringRef Str);\n";
329336

330337
OS << "inline Directive get" << Lang << "DirectiveKind(StringRef Str) {\n";
@@ -336,7 +343,7 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
336343
<< "DirectiveName(Directive D, unsigned Ver = 0);\n";
337344
OS << "\n";
338345

339-
OS << "LLVM_ABI std::pair<Clause, VersionRange> get" << Lang
346+
OS << "LLVM_ABI std::pair<Clause, directive::VersionRange> get" << Lang
340347
<< "ClauseKindAndVersions(StringRef Str);\n";
341348
OS << "\n";
342349

@@ -373,6 +380,33 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
373380
OS << "#endif // LLVM_" << Lang << "_INC\n";
374381
}
375382

383+
// Given a list of spellings (for a given clause/directive), order them
384+
// in a way that allows the use of binary search to locate a spelling
385+
// for a specified version.
386+
static std::vector<Spelling::Value>
387+
orderSpellings(ArrayRef<Spelling::Value> Spellings) {
388+
std::vector<Spelling::Value> List(Spellings.begin(), Spellings.end());
389+
390+
// There are two intertwined orderings: (1) the order between spellings
391+
// (used here), and (2) the order between a spelling and a version (used
392+
// at runtime).
393+
// Define order (2) as such that the first A that is not less than V
394+
// will be the selected spelling given V. Specifically,
395+
// V <(2) A <=> V < A.Min
396+
// A <(2) V <=> A.Max < V
397+
//
398+
// The orders have to be compatible, i.e.
399+
// A <(2) V and !(V <(2) B) => A <(1) B, and
400+
// !(A <(2) v) and V <(2) B => A <(1) B
401+
// In other words, the transitive closure of (2) must contain (1).
402+
llvm::stable_sort(List,
403+
[](const Spelling::Value &A, const Spelling::Value &B) {
404+
return A.Versions < B.Versions;
405+
});
406+
407+
return List;
408+
}
409+
376410
// Generate function implementation for get<Enum>Name(StringRef Str)
377411
static void generateGetName(ArrayRef<const Record *> Records, raw_ostream &OS,
378412
StringRef Enum, const DirectiveLanguage &DirLang,
@@ -381,14 +415,31 @@ static void generateGetName(ArrayRef<const Record *> Records, raw_ostream &OS,
381415
std::string Qual = getQualifier(DirLang);
382416
OS << "\n";
383417
OS << "llvm::StringRef " << Qual << "get" << Lang << Enum << "Name(" << Qual
384-
<< Enum << " Kind, unsigned) {\n";
418+
<< Enum << " Kind, unsigned Version) {\n";
385419
OS << " switch (Kind) {\n";
386420
for (const Record *R : Records) {
387-
OS << " case " << getIdentifierName(R, Prefix) << ":\n";
388-
// FIXME: This will need to recognize different spellings for different
389-
// versions.
390-
OS << " return \"" << BaseRecord(R).getSpellingForIdentifier()
391-
<< "\";\n";
421+
BaseRecord Rec(R);
422+
std::string Ident = getIdentifierName(R, Prefix);
423+
OS << " case " << Ident << ":";
424+
auto Spellings(orderSpellings(Rec.getSpellings()));
425+
assert(Spellings.size() != 0 && "No spellings for this item");
426+
if (Spellings.size() == 1) {
427+
OS << "\n";
428+
OS << " return \"" << Spellings.front().Name << "\";\n";
429+
} else {
430+
OS << " {\n";
431+
std::string SpellingsName = Ident + "_spellings";
432+
OS << " static const llvm::directive::Spelling " << SpellingsName
433+
<< "[] = {\n";
434+
for (auto &S : Spellings) {
435+
OS << " {\"" << S.Name << "\", {" << S.Versions.Min << ", "
436+
<< S.Versions.Max << "}},\n";
437+
}
438+
OS << " };\n";
439+
OS << " return llvm::directive::FindName(" << SpellingsName
440+
<< ", Version);\n";
441+
OS << " }\n";
442+
}
392443
}
393444
OS << " }\n"; // switch
394445
OS << " llvm_unreachable(\"Invalid " << Lang << " " << Enum << " kind\");\n";
@@ -415,23 +466,29 @@ static void generateGetKind(ArrayRef<const Record *> Records, raw_ostream &OS,
415466
// std::pair<<Enum>, VersionRange>
416467
// get<DirLang><Enum>KindAndVersions(StringRef Str);
417468
OS << "\n";
418-
OS << "std::pair<" << Qual << Enum << ", " << Qual << "VersionRange> " << Qual
419-
<< "get" << DirLang.getName() << Enum
469+
OS << "std::pair<" << Qual << Enum << ", llvm::directive::VersionRange> "
470+
<< Qual << "get" << DirLang.getName() << Enum
420471
<< "KindAndVersions(llvm::StringRef Str) {\n";
421-
OS << " VersionRange All{}; // Default-initialized to \"all-versions\"\n";
472+
OS << " directive::VersionRange All; // Default-initialized to \"all "
473+
"versions\"\n";
422474
OS << " return StringSwitch<std::pair<" << Enum << ", "
423-
<< "VersionRange>>(Str)\n";
475+
<< "directive::VersionRange>>(Str)\n";
476+
477+
directive::VersionRange All;
424478

425479
for (const Record *R : Records) {
426480
BaseRecord Rec(R);
427-
// FIXME: This will need to recognize different spellings for different
428-
// versions.
429-
StringRef Name = Rec.getSpellingForIdentifier();
430-
if (ImplicitAsUnknown && R->getValueAsBit("isImplicit")) {
431-
OS << " .Case(\"" << Name << "\", {" << DefaultName << ", All})\n";
432-
} else {
433-
OS << " .Case(\"" << Name << "\", {"
434-
<< getIdentifierName(R, Prefix) << ", All})\n";
481+
std::string Ident = ImplicitAsUnknown && R->getValueAsBit("isImplicit")
482+
? DefaultName
483+
: getIdentifierName(R, Prefix);
484+
485+
for (auto &[Name, Versions] : Rec.getSpellings()) {
486+
OS << " .Case(\"" << Name << "\", {" << Ident << ", ";
487+
if (Versions.Min == All.Min && Versions.Max == All.Max) {
488+
OS << "All})\n";
489+
} else {
490+
OS << "{" << Versions.Min << ", " << Versions.Max << "}})\n";
491+
}
435492
}
436493
}
437494
OS << " .Default({" << DefaultName << ", All});\n";
@@ -1144,47 +1201,29 @@ static void generateFlangClauseParserKindMap(const DirectiveLanguage &DirLang,
11441201
<< " Parser clause\");\n";
11451202
}
11461203

1147-
using RecordWithText = std::pair<const Record *, StringRef>;
1148-
1149-
static bool compareRecordText(const RecordWithText &A,
1150-
const RecordWithText &B) {
1151-
return A.second > B.second;
1152-
}
1153-
1154-
static std::vector<RecordWithText>
1155-
getSpellingTexts(ArrayRef<const Record *> Records) {
1156-
std::vector<RecordWithText> List;
1157-
for (const Record *R : Records) {
1158-
Clause C(R);
1159-
llvm::transform(
1160-
C.getSpellings(), std::back_inserter(List),
1161-
[R](Spelling::Value V) { return std::make_pair(R, V.first); });
1162-
}
1163-
return List;
1164-
}
1165-
11661204
// Generate the parser for the clauses.
11671205
static void generateFlangClausesParser(const DirectiveLanguage &DirLang,
11681206
raw_ostream &OS) {
11691207
std::vector<const Record *> Clauses = DirLang.getClauses();
11701208
// Sort clauses in the reverse alphabetical order with respect to their
11711209
// names and aliases, so that longer names are tried before shorter ones.
1172-
std::vector<std::pair<const Record *, StringRef>> Names =
1173-
getSpellingTexts(Clauses);
1174-
llvm::sort(Names, compareRecordText);
1210+
std::vector<RecordWithSpelling> Names = getSpellings(Clauses);
1211+
llvm::sort(Names, [](const auto &A, const auto &B) {
1212+
return A.second.Name > B.second.Name;
1213+
});
11751214
IfDefScope Scope("GEN_FLANG_CLAUSES_PARSER", OS);
11761215
StringRef Base = DirLang.getFlangClauseBaseClass();
11771216

11781217
unsigned LastIndex = Names.size() - 1;
11791218
OS << "\n";
11801219
OS << "TYPE_PARSER(\n";
1181-
for (auto [Index, RecTxt] : llvm::enumerate(Names)) {
1182-
auto [R, N] = RecTxt;
1220+
for (auto [Index, RecSp] : llvm::enumerate(Names)) {
1221+
auto [R, S] = RecSp;
11831222
Clause C(R);
11841223

11851224
StringRef FlangClass = C.getFlangClass();
1186-
OS << " \"" << N << "\" >> construct<" << Base << ">(construct<" << Base
1187-
<< "::" << C.getFormattedParserClassName() << ">(";
1225+
OS << " \"" << S.Name << "\" >> construct<" << Base << ">(construct<"
1226+
<< Base << "::" << C.getFormattedParserClassName() << ">(";
11881227
if (FlangClass.empty()) {
11891228
OS << "))";
11901229
if (Index != LastIndex)
@@ -1337,6 +1376,7 @@ void emitDirectivesBasicImpl(const DirectiveLanguage &DirLang,
13371376
StringRef CPrefix = DirLang.getClausePrefix();
13381377

13391378
OS << "\n";
1379+
OS << "#include \"llvm/Frontend/Directive/Spelling.h\"\n";
13401380
OS << "#include \"llvm/Support/ErrorHandling.h\"\n";
13411381
OS << "#include <utility>\n";
13421382

0 commit comments

Comments
 (0)
Please sign in to comment.