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 emitMacro(const Record *R, raw_ostream &OS) {
58 OS << recordKindToMacro(R) << "(";
59 if (R->isSubClassOf(Name: "TransformTypeTrait")) {
60 const StringRef StdName = R->getValueAsString(FieldName: "StdName");
61 OS << R->getName() << ", " << StdName;
62 } else if (R->isSubClassOf(Name: "Alias")) {
63 const Record *Primary = R->getValueAsDef(FieldName: "Primary");
64 OS << "\"" << R->getValueAsString(FieldName: "Spelling") << "\", "
65 << Primary->getValueAsString(FieldName: "Spelling") << ", ";
66 emitKeyFlags(KeyFlags: R->getValueAsListOfDefs(FieldName: "KeyFlags"), OS);
67 } else {
68 OS << R->getValueAsString(FieldName: "Spelling") << ", " << R->getName() << ", ";
69 emitKeyFlags(KeyFlags: R->getValueAsListOfDefs(FieldName: "KeyFlags"), OS);
70 }
71 OS << ")\n";
72}
73
74void emitMacroDefs(const RecordKeeper &Records, raw_ostream &OS) {
75 constexpr std::pair<StringRef, StringRef> MacroDefs[] = {
76 {"TYPE_TRAIT_1", "(I,E,K)"},
77 {"TYPE_TRAIT_2", "(I,E,K)"},
78 {"TYPE_TRAIT_N", "(I,E,K)"},
79 {"ARRAY_TYPE_TRAIT", "(I,E,K)"},
80 {"UNARY_EXPR_OR_TYPE_TRAIT", "(I,E,K)"},
81 {"CXX11_UNARY_EXPR_OR_TYPE_TRAIT", "(I,E,K)"},
82 {"EXPRESSION_TRAIT", "(I,E,K)"},
83 {"TRANSFORM_TYPE_TRAIT_DEF", "(K, Trait)"},
84 {"ALIAS", "(X,Y,Z)"}};
85
86 for (const auto &[MacroName, MacroArgs] : MacroDefs) {
87 OS << "#ifndef " << MacroName << "\n"
88 << "#define " << MacroName << MacroArgs << "\n"
89 << "#endif\n";
90 }
91
92 OS << '\n';
93
94 const auto Traits = getAllDerivedDefsInDeclOrder(Records, ClassName: "Trait");
95 const auto Aliases = getAllDerivedDefsInDeclOrder(Records, ClassName: "Alias");
96 for (const Record *R : concat<const Record *const>(Ranges: Traits, Ranges: Aliases))
97 emitMacro(R, OS);
98
99 for (const auto &[MacroName, _] : reverse(C: MacroDefs))
100 OS << "#undef " << MacroName << "\n";
101}
102
103template <typename RangeT>
104void emitEnumerators(raw_ostream &OS, RangeT &&Range) {
105 for (const Record *R : Range)
106 OS << " " << R->getValueAsString(FieldName: "Prefix") << '_' << R->getName() << ",\n";
107}
108
109void emitEnums(const RecordKeeper &Records, raw_ostream &OS) {
110 const auto UnaryTraits = getAllDerivedDefsInDeclOrder(Records, ClassName: "UnaryTrait");
111 const auto BinaryTraits =
112 getAllDerivedDefsInDeclOrder(Records, ClassName: "BinaryTrait");
113 const auto VariadicTraits =
114 getAllDerivedDefsInDeclOrder(Records, ClassName: "VariadicTrait");
115
116 OS << "/// Names for traits that operate specifically on types.\n"
117 "enum TypeTrait {\n";
118 emitEnumerators(OS, Range: UnaryTraits);
119 OS << " UTT_Last = " << UnaryTraits.size() - 1
120 << ", // UTT_Last == last UTT_XX in the enum.\n";
121
122 emitEnumerators(OS, Range: BinaryTraits);
123 OS << " BTT_Last = " << UnaryTraits.size() + BinaryTraits.size() - 1
124 << ", // BTT_Last == last BTT_XX in the enum.\n";
125
126 emitEnumerators(OS, Range: VariadicTraits);
127 OS << " TT_Last = "
128 << UnaryTraits.size() + BinaryTraits.size() + VariadicTraits.size() - 1
129 << " // TT_Last == last TT_XX in the enum.\n"
130 << "};\n\n";
131
132 const auto ArrayTraits = getAllDerivedDefsInDeclOrder(Records, ClassName: "ArrayTrait");
133 OS << "/// Names for the array type traits.\n"
134 "enum ArrayTypeTrait {\n";
135 emitEnumerators(OS, Range: ArrayTraits);
136 OS << " ATT_Last = " << ArrayTraits.size() - 1
137 << " // ATT_Last == last ATT\n"
138 << "};\n\n";
139
140 const auto UETTs =
141 getAllDerivedDefsInDeclOrder(Records, ClassName: "UnaryExprOrTypeTrait");
142 const auto CXX11UETTs =
143 getAllDerivedDefsInDeclOrder(Records, ClassName: "CXX11UnaryExprOrTypeTrait");
144 OS << "/// Names for the \"expression or type\" traits.\n"
145 "enum UnaryExprOrTypeTrait {\n";
146 emitEnumerators(OS, Range: concat<const Record *const>(Ranges: UETTs, Ranges: CXX11UETTs));
147 OS << " UETT_Last = " << UETTs.size() + CXX11UETTs.size() - 1
148 << " // UETT_Last == last UETT_XX in the enum.\n"
149 << "};\n\n";
150}
151
152template <typename RangeT>
153void emitNamesAndSpellings(raw_ostream &OS, StringRef Name, RangeT Range) {
154 OS << "static constexpr const char *" << Name << "Names[] = {\n";
155 for (const Record *R : Range) {
156 OS << " \"" << R->getName() << "\",\n";
157 }
158 OS << "};\n\n";
159
160 OS << "static constexpr const char *" << Name << "Spellings[] = {\n";
161 for (const Record *R : Range) {
162 OS << " \"" << R->getValueAsString(FieldName: "Spelling") << "\",\n";
163 }
164 OS << "};\n\n";
165}
166
167void emitArrays(const RecordKeeper &Records, raw_ostream &OS) {
168 const auto UnaryTraits = getAllDerivedDefsInDeclOrder(Records, ClassName: "UnaryTrait");
169 const auto BinaryTraits =
170 getAllDerivedDefsInDeclOrder(Records, ClassName: "BinaryTrait");
171 const auto VariadicTraits =
172 getAllDerivedDefsInDeclOrder(Records, ClassName: "VariadicTrait");
173
174 emitNamesAndSpellings(
175 OS, Name: "TypeTrait",
176 Range: concat<const Record *const>(Ranges: UnaryTraits, Ranges: BinaryTraits, Ranges: VariadicTraits));
177
178 OS << "static constexpr const unsigned TypeTraitArities[] = {\n";
179 interleaveComma(c: UnaryTraits, os&: OS, each_fn: [&](auto) { OS << '1'; });
180 if (!UnaryTraits.empty())
181 OS << ",\n";
182 interleaveComma(c: BinaryTraits, os&: OS, each_fn: [&](auto) { OS << '2'; });
183 if (!BinaryTraits.empty())
184 OS << ",\n";
185 interleaveComma(c: VariadicTraits, os&: OS, each_fn: [&](auto) { OS << '0'; });
186 OS << "\n};\n\n";
187
188 emitNamesAndSpellings(OS, Name: "ArrayTypeTrait",
189 Range: getAllDerivedDefsInDeclOrder(Records, ClassName: "ArrayTrait"));
190 emitNamesAndSpellings(
191 OS, Name: "UnaryExprOrTypeTrait",
192 Range: concat<const Record *const>(
193 Ranges: getAllDerivedDefsInDeclOrder(Records, ClassName: "UnaryExprOrTypeTrait"),
194 Ranges: getAllDerivedDefsInDeclOrder(Records, ClassName: "CXX11UnaryExprOrTypeTrait")));
195}
196
197void emitStdNameCases(const RecordKeeper &Records, raw_ostream &OS) {
198 for (const Record *R : getAllDerivedDefsInDeclOrder(Records, ClassName: "TypeTrait")) {
199 const StringRef StdName = R->getValueAsString(FieldName: "StdName");
200 if (StdName.empty())
201 continue;
202
203 OS << " .Case(\"" << StdName
204 << "\", TypeTrait::" << R->getValueAsString(FieldName: "Prefix") << '_'
205 << R->getName() << ")\n";
206 }
207}
208
209} // namespace
210
211void clang::EmitClangTraits(const RecordKeeper &Records, raw_ostream &OS) {
212 emitSourceFileHeader(Desc: "Type and expression traits", OS, Record: Records);
213 OS << "#if defined(EMIT_ENUMS)\n";
214 emitEnums(Records, OS);
215
216 OS << "#elif defined(EMIT_ARRAYS)\n";
217 emitArrays(Records, OS);
218
219 OS << "#elif defined(EMIT_STD_NAME_CASES)\n";
220 emitStdNameCases(Records, OS);
221
222 OS << "#else\n";
223 emitMacroDefs(Records, OS);
224
225 OS << "#endif\n\n"
226 << R"(
227#undef EMIT_ARRAYS
228#undef EMIT_ENUMS
229#undef EMIT_STD_NAME_CASES
230
231)";
232}
233