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