xref: /llvm-project/clang/utils/TableGen/ClangBuiltinsEmitter.cpp (revision b968fd95026639a2a1d2057627b41622f3b5c97d)
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/TableGenBackend.h"
19 
20 using namespace llvm;
21 
22 namespace {
23 enum class BuiltinType {
24   Builtin,
25   AtomicBuiltin,
26   LibBuiltin,
27   LangBuiltin,
28   TargetBuiltin,
29   TargetLibBuiltin,
30 };
31 
32 class PrototypeParser {
33 public:
34   PrototypeParser(StringRef Substitution, const Record *Builtin)
35       : Loc(Builtin->getFieldLoc("Prototype")), Substitution(Substitution),
36         EnableOpenCLLong(Builtin->getValueAsBit("EnableOpenCLLong")) {
37     ParsePrototype(Builtin->getValueAsString("Prototype"));
38   }
39 
40 private:
41   void ParsePrototype(StringRef Prototype) {
42     Prototype = Prototype.trim();
43 
44     // Some builtins don't have an expressible prototype, simply emit an empty
45     // string for them.
46     if (Prototype.empty()) {
47       Type = "";
48       return;
49     }
50 
51     ParseTypes(Prototype);
52   }
53 
54   void ParseTypes(StringRef &Prototype) {
55     auto ReturnType = Prototype.take_until([](char c) { return c == '('; });
56     ParseType(ReturnType);
57     Prototype = Prototype.drop_front(ReturnType.size() + 1);
58     if (!Prototype.ends_with(")"))
59       PrintFatalError(Loc, "Expected closing brace at end of prototype");
60     Prototype = Prototype.drop_back();
61 
62     // Look through the input parameters.
63     const size_t end = Prototype.size();
64     for (size_t I = 0; I != end;) {
65       const StringRef Current = Prototype.substr(I, end);
66       // Skip any leading space or commas
67       if (Current.starts_with(" ") || Current.starts_with(",")) {
68         ++I;
69         continue;
70       }
71 
72       // Check if we are in _ExtVector. We do this first because
73       // extended vectors are written in template form with the syntax
74       // _ExtVector< ..., ...>, so we need to make sure we are not
75       // detecting the comma of the template class as a separator for
76       // the parameters of the prototype. Note: the assumption is that
77       // we cannot have nested _ExtVector.
78       if (Current.starts_with("_ExtVector<") ||
79           Current.starts_with("_Vector<")) {
80         const size_t EndTemplate = Current.find('>', 0);
81         ParseType(Current.substr(0, EndTemplate + 1));
82         // Move the prototype beyond _ExtVector<...>
83         I += EndTemplate + 1;
84         continue;
85       }
86 
87       // We know that we are past _ExtVector, therefore the first seen
88       // comma is the boundary of a parameter in the prototype.
89       if (size_t CommaPos = Current.find(',', 0)) {
90         if (CommaPos != StringRef::npos) {
91           StringRef T = Current.substr(0, CommaPos);
92           ParseType(T);
93           // Move the prototype beyond the comma.
94           I += CommaPos + 1;
95           continue;
96         }
97       }
98 
99       // No more commas, parse final parameter.
100       ParseType(Current);
101       I = end;
102     }
103   }
104 
105   void ParseType(StringRef T) {
106     T = T.trim();
107 
108     auto ConsumeAddrSpace = [&]() -> std::optional<unsigned> {
109       T = T.trim();
110       if (!T.consume_back(">"))
111         return std::nullopt;
112 
113       auto Open = T.find_last_of('<');
114       if (Open == StringRef::npos)
115         PrintFatalError(Loc, "Mismatched angle-brackets in type");
116 
117       StringRef ArgStr = T.substr(Open + 1);
118       T = T.slice(0, Open);
119       if (!T.consume_back("address_space"))
120         PrintFatalError(Loc,
121                         "Only `address_space<N>` supported as a parameterized "
122                         "pointer or reference type qualifier");
123 
124       unsigned Number = 0;
125       if (ArgStr.getAsInteger(10, Number))
126         PrintFatalError(
127             Loc, "Expected an integer argument to the address_space qualifier");
128       if (Number == 0)
129         PrintFatalError(Loc, "No need for a qualifier for address space `0`");
130       return Number;
131     };
132 
133     if (T.consume_back("*")) {
134       // Pointers may have an address space qualifier immediately before them.
135       std::optional<unsigned> AS = ConsumeAddrSpace();
136       ParseType(T);
137       Type += "*";
138       if (AS)
139         Type += std::to_string(*AS);
140     } else if (T.consume_back("const")) {
141       ParseType(T);
142       Type += "C";
143     } else if (T.consume_back("volatile")) {
144       ParseType(T);
145       Type += "D";
146     } else if (T.consume_back("restrict")) {
147       ParseType(T);
148       Type += "R";
149     } else if (T.consume_back("&")) {
150       // References may have an address space qualifier immediately before them.
151       std::optional<unsigned> AS = ConsumeAddrSpace();
152       ParseType(T);
153       Type += "&";
154       if (AS)
155         Type += std::to_string(*AS);
156     } else if (T.consume_back(")")) {
157       ParseType(T);
158       Type += "&";
159     } else if (EnableOpenCLLong && T.consume_front("long long")) {
160       Type += "O";
161       ParseType(T);
162     } else if (T.consume_front("long")) {
163       Type += "L";
164       ParseType(T);
165     } else if (T.consume_front("signed")) {
166       Type += "S";
167       ParseType(T);
168     } else if (T.consume_front("unsigned")) {
169       Type += "U";
170       ParseType(T);
171     } else if (T.consume_front("_Complex")) {
172       Type += "X";
173       ParseType(T);
174     } else if (T.consume_front("_Constant")) {
175       Type += "I";
176       ParseType(T);
177     } else if (T.consume_front("T")) {
178       if (Substitution.empty())
179         PrintFatalError(Loc, "Not a template");
180       ParseType(Substitution);
181     } else if (auto IsExt = T.consume_front("_ExtVector");
182                IsExt || T.consume_front("_Vector")) {
183       // Clang extended vector types are mangled as follows:
184       //
185       // '_ExtVector<' <lanes> ',' <scalar type> '>'
186 
187       // Before parsing T(=<scalar type>), make sure the syntax of
188       // `_ExtVector<N, T>` is correct...
189       if (!T.consume_front("<"))
190         PrintFatalError(Loc, "Expected '<' after '_ExtVector'");
191       unsigned long long Lanes;
192       if (consumeUnsignedInteger(T, 10, Lanes))
193         PrintFatalError(Loc, "Expected number of lanes after '_ExtVector<'");
194       Type += (IsExt ? "E" : "V") + std::to_string(Lanes);
195       if (!T.consume_front(","))
196         PrintFatalError(Loc,
197                         "Expected ',' after number of lanes in '_ExtVector<'");
198       if (!T.consume_back(">"))
199         PrintFatalError(
200             Loc, "Expected '>' after scalar type in '_ExtVector<N, type>'");
201 
202       // ...all good, we can check if we have a valid `<scalar type>`.
203       ParseType(T);
204     } else {
205       auto ReturnTypeVal = StringSwitch<std::string>(T)
206                                .Case("__builtin_va_list_ref", "A")
207                                .Case("__builtin_va_list", "a")
208                                .Case("__float128", "LLd")
209                                .Case("__fp16", "h")
210                                .Case("__int128_t", "LLLi")
211                                .Case("_Float16", "x")
212                                .Case("__bf16", "y")
213                                .Case("bool", "b")
214                                .Case("char", "c")
215                                .Case("constant_CFString", "F")
216                                .Case("double", "d")
217                                .Case("FILE", "P")
218                                .Case("float", "f")
219                                .Case("id", "G")
220                                .Case("int", "i")
221                                .Case("int32_t", "Zi")
222                                .Case("int64_t", "Wi")
223                                .Case("jmp_buf", "J")
224                                .Case("msint32_t", "Ni")
225                                .Case("msuint32_t", "UNi")
226                                .Case("objc_super", "M")
227                                .Case("pid_t", "p")
228                                .Case("ptrdiff_t", "Y")
229                                .Case("SEL", "H")
230                                .Case("short", "s")
231                                .Case("sigjmp_buf", "SJ")
232                                .Case("size_t", "z")
233                                .Case("ucontext_t", "K")
234                                .Case("uint32_t", "UZi")
235                                .Case("uint64_t", "UWi")
236                                .Case("void", "v")
237                                .Case("wchar_t", "w")
238                                .Case("...", ".")
239                                .Default("error");
240       if (ReturnTypeVal == "error")
241         PrintFatalError(Loc, "Unknown Type: " + T);
242       Type += ReturnTypeVal;
243     }
244   }
245 
246 public:
247   void Print(raw_ostream &OS) const { OS << ", \"" << Type << '\"'; }
248 
249 private:
250   SMLoc Loc;
251   StringRef Substitution;
252   bool EnableOpenCLLong;
253   std::string Type;
254 };
255 
256 class HeaderNameParser {
257 public:
258   HeaderNameParser(const Record *Builtin) {
259     for (char c : Builtin->getValueAsString("Header")) {
260       if (std::islower(c))
261         HeaderName += static_cast<char>(std::toupper(c));
262       else if (c == '.' || c == '_' || c == '/' || c == '-')
263         HeaderName += '_';
264       else
265         PrintFatalError(Builtin->getLoc(), "Unexpected header name");
266     }
267   }
268 
269   void Print(raw_ostream &OS) const { OS << HeaderName; }
270 
271 private:
272   std::string HeaderName;
273 };
274 
275 void PrintAttributes(const Record *Builtin, BuiltinType BT, raw_ostream &OS) {
276   OS << '\"';
277   if (Builtin->isSubClassOf("LibBuiltin")) {
278     if (BT == BuiltinType::LibBuiltin) {
279       OS << 'f';
280     } else {
281       OS << 'F';
282       if (Builtin->getValueAsBit("OnlyBuiltinPrefixedAliasIsConstexpr"))
283         OS << 'E';
284     }
285   }
286 
287   if (auto NS = Builtin->getValueAsOptionalString("Namespace")) {
288     if (NS != "std")
289       PrintFatalError(Builtin->getFieldLoc("Namespace"), "Unknown namespace: ");
290     OS << "z";
291   }
292 
293   for (const auto *Attr : Builtin->getValueAsListOfDefs("Attributes")) {
294     OS << Attr->getValueAsString("Mangling");
295     if (Attr->isSubClassOf("IndexedAttribute")) {
296       OS << ':' << Attr->getValueAsInt("Index") << ':';
297     } else if (Attr->isSubClassOf("MultiIndexAttribute")) {
298       OS << '<';
299       llvm::ListSeparator Sep(",");
300       for (int64_t Index : Attr->getValueAsListOfInts("Indices"))
301         OS << Sep << Index;
302       OS << '>';
303     }
304   }
305   OS << '\"';
306 }
307 
308 void EmitBuiltinDef(raw_ostream &OS, StringRef Substitution,
309                     const Record *Builtin, Twine Spelling, BuiltinType BT) {
310   if (Builtin->getValueAsBit("RequiresUndef"))
311     OS << "#undef " << Spelling << '\n';
312   switch (BT) {
313   case BuiltinType::LibBuiltin:
314     OS << "LIBBUILTIN";
315     break;
316   case BuiltinType::LangBuiltin:
317     OS << "LANGBUILTIN";
318     break;
319   case BuiltinType::Builtin:
320     OS << "BUILTIN";
321     break;
322   case BuiltinType::AtomicBuiltin:
323     OS << "ATOMIC_BUILTIN";
324     break;
325   case BuiltinType::TargetBuiltin:
326     OS << "TARGET_BUILTIN";
327     break;
328   case BuiltinType::TargetLibBuiltin:
329     OS << "TARGET_HEADER_BUILTIN";
330     break;
331   }
332 
333   OS << "(" << Spelling;
334   PrototypeParser{Substitution, Builtin}.Print(OS);
335   OS << ", ";
336   PrintAttributes(Builtin, BT, OS);
337 
338   switch (BT) {
339   case BuiltinType::LibBuiltin: {
340     OS << ", ";
341     HeaderNameParser{Builtin}.Print(OS);
342     [[fallthrough]];
343   }
344   case BuiltinType::LangBuiltin: {
345     OS << ", " << Builtin->getValueAsString("Languages");
346     break;
347   }
348   case BuiltinType::TargetLibBuiltin: {
349     OS << ", ";
350     HeaderNameParser{Builtin}.Print(OS);
351     OS << ", " << Builtin->getValueAsString("Languages");
352     [[fallthrough]];
353   }
354   case BuiltinType::TargetBuiltin:
355     OS << ", \"" << Builtin->getValueAsString("Features") << "\"";
356     break;
357   case BuiltinType::AtomicBuiltin:
358   case BuiltinType::Builtin:
359     break;
360   }
361   OS << ")\n";
362 }
363 
364 struct TemplateInsts {
365   std::vector<std::string> Substitution;
366   std::vector<std::string> Affix;
367   bool IsPrefix;
368 };
369 
370 TemplateInsts getTemplateInsts(const Record *R) {
371   TemplateInsts temp;
372   auto Substitutions = R->getValueAsListOfStrings("Substitutions");
373   auto Affixes = R->getValueAsListOfStrings("Affixes");
374   temp.IsPrefix = R->getValueAsBit("AsPrefix");
375 
376   if (Substitutions.size() != Affixes.size())
377     PrintFatalError(R->getLoc(), "Substitutions and affixes "
378                                  "don't have the same lengths");
379 
380   for (auto [Affix, Substitution] : zip(Affixes, Substitutions)) {
381     temp.Substitution.emplace_back(Substitution);
382     temp.Affix.emplace_back(Affix);
383   }
384   return temp;
385 }
386 
387 void EmitBuiltin(raw_ostream &OS, const Record *Builtin) {
388   TemplateInsts Templates = {};
389   if (Builtin->isSubClassOf("Template")) {
390     Templates = getTemplateInsts(Builtin);
391   } else {
392     Templates.Affix.emplace_back();
393     Templates.Substitution.emplace_back();
394   }
395 
396   for (auto [Substitution, Affix] :
397        zip(Templates.Substitution, Templates.Affix)) {
398     for (StringRef Spelling : Builtin->getValueAsListOfStrings("Spellings")) {
399       auto FullSpelling =
400           (Templates.IsPrefix ? Affix + Spelling : Spelling + Affix).str();
401       BuiltinType BT = BuiltinType::Builtin;
402       if (Builtin->isSubClassOf("AtomicBuiltin")) {
403         BT = BuiltinType::AtomicBuiltin;
404       } else if (Builtin->isSubClassOf("LangBuiltin")) {
405         BT = BuiltinType::LangBuiltin;
406       } else if (Builtin->isSubClassOf("TargetLibBuiltin")) {
407         BT = BuiltinType::TargetLibBuiltin;
408       } else if (Builtin->isSubClassOf("TargetBuiltin")) {
409         BT = BuiltinType::TargetBuiltin;
410       } else if (Builtin->isSubClassOf("LibBuiltin")) {
411         BT = BuiltinType::LibBuiltin;
412         if (Builtin->getValueAsBit("AddBuiltinPrefixedAlias"))
413           EmitBuiltinDef(OS, Substitution, Builtin,
414                          std::string("__builtin_") + FullSpelling,
415                          BuiltinType::Builtin);
416       }
417       EmitBuiltinDef(OS, Substitution, Builtin, FullSpelling, BT);
418     }
419   }
420 }
421 } // namespace
422 
423 void clang::EmitClangBuiltins(const RecordKeeper &Records, raw_ostream &OS) {
424   emitSourceFileHeader("List of builtins that Clang recognizes", OS);
425 
426   OS << R"c++(
427 #if defined(BUILTIN) && !defined(LIBBUILTIN)
428 #  define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS)
429 #endif
430 
431 #if defined(BUILTIN) && !defined(LANGBUILTIN)
432 #  define LANGBUILTIN(ID, TYPE, ATTRS, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS)
433 #endif
434 
435 // Some of our atomics builtins are handled by AtomicExpr rather than
436 // as normal builtin CallExprs. This macro is used for such builtins.
437 #ifndef ATOMIC_BUILTIN
438 #  define ATOMIC_BUILTIN(ID, TYPE, ATTRS) BUILTIN(ID, TYPE, ATTRS)
439 #endif
440 
441 #if defined(BUILTIN) && !defined(TARGET_BUILTIN)
442 #  define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS)
443 #endif
444 
445 #if defined(BUILTIN) && !defined(TARGET_HEADER_BUILTIN)
446 #  define TARGET_HEADER_BUILTIN(ID, TYPE, ATTRS, HEADER, LANG, FEATURE) BUILTIN(ID, TYPE, ATTRS)
447 #endif
448 )c++";
449 
450   // AtomicBuiltins are order dependent
451   // emit them first to make manual checking easier
452   for (const auto *Builtin : Records.getAllDerivedDefinitions("AtomicBuiltin"))
453     EmitBuiltin(OS, Builtin);
454 
455   for (const auto *Builtin : Records.getAllDerivedDefinitions("Builtin")) {
456     if (Builtin->isSubClassOf("AtomicBuiltin"))
457       continue;
458     EmitBuiltin(OS, Builtin);
459   }
460 
461   OS << R"c++(
462 #undef ATOMIC_BUILTIN
463 #undef BUILTIN
464 #undef LIBBUILTIN
465 #undef LANGBUILTIN
466 #undef TARGET_BUILTIN
467 #undef TARGET_HEADER_BUILTIN
468 )c++";
469 }
470