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