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