ClangOpcodesEmitter.cpp revision 360784
1//=== ClangOpcodesEmitter.cpp - constexpr interpreter opcodes ---*- C++ -*-===//
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  RecordKeeper &Records;
24  Record Root;
25  unsigned NumTypes;
26
27public:
28  ClangOpcodesEmitter(RecordKeeper &R)
29    : Records(R), Root("Opcode", SMLoc(), R),
30      NumTypes(Records.getAllDerivedDefinitions("Type").size()) {}
31
32  void run(raw_ostream &OS);
33
34private:
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);
38
39  /// Emits the switch case and the invocation in the interpreter.
40  void EmitInterp(raw_ostream &OS, StringRef N, Record *R);
41
42  /// Emits the disassembler.
43  void EmitDisasm(raw_ostream &OS, StringRef N, Record *R);
44
45  /// Emits the byte code emitter method.
46  void EmitEmitter(raw_ostream &OS, StringRef N, Record *R);
47
48  /// Emits the prototype.
49  void EmitProto(raw_ostream &OS, StringRef N, Record *R);
50
51  /// Emits the prototype to dispatch from a type.
52  void EmitGroup(raw_ostream &OS, StringRef N, Record *R);
53
54  /// Emits the evaluator method.
55  void EmitEval(raw_ostream &OS, StringRef N, Record *R);
56
57  void PrintTypes(raw_ostream &OS, ArrayRef<Record *> Types);
58};
59
60void Enumerate(const Record *R,
61               StringRef N,
62               std::function<void(ArrayRef<Record *>, Twine)> &&F) {
63  llvm::SmallVector<Record *, 2> TypePath;
64  auto *Types = R->getValueAsListInit("Types");
65
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()) {
69      F(TypePath, ID);
70      return;
71    }
72
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());
77        TypePath.pop_back();
78      }
79    } else {
80      PrintFatalError("Expected a type class");
81    }
82  };
83  Rec(0, N);
84}
85
86} // namespace
87
88void 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");
92    if (N.empty())
93      N = Opcode->getName();
94
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);
102  }
103}
104
105void 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";
109  });
110  OS << "#endif\n";
111}
112
113void ClangOpcodesEmitter::EmitInterp(raw_ostream &OS, StringRef N, Record *R) {
114  OS << "#ifdef GET_INTERP\n";
115
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");
120
121    OS << "case OP_" << ID << ": {\n";
122
123    // Emit calls to read arguments.
124    for (size_t I = 0, N = Args.size(); I < N; ++I) {
125      OS << "\tauto V" << I;
126      OS << " = ";
127      OS << "PC.read<" << Args[I]->getValueAsString("Name") << ">();\n";
128    }
129
130    // Emit a call to the template method and pass arguments.
131    OS << "\tif (!" << N;
132    PrintTypes(OS, TS);
133    OS << "(S";
134    if (ChangesPC)
135      OS << ", PC";
136    else
137      OS << ", OpPC";
138    if (CanReturn)
139      OS << ", Result";
140    for (size_t I = 0, N = Args.size(); I < N; ++I)
141      OS << ", V" << I;
142    OS << "))\n";
143    OS << "\t\treturn false;\n";
144
145    // Bail out if interpreter returned.
146    if (CanReturn) {
147      OS << "\tif (!S.Current || S.Current->isRoot())\n";
148      OS << "\t\treturn true;\n";
149    }
150
151    OS << "\tcontinue;\n";
152    OS << "}\n";
153  });
154  OS << "#endif\n";
155}
156
157void 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\"";
163
164    for (auto *Arg : R->getValueAsListOfDefs("Args"))
165      OS << " << PC.read<" << Arg->getValueAsString("Name") << ">() << \" \"";
166
167    OS << "<< \"\\n\";\n";
168    OS << "\tcontinue;\n";
169  });
170  OS << "#endif\n";
171}
172
173void ClangOpcodesEmitter::EmitEmitter(raw_ostream &OS, StringRef N, Record *R) {
174  if (R->getValueAsBit("HasCustomLink"))
175    return;
176
177  OS << "#ifdef GET_LINK_IMPL\n";
178  Enumerate(R, N, [R, &OS](ArrayRef<Record *>, const Twine &ID) {
179    auto Args = R->getValueAsListOfDefs("Args");
180
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";
186
187    // Emit a call to write the opcodes.
188    OS << "\treturn emitOp<";
189    for (size_t I = 0, N = Args.size(); I < N; ++I) {
190      if (I != 0)
191        OS << ", ";
192      OS << Args[I]->getValueAsString("Name");
193    }
194    OS << ">(OP_" << ID;
195    for (size_t I = 0, N = Args.size(); I < N; ++I)
196      OS << ", A" << I;
197    OS << ", L);\n";
198    OS << "}\n";
199  });
200  OS << "#endif\n";
201}
202
203void 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";
211  });
212
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";
217    OS << "template<";
218    for (size_t I = 0; I < TypeCount; ++I) {
219      if (I != 0)
220        OS << ", ";
221      OS << "PrimType";
222    }
223    OS << ">\n";
224    OS << "bool emit" << N << "(";
225    for (auto *Arg : Args)
226      OS << Arg->getValueAsString("Name") << ", ";
227    OS << "const SourceInfo &);\n";
228    OS << "#endif\n";
229  }
230
231  OS << "#endif\n";
232}
233
234void ClangOpcodesEmitter::EmitGroup(raw_ostream &OS, StringRef N, Record *R) {
235  if (!R->getValueAsBit("HasGroup"))
236    return;
237
238  auto *Types = R->getValueAsListInit("Types");
239  auto Args = R->getValueAsListOfDefs("Args");
240
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)
245    OS << "PrimType, ";
246  for (auto *Arg : Args)
247    OS << Arg->getValueAsString("Name") << ", ";
248  OS << "const SourceInfo &I);\n";
249  OS << "#endif\n";
250
251  // Emit the dispatch implementation in the source.
252  OS << "#if defined(GET_EVAL_IMPL) || defined(GET_LINK_IMPL)\n";
253  OS << "bool \n";
254  OS << "#if defined(GET_EVAL_IMPL)\n";
255  OS << "EvalEmitter\n";
256  OS << "#else\n";
257  OS << "ByteCodeEmitter\n";
258  OS << "#endif\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";
265
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";
275        OS << "#else\n";
276        OS << "return emit" << N;
277        PrintTypes(OS, TS);
278        OS << "\n#endif\n";
279      } else {
280        OS << "return emit" << ID;
281      }
282
283      OS << "(";
284      for (size_t I = 0; I < Args.size(); ++I) {
285        OS << "A" << I << ", ";
286      }
287      OS << "I);\n";
288      return;
289    }
290
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";
297        TS.push_back(Case);
298        Rec(I + 1, ID + Case->getName());
299        TS.pop_back();
300      }
301      // Emit a default case if not all types are present.
302      if (Cases.size() < NumTypes)
303        OS << "default: llvm_unreachable(\"invalid type\");\n";
304      OS << "}\n";
305      OS << "llvm_unreachable(\"invalid enum value\");\n";
306    } else {
307      PrintFatalError("Expected a type class");
308    }
309  };
310  Rec(0, N);
311
312  OS << "}\n";
313  OS << "#endif\n";
314}
315
316void ClangOpcodesEmitter::EmitEval(raw_ostream &OS, StringRef N, Record *R) {
317  if (R->getValueAsBit("HasCustomEval"))
318    return;
319
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");
323
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";
330
331    OS << "return " << N;
332    PrintTypes(OS, TS);
333    OS << "(S, OpPC";
334    for (size_t I = 0, N = Args.size(); I < N; ++I)
335      OS << ", A" << I;
336    OS << ");\n";
337    OS << "}\n";
338  });
339
340  OS << "#endif\n";
341}
342
343void ClangOpcodesEmitter::PrintTypes(raw_ostream &OS, ArrayRef<Record *> Types) {
344  if (Types.empty())
345    return;
346  OS << "<";
347  for (size_t I = 0, N = Types.size(); I < N; ++I) {
348    if (I != 0)
349      OS << ", ";
350    OS << "PT_" << Types[I]->getName();
351  }
352  OS << ">";
353}
354
355void clang::EmitClangOpcodes(RecordKeeper &Records, raw_ostream &OS) {
356  ClangOpcodesEmitter(Records).run(OS);
357}
358