1//===-- ClangOpcodesEmitter.cpp - constexpr interpreter opcodes -----------===//
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
19using namespace llvm;
20
21namespace {
22class ClangOpcodesEmitter {
23 const RecordKeeper &Records;
24 unsigned NumTypes;
25
26public:
27 ClangOpcodesEmitter(const RecordKeeper &R)
28 : Records(R), NumTypes(Records.getAllDerivedDefinitions(ClassName: "Type").size()) {}
29
30 void run(raw_ostream &OS);
31
32private:
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 void EmitInterpFnList(raw_ostream &OS, StringRef N, const Record *R);
38 void EmitInterpFnDispatchers(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
58void Enumerate(const Record *R, StringRef N,
59 std::function<void(ArrayRef<const Record *>, Twine)> &&F) {
60 SmallVector<const Record *, 2> TypePath;
61 const auto *Types = R->getValueAsListInit(FieldName: "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>(Val: Types->getElement(Idx: I))) {
71 for (const auto *Type :
72 TypeClass->getDef()->getValueAsListOfDefs(FieldName: "Types")) {
73 TypePath.push_back(Elt: Type);
74 Rec(I + 1, ID + Type->getName());
75 TypePath.pop_back();
76 }
77 } else {
78 PrintFatalError(Msg: "Expected a type class");
79 }
80 };
81 Rec(0, N);
82}
83
84} // namespace
85
86void ClangOpcodesEmitter::run(raw_ostream &OS) {
87 for (const auto *Opcode : Records.getAllDerivedDefinitions(ClassName: "Opcode")) {
88 // The name is the record name, unless overriden.
89 StringRef N = Opcode->getValueAsString(FieldName: "Name");
90 if (N.empty())
91 N = Opcode->getName();
92
93 EmitEnum(OS, N, R: Opcode);
94 EmitInterpFnList(OS, N, R: Opcode);
95 EmitInterpFnDispatchers(OS, N, R: Opcode);
96 EmitDisasm(OS, N, R: Opcode);
97 EmitProto(OS, N, R: Opcode);
98 EmitGroup(OS, N, R: Opcode);
99 EmitEmitter(OS, N, R: Opcode);
100 EmitEval(OS, N, R: Opcode);
101 }
102}
103
104void ClangOpcodesEmitter::EmitEnum(raw_ostream &OS, StringRef N,
105 const Record *R) {
106 OS << "#ifdef GET_OPCODE_NAMES\n";
107 Enumerate(R, N, F: [&OS](ArrayRef<const Record *>, const Twine &ID) {
108 OS << "OP_" << ID << ",\n";
109 });
110 OS << "#endif\n";
111}
112
113void ClangOpcodesEmitter::EmitInterpFnDispatchers(raw_ostream &OS, StringRef N,
114 const Record *R) {
115 OS << "#ifdef GET_INTERPFN_DISPATCHERS\n";
116 // PRESERVE NONE static bool Interp_* (InterpState &S, CodePtr &PC) {
117 Enumerate(R, N, F: [&](ArrayRef<const Record *> TS, const Twine &ID) {
118 OS << "PRESERVE_NONE\nstatic bool Interp_" << ID << "(InterpState &S) {\n";
119
120 if (ID.str() == "EndSpeculation") {
121 OS << " MUSTTAIL return EndSpeculation(S);\n";
122 OS << "}\n";
123 return;
124 }
125
126 bool CanReturn = R->getValueAsBit(FieldName: "CanReturn");
127 const auto &Args = R->getValueAsListOfDefs(FieldName: "Args");
128 bool CanFail = R->getValueAsBit(FieldName: "CanFail");
129 bool PassOpPC = R->getValueAsBit(FieldName: "NeedsOpPC");
130
131 if (Args.empty()) {
132 if (CanReturn) {
133 OS << " MUSTTAIL return " << N;
134 PrintTypes(OS, Types: TS);
135 OS << "(S);\n";
136 OS << "}\n";
137 return;
138 }
139
140 OS << " ";
141 if (CanFail)
142 OS << "if (!";
143
144 OS << N;
145 PrintTypes(OS, Types: TS);
146 OS << "(S";
147 if (PassOpPC)
148 OS << ", S.PC)";
149 else
150 OS << ")";
151
152 if (CanFail)
153 OS << ") return false";
154
155 OS << ";\n";
156
157 OS << "#if USE_TAILCALLS\n";
158 OS << " MUSTTAIL return InterpNext(S);\n";
159 OS << "#else\n";
160 OS << " return true;\n";
161 OS << "#endif\n";
162 OS << "}\n";
163 return;
164 }
165
166 OS << " {\n";
167
168 if (PassOpPC)
169 OS << " CodePtr OpPC = S.PC;\n";
170
171 // Emit calls to read arguments.
172 for (size_t I = 0, N = Args.size(); I < N; ++I) {
173 const auto *Arg = Args[I];
174 bool AsRef = Arg->getValueAsBit(FieldName: "AsRef");
175
176 if (AsRef)
177 OS << " const auto &V" << I;
178 else
179 OS << " const auto V" << I;
180 OS << " = ";
181 OS << "ReadArg<" << Arg->getValueAsString(FieldName: "Name") << ">(S, S.PC);\n";
182 }
183
184 OS << " ";
185 if (CanFail)
186 OS << "if (!";
187
188 OS << N;
189 PrintTypes(OS, Types: TS);
190 OS << "(S";
191 if (PassOpPC)
192 OS << ", OpPC";
193 for (size_t I = 0, N = Args.size(); I < N; ++I)
194 OS << ", V" << I;
195
196 OS << ")";
197
198 if (CanFail)
199 OS << ") return false";
200
201 OS << ";\n";
202 OS << " }\n";
203
204 if (!CanReturn) {
205 OS << "#if USE_TAILCALLS\n";
206 OS << " MUSTTAIL return InterpNext(S);\n";
207 OS << "#else\n";
208 OS << " return true;\n";
209 OS << "#endif\n";
210 } else
211 OS << " return true;\n";
212
213 OS << "}\n";
214 });
215 OS << "#endif\n";
216}
217
218void ClangOpcodesEmitter::EmitInterpFnList(raw_ostream &OS, StringRef N,
219 const Record *R) {
220 OS << "#ifdef GET_INTERPFN_LIST\n";
221 Enumerate(R, N, F: [&OS](ArrayRef<const Record *>, const Twine &ID) {
222 OS << "&Interp_" << ID << ",\n";
223 });
224 OS << "#endif\n";
225}
226
227void ClangOpcodesEmitter::EmitDisasm(raw_ostream &OS, StringRef N,
228 const Record *R) {
229 OS << "#ifdef GET_DISASM\n";
230 Enumerate(R, N, F: [R, &OS](ArrayRef<const Record *>, const Twine &ID) {
231 OS << "case OP_" << ID << ":\n";
232 OS << " Text.Op = PrintName(\"" << ID << "\");\n";
233 for (const auto *Arg : R->getValueAsListOfDefs(FieldName: "Args"))
234 OS << " Text.Args.push_back(printArg<" << Arg->getValueAsString(FieldName: "Name")
235 << ">(P, PC));\n";
236
237 OS << " break;\n";
238 });
239 OS << "#endif\n";
240}
241
242void ClangOpcodesEmitter::EmitEmitter(raw_ostream &OS, StringRef N,
243 const Record *R) {
244 if (R->getValueAsBit(FieldName: "HasCustomLink"))
245 return;
246
247 OS << "#ifdef GET_LINK_IMPL\n";
248 Enumerate(R, N, F: [R, &OS](ArrayRef<const Record *>, const Twine &ID) {
249 const auto &Args = R->getValueAsListOfDefs(FieldName: "Args");
250
251 // Emit the list of arguments.
252 OS << "bool ByteCodeEmitter::emit" << ID << "(";
253 for (size_t I = 0, N = Args.size(); I < N; ++I) {
254 const auto *Arg = Args[I];
255 bool AsRef = Arg->getValueAsBit(FieldName: "AsRef");
256 auto Name = Arg->getValueAsString(FieldName: "Name");
257
258 OS << (AsRef ? "const " : " ") << Name << " " << (AsRef ? "&" : "") << "A"
259 << I << ", ";
260 }
261 OS << "SourceInfo L) {\n";
262
263 // Emit a call to write the opcodes.
264 OS << " return emitOp<";
265 for (size_t I = 0, N = Args.size(); I < N; ++I) {
266 if (I != 0)
267 OS << ", ";
268 OS << Args[I]->getValueAsString(FieldName: "Name");
269 }
270 OS << ">(OP_" << ID;
271 for (size_t I = 0, N = Args.size(); I < N; ++I)
272 OS << ", A" << I;
273 OS << ", L);\n";
274 OS << "}\n";
275 });
276 OS << "#endif\n";
277}
278
279void ClangOpcodesEmitter::EmitProto(raw_ostream &OS, StringRef N,
280 const Record *R) {
281 OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n";
282 auto Args = R->getValueAsListOfDefs(FieldName: "Args");
283 Enumerate(R, N, F: [&OS, &Args](ArrayRef<const Record *> TS, const Twine &ID) {
284 OS << "bool emit" << ID << "(";
285 for (const Record *Arg : Args) {
286 bool AsRef = Arg->getValueAsBit(FieldName: "AsRef");
287 auto Name = Arg->getValueAsString(FieldName: "Name");
288
289 OS << (AsRef ? "const " : " ") << Name << " " << (AsRef ? "&" : "")
290 << ", ";
291 }
292 OS << "SourceInfo);\n";
293 });
294
295 // Emit a template method for custom emitters to have less to implement.
296 auto TypeCount = R->getValueAsListInit(FieldName: "Types")->size();
297 if (R->getValueAsBit(FieldName: "HasCustomEval") && TypeCount) {
298 OS << "#if defined(GET_EVAL_PROTO)\n";
299 OS << "template<";
300 for (size_t I = 0; I < TypeCount; ++I) {
301 if (I != 0)
302 OS << ", ";
303 OS << "PrimType";
304 }
305 OS << ">\n";
306 OS << "bool emit" << N << "(";
307 for (const auto *Arg : Args)
308 OS << Arg->getValueAsString(FieldName: "Name") << ", ";
309 OS << "SourceInfo);\n";
310 OS << "#endif\n";
311 }
312
313 OS << "#endif\n";
314}
315
316void ClangOpcodesEmitter::EmitGroup(raw_ostream &OS, StringRef N,
317 const Record *R) {
318 if (!R->getValueAsBit(FieldName: "HasGroup"))
319 return;
320
321 const auto *Types = R->getValueAsListInit(FieldName: "Types");
322 const auto &Args = R->getValueAsListOfDefs(FieldName: "Args");
323
324 if (Types->empty()) {
325 PrintFatalError(Msg: "HasGroup only makes sense for opcodes with types");
326 return;
327 }
328
329 Twine EmitFuncName = "emit" + N;
330
331 // Emit the prototype of the group emitter in the header.
332 OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n";
333 OS << "[[nodiscard]] bool " << EmitFuncName << "(";
334 for (size_t I = 0, N = Types->size(); I < N; ++I)
335 OS << "PrimType, ";
336 for (auto *Arg : Args)
337 OS << Arg->getValueAsString(FieldName: "Name") << ", ";
338 OS << "SourceInfo I);\n";
339 OS << "#endif\n";
340
341 // Emit the dispatch implementation in the source.
342 OS << "#if defined(GET_EVAL_IMPL) || defined(GET_LINK_IMPL)\n";
343 OS << "bool\n";
344 OS << "#if defined(GET_EVAL_IMPL)\n";
345 OS << "EvalEmitter\n";
346 OS << "#else\n";
347 OS << "ByteCodeEmitter\n";
348 OS << "#endif\n";
349 OS << "::" << EmitFuncName << "(";
350 for (size_t I = 0, N = Types->size(); I < N; ++I)
351 OS << "PrimType T" << I << ", ";
352 for (size_t I = 0, N = Args.size(); I < N; ++I) {
353 const auto *Arg = Args[I];
354 bool AsRef = Arg->getValueAsBit(FieldName: "AsRef");
355 auto Name = Arg->getValueAsString(FieldName: "Name");
356
357 OS << (AsRef ? "const " : " ") << Name << " " << (AsRef ? "&" : "") << "A"
358 << I << ", ";
359 }
360 OS << "SourceInfo I) {\n";
361
362 std::function<void(size_t, const Twine &)> Rec;
363 SmallVector<const Record *, 2> TS;
364 Rec = [this, &Rec, &OS, Types, &Args, R, &TS, N,
365 EmitFuncName](size_t I, const Twine &ID) {
366 if (I >= Types->size()) {
367 // Print a call to the emitter method.
368 // Custom evaluator methods dispatch to template methods.
369 if (R->getValueAsBit(FieldName: "HasCustomEval")) {
370 OS << "#ifdef GET_LINK_IMPL\n";
371 OS << " return emit" << ID << "\n";
372 OS << "#else\n";
373 OS << " return emit" << N;
374 PrintTypes(OS, Types: TS);
375 OS << "\n#endif\n";
376 OS << " ";
377 } else {
378 OS << " return emit" << ID;
379 }
380
381 OS << "(";
382 for (size_t I = 0; I < Args.size(); ++I) {
383 OS << "A" << I << ", ";
384 }
385 OS << "I);\n";
386 return;
387 }
388
389 // Print a switch statement selecting T.
390 if (auto *TypeClass = dyn_cast<DefInit>(Val: Types->getElement(Idx: I))) {
391 OS << " switch (T" << I << ") {\n";
392 auto Cases = TypeClass->getDef()->getValueAsListOfDefs(FieldName: "Types");
393 for (auto *Case : Cases) {
394 OS << " case PT_" << Case->getName() << ":\n";
395 TS.push_back(Elt: Case);
396 Rec(I + 1, ID + Case->getName());
397 TS.pop_back();
398 }
399 // Emit a default case if not all types are present.
400 if (Cases.size() < NumTypes)
401 OS << " default: llvm_unreachable(\"invalid type: " << EmitFuncName
402 << "\");\n";
403 OS << " }\n";
404 OS << " llvm_unreachable(\"invalid enum value\");\n";
405 } else {
406 PrintFatalError(Msg: "Expected a type class");
407 }
408 };
409 Rec(0, N);
410
411 OS << "}\n";
412 OS << "#endif\n";
413}
414
415void ClangOpcodesEmitter::EmitEval(raw_ostream &OS, StringRef N,
416 const Record *R) {
417 if (R->getValueAsBit(FieldName: "HasCustomEval"))
418 return;
419
420 OS << "#ifdef GET_EVAL_IMPL\n";
421 Enumerate(R, N,
422 F: [this, R, &N, &OS](ArrayRef<const Record *> TS, const Twine &ID) {
423 auto Args = R->getValueAsListOfDefs(FieldName: "Args");
424
425 OS << "bool EvalEmitter::emit" << ID << "(";
426 for (size_t I = 0, N = Args.size(); I < N; ++I) {
427 const auto *Arg = Args[I];
428 bool AsRef = Arg->getValueAsBit(FieldName: "AsRef");
429 auto Name = Arg->getValueAsString(FieldName: "Name");
430
431 OS << (AsRef ? "const " : " ") << Name << " "
432 << (AsRef ? "&" : "") << "A" << I << ", ";
433 }
434 OS << "SourceInfo L) {\n";
435 OS << " if (!isActive()) return true;\n";
436 OS << " CurrentSource = L;\n";
437
438 if (N == "EndSpeculation") {
439 OS << "return EndSpeculation(S);\n";
440 } else {
441 bool PassOpPC = R->getValueAsBit(FieldName: "NeedsOpPC");
442
443 OS << " return " << N;
444 PrintTypes(OS, Types: TS);
445 OS << "(S";
446 if (PassOpPC)
447 OS << ", CodePtr()";
448 for (size_t I = 0, N = Args.size(); I < N; ++I)
449 OS << ", A" << I;
450 OS << ");\n";
451 }
452 OS << "}\n";
453 });
454
455 OS << "#endif\n";
456}
457
458void ClangOpcodesEmitter::PrintTypes(raw_ostream &OS,
459 ArrayRef<const Record *> Types) {
460 if (Types.empty())
461 return;
462 OS << "<";
463 for (size_t I = 0, N = Types.size(); I < N; ++I) {
464 if (I != 0)
465 OS << ", ";
466 OS << "PT_" << Types[I]->getName();
467 }
468 OS << ">";
469}
470
471void clang::EmitClangOpcodes(const RecordKeeper &Records, raw_ostream &OS) {
472 ClangOpcodesEmitter(Records).run(OS);
473}
474