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