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