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.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "TableGenBackends.h"
14 #include "llvm/ADT/StringExtras.h"
15 #include "llvm/ADT/StringSwitch.h"
16 #include "llvm/TableGen/Error.h"
17 #include "llvm/TableGen/Record.h"
18 #include "llvm/TableGen/StringToOffsetTable.h"
19 #include "llvm/TableGen/TableGenBackend.h"
20 #include <sstream>
21
22 using namespace llvm;
23
24 namespace {
25 enum class BuiltinType {
26 Builtin,
27 AtomicBuiltin,
28 LibBuiltin,
29 LangBuiltin,
30 TargetBuiltin,
31 TargetLibBuiltin,
32 };
33
34 class HeaderNameParser {
35 public:
HeaderNameParser(const Record * Builtin)36 HeaderNameParser(const Record *Builtin) {
37 for (char c : Builtin->getValueAsString("Header")) {
38 if (std::islower(c))
39 HeaderName += static_cast<char>(std::toupper(c));
40 else if (c == '.' || c == '_' || c == '/' || c == '-')
41 HeaderName += '_';
42 else
43 PrintFatalError(Builtin->getLoc(), "Unexpected header name");
44 }
45 }
46
Print(raw_ostream & OS) const47 void Print(raw_ostream &OS) const { OS << HeaderName; }
48
49 private:
50 std::string HeaderName;
51 };
52
53 struct Builtin {
54 BuiltinType BT;
55 std::string Name;
56 std::string Type;
57 std::string Attributes;
58
59 const Record *BuiltinRecord;
60
EmitEnumerator__anon1f5e8a8e0111::Builtin61 void EmitEnumerator(llvm::raw_ostream &OS) const {
62 OS << " BI";
63 // If there is a required name prefix, include its spelling in the
64 // enumerator.
65 if (auto *PrefixRecord =
66 BuiltinRecord->getValueAsOptionalDef("RequiredNamePrefix"))
67 OS << PrefixRecord->getValueAsString("Spelling");
68 OS << Name << ",\n";
69 }
70
EmitInfo__anon1f5e8a8e0111::Builtin71 void EmitInfo(llvm::raw_ostream &OS, const StringToOffsetTable &Table) const {
72 OS << " Builtin::Info{Builtin::Info::StrOffsets{"
73 << Table.GetStringOffset(Name) << " /* " << Name << " */, "
74 << Table.GetStringOffset(Type) << " /* " << Type << " */, "
75 << Table.GetStringOffset(Attributes) << " /* " << Attributes << " */, ";
76 if (BT == BuiltinType::TargetBuiltin) {
77 const auto &Features = BuiltinRecord->getValueAsString("Features");
78 OS << Table.GetStringOffset(Features) << " /* " << Features << " */";
79 } else {
80 OS << "0";
81 }
82 OS << "}, ";
83 if (BT == BuiltinType::LibBuiltin || BT == BuiltinType::TargetLibBuiltin) {
84 OS << "HeaderDesc::";
85 HeaderNameParser{BuiltinRecord}.Print(OS);
86 } else {
87 OS << "HeaderDesc::NO_HEADER";
88 }
89 OS << ", ";
90 if (BT == BuiltinType::LibBuiltin || BT == BuiltinType::LangBuiltin ||
91 BT == BuiltinType::TargetLibBuiltin) {
92 OS << BuiltinRecord->getValueAsString("Languages");
93 } else {
94 OS << "ALL_LANGUAGES";
95 }
96 OS << "},\n";
97 }
98
EmitXMacro__anon1f5e8a8e0111::Builtin99 void EmitXMacro(llvm::raw_ostream &OS) const {
100 if (BuiltinRecord->getValueAsBit("RequiresUndef"))
101 OS << "#undef " << Name << '\n';
102 switch (BT) {
103 case BuiltinType::LibBuiltin:
104 OS << "LIBBUILTIN";
105 break;
106 case BuiltinType::LangBuiltin:
107 OS << "LANGBUILTIN";
108 break;
109 case BuiltinType::Builtin:
110 OS << "BUILTIN";
111 break;
112 case BuiltinType::AtomicBuiltin:
113 OS << "ATOMIC_BUILTIN";
114 break;
115 case BuiltinType::TargetBuiltin:
116 OS << "TARGET_BUILTIN";
117 break;
118 case BuiltinType::TargetLibBuiltin:
119 OS << "TARGET_HEADER_BUILTIN";
120 break;
121 }
122
123 OS << "(" << Name << ", \"" << Type << "\", \"" << Attributes << "\"";
124
125 switch (BT) {
126 case BuiltinType::LibBuiltin: {
127 OS << ", ";
128 HeaderNameParser{BuiltinRecord}.Print(OS);
129 [[fallthrough]];
130 }
131 case BuiltinType::LangBuiltin: {
132 OS << ", " << BuiltinRecord->getValueAsString("Languages");
133 break;
134 }
135 case BuiltinType::TargetLibBuiltin: {
136 OS << ", ";
137 HeaderNameParser{BuiltinRecord}.Print(OS);
138 OS << ", " << BuiltinRecord->getValueAsString("Languages");
139 [[fallthrough]];
140 }
141 case BuiltinType::TargetBuiltin: {
142 OS << ", \"" << BuiltinRecord->getValueAsString("Features") << "\"";
143 break;
144 }
145 case BuiltinType::AtomicBuiltin:
146 case BuiltinType::Builtin:
147 break;
148 }
149 OS << ")\n";
150 }
151 };
152
153 class PrototypeParser {
154 public:
PrototypeParser(StringRef Substitution,const Record * Builtin)155 PrototypeParser(StringRef Substitution, const Record *Builtin)
156 : Loc(Builtin->getFieldLoc("Prototype")), Substitution(Substitution),
157 EnableOpenCLLong(Builtin->getValueAsBit("EnableOpenCLLong")) {
158 ParsePrototype(Builtin->getValueAsString("Prototype"));
159 }
160
takeTypeString()161 std::string takeTypeString() && { return std::move(Type); }
162
163 private:
ParsePrototype(StringRef Prototype)164 void ParsePrototype(StringRef Prototype) {
165 Prototype = Prototype.trim();
166
167 // Some builtins don't have an expressible prototype, simply emit an empty
168 // string for them.
169 if (Prototype.empty()) {
170 Type = "";
171 return;
172 }
173
174 ParseTypes(Prototype);
175 }
176
ParseTypes(StringRef & Prototype)177 void ParseTypes(StringRef &Prototype) {
178 auto ReturnType = Prototype.take_until([](char c) { return c == '('; });
179 ParseType(ReturnType);
180 Prototype = Prototype.drop_front(ReturnType.size() + 1);
181 if (!Prototype.ends_with(")"))
182 PrintFatalError(Loc, "Expected closing brace at end of prototype");
183 Prototype = Prototype.drop_back();
184
185 // Look through the input parameters.
186 const size_t end = Prototype.size();
187 for (size_t I = 0; I != end;) {
188 const StringRef Current = Prototype.substr(I, end);
189 // Skip any leading space or commas
190 if (Current.starts_with(" ") || Current.starts_with(",")) {
191 ++I;
192 continue;
193 }
194
195 // Check if we are in _ExtVector. We do this first because
196 // extended vectors are written in template form with the syntax
197 // _ExtVector< ..., ...>, so we need to make sure we are not
198 // detecting the comma of the template class as a separator for
199 // the parameters of the prototype. Note: the assumption is that
200 // we cannot have nested _ExtVector.
201 if (Current.starts_with("_ExtVector<") ||
202 Current.starts_with("_Vector<")) {
203 const size_t EndTemplate = Current.find('>', 0);
204 ParseType(Current.substr(0, EndTemplate + 1));
205 // Move the prototype beyond _ExtVector<...>
206 I += EndTemplate + 1;
207 continue;
208 }
209
210 // We know that we are past _ExtVector, therefore the first seen
211 // comma is the boundary of a parameter in the prototype.
212 if (size_t CommaPos = Current.find(',', 0)) {
213 if (CommaPos != StringRef::npos) {
214 StringRef T = Current.substr(0, CommaPos);
215 ParseType(T);
216 // Move the prototype beyond the comma.
217 I += CommaPos + 1;
218 continue;
219 }
220 }
221
222 // No more commas, parse final parameter.
223 ParseType(Current);
224 I = end;
225 }
226 }
227
ParseType(StringRef T)228 void ParseType(StringRef T) {
229 T = T.trim();
230
231 auto ConsumeAddrSpace = [&]() -> std::optional<unsigned> {
232 T = T.trim();
233 if (!T.consume_back(">"))
234 return std::nullopt;
235
236 auto Open = T.find_last_of('<');
237 if (Open == StringRef::npos)
238 PrintFatalError(Loc, "Mismatched angle-brackets in type");
239
240 StringRef ArgStr = T.substr(Open + 1);
241 T = T.slice(0, Open);
242 if (!T.consume_back("address_space"))
243 PrintFatalError(Loc,
244 "Only `address_space<N>` supported as a parameterized "
245 "pointer or reference type qualifier");
246
247 unsigned Number = 0;
248 if (ArgStr.getAsInteger(10, Number))
249 PrintFatalError(
250 Loc, "Expected an integer argument to the address_space qualifier");
251 if (Number == 0)
252 PrintFatalError(Loc, "No need for a qualifier for address space `0`");
253 return Number;
254 };
255
256 if (T.consume_back("*")) {
257 // Pointers may have an address space qualifier immediately before them.
258 std::optional<unsigned> AS = ConsumeAddrSpace();
259 ParseType(T);
260 Type += "*";
261 if (AS)
262 Type += std::to_string(*AS);
263 } else if (T.consume_back("const")) {
264 ParseType(T);
265 Type += "C";
266 } else if (T.consume_back("volatile")) {
267 ParseType(T);
268 Type += "D";
269 } else if (T.consume_back("restrict")) {
270 ParseType(T);
271 Type += "R";
272 } else if (T.consume_back("&")) {
273 // References may have an address space qualifier immediately before them.
274 std::optional<unsigned> AS = ConsumeAddrSpace();
275 ParseType(T);
276 Type += "&";
277 if (AS)
278 Type += std::to_string(*AS);
279 } else if (T.consume_back(")")) {
280 ParseType(T);
281 Type += "&";
282 } else if (EnableOpenCLLong && T.consume_front("long long")) {
283 Type += "O";
284 ParseType(T);
285 } else if (T.consume_front("long")) {
286 Type += "L";
287 ParseType(T);
288 } else if (T.consume_front("signed")) {
289 Type += "S";
290 ParseType(T);
291 } else if (T.consume_front("unsigned")) {
292 Type += "U";
293 ParseType(T);
294 } else if (T.consume_front("_Complex")) {
295 Type += "X";
296 ParseType(T);
297 } else if (T.consume_front("_Constant")) {
298 Type += "I";
299 ParseType(T);
300 } else if (T.consume_front("T")) {
301 if (Substitution.empty())
302 PrintFatalError(Loc, "Not a template");
303 ParseType(Substitution);
304 } else if (auto IsExt = T.consume_front("_ExtVector");
305 IsExt || T.consume_front("_Vector")) {
306 // Clang extended vector types are mangled as follows:
307 //
308 // '_ExtVector<' <lanes> ',' <scalar type> '>'
309
310 // Before parsing T(=<scalar type>), make sure the syntax of
311 // `_ExtVector<N, T>` is correct...
312 if (!T.consume_front("<"))
313 PrintFatalError(Loc, "Expected '<' after '_ExtVector'");
314 unsigned long long Lanes;
315 if (consumeUnsignedInteger(T, 10, Lanes))
316 PrintFatalError(Loc, "Expected number of lanes after '_ExtVector<'");
317 Type += (IsExt ? "E" : "V") + std::to_string(Lanes);
318 if (!T.consume_front(","))
319 PrintFatalError(Loc,
320 "Expected ',' after number of lanes in '_ExtVector<'");
321 if (!T.consume_back(">"))
322 PrintFatalError(
323 Loc, "Expected '>' after scalar type in '_ExtVector<N, type>'");
324
325 // ...all good, we can check if we have a valid `<scalar type>`.
326 ParseType(T);
327 } else {
328 auto ReturnTypeVal = StringSwitch<std::string>(T)
329 .Case("__builtin_va_list_ref", "A")
330 .Case("__builtin_va_list", "a")
331 .Case("__float128", "LLd")
332 .Case("__fp16", "h")
333 .Case("__int128_t", "LLLi")
334 .Case("_Float16", "x")
335 .Case("__bf16", "y")
336 .Case("bool", "b")
337 .Case("char", "c")
338 .Case("constant_CFString", "F")
339 .Case("double", "d")
340 .Case("FILE", "P")
341 .Case("float", "f")
342 .Case("id", "G")
343 .Case("int", "i")
344 .Case("int32_t", "Zi")
345 .Case("int64_t", "Wi")
346 .Case("jmp_buf", "J")
347 .Case("msint32_t", "Ni")
348 .Case("msuint32_t", "UNi")
349 .Case("objc_super", "M")
350 .Case("pid_t", "p")
351 .Case("ptrdiff_t", "Y")
352 .Case("SEL", "H")
353 .Case("short", "s")
354 .Case("sigjmp_buf", "SJ")
355 .Case("size_t", "z")
356 .Case("ucontext_t", "K")
357 .Case("uint32_t", "UZi")
358 .Case("uint64_t", "UWi")
359 .Case("void", "v")
360 .Case("wchar_t", "w")
361 .Case("...", ".")
362 .Default("error");
363 if (ReturnTypeVal == "error")
364 PrintFatalError(Loc, "Unknown Type: " + T);
365 Type += ReturnTypeVal;
366 }
367 }
368
369 SMLoc Loc;
370 StringRef Substitution;
371 bool EnableOpenCLLong;
372 std::string Type;
373 };
374
renderAttributes(const Record * Builtin,BuiltinType BT)375 std::string renderAttributes(const Record *Builtin, BuiltinType BT) {
376 std::string Attributes;
377 raw_string_ostream OS(Attributes);
378 if (Builtin->isSubClassOf("LibBuiltin")) {
379 if (BT == BuiltinType::LibBuiltin) {
380 OS << 'f';
381 } else {
382 OS << 'F';
383 if (Builtin->getValueAsBit("OnlyBuiltinPrefixedAliasIsConstexpr"))
384 OS << 'E';
385 }
386 }
387
388 if (auto NS = Builtin->getValueAsOptionalString("Namespace")) {
389 if (NS != "std")
390 PrintFatalError(Builtin->getFieldLoc("Namespace"), "Unknown namespace: ");
391 OS << "z";
392 }
393
394 for (const auto *Attr : Builtin->getValueAsListOfDefs("Attributes")) {
395 OS << Attr->getValueAsString("Mangling");
396 if (Attr->isSubClassOf("IndexedAttribute")) {
397 OS << ':' << Attr->getValueAsInt("Index") << ':';
398 } else if (Attr->isSubClassOf("MultiIndexAttribute")) {
399 OS << '<';
400 llvm::ListSeparator Sep(",");
401 for (int64_t Index : Attr->getValueAsListOfInts("Indices"))
402 OS << Sep << Index;
403 OS << '>';
404 }
405 }
406 return Attributes;
407 }
408
buildBuiltin(StringRef Substitution,const Record * BuiltinRecord,Twine Spelling,BuiltinType BT)409 Builtin buildBuiltin(StringRef Substitution, const Record *BuiltinRecord,
410 Twine Spelling, BuiltinType BT) {
411 Builtin B;
412 B.BT = BT;
413 B.Name = Spelling.str();
414 B.Type = PrototypeParser(Substitution, BuiltinRecord).takeTypeString();
415 B.Attributes = renderAttributes(BuiltinRecord, BT);
416 B.BuiltinRecord = BuiltinRecord;
417 return B;
418 }
419
420 struct TemplateInsts {
421 std::vector<std::string> Substitution;
422 std::vector<std::string> Affix;
423 bool IsPrefix;
424 };
425
getTemplateInsts(const Record * R)426 TemplateInsts getTemplateInsts(const Record *R) {
427 TemplateInsts temp;
428 auto Substitutions = R->getValueAsListOfStrings("Substitutions");
429 auto Affixes = R->getValueAsListOfStrings("Affixes");
430 temp.IsPrefix = R->getValueAsBit("AsPrefix");
431
432 if (Substitutions.size() != Affixes.size())
433 PrintFatalError(R->getLoc(), "Substitutions and affixes "
434 "don't have the same lengths");
435
436 for (auto [Affix, Substitution] : zip(Affixes, Substitutions)) {
437 temp.Substitution.emplace_back(Substitution);
438 temp.Affix.emplace_back(Affix);
439 }
440 return temp;
441 }
442
collectBuiltins(const Record * BuiltinRecord,SmallVectorImpl<Builtin> & Builtins)443 void collectBuiltins(const Record *BuiltinRecord,
444 SmallVectorImpl<Builtin> &Builtins) {
445 TemplateInsts Templates = {};
446 if (BuiltinRecord->isSubClassOf("Template")) {
447 Templates = getTemplateInsts(BuiltinRecord);
448 } else {
449 Templates.Affix.emplace_back();
450 Templates.Substitution.emplace_back();
451 }
452
453 for (auto [Substitution, Affix] :
454 zip(Templates.Substitution, Templates.Affix)) {
455 for (StringRef Spelling :
456 BuiltinRecord->getValueAsListOfStrings("Spellings")) {
457 auto FullSpelling =
458 (Templates.IsPrefix ? Affix + Spelling : Spelling + Affix).str();
459 BuiltinType BT = BuiltinType::Builtin;
460 if (BuiltinRecord->isSubClassOf("AtomicBuiltin")) {
461 BT = BuiltinType::AtomicBuiltin;
462 } else if (BuiltinRecord->isSubClassOf("LangBuiltin")) {
463 BT = BuiltinType::LangBuiltin;
464 } else if (BuiltinRecord->isSubClassOf("TargetLibBuiltin")) {
465 BT = BuiltinType::TargetLibBuiltin;
466 } else if (BuiltinRecord->isSubClassOf("TargetBuiltin")) {
467 BT = BuiltinType::TargetBuiltin;
468 } else if (BuiltinRecord->isSubClassOf("LibBuiltin")) {
469 BT = BuiltinType::LibBuiltin;
470 if (BuiltinRecord->getValueAsBit("AddBuiltinPrefixedAlias"))
471 Builtins.push_back(buildBuiltin(
472 Substitution, BuiltinRecord,
473 std::string("__builtin_") + FullSpelling, BuiltinType::Builtin));
474 }
475 Builtins.push_back(
476 buildBuiltin(Substitution, BuiltinRecord, FullSpelling, BT));
477 }
478 }
479 }
480 } // namespace
481
EmitClangBuiltins(const RecordKeeper & Records,raw_ostream & OS)482 void clang::EmitClangBuiltins(const RecordKeeper &Records, raw_ostream &OS) {
483 emitSourceFileHeader("List of builtins that Clang recognizes", OS);
484
485 SmallVector<Builtin> Builtins;
486 // AtomicBuiltins are order dependent. Emit them first to make manual checking
487 // easier and so we can build a special atomic builtin X-macro.
488 for (const auto *BuiltinRecord :
489 Records.getAllDerivedDefinitions("AtomicBuiltin"))
490 collectBuiltins(BuiltinRecord, Builtins);
491 unsigned NumAtomicBuiltins = Builtins.size();
492
493 for (const auto *BuiltinRecord :
494 Records.getAllDerivedDefinitions("Builtin")) {
495 if (BuiltinRecord->isSubClassOf("AtomicBuiltin"))
496 continue;
497 // Prefixed builtins are also special and we emit them last so they can have
498 // their own representation that skips the prefix.
499 if (BuiltinRecord->getValueAsOptionalDef("RequiredNamePrefix"))
500 continue;
501
502 collectBuiltins(BuiltinRecord, Builtins);
503 }
504
505 // Now collect (and count) the prefixed builtins.
506 unsigned NumPrefixedBuiltins = Builtins.size();
507 const Record *FirstPrefix = nullptr;
508 for (const auto *BuiltinRecord :
509 Records.getAllDerivedDefinitions("Builtin")) {
510 auto *Prefix = BuiltinRecord->getValueAsOptionalDef("RequiredNamePrefix");
511 if (!Prefix)
512 continue;
513
514 if (!FirstPrefix)
515 FirstPrefix = Prefix;
516 assert(Prefix == FirstPrefix &&
517 "Multiple distinct prefixes which is not currently supported!");
518 assert(!BuiltinRecord->isSubClassOf("AtomicBuiltin") &&
519 "Cannot require a name prefix for an atomic builtin.");
520 collectBuiltins(BuiltinRecord, Builtins);
521 }
522 NumPrefixedBuiltins = Builtins.size() - NumPrefixedBuiltins;
523
524 auto AtomicBuiltins = ArrayRef(Builtins).slice(0, NumAtomicBuiltins);
525 auto UnprefixedBuiltins = ArrayRef(Builtins).drop_back(NumPrefixedBuiltins);
526 auto PrefixedBuiltins = ArrayRef(Builtins).take_back(NumPrefixedBuiltins);
527
528 // Collect strings into a table.
529 StringToOffsetTable Table;
530 Table.GetOrAddStringOffset("");
531 for (const auto &B : Builtins) {
532 Table.GetOrAddStringOffset(B.Name);
533 Table.GetOrAddStringOffset(B.Type);
534 Table.GetOrAddStringOffset(B.Attributes);
535 if (B.BT == BuiltinType::TargetBuiltin)
536 Table.GetOrAddStringOffset(B.BuiltinRecord->getValueAsString("Features"));
537 }
538
539 // Emit enumerators.
540 OS << R"c++(
541 #ifdef GET_BUILTIN_ENUMERATORS
542 )c++";
543 for (const auto &B : Builtins)
544 B.EmitEnumerator(OS);
545 OS << R"c++(
546 #endif // GET_BUILTIN_ENUMERATORS
547 )c++";
548
549 // Emit a string table that can be referenced for these builtins.
550 OS << R"c++(
551 #ifdef GET_BUILTIN_STR_TABLE
552 )c++";
553 Table.EmitStringTableDef(OS, "BuiltinStrings");
554 OS << R"c++(
555 #endif // GET_BUILTIN_STR_TABLE
556 )c++";
557
558 // Emit a direct set of `Builtin::Info` initializers, first for the unprefixed
559 // builtins and then for the prefixed builtins.
560 OS << R"c++(
561 #ifdef GET_BUILTIN_INFOS
562 )c++";
563 for (const auto &B : UnprefixedBuiltins)
564 B.EmitInfo(OS, Table);
565 OS << R"c++(
566 #endif // GET_BUILTIN_INFOS
567 )c++";
568
569 OS << R"c++(
570 #ifdef GET_BUILTIN_PREFIXED_INFOS
571 )c++";
572 for (const auto &B : PrefixedBuiltins)
573 B.EmitInfo(OS, Table);
574 OS << R"c++(
575 #endif // GET_BUILTIN_PREFIXED_INFOS
576 )c++";
577
578 // Emit X-macros for the atomic builtins to support various custome patterns
579 // used exclusively with those builtins.
580 //
581 // FIXME: We should eventually move this to a separate file so that users
582 // don't need to include the full set of builtins.
583 OS << R"c++(
584 #ifdef ATOMIC_BUILTIN
585 )c++";
586 for (const auto &Builtin : AtomicBuiltins) {
587 Builtin.EmitXMacro(OS);
588 }
589 OS << R"c++(
590 #endif // ATOMIC_BUILTIN
591 #undef ATOMIC_BUILTIN
592 )c++";
593 }
594