Skip to content

Commit 661cbd5

Browse files
authored
[utils][TableGen] Make some non-bitmask enums iterable (#148647)
Additionally, add sentinel values <Enum>::First_ and <Enum>::Last_ to each one of those enums. This will allow using `enum_seq_inclusive` to generate the list of enum-typed values of any generated scoped (non-bitmask) enum.
1 parent e8a891b commit 661cbd5

File tree

4 files changed

+76
-17
lines changed

4 files changed

+76
-17
lines changed

llvm/test/TableGen/directive1.td

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
5353
// CHECK-EMPTY:
5454
// CHECK-NEXT: #include "llvm/ADT/ArrayRef.h"
5555
// CHECK-NEXT: #include "llvm/ADT/BitmaskEnum.h"
56+
// CHECK-NEXT: #include "llvm/ADT/Sequence.h"
5657
// CHECK-NEXT: #include "llvm/ADT/StringRef.h"
5758
// CHECK-NEXT: #include "llvm/Frontend/Directive/Spelling.h"
5859
// CHECK-NEXT: #include "llvm/Support/Compiler.h"
@@ -66,22 +67,26 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
6667
// CHECK-EMPTY:
6768
// CHECK-NEXT: enum class Association {
6869
// CHECK-NEXT: Block,
70+
// CHECK-NEXT: First_ = Block,
6971
// CHECK-NEXT: Declaration,
7072
// CHECK-NEXT: Delimited,
7173
// CHECK-NEXT: Loop,
7274
// CHECK-NEXT: None,
7375
// CHECK-NEXT: Separating,
76+
// CHECK-NEXT: Last_ = Separating,
7477
// CHECK-NEXT: };
7578
// CHECK-EMPTY:
7679
// CHECK-NEXT: static constexpr std::size_t Association_enumSize = 6;
7780
// CHECK-EMPTY:
7881
// CHECK-NEXT: enum class Category {
7982
// CHECK-NEXT: Declarative,
83+
// CHECK-NEXT: First_ = Declarative,
8084
// CHECK-NEXT: Executable,
8185
// CHECK-NEXT: Informational,
8286
// CHECK-NEXT: Meta,
8387
// CHECK-NEXT: Subsidiary,
8488
// CHECK-NEXT: Utility,
89+
// CHECK-NEXT: Last_ = Utility,
8590
// CHECK-NEXT: };
8691
// CHECK-EMPTY:
8792
// CHECK-NEXT: static constexpr std::size_t Category_enumSize = 6;
@@ -96,6 +101,8 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
96101
// CHECK-EMPTY:
97102
// CHECK-NEXT: enum class Directive {
98103
// CHECK-NEXT: TDLD_dira,
104+
// CHECK-NEXT: First_ = TDLD_dira,
105+
// CHECK-NEXT: Last_ = TDLD_dira,
99106
// CHECK-NEXT: };
100107
// CHECK-EMPTY:
101108
// CHECK-NEXT: static constexpr std::size_t Directive_enumSize = 1;
@@ -104,8 +111,10 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
104111
// CHECK-EMPTY:
105112
// CHECK-NEXT: enum class Clause {
106113
// CHECK-NEXT: TDLC_clausea,
114+
// CHECK-NEXT: First_ = TDLC_clausea,
107115
// CHECK-NEXT: TDLC_clauseb,
108116
// CHECK-NEXT: TDLC_clausec,
117+
// CHECK-NEXT: Last_ = TDLC_clausec,
109118
// CHECK-NEXT: };
110119
// CHECK-EMPTY:
111120
// CHECK-NEXT: static constexpr std::size_t Clause_enumSize = 3;
@@ -151,6 +160,22 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
151160
// CHECK-NEXT: LLVM_ABI StringRef getTdlAKindName(AKind x);
152161
// CHECK-EMPTY:
153162
// CHECK-NEXT: } // namespace tdl
163+
// CHECK-EMPTY:
164+
// CHECK-NEXT: template <> struct enum_iteration_traits<tdl::Association> {
165+
// CHECK-NEXT: static constexpr bool is_iterable = true;
166+
// CHECK-NEXT: };
167+
// CHECK-EMPTY:
168+
// CHECK-NEXT: template <> struct enum_iteration_traits<tdl::Category> {
169+
// CHECK-NEXT: static constexpr bool is_iterable = true;
170+
// CHECK-NEXT: };
171+
// CHECK-EMPTY:
172+
// CHECK-NEXT: template <> struct enum_iteration_traits<tdl::Directive> {
173+
// CHECK-NEXT: static constexpr bool is_iterable = true;
174+
// CHECK-NEXT: };
175+
// CHECK-EMPTY:
176+
// CHECK-NEXT: template <> struct enum_iteration_traits<tdl::Clause> {
177+
// CHECK-NEXT: static constexpr bool is_iterable = true;
178+
// CHECK-NEXT: };
154179
// CHECK-NEXT: } // namespace llvm
155180
// CHECK-NEXT: #endif // LLVM_Tdl_INC
156181

llvm/test/TableGen/directive2.td

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
4646
// CHECK-NEXT: #define LLVM_Tdl_INC
4747
// CHECK-EMPTY:
4848
// CHECK-NEXT: #include "llvm/ADT/ArrayRef.h"
49+
// CHECK-NEXT: #include "llvm/ADT/Sequence.h"
4950
// CHECK-NEXT: #include "llvm/ADT/StringRef.h"
5051
// CHECK-NEXT: #include "llvm/Frontend/Directive/Spelling.h"
5152
// CHECK-NEXT: #include "llvm/Support/Compiler.h"
@@ -57,22 +58,26 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
5758
// CHECK-EMPTY:
5859
// CHECK-NEXT: enum class Association {
5960
// CHECK-NEXT: Block,
61+
// CHECK-NEXT: First_ = Block,
6062
// CHECK-NEXT: Declaration,
6163
// CHECK-NEXT: Delimited,
6264
// CHECK-NEXT: Loop,
6365
// CHECK-NEXT: None,
6466
// CHECK-NEXT: Separating,
67+
// CHECK-NEXT: Last_ = Separating,
6568
// CHECK-NEXT: };
6669
// CHECK-EMPTY:
6770
// CHECK-NEXT: static constexpr std::size_t Association_enumSize = 6;
6871
// CHECK-EMPTY:
6972
// CHECK-NEXT: enum class Category {
7073
// CHECK-NEXT: Declarative,
74+
// CHECK-NEXT: First_ = Declarative,
7175
// CHECK-NEXT: Executable,
7276
// CHECK-NEXT: Informational,
7377
// CHECK-NEXT: Meta,
7478
// CHECK-NEXT: Subsidiary,
7579
// CHECK-NEXT: Utility,
80+
// CHECK-NEXT: Last_ = Utility,
7681
// CHECK-NEXT: };
7782
// CHECK-EMPTY:
7883
// CHECK-NEXT: static constexpr std::size_t Category_enumSize = 6;
@@ -87,15 +92,19 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
8792
// CHECK-EMPTY:
8893
// CHECK-NEXT: enum class Directive {
8994
// CHECK-NEXT: TDLD_dira,
95+
// CHECK-NEXT: First_ = TDLD_dira,
96+
// CHECK-NEXT: Last_ = TDLD_dira,
9097
// CHECK-NEXT: };
9198
// CHECK-EMPTY:
9299
// CHECK-NEXT: static constexpr std::size_t Directive_enumSize = 1;
93100
// CHECK-EMPTY:
94101
// CHECK-NEXT: enum class Clause {
95102
// CHECK-NEXT: TDLC_clausea,
103+
// CHECK-NEXT: First_ = TDLC_clausea,
96104
// CHECK-NEXT: TDLC_clauseb,
97105
// CHECK-NEXT: TDLC_clausec,
98106
// CHECK-NEXT: TDLC_claused,
107+
// CHECK-NEXT: Last_ = TDLC_claused,
99108
// CHECK-NEXT: };
100109
// CHECK-EMPTY:
101110
// CHECK-NEXT: static constexpr std::size_t Clause_enumSize = 4;
@@ -124,6 +133,22 @@ def TDL_DirA : Directive<[Spelling<"dira">]> {
124133
// CHECK-NEXT: LLVM_ABI Category getDirectiveCategory(Directive D);
125134
// CHECK-NEXT: LLVM_ABI SourceLanguage getDirectiveLanguages(Directive D);
126135
// CHECK-NEXT: } // namespace tdl
136+
// CHECK-EMPTY:
137+
// CHECK-NEXT: template <> struct enum_iteration_traits<tdl::Association> {
138+
// CHECK-NEXT: static constexpr bool is_iterable = true;
139+
// CHECK-NEXT: };
140+
// CHECK-EMPTY:
141+
// CHECK-NEXT: template <> struct enum_iteration_traits<tdl::Category> {
142+
// CHECK-NEXT: static constexpr bool is_iterable = true;
143+
// CHECK-NEXT: };
144+
// CHECK-EMPTY:
145+
// CHECK-NEXT: template <> struct enum_iteration_traits<tdl::Directive> {
146+
// CHECK-NEXT: static constexpr bool is_iterable = true;
147+
// CHECK-NEXT: };
148+
// CHECK-EMPTY:
149+
// CHECK-NEXT: template <> struct enum_iteration_traits<tdl::Clause> {
150+
// CHECK-NEXT: static constexpr bool is_iterable = true;
151+
// CHECK-NEXT: };
127152
// CHECK-NEXT: } // namespace llvm
128153
// CHECK-NEXT: #endif // LLVM_Tdl_INC
129154

llvm/unittests/Frontend/OpenMPDirectiveNameParserTest.cpp

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,6 @@ static std::string &prepareParamName(std::string &Name) {
4848
return Name;
4949
}
5050

51-
namespace llvm {
52-
template <> struct enum_iteration_traits<omp::Directive> {
53-
static constexpr bool is_iterable = true;
54-
};
55-
} // namespace llvm
56-
5751
// Test tokenizing.
5852

5953
class Tokenize : public testing::TestWithParam<omp::Directive> {};
@@ -87,12 +81,10 @@ getParamName1(const testing::TestParamInfo<Tokenize::ParamType> &Info) {
8781
return prepareParamName(Name);
8882
}
8983

90-
INSTANTIATE_TEST_SUITE_P(
91-
DirectiveNameParserTest, Tokenize,
92-
testing::ValuesIn(
93-
llvm::enum_seq(static_cast<omp::Directive>(0),
94-
static_cast<omp::Directive>(omp::Directive_enumSize))),
95-
getParamName1);
84+
INSTANTIATE_TEST_SUITE_P(DirectiveNameParserTest, Tokenize,
85+
testing::ValuesIn(llvm::enum_seq_inclusive(
86+
omp::Directive::First_, omp::Directive::Last_)),
87+
getParamName1);
9688

9789
// Test parsing of valid names.
9890

@@ -131,9 +123,8 @@ getParamName2(const testing::TestParamInfo<ParseValid::ParamType> &Info) {
131123

132124
INSTANTIATE_TEST_SUITE_P(
133125
DirectiveNameParserTest, ParseValid,
134-
testing::Combine(testing::ValuesIn(llvm::enum_seq(
135-
static_cast<omp::Directive>(0),
136-
static_cast<omp::Directive>(omp::Directive_enumSize))),
126+
testing::Combine(testing::ValuesIn(llvm::enum_seq_inclusive(
127+
omp::Directive::First_, omp::Directive::Last_)),
137128
testing::ValuesIn(omp::getOpenMPVersions())),
138129
getParamName2);
139130

llvm/utils/TableGen/Basic/DirectiveEmitter.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,16 @@ static void generateEnumClass(ArrayRef<const Record *> Records, raw_ostream &OS,
106106
bool ExportEnums) {
107107
OS << "\n";
108108
OS << "enum class " << Enum << " {\n";
109-
for (const Record *R : Records) {
110-
OS << " " << getIdentifierName(R, Prefix) << ",\n";
109+
if (!Records.empty()) {
110+
std::string N;
111+
for (auto [I, R] : llvm::enumerate(Records)) {
112+
N = getIdentifierName(R, Prefix);
113+
OS << " " << N << ",\n";
114+
// Make the sentinel names less likely to conflict with actual names...
115+
if (I == 0)
116+
OS << " First_ = " << N << ",\n";
117+
}
118+
OS << " Last_ = " << N << ",\n";
111119
}
112120
OS << "};\n";
113121
OS << "\n";
@@ -282,6 +290,7 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
282290
if (DirLang.hasEnableBitmaskEnumInNamespace())
283291
OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n";
284292

293+
OS << "#include \"llvm/ADT/Sequence.h\"\n";
285294
OS << "#include \"llvm/ADT/StringRef.h\"\n";
286295
OS << "#include \"llvm/Frontend/Directive/Spelling.h\"\n";
287296
OS << "#include \"llvm/Support/Compiler.h\"\n";
@@ -375,6 +384,15 @@ static void emitDirectivesDecl(const RecordKeeper &Records, raw_ostream &OS) {
375384
for (auto Ns : reverse(Namespaces))
376385
OS << "} // namespace " << Ns << "\n";
377386

387+
// These specializations need to be in ::llvm.
388+
for (StringRef Enum : {"Association", "Category", "Directive", "Clause"}) {
389+
OS << "\n";
390+
OS << "template <> struct enum_iteration_traits<"
391+
<< DirLang.getCppNamespace() << "::" << Enum << "> {\n";
392+
OS << " static constexpr bool is_iterable = true;\n";
393+
OS << "};\n";
394+
}
395+
378396
OS << "} // namespace llvm\n";
379397

380398
OS << "#endif // LLVM_" << Lang << "_INC\n";

0 commit comments

Comments
 (0)