Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/utils/TableGen/ClangOpcodesEmitter.cpp
35230 views
1
//=== ClangOpcodesEmitter.cpp - constexpr interpreter opcodes ---*- 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
// These tablegen backends emit Clang AST node tables
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "TableGenBackends.h"
14
#include "llvm/TableGen/Error.h"
15
#include "llvm/TableGen/Record.h"
16
#include "llvm/TableGen/StringMatcher.h"
17
#include "llvm/TableGen/TableGenBackend.h"
18
19
using namespace llvm;
20
21
namespace {
22
class ClangOpcodesEmitter {
23
RecordKeeper &Records;
24
unsigned NumTypes;
25
26
public:
27
ClangOpcodesEmitter(RecordKeeper &R)
28
: Records(R), NumTypes(Records.getAllDerivedDefinitions("Type").size()) {}
29
30
void run(raw_ostream &OS);
31
32
private:
33
/// Emits the opcode name for the opcode enum.
34
/// The name is obtained by concatenating the name with the list of types.
35
void EmitEnum(raw_ostream &OS, StringRef N, const Record *R);
36
37
/// Emits the switch case and the invocation in the interpreter.
38
void EmitInterp(raw_ostream &OS, StringRef N, const Record *R);
39
40
/// Emits the disassembler.
41
void EmitDisasm(raw_ostream &OS, StringRef N, const Record *R);
42
43
/// Emits the byte code emitter method.
44
void EmitEmitter(raw_ostream &OS, StringRef N, const Record *R);
45
46
/// Emits the prototype.
47
void EmitProto(raw_ostream &OS, StringRef N, const Record *R);
48
49
/// Emits the prototype to dispatch from a type.
50
void EmitGroup(raw_ostream &OS, StringRef N, const Record *R);
51
52
/// Emits the evaluator method.
53
void EmitEval(raw_ostream &OS, StringRef N, const Record *R);
54
55
void PrintTypes(raw_ostream &OS, ArrayRef<const Record *> Types);
56
};
57
58
void Enumerate(const Record *R, StringRef N,
59
std::function<void(ArrayRef<const Record *>, Twine)> &&F) {
60
llvm::SmallVector<const Record *, 2> TypePath;
61
const auto *Types = R->getValueAsListInit("Types");
62
63
std::function<void(size_t, const Twine &)> Rec;
64
Rec = [&TypePath, Types, &Rec, &F](size_t I, const Twine &ID) {
65
if (I >= Types->size()) {
66
F(TypePath, ID);
67
return;
68
}
69
70
if (const auto *TypeClass = dyn_cast<DefInit>(Types->getElement(I))) {
71
for (const auto *Type :
72
TypeClass->getDef()->getValueAsListOfDefs("Types")) {
73
TypePath.push_back(Type);
74
Rec(I + 1, ID + Type->getName());
75
TypePath.pop_back();
76
}
77
} else {
78
PrintFatalError("Expected a type class");
79
}
80
};
81
Rec(0, N);
82
}
83
84
} // namespace
85
86
void ClangOpcodesEmitter::run(raw_ostream &OS) {
87
for (const auto *Opcode : Records.getAllDerivedDefinitions("Opcode")) {
88
// The name is the record name, unless overriden.
89
StringRef N = Opcode->getValueAsString("Name");
90
if (N.empty())
91
N = Opcode->getName();
92
93
EmitEnum(OS, N, Opcode);
94
EmitInterp(OS, N, Opcode);
95
EmitDisasm(OS, N, Opcode);
96
EmitProto(OS, N, Opcode);
97
EmitGroup(OS, N, Opcode);
98
EmitEmitter(OS, N, Opcode);
99
EmitEval(OS, N, Opcode);
100
}
101
}
102
103
void ClangOpcodesEmitter::EmitEnum(raw_ostream &OS, StringRef N,
104
const Record *R) {
105
OS << "#ifdef GET_OPCODE_NAMES\n";
106
Enumerate(R, N, [&OS](ArrayRef<const Record *>, const Twine &ID) {
107
OS << "OP_" << ID << ",\n";
108
});
109
OS << "#endif\n";
110
}
111
112
void ClangOpcodesEmitter::EmitInterp(raw_ostream &OS, StringRef N,
113
const Record *R) {
114
OS << "#ifdef GET_INTERP\n";
115
116
Enumerate(R, N,
117
[this, R, &OS, &N](ArrayRef<const Record *> TS, const Twine &ID) {
118
bool CanReturn = R->getValueAsBit("CanReturn");
119
bool ChangesPC = R->getValueAsBit("ChangesPC");
120
const auto &Args = R->getValueAsListOfDefs("Args");
121
122
OS << "case OP_" << ID << ": {\n";
123
124
if (CanReturn)
125
OS << " bool DoReturn = (S.Current == StartFrame);\n";
126
127
// Emit calls to read arguments.
128
for (size_t I = 0, N = Args.size(); I < N; ++I) {
129
const auto *Arg = Args[I];
130
bool AsRef = Arg->getValueAsBit("AsRef");
131
132
if (AsRef)
133
OS << " const auto &V" << I;
134
else
135
OS << " const auto V" << I;
136
OS << " = ";
137
OS << "ReadArg<" << Arg->getValueAsString("Name")
138
<< ">(S, PC);\n";
139
}
140
141
// Emit a call to the template method and pass arguments.
142
OS << " if (!" << N;
143
PrintTypes(OS, TS);
144
OS << "(S";
145
if (ChangesPC)
146
OS << ", PC";
147
else
148
OS << ", OpPC";
149
if (CanReturn)
150
OS << ", Result";
151
for (size_t I = 0, N = Args.size(); I < N; ++I)
152
OS << ", V" << I;
153
OS << "))\n";
154
OS << " return false;\n";
155
156
// Bail out if interpreter returned.
157
if (CanReturn) {
158
OS << " if (!S.Current || S.Current->isRoot())\n";
159
OS << " return true;\n";
160
161
OS << " if (DoReturn)\n";
162
OS << " return true;\n";
163
}
164
165
OS << " continue;\n";
166
OS << "}\n";
167
});
168
OS << "#endif\n";
169
}
170
171
void ClangOpcodesEmitter::EmitDisasm(raw_ostream &OS, StringRef N,
172
const Record *R) {
173
OS << "#ifdef GET_DISASM\n";
174
Enumerate(R, N, [R, &OS](ArrayRef<const Record *>, const Twine &ID) {
175
OS << "case OP_" << ID << ":\n";
176
OS << " PrintName(\"" << ID << "\");\n";
177
OS << " OS << \"\\t\"";
178
179
for (const auto *Arg : R->getValueAsListOfDefs("Args")) {
180
OS << " << ReadArg<" << Arg->getValueAsString("Name") << ">(P, PC)";
181
OS << " << \" \"";
182
}
183
184
OS << " << \"\\n\";\n";
185
OS << " continue;\n";
186
});
187
OS << "#endif\n";
188
}
189
190
void ClangOpcodesEmitter::EmitEmitter(raw_ostream &OS, StringRef N,
191
const Record *R) {
192
if (R->getValueAsBit("HasCustomLink"))
193
return;
194
195
OS << "#ifdef GET_LINK_IMPL\n";
196
Enumerate(R, N, [R, &OS](ArrayRef<const Record *>, const Twine &ID) {
197
const auto &Args = R->getValueAsListOfDefs("Args");
198
199
// Emit the list of arguments.
200
OS << "bool ByteCodeEmitter::emit" << ID << "(";
201
for (size_t I = 0, N = Args.size(); I < N; ++I) {
202
const auto *Arg = Args[I];
203
bool AsRef = Arg->getValueAsBit("AsRef");
204
auto Name = Arg->getValueAsString("Name");
205
206
OS << (AsRef ? "const " : " ") << Name << " " << (AsRef ? "&" : "") << "A"
207
<< I << ", ";
208
}
209
OS << "const SourceInfo &L) {\n";
210
211
// Emit a call to write the opcodes.
212
OS << " return emitOp<";
213
for (size_t I = 0, N = Args.size(); I < N; ++I) {
214
if (I != 0)
215
OS << ", ";
216
OS << Args[I]->getValueAsString("Name");
217
}
218
OS << ">(OP_" << ID;
219
for (size_t I = 0, N = Args.size(); I < N; ++I)
220
OS << ", A" << I;
221
OS << ", L);\n";
222
OS << "}\n";
223
});
224
OS << "#endif\n";
225
}
226
227
void ClangOpcodesEmitter::EmitProto(raw_ostream &OS, StringRef N,
228
const Record *R) {
229
OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n";
230
auto Args = R->getValueAsListOfDefs("Args");
231
Enumerate(R, N, [&OS, &Args](ArrayRef<const Record *> TS, const Twine &ID) {
232
OS << "bool emit" << ID << "(";
233
for (size_t I = 0, N = Args.size(); I < N; ++I) {
234
const auto *Arg = Args[I];
235
bool AsRef = Arg->getValueAsBit("AsRef");
236
auto Name = Arg->getValueAsString("Name");
237
238
OS << (AsRef ? "const " : " ") << Name << " " << (AsRef ? "&" : "")
239
<< ", ";
240
}
241
OS << "const SourceInfo &);\n";
242
});
243
244
// Emit a template method for custom emitters to have less to implement.
245
auto TypeCount = R->getValueAsListInit("Types")->size();
246
if (R->getValueAsBit("HasCustomEval") && TypeCount) {
247
OS << "#if defined(GET_EVAL_PROTO)\n";
248
OS << "template<";
249
for (size_t I = 0; I < TypeCount; ++I) {
250
if (I != 0)
251
OS << ", ";
252
OS << "PrimType";
253
}
254
OS << ">\n";
255
OS << "bool emit" << N << "(";
256
for (const auto *Arg : Args)
257
OS << Arg->getValueAsString("Name") << ", ";
258
OS << "const SourceInfo &);\n";
259
OS << "#endif\n";
260
}
261
262
OS << "#endif\n";
263
}
264
265
void ClangOpcodesEmitter::EmitGroup(raw_ostream &OS, StringRef N,
266
const Record *R) {
267
if (!R->getValueAsBit("HasGroup"))
268
return;
269
270
const auto *Types = R->getValueAsListInit("Types");
271
const auto &Args = R->getValueAsListOfDefs("Args");
272
273
Twine EmitFuncName = "emit" + N;
274
275
// Emit the prototype of the group emitter in the header.
276
OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n";
277
OS << "[[nodiscard]] bool " << EmitFuncName << "(";
278
for (size_t I = 0, N = Types->size(); I < N; ++I)
279
OS << "PrimType, ";
280
for (auto *Arg : Args)
281
OS << Arg->getValueAsString("Name") << ", ";
282
OS << "const SourceInfo &I);\n";
283
OS << "#endif\n";
284
285
// Emit the dispatch implementation in the source.
286
OS << "#if defined(GET_EVAL_IMPL) || defined(GET_LINK_IMPL)\n";
287
OS << "bool\n";
288
OS << "#if defined(GET_EVAL_IMPL)\n";
289
OS << "EvalEmitter\n";
290
OS << "#else\n";
291
OS << "ByteCodeEmitter\n";
292
OS << "#endif\n";
293
OS << "::" << EmitFuncName << "(";
294
for (size_t I = 0, N = Types->size(); I < N; ++I)
295
OS << "PrimType T" << I << ", ";
296
for (size_t I = 0, N = Args.size(); I < N; ++I) {
297
const auto *Arg = Args[I];
298
bool AsRef = Arg->getValueAsBit("AsRef");
299
auto Name = Arg->getValueAsString("Name");
300
301
OS << (AsRef ? "const " : " ") << Name << " " << (AsRef ? "&" : "") << "A"
302
<< I << ", ";
303
}
304
OS << "const SourceInfo &I) {\n";
305
306
std::function<void(size_t, const Twine &)> Rec;
307
llvm::SmallVector<const Record *, 2> TS;
308
Rec = [this, &Rec, &OS, Types, &Args, R, &TS, N,
309
EmitFuncName](size_t I, const Twine &ID) {
310
if (I >= Types->size()) {
311
// Print a call to the emitter method.
312
// Custom evaluator methods dispatch to template methods.
313
if (R->getValueAsBit("HasCustomEval")) {
314
OS << "#ifdef GET_LINK_IMPL\n";
315
OS << " return emit" << ID << "\n";
316
OS << "#else\n";
317
OS << " return emit" << N;
318
PrintTypes(OS, TS);
319
OS << "\n#endif\n";
320
OS << " ";
321
} else {
322
OS << " return emit" << ID;
323
}
324
325
OS << "(";
326
for (size_t I = 0; I < Args.size(); ++I) {
327
OS << "A" << I << ", ";
328
}
329
OS << "I);\n";
330
return;
331
}
332
333
// Print a switch statement selecting T.
334
if (auto *TypeClass = dyn_cast<DefInit>(Types->getElement(I))) {
335
OS << " switch (T" << I << ") {\n";
336
auto Cases = TypeClass->getDef()->getValueAsListOfDefs("Types");
337
for (auto *Case : Cases) {
338
OS << " case PT_" << Case->getName() << ":\n";
339
TS.push_back(Case);
340
Rec(I + 1, ID + Case->getName());
341
TS.pop_back();
342
}
343
// Emit a default case if not all types are present.
344
if (Cases.size() < NumTypes)
345
OS << " default: llvm_unreachable(\"invalid type: " << EmitFuncName
346
<< "\");\n";
347
OS << " }\n";
348
OS << " llvm_unreachable(\"invalid enum value\");\n";
349
} else {
350
PrintFatalError("Expected a type class");
351
}
352
};
353
Rec(0, N);
354
355
OS << "}\n";
356
OS << "#endif\n";
357
}
358
359
void ClangOpcodesEmitter::EmitEval(raw_ostream &OS, StringRef N,
360
const Record *R) {
361
if (R->getValueAsBit("HasCustomEval"))
362
return;
363
364
OS << "#ifdef GET_EVAL_IMPL\n";
365
Enumerate(R, N,
366
[this, R, &N, &OS](ArrayRef<const Record *> TS, const Twine &ID) {
367
auto Args = R->getValueAsListOfDefs("Args");
368
369
OS << "bool EvalEmitter::emit" << ID << "(";
370
for (size_t I = 0, N = Args.size(); I < N; ++I) {
371
const auto *Arg = Args[I];
372
bool AsRef = Arg->getValueAsBit("AsRef");
373
auto Name = Arg->getValueAsString("Name");
374
375
OS << (AsRef ? "const " : " ") << Name << " "
376
<< (AsRef ? "&" : "") << "A" << I << ", ";
377
}
378
OS << "const SourceInfo &L) {\n";
379
OS << " if (!isActive()) return true;\n";
380
OS << " CurrentSource = L;\n";
381
382
OS << " return " << N;
383
PrintTypes(OS, TS);
384
OS << "(S, OpPC";
385
for (size_t I = 0, N = Args.size(); I < N; ++I)
386
OS << ", A" << I;
387
OS << ");\n";
388
OS << "}\n";
389
});
390
391
OS << "#endif\n";
392
}
393
394
void ClangOpcodesEmitter::PrintTypes(raw_ostream &OS,
395
ArrayRef<const Record *> Types) {
396
if (Types.empty())
397
return;
398
OS << "<";
399
for (size_t I = 0, N = Types.size(); I < N; ++I) {
400
if (I != 0)
401
OS << ", ";
402
OS << "PT_" << Types[I]->getName();
403
}
404
OS << ">";
405
}
406
407
void clang::EmitClangOpcodes(RecordKeeper &Records, raw_ostream &OS) {
408
ClangOpcodesEmitter(Records).run(OS);
409
}
410
411