1 //===-- ClangBuiltinsEmitter.cpp - Generate Clang builtins tables ---------===//
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
7 //===----------------------------------------------------------------------===//
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"
22 enum class BuiltinType
{
30 class PrototypeParser
{
32 PrototypeParser(StringRef Substitution
, const Record
*Builtin
)
33 : Loc(Builtin
->getFieldLoc("Prototype")), Substitution(Substitution
) {
34 ParsePrototype(Builtin
->getValueAsString("Prototype"));
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(",")) {
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<...>
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
);
82 // Move the prototype beyond the comma.
88 // No more commas, parse final parameter.
94 void ParseType(StringRef T
) {
96 if (T
.consume_back("*")) {
99 } else if (T
.consume_back("const")) {
102 } else if (T
.consume_back("volatile")) {
105 } else if (T
.consume_back("restrict")) {
108 } else if (T
.consume_back("&")) {
111 } else if (T
.consume_front("long")) {
114 } else if (T
.consume_front("unsigned")) {
117 } else if (T
.consume_front("_Complex")) {
120 } else if (T
.consume_front("_Constant")) {
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(","))
143 "Expected ',' after number of lanes in '_ExtVector<'");
144 if (!T
.consume_back(">"))
146 Loc
, "Expected '>' after scalar type in '_ExtVector<N, type>'");
148 // ...all good, we can check if we have a valid `<scalar type>`.
151 auto ReturnTypeVal
= StringSwitch
<std::string
>(T
)
152 .Case("__builtin_va_list_ref", "A")
153 .Case("__builtin_va_list", "a")
154 .Case("__float128", "LLd")
156 .Case("__int128_t", "LLLi")
157 .Case("_Float16", "x")
160 .Case("constant_CFString", "F")
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")
173 .Case("ptrdiff_t", "Y")
176 .Case("sigjmp_buf", "SJ")
178 .Case("ucontext_t", "K")
179 .Case("uint32_t", "UZi")
180 .Case("uint64_t", "UWi")
182 .Case("wchar_t", "w")
185 if (ReturnTypeVal
== "error")
186 PrintFatalError(Loc
, "Unknown Type: " + T
);
187 Type
+= ReturnTypeVal
;
192 void Print(raw_ostream
&OS
) const { OS
<< ", \"" << Type
<< '\"'; }
196 StringRef Substitution
;
200 class HeaderNameParser
{
202 HeaderNameParser(const Record
*Builtin
) {
203 for (char c
: Builtin
->getValueAsString("Header")) {
205 HeaderName
+= static_cast<char>(std::toupper(c
));
206 else if (c
== '.' || c
== '_' || c
== '/' || c
== '-')
209 PrintFatalError(Builtin
->getLoc(), "Unexpected header name");
213 void Print(raw_ostream
&OS
) const { OS
<< HeaderName
; }
216 std::string HeaderName
;
219 void PrintAttributes(const Record
*Builtin
, BuiltinType BT
, raw_ostream
&OS
) {
221 if (Builtin
->isSubClassOf("LibBuiltin")) {
222 if (BT
== BuiltinType::LibBuiltin
) {
226 if (Builtin
->getValueAsBit("OnlyBuiltinPrefixedAliasIsConstexpr"))
231 if (auto NS
= Builtin
->getValueAsOptionalString("Namespace")) {
233 PrintFatalError(Builtin
->getFieldLoc("Namespace"), "Unknown namespace: ");
237 for (const auto *Attr
: Builtin
->getValueAsListOfDefs("Attributes")) {
238 OS
<< Attr
->getValueAsString("Mangling");
239 if (Attr
->isSubClassOf("IndexedAttribute"))
240 OS
<< ':' << Attr
->getValueAsInt("Index") << ':';
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';
250 case BuiltinType::LibBuiltin
:
253 case BuiltinType::LangBuiltin
:
256 case BuiltinType::Builtin
:
259 case BuiltinType::AtomicBuiltin
:
260 OS
<< "ATOMIC_BUILTIN";
262 case BuiltinType::TargetBuiltin
:
263 OS
<< "TARGET_BUILTIN";
267 OS
<< "(" << Spelling
;
268 PrototypeParser
{Substitution
, Builtin
}.Print(OS
);
270 PrintAttributes(Builtin
, BT
, OS
);
273 case BuiltinType::LibBuiltin
: {
275 HeaderNameParser
{Builtin
}.Print(OS
);
278 case BuiltinType::LangBuiltin
: {
279 OS
<< ", " << Builtin
->getValueAsString("Languages");
282 case BuiltinType::TargetBuiltin
:
283 OS
<< ", \"" << Builtin
->getValueAsString("Features") << "\"";
285 case BuiltinType::AtomicBuiltin
:
286 case BuiltinType::Builtin
:
292 struct TemplateInsts
{
293 std::vector
<std::string
> Substitution
;
294 std::vector
<std::string
> Affix
;
298 TemplateInsts
getTemplateInsts(const Record
*R
) {
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
);
315 void EmitBuiltin(raw_ostream
&OS
, const Record
*Builtin
) {
316 TemplateInsts Templates
= {};
317 if (Builtin
->isSubClassOf("Template")) {
318 Templates
= getTemplateInsts(Builtin
);
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")) {
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
);
349 void clang::EmitClangBuiltins(const RecordKeeper
&Records
, raw_ostream
&OS
) {
350 emitSourceFileHeader("List of builtins that Clang recognizes", OS
);
353 #if defined(BUILTIN) && !defined(LIBBUILTIN)
354 # define LIBBUILTIN(ID, TYPE, ATTRS, HEADER, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS)
357 #if defined(BUILTIN) && !defined(LANGBUILTIN)
358 # define LANGBUILTIN(ID, TYPE, ATTRS, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS)
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)
367 #if defined(BUILTIN) && !defined(TARGET_BUILTIN)
368 # define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS)
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"))
380 EmitBuiltin(OS
, Builtin
);
383 for (const auto *Entry
: Records
.getAllDerivedDefinitions("CustomEntry")) {
384 OS
<< Entry
->getValueAsString("Entry") << '\n';
388 #undef ATOMIC_BUILTIN
392 #undef TARGET_BUILTIN