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

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of clang/utils/TableGen/ClangOpcodesEmitter.cpp