1 //=== ClangOpcodesEmitter.cpp - constexpr interpreter opcodes ---*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // These tablegen backends emit Clang AST node tables
11 //===----------------------------------------------------------------------===//
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"
22 class ClangOpcodesEmitter {
23 RecordKeeper &Records;
28 ClangOpcodesEmitter(RecordKeeper &R)
29 : Records(R), Root("Opcode", SMLoc(), R),
30 NumTypes(Records.getAllDerivedDefinitions("Type").size()) {}
32 void run(raw_ostream &OS);
35 /// Emits the opcode name for the opcode enum.
36 /// The name is obtained by concatenating the name with the list of types.
37 void EmitEnum(raw_ostream &OS, StringRef N, Record *R);
39 /// Emits the switch case and the invocation in the interpreter.
40 void EmitInterp(raw_ostream &OS, StringRef N, Record *R);
42 /// Emits the disassembler.
43 void EmitDisasm(raw_ostream &OS, StringRef N, Record *R);
45 /// Emits the byte code emitter method.
46 void EmitEmitter(raw_ostream &OS, StringRef N, Record *R);
48 /// Emits the prototype.
49 void EmitProto(raw_ostream &OS, StringRef N, Record *R);
51 /// Emits the prototype to dispatch from a type.
52 void EmitGroup(raw_ostream &OS, StringRef N, Record *R);
54 /// Emits the evaluator method.
55 void EmitEval(raw_ostream &OS, StringRef N, Record *R);
57 void PrintTypes(raw_ostream &OS, ArrayRef<Record *> Types);
60 void Enumerate(const Record *R,
62 std::function<void(ArrayRef<Record *>, Twine)> &&F) {
63 llvm::SmallVector<Record *, 2> TypePath;
64 auto *Types = R->getValueAsListInit("Types");
66 std::function<void(size_t, const Twine &)> Rec;
67 Rec = [&TypePath, Types, &Rec, &F](size_t I, const Twine &ID) {
68 if (I >= Types->size()) {
73 if (auto *TypeClass = dyn_cast<DefInit>(Types->getElement(I))) {
74 for (auto *Type : TypeClass->getDef()->getValueAsListOfDefs("Types")) {
75 TypePath.push_back(Type);
76 Rec(I + 1, ID + Type->getName());
80 PrintFatalError("Expected a type class");
88 void ClangOpcodesEmitter::run(raw_ostream &OS) {
89 for (auto *Opcode : Records.getAllDerivedDefinitions(Root.getName())) {
90 // The name is the record name, unless overriden.
91 StringRef N = Opcode->getValueAsString("Name");
93 N = Opcode->getName();
95 EmitEnum(OS, N, Opcode);
96 EmitInterp(OS, N, Opcode);
97 EmitDisasm(OS, N, Opcode);
98 EmitProto(OS, N, Opcode);
99 EmitGroup(OS, N, Opcode);
100 EmitEmitter(OS, N, Opcode);
101 EmitEval(OS, N, Opcode);
105 void ClangOpcodesEmitter::EmitEnum(raw_ostream &OS, StringRef N, Record *R) {
106 OS << "#ifdef GET_OPCODE_NAMES\n";
107 Enumerate(R, N, [&OS](ArrayRef<Record *>, const Twine &ID) {
108 OS << "OP_" << ID << ",\n";
113 void ClangOpcodesEmitter::EmitInterp(raw_ostream &OS, StringRef N, Record *R) {
114 OS << "#ifdef GET_INTERP\n";
116 Enumerate(R, N, [this, R, &OS, &N](ArrayRef<Record *> TS, const Twine &ID) {
117 bool CanReturn = R->getValueAsBit("CanReturn");
118 bool ChangesPC = R->getValueAsBit("ChangesPC");
119 auto Args = R->getValueAsListOfDefs("Args");
121 OS << "case OP_" << ID << ": {\n";
123 // Emit calls to read arguments.
124 for (size_t I = 0, N = Args.size(); I < N; ++I) {
125 OS << "\tauto V" << I;
127 OS << "PC.read<" << Args[I]->getValueAsString("Name") << ">();\n";
130 // Emit a call to the template method and pass arguments.
131 OS << "\tif (!" << N;
140 for (size_t I = 0, N = Args.size(); I < N; ++I)
143 OS << "\t\treturn false;\n";
145 // Bail out if interpreter returned.
147 OS << "\tif (!S.Current || S.Current->isRoot())\n";
148 OS << "\t\treturn true;\n";
151 OS << "\tcontinue;\n";
157 void ClangOpcodesEmitter::EmitDisasm(raw_ostream &OS, StringRef N, Record *R) {
158 OS << "#ifdef GET_DISASM\n";
159 Enumerate(R, N, [R, &OS](ArrayRef<Record *>, const Twine &ID) {
160 OS << "case OP_" << ID << ":\n";
161 OS << "\tPrintName(\"" << ID << "\");\n";
162 OS << "\tOS << \"\\t\"";
164 for (auto *Arg : R->getValueAsListOfDefs("Args"))
165 OS << " << PC.read<" << Arg->getValueAsString("Name") << ">() << \" \"";
167 OS << "<< \"\\n\";\n";
168 OS << "\tcontinue;\n";
173 void ClangOpcodesEmitter::EmitEmitter(raw_ostream &OS, StringRef N, Record *R) {
174 if (R->getValueAsBit("HasCustomLink"))
177 OS << "#ifdef GET_LINK_IMPL\n";
178 Enumerate(R, N, [R, &OS](ArrayRef<Record *>, const Twine &ID) {
179 auto Args = R->getValueAsListOfDefs("Args");
181 // Emit the list of arguments.
182 OS << "bool ByteCodeEmitter::emit" << ID << "(";
183 for (size_t I = 0, N = Args.size(); I < N; ++I)
184 OS << Args[I]->getValueAsString("Name") << " A" << I << ",";
185 OS << "const SourceInfo &L) {\n";
187 // Emit a call to write the opcodes.
188 OS << "\treturn emitOp<";
189 for (size_t I = 0, N = Args.size(); I < N; ++I) {
192 OS << Args[I]->getValueAsString("Name");
195 for (size_t I = 0, N = Args.size(); I < N; ++I)
203 void ClangOpcodesEmitter::EmitProto(raw_ostream &OS, StringRef N, Record *R) {
204 OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n";
205 auto Args = R->getValueAsListOfDefs("Args");
206 Enumerate(R, N, [&OS, &Args](ArrayRef<Record *> TS, const Twine &ID) {
207 OS << "bool emit" << ID << "(";
208 for (auto *Arg : Args)
209 OS << Arg->getValueAsString("Name") << ", ";
210 OS << "const SourceInfo &);\n";
213 // Emit a template method for custom emitters to have less to implement.
214 auto TypeCount = R->getValueAsListInit("Types")->size();
215 if (R->getValueAsBit("HasCustomEval") && TypeCount) {
216 OS << "#if defined(GET_EVAL_PROTO)\n";
218 for (size_t I = 0; I < TypeCount; ++I) {
224 OS << "bool emit" << N << "(";
225 for (auto *Arg : Args)
226 OS << Arg->getValueAsString("Name") << ", ";
227 OS << "const SourceInfo &);\n";
234 void ClangOpcodesEmitter::EmitGroup(raw_ostream &OS, StringRef N, Record *R) {
235 if (!R->getValueAsBit("HasGroup"))
238 auto *Types = R->getValueAsListInit("Types");
239 auto Args = R->getValueAsListOfDefs("Args");
241 // Emit the prototype of the group emitter in the header.
242 OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n";
243 OS << "bool emit" << N << "(";
244 for (size_t I = 0, N = Types->size(); I < N; ++I)
246 for (auto *Arg : Args)
247 OS << Arg->getValueAsString("Name") << ", ";
248 OS << "const SourceInfo &I);\n";
251 // Emit the dispatch implementation in the source.
252 OS << "#if defined(GET_EVAL_IMPL) || defined(GET_LINK_IMPL)\n";
254 OS << "#if defined(GET_EVAL_IMPL)\n";
255 OS << "EvalEmitter\n";
257 OS << "ByteCodeEmitter\n";
259 OS << "::emit" << N << "(";
260 for (size_t I = 0, N = Types->size(); I < N; ++I)
261 OS << "PrimType T" << I << ", ";
262 for (size_t I = 0, N = Args.size(); I < N; ++I)
263 OS << Args[I]->getValueAsString("Name") << " A" << I << ", ";
264 OS << "const SourceInfo &I) {\n";
266 std::function<void(size_t, const Twine &)> Rec;
267 llvm::SmallVector<Record *, 2> TS;
268 Rec = [this, &Rec, &OS, Types, &Args, R, &TS, N](size_t I, const Twine &ID) {
269 if (I >= Types->size()) {
270 // Print a call to the emitter method.
271 // Custom evaluator methods dispatch to template methods.
272 if (R->getValueAsBit("HasCustomEval")) {
273 OS << "#ifdef GET_LINK_IMPL\n";
274 OS << "return emit" << ID << "\n";
276 OS << "return emit" << N;
280 OS << "return emit" << ID;
284 for (size_t I = 0; I < Args.size(); ++I) {
285 OS << "A" << I << ", ";
291 // Print a switch statement selecting T.
292 if (auto *TypeClass = dyn_cast<DefInit>(Types->getElement(I))) {
293 OS << "switch (T" << I << "){\n";
294 auto Cases = TypeClass->getDef()->getValueAsListOfDefs("Types");
295 for (auto *Case : Cases) {
296 OS << "case PT_" << Case->getName() << ":\n";
298 Rec(I + 1, ID + Case->getName());
301 // Emit a default case if not all types are present.
302 if (Cases.size() < NumTypes)
303 OS << "default: llvm_unreachable(\"invalid type\");\n";
305 OS << "llvm_unreachable(\"invalid enum value\");\n";
307 PrintFatalError("Expected a type class");
316 void ClangOpcodesEmitter::EmitEval(raw_ostream &OS, StringRef N, Record *R) {
317 if (R->getValueAsBit("HasCustomEval"))
320 OS << "#ifdef GET_EVAL_IMPL\n";
321 Enumerate(R, N, [this, R, &N, &OS](ArrayRef<Record *> TS, const Twine &ID) {
322 auto Args = R->getValueAsListOfDefs("Args");
324 OS << "bool EvalEmitter::emit" << ID << "(";
325 for (size_t I = 0, N = Args.size(); I < N; ++I)
326 OS << Args[I]->getValueAsString("Name") << " A" << I << ",";
327 OS << "const SourceInfo &L) {\n";
328 OS << "if (!isActive()) return true;\n";
329 OS << "CurrentSource = L;\n";
331 OS << "return " << N;
334 for (size_t I = 0, N = Args.size(); I < N; ++I)
343 void ClangOpcodesEmitter::PrintTypes(raw_ostream &OS, ArrayRef<Record *> Types) {
347 for (size_t I = 0, N = Types.size(); I < N; ++I) {
350 OS << "PT_" << Types[I]->getName();
355 void clang::EmitClangOpcodes(RecordKeeper &Records, raw_ostream &OS) {
356 ClangOpcodesEmitter(Records).run(OS);