1//==--- Traits.td - Generate expression and type traits -------------------===//
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 "TableGenBackends.h"
10#include "llvm/ADT/ArrayRef.h"
11#include "llvm/ADT/STLExtras.h"
12#include "llvm/ADT/StringRef.h"
13#include "llvm/ADT/StringSwitch.h"
14#include "llvm/Support/ErrorHandling.h"
15#include "llvm/Support/raw_ostream.h"
16#include "llvm/TableGen/Record.h"
17#include "llvm/TableGen/TableGenBackend.h"
18
19using namespace llvm;
20
21namespace {
22
23std::vector<const Record *>
24getAllDerivedDefsInDeclOrder(const RecordKeeper &Records, StringRef ClassName) {
25 std::vector<const Record *> Defs =
26 Records.getAllDerivedDefinitions(ClassName);
27 llvm::sort(C&: Defs, Comp: [](const Record *A, const Record *B) {
28 return A->getID() < B->getID();
29 });
30 return Defs;
31}
32
33void emitKeyFlags(ArrayRef<const Record *> KeyFlags, raw_ostream &OS) {
34 assert(!KeyFlags.empty() && "KeyFlags should never be empty");
35 interleave(
36 c: KeyFlags, os&: OS, each_fn: [&](const Record *KeyFlag) { OS << KeyFlag->getName(); },
37 separator: " | ");
38}
39
40StringRef recordKindToMacro(const Record *R) {
41 auto const Macro =
42 StringSwitch<StringRef>(R->getType()->getAsString())
43 .Case(S: "UnaryTrait", Value: "TYPE_TRAIT_1")
44 .Case(S: "BinaryTrait", Value: "TYPE_TRAIT_2")
45 .Case(S: "VariadicTrait", Value: "TYPE_TRAIT_N")
46 .Case(S: "ArrayTrait", Value: "ARRAY_TYPE_TRAIT")
47 .Case(S: "ExpressionTrait", Value: "EXPRESSION_TRAIT")
48 .Case(S: "UnaryExprOrTypeTrait", Value: "UNARY_EXPR_OR_TYPE_TRAIT")
49 .Case(S: "CXX11UnaryExprOrTypeTrait", Value: "CXX11_UNARY_EXPR_OR_TYPE_TRAIT")
50 .Case(S: "TransformTypeTrait", Value: "TRANSFORM_TYPE_TRAIT_DEF")
51 .Case(S: "Alias", Value: "ALIAS")
52 .Default(Value: "");
53 assert(!Macro.empty() && "unexpected record class");
54 return Macro;
55}
56
57void emitTokenKey(const RecordKeeper &Records, raw_ostream &OS) {
58 for (const Record *R : getAllDerivedDefsInDeclOrder(Records, ClassName: "TokenKey")) {
59 OS << " " << R->getName() << " = " << R->getValueAsInt(FieldName: "Value") << ",\n";
60 }
61}
62
63void emitMacro(const Record *R, raw_ostream &OS) {
64 OS << recordKindToMacro(R) << "(";
65 if (R->isSubClassOf(Name: "TransformTypeTrait")) {
66 const StringRef StdName = R->getValueAsString(FieldName: "StdName");
67 OS << R->getName() << ", " << StdName;
68 } else if (R->isSubClassOf(Name: "Alias")) {
69 const Record *Primary = R->getValueAsDef(FieldName: "Primary");
70 OS << "\"" << R->getValueAsString(FieldName: "Spelling") << "\", "
71 << Primary->getValueAsString(FieldName: "Spelling") << ", ";
72 emitKeyFlags(KeyFlags: R->getValueAsListOfDefs(FieldName: "KeyFlags"), OS);
73 } else {
74 OS << R->getValueAsString(FieldName: "Spelling") << ", " << R->getName() << ", ";
75 emitKeyFlags(KeyFlags: R->getValueAsListOfDefs(FieldName: "KeyFlags"), OS);
76 }
77 OS << ")\n";
78}
79
80void emitMacroDefs(const RecordKeeper &Records, raw_ostream &OS) {
81 constexpr std::pair<StringRef, StringRef> MacroDefs[] = {
82 {"TYPE_TRAIT_1", "(I,E,K)"},
83 {"TYPE_TRAIT_2", "(I,E,K)"},
84 {"TYPE_TRAIT_N", "(I,E,K)"},
85 {"ARRAY_TYPE_TRAIT", "(I,E,K)"},
86 {"UNARY_EXPR_OR_TYPE_TRAIT", "(I,E,K)"},
87 {"CXX11_UNARY_EXPR_OR_TYPE_TRAIT", "(I,E,K)"},
88 {"EXPRESSION_TRAIT", "(I,E,K)"},
89 {"TRANSFORM_TYPE_TRAIT_DEF", "(K, Trait)"},
90 {"ALIAS", "(X,Y,Z)"}};
91
92 for (const auto &[MacroName, MacroArgs] : MacroDefs) {
93 OS << "#ifndef " << MacroName << "\n"
94 << "#define " << MacroName << MacroArgs << "\n"
95 << "#endif\n";
96 }
97
98 OS << '\n';
99
100 const auto Traits = getAllDerivedDefsInDeclOrder(Records, ClassName: "Trait");
101 const auto Aliases = getAllDerivedDefsInDeclOrder(Records, ClassName: "Alias");
102 for (const Record *R : concat<const Record *const>(Ranges: Traits, Ranges: Aliases))
103 emitMacro(R, OS);
104
105 for (const auto &[MacroName, _] : reverse(C: MacroDefs))
106 OS << "#undef " << MacroName << "\n";
107}
108
109template <typename RangeT>
110void emitEnumerators(raw_ostream &OS, RangeT &&Range) {
111 for (const Record *R : Range)
112 OS << " " << R->getValueAsString(FieldName: "Prefix") << '_' << R->getName() << ",\n";
113}
114
115void emitEnums(const RecordKeeper &Records, raw_ostream &OS) {
116 const auto UnaryTraits = getAllDerivedDefsInDeclOrder(Records, ClassName: "UnaryTrait");
117 const auto BinaryTraits =
118 getAllDerivedDefsInDeclOrder(Records, ClassName: "BinaryTrait");
119 const auto VariadicTraits =
120 getAllDerivedDefsInDeclOrder(Records, ClassName: "VariadicTrait");
121
122 OS << "/// Names for traits that operate specifically on types.\n"
123 "enum TypeTrait {\n";
124 emitEnumerators(OS, Range: UnaryTraits);
125 OS << " UTT_Last = " << UnaryTraits.size() - 1
126 << ", // UTT_Last == last UTT_XX in the enum.\n";
127
128 emitEnumerators(OS, Range: BinaryTraits);
129 OS << " BTT_Last = " << UnaryTraits.size() + BinaryTraits.size() - 1
130 << ", // BTT_Last == last BTT_XX in the enum.\n";
131
132 emitEnumerators(OS, Range: VariadicTraits);
133 OS << " TT_Last = "
134 << UnaryTraits.size() + BinaryTraits.size() + VariadicTraits.size() - 1
135 << " // TT_Last == last TT_XX in the enum.\n"
136 << "};\n\n";
137
138 const auto ArrayTraits = getAllDerivedDefsInDeclOrder(Records, ClassName: "ArrayTrait");
139 OS << "/// Names for the array type traits.\n"
140 "enum ArrayTypeTrait {\n";
141 emitEnumerators(OS, Range: ArrayTraits);
142 OS << " ATT_Last = " << ArrayTraits.size() - 1
143 << " // ATT_Last == last ATT\n"
144 << "};\n\n";
145
146 const auto UETTs =
147 getAllDerivedDefsInDeclOrder(Records, ClassName: "UnaryExprOrTypeTrait");
148 const auto CXX11UETTs =
149 getAllDerivedDefsInDeclOrder(Records, ClassName: "CXX11UnaryExprOrTypeTrait");
150 OS << "/// Names for the \"expression or type\" traits.\n"
151 "enum UnaryExprOrTypeTrait {\n";
152 emitEnumerators(OS, Range: concat<const Record *const>(Ranges: UETTs, Ranges: CXX11UETTs));
153 OS << " UETT_Last = " << UETTs.size() + CXX11UETTs.size() - 1
154 << " // UETT_Last == last UETT_XX in the enum.\n"
155 << "};\n\n";
156
157 const auto ExpressionTraits =
158 getAllDerivedDefsInDeclOrder(Records, ClassName: "ExpressionTrait");
159 OS << "/// Names for the expression traits.\n"
160 "enum ExpressionTrait {\n";
161 emitEnumerators(OS, Range: ExpressionTraits);
162 OS << " ET_Last = " << ExpressionTraits.size() - 1
163 << " // ET_Last == last ET_XX in the enum.\n"
164 << "};\n\n";
165}
166
167template <typename RangeT>
168void emitNamesAndSpellings(raw_ostream &OS, StringRef Name, RangeT Range) {
169 OS << "static constexpr const char *" << Name << "Names[] = {\n";
170 for (const Record *R : Range) {
171 OS << " \"" << R->getName() << "\",\n";
172 }
173 OS << "};\n\n";
174
175 OS << "static constexpr const char *" << Name << "Spellings[] = {\n";
176 for (const Record *R : Range) {
177 OS << " \"" << R->getValueAsString(FieldName: "Spelling") << "\",\n";
178 }
179 OS << "};\n\n";
180}
181
182void emitArrays(const RecordKeeper &Records, raw_ostream &OS) {
183 const auto UnaryTraits = getAllDerivedDefsInDeclOrder(Records, ClassName: "UnaryTrait");
184 const auto BinaryTraits =
185 getAllDerivedDefsInDeclOrder(Records, ClassName: "BinaryTrait");
186 const auto VariadicTraits =
187 getAllDerivedDefsInDeclOrder(Records, ClassName: "VariadicTrait");
188
189 emitNamesAndSpellings(
190 OS, Name: "TypeTrait",
191 Range: concat<const Record *const>(Ranges: UnaryTraits, Ranges: BinaryTraits, Ranges: VariadicTraits));
192
193 OS << "static constexpr const unsigned TypeTraitArities[] = {\n";
194 interleaveComma(c: UnaryTraits, os&: OS, each_fn: [&](auto) { OS << '1'; });
195 if (!UnaryTraits.empty())
196 OS << ",\n";
197 interleaveComma(c: BinaryTraits, os&: OS, each_fn: [&](auto) { OS << '2'; });
198 if (!BinaryTraits.empty())
199 OS << ",\n";
200 interleaveComma(c: VariadicTraits, os&: OS, each_fn: [&](auto) { OS << '0'; });
201 OS << "\n};\n\n";
202
203 emitNamesAndSpellings(OS, Name: "ArrayTypeTrait",
204 Range: getAllDerivedDefsInDeclOrder(Records, ClassName: "ArrayTrait"));
205 emitNamesAndSpellings(
206 OS, Name: "UnaryExprOrTypeTrait",
207 Range: concat<const Record *const>(
208 Ranges: getAllDerivedDefsInDeclOrder(Records, ClassName: "UnaryExprOrTypeTrait"),
209 Ranges: getAllDerivedDefsInDeclOrder(Records, ClassName: "CXX11UnaryExprOrTypeTrait")));
210 emitNamesAndSpellings(
211 OS, Name: "ExpressionTrait",
212 Range: getAllDerivedDefsInDeclOrder(Records, ClassName: "ExpressionTrait"));
213}
214
215void emitStdNameCases(const RecordKeeper &Records, raw_ostream &OS) {
216 for (const Record *R : getAllDerivedDefsInDeclOrder(Records, ClassName: "TypeTrait")) {
217 const StringRef StdName = R->getValueAsString(FieldName: "StdName");
218 if (StdName.empty())
219 continue;
220
221 OS << " .Case(\"" << StdName
222 << "\", TypeTrait::" << R->getValueAsString(FieldName: "Prefix") << '_'
223 << R->getName() << ")\n";
224 }
225}
226
227} // namespace
228
229void clang::EmitClangBuiltinTraits(const RecordKeeper &Records,
230 raw_ostream &OS) {
231 emitSourceFileHeader(Desc: "Type and expression traits", OS, Record: Records);
232 OS << "#if defined(EMIT_TOKENKEY)\n";
233 emitTokenKey(Records, OS);
234
235 OS << "#elif defined(EMIT_ENUMS)\n";
236 emitEnums(Records, OS);
237
238 OS << "#elif defined(EMIT_ARRAYS)\n";
239 emitArrays(Records, OS);
240
241 OS << "#elif defined(EMIT_STD_NAME_CASES)\n";
242 emitStdNameCases(Records, OS);
243
244 OS << "#else\n";
245 emitMacroDefs(Records, OS);
246
247 OS << "#endif\n\n"
248 << R"(
249#undef EMIT_ARRAYS
250#undef EMIT_ENUMS
251#undef EMIT_STD_NAME_CASES
252#undef EMIT_TOKENKEY
253
254)";
255}
256