xref: /freebsd/contrib/llvm-project/clang/utils/TableGen/ClangBuiltinsEmitter.cpp (revision 9c77fb6aaa366cbabc80ee1b834bcfe4df135491)
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:
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 
47   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 
61   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 
71   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 
99   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:
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 
161   std::string takeTypeString() && { return std::move(Type); }
162 
163 private:
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 
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 
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 
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 
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 
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 
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 
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