[memprof] Upgrade a unit test to MemProf Version 3 (#117063)
[llvm-project.git] / clang / utils / TableGen / ClangBuiltinsEmitter.cpp
blob6c3604adc92b994f4b30fe59ce29dd9f5534a180
1 //===-- ClangBuiltinsEmitter.cpp - Generate Clang builtins tables ---------===//
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 // This tablegen backend emits Clang's builtins tables.
11 //===----------------------------------------------------------------------===//
13 #include "TableGenBackends.h"
14 #include "llvm/ADT/StringSwitch.h"
15 #include "llvm/TableGen/Error.h"
16 #include "llvm/TableGen/Record.h"
17 #include "llvm/TableGen/TableGenBackend.h"
19 using namespace llvm;
21 namespace {
22 enum class BuiltinType {
23 Builtin,
24 AtomicBuiltin,
25 LibBuiltin,
26 LangBuiltin,
27 TargetBuiltin,
30 class PrototypeParser {
31 public:
32 PrototypeParser(StringRef Substitution, const Record *Builtin)
33 : Loc(Builtin->getFieldLoc("Prototype")), Substitution(Substitution) {
34 ParsePrototype(Builtin->getValueAsString("Prototype"));
37 private:
38 void ParsePrototype(StringRef Prototype) {
39 Prototype = Prototype.trim();
40 ParseTypes(Prototype);
43 void ParseTypes(StringRef &Prototype) {
44 auto ReturnType = Prototype.take_until([](char c) { return c == '('; });
45 ParseType(ReturnType);
46 Prototype = Prototype.drop_front(ReturnType.size() + 1);
47 if (!Prototype.ends_with(")"))
48 PrintFatalError(Loc, "Expected closing brace at end of prototype");
49 Prototype = Prototype.drop_back();
51 // Look through the input parameters.
52 const size_t end = Prototype.size();
53 for (size_t I = 0; I != end;) {
54 const StringRef Current = Prototype.substr(I, end);
55 // Skip any leading space or commas
56 if (Current.starts_with(" ") || Current.starts_with(",")) {
57 ++I;
58 continue;
61 // Check if we are in _ExtVector. We do this first because
62 // extended vectors are written in template form with the syntax
63 // _ExtVector< ..., ...>, so we need to make sure we are not
64 // detecting the comma of the template class as a separator for
65 // the parameters of the prototype. Note: the assumption is that
66 // we cannot have nested _ExtVector.
67 if (Current.starts_with("_ExtVector<") ||
68 Current.starts_with("_Vector<")) {
69 const size_t EndTemplate = Current.find('>', 0);
70 ParseType(Current.substr(0, EndTemplate + 1));
71 // Move the prototype beyond _ExtVector<...>
72 I += EndTemplate + 1;
73 continue;
76 // We know that we are past _ExtVector, therefore the first seen
77 // comma is the boundary of a parameter in the prototype.
78 if (size_t CommaPos = Current.find(',', 0)) {
79 if (CommaPos != StringRef::npos) {
80 StringRef T = Current.substr(0, CommaPos);
81 ParseType(T);
82 // Move the prototype beyond the comma.
83 I += CommaPos + 1;
84 continue;
88 // No more commas, parse final parameter.
89 ParseType(Current);
90 I = end;
94 void ParseType(StringRef T) {
95 T = T.trim();
96 if (T.consume_back("*")) {
97 ParseType(T);
98 Type += "*";
99 } else if (T.consume_back("const")) {
100 ParseType(T);
101 Type += "C";
102 } else if (T.consume_back("volatile")) {
103 ParseType(T);
104 Type += "D";
105 } else if (T.consume_back("restrict")) {
106 ParseType(T);
107 Type += "R";
108 } else if (T.consume_back("&")) {
109 ParseType(T);
110 Type += "&";
111 } else if (T.consume_front("long")) {
112 Type += "L";
113 ParseType(T);
114 } else if (T.consume_front("unsigned")) {
115 Type += "U";
116 ParseType(T);
117 } else if (T.consume_front("_Complex")) {
118 Type += "X";
119 ParseType(T);
120 } else if (T.consume_front("_Constant")) {
121 Type += "I";
122 ParseType(T);
123 } else if (T.consume_front("T")) {
124 if (Substitution.empty())
125 PrintFatalError(Loc, "Not a template");
126 ParseType(Substitution);
127 } else if (auto IsExt = T.consume_front("_ExtVector");
128 IsExt || T.consume_front("_Vector")) {
129 // Clang extended vector types are mangled as follows:
131 // '_ExtVector<' <lanes> ',' <scalar type> '>'
133 // Before parsing T(=<scalar type>), make sure the syntax of
134 // `_ExtVector<N, T>` is correct...
135 if (!T.consume_front("<"))
136 PrintFatalError(Loc, "Expected '<' after '_ExtVector'");
137 unsigned long long Lanes;
138 if (consumeUnsignedInteger(T, 10, Lanes))
139 PrintFatalError(Loc, "Expected number of lanes after '_ExtVector<'");
140 Type += (IsExt ? "E" : "V") + std::to_string(Lanes);
141 if (!T.consume_front(","))
142 PrintFatalError(Loc,
143 "Expected ',' after number of lanes in '_ExtVector<'");
144 if (!T.consume_back(">"))
145 PrintFatalError(
146 Loc, "Expected '>' after scalar type in '_ExtVector<N, type>'");
148 // ...all good, we can check if we have a valid `<scalar type>`.
149 ParseType(T);
150 } else {
151 auto ReturnTypeVal = StringSwitch<std::string>(T)
152 .Case("__builtin_va_list_ref", "A")
153 .Case("__builtin_va_list", "a")
154 .Case("__float128", "LLd")
155 .Case("__fp16", "h")
156 .Case("__int128_t", "LLLi")
157 .Case("_Float16", "x")
158 .Case("bool", "b")
159 .Case("char", "c")
160 .Case("constant_CFString", "F")
161 .Case("double", "d")
162 .Case("FILE", "P")
163 .Case("float", "f")
164 .Case("id", "G")
165 .Case("int", "i")
166 .Case("int32_t", "Zi")
167 .Case("int64_t", "Wi")
168 .Case("jmp_buf", "J")
169 .Case("msint32_t", "Ni")
170 .Case("msuint32_t", "UNi")
171 .Case("objc_super", "M")
172 .Case("pid_t", "p")
173 .Case("ptrdiff_t", "Y")
174 .Case("SEL", "H")
175 .Case("short", "s")
176 .Case("sigjmp_buf", "SJ")
177 .Case("size_t", "z")
178 .Case("ucontext_t", "K")
179 .Case("uint32_t", "UZi")
180 .Case("uint64_t", "UWi")
181 .Case("void", "v")
182 .Case("wchar_t", "w")
183 .Case("...", ".")
184 .Default("error");
185 if (ReturnTypeVal == "error")
186 PrintFatalError(Loc, "Unknown Type: " + T);
187 Type += ReturnTypeVal;
191 public:
192 void Print(raw_ostream &OS) const { OS << ", \"" << Type << '\"'; }
194 private:
195 SMLoc Loc;
196 StringRef Substitution;
197 std::string Type;
200 class HeaderNameParser {
201 public:
202 HeaderNameParser(const Record *Builtin) {
203 for (char c : Builtin->getValueAsString("Header")) {
204 if (std::islower(c))
205 HeaderName += static_cast<char>(std::toupper(c));
206 else if (c == '.' || c == '_' || c == '/' || c == '-')
207 HeaderName += '_';
208 else
209 PrintFatalError(Builtin->getLoc(), "Unexpected header name");
213 void Print(raw_ostream &OS) const { OS << HeaderName; }
215 private:
216 std::string HeaderName;
219 void PrintAttributes(const Record *Builtin, BuiltinType BT, raw_ostream &OS) {
220 OS << '\"';
221 if (Builtin->isSubClassOf("LibBuiltin")) {
222 if (BT == BuiltinType::LibBuiltin) {
223 OS << 'f';
224 } else {
225 OS << 'F';
226 if (Builtin->getValueAsBit("OnlyBuiltinPrefixedAliasIsConstexpr"))
227 OS << 'E';
231 if (auto NS = Builtin->getValueAsOptionalString("Namespace")) {
232 if (NS != "std")
233 PrintFatalError(Builtin->getFieldLoc("Namespace"), "Unknown namespace: ");
234 OS << "z";
237 for (const auto *Attr : Builtin->getValueAsListOfDefs("Attributes")) {
238 OS << Attr->getValueAsString("Mangling");
239 if (Attr->isSubClassOf("IndexedAttribute"))
240 OS << ':' << Attr->getValueAsInt("Index") << ':';
242 OS << '\"';
245 void EmitBuiltinDef(raw_ostream &OS, StringRef Substitution,
246 const Record *Builtin, Twine Spelling, BuiltinType BT) {
247 if (Builtin->getValueAsBit("RequiresUndef"))
248 OS << "#undef " << Spelling << '\n';
249 switch (BT) {
250 case BuiltinType::LibBuiltin:
251 OS << "LIBBUILTIN";
252 break;
253 case BuiltinType::LangBuiltin:
254 OS << "LANGBUILTIN";
255 break;
256 case BuiltinType::Builtin:
257 OS << "BUILTIN";
258 break;
259 case BuiltinType::AtomicBuiltin:
260 OS << "ATOMIC_BUILTIN";
261 break;
262 case BuiltinType::TargetBuiltin:
263 OS << "TARGET_BUILTIN";
264 break;
267 OS << "(" << Spelling;
268 PrototypeParser{Substitution, Builtin}.Print(OS);
269 OS << ", ";
270 PrintAttributes(Builtin, BT, OS);
272 switch (BT) {
273 case BuiltinType::LibBuiltin: {
274 OS << ", ";
275 HeaderNameParser{Builtin}.Print(OS);
276 [[fallthrough]];
278 case BuiltinType::LangBuiltin: {
279 OS << ", " << Builtin->getValueAsString("Languages");
280 break;
282 case BuiltinType::TargetBuiltin:
283 OS << ", \"" << Builtin->getValueAsString("Features") << "\"";
284 break;
285 case BuiltinType::AtomicBuiltin:
286 case BuiltinType::Builtin:
287 break;
289 OS << ")\n";
292 struct TemplateInsts {
293 std::vector<std::string> Substitution;
294 std::vector<std::string> Affix;
295 bool IsPrefix;
298 TemplateInsts getTemplateInsts(const Record *R) {
299 TemplateInsts temp;
300 auto Substitutions = R->getValueAsListOfStrings("Substitutions");
301 auto Affixes = R->getValueAsListOfStrings("Affixes");
302 temp.IsPrefix = R->getValueAsBit("AsPrefix");
304 if (Substitutions.size() != Affixes.size())
305 PrintFatalError(R->getLoc(), "Substitutions and affixes "
306 "don't have the same lengths");
308 for (auto [Affix, Substitution] : zip(Affixes, Substitutions)) {
309 temp.Substitution.emplace_back(Substitution);
310 temp.Affix.emplace_back(Affix);
312 return temp;
315 void EmitBuiltin(raw_ostream &OS, const Record *Builtin) {
316 TemplateInsts Templates = {};
317 if (Builtin->isSubClassOf("Template")) {
318 Templates = getTemplateInsts(Builtin);
319 } else {
320 Templates.Affix.emplace_back();
321 Templates.Substitution.emplace_back();
324 for (auto [Substitution, Affix] :
325 zip(Templates.Substitution, Templates.Affix)) {
326 for (StringRef Spelling : Builtin->getValueAsListOfStrings("Spellings")) {
327 auto FullSpelling =
328 (Templates.IsPrefix ? Affix + Spelling : Spelling + Affix).str();
329 BuiltinType BT = BuiltinType::Builtin;
330 if (Builtin->isSubClassOf("AtomicBuiltin")) {
331 BT = BuiltinType::AtomicBuiltin;
332 } else if (Builtin->isSubClassOf("LangBuiltin")) {
333 BT = BuiltinType::LangBuiltin;
334 } else if (Builtin->isSubClassOf("TargetBuiltin")) {
335 BT = BuiltinType::TargetBuiltin;
336 } else if (Builtin->isSubClassOf("LibBuiltin")) {
337 BT = BuiltinType::LibBuiltin;
338 if (Builtin->getValueAsBit("AddBuiltinPrefixedAlias"))
339 EmitBuiltinDef(OS, Substitution, Builtin,
340 std::string("__builtin_") + FullSpelling,
341 BuiltinType::Builtin);
343 EmitBuiltinDef(OS, Substitution, Builtin, FullSpelling, BT);
347 } // namespace
349 void clang::EmitClangBuiltins(const RecordKeeper &Records, raw_ostream &OS) {
350 emitSourceFileHeader("List of builtins that Clang recognizes", OS);
352 OS << R"c++(
353 #if defined(BUILTIN) && !defined(LIBBUILTIN)
354 # define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS)
355 #endif
357 #if defined(BUILTIN) && !defined(LANGBUILTIN)
358 # define LANGBUILTIN(ID, TYPE, ATTRS, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS)
359 #endif
361 // Some of our atomics builtins are handled by AtomicExpr rather than
362 // as normal builtin CallExprs. This macro is used for such builtins.
363 #ifndef ATOMIC_BUILTIN
364 # define ATOMIC_BUILTIN(ID, TYPE, ATTRS) BUILTIN(ID, TYPE, ATTRS)
365 #endif
367 #if defined(BUILTIN) && !defined(TARGET_BUILTIN)
368 # define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS)
369 #endif
370 )c++";
372 // AtomicBuiltins are order dependent
373 // emit them first to make manual checking easier
374 for (const auto *Builtin : Records.getAllDerivedDefinitions("AtomicBuiltin"))
375 EmitBuiltin(OS, Builtin);
377 for (const auto *Builtin : Records.getAllDerivedDefinitions("Builtin")) {
378 if (Builtin->isSubClassOf("AtomicBuiltin"))
379 continue;
380 EmitBuiltin(OS, Builtin);
383 for (const auto *Entry : Records.getAllDerivedDefinitions("CustomEntry")) {
384 OS << Entry->getValueAsString("Entry") << '\n';
387 OS << R"c++(
388 #undef ATOMIC_BUILTIN
389 #undef BUILTIN
390 #undef LIBBUILTIN
391 #undef LANGBUILTIN
392 #undef TARGET_BUILTIN
393 )c++";