xref: /freebsd/contrib/llvm-project/clang/utils/TableGen/ClangOpcodesEmitter.cpp (revision 7ef62cebc2f965b0f640263e179276928885e33d)
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 
19 using namespace llvm;
20 
21 namespace {
22 class ClangOpcodesEmitter {
23   RecordKeeper &Records;
24   Record Root;
25   unsigned NumTypes;
26 
27 public:
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 
34 private:
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 
60 void 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 
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");
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 
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";
109   });
110   OS << "#endif\n";
111 }
112 
113 void 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     if (CanReturn)
124       OS << "  bool DoReturn = (S.Current == StartFrame);\n";
125 
126     // Emit calls to read arguments.
127     for (size_t I = 0, N = Args.size(); I < N; ++I) {
128       OS << "  auto V" << I;
129       OS << " = ";
130       OS << "ReadArg<" << Args[I]->getValueAsString("Name") << ">(S, PC);\n";
131     }
132 
133     // Emit a call to the template method and pass arguments.
134     OS << "  if (!" << N;
135     PrintTypes(OS, TS);
136     OS << "(S";
137     if (ChangesPC)
138       OS << ", PC";
139     else
140       OS << ", OpPC";
141     if (CanReturn)
142       OS << ", Result";
143     for (size_t I = 0, N = Args.size(); I < N; ++I)
144       OS << ", V" << I;
145     OS << "))\n";
146     OS << "    return false;\n";
147 
148     // Bail out if interpreter returned.
149     if (CanReturn) {
150       OS << "  if (!S.Current || S.Current->isRoot())\n";
151       OS << "    return true;\n";
152 
153       OS << "  if (DoReturn)\n";
154       OS << "    return true;\n";
155     }
156 
157     OS << "  continue;\n";
158     OS << "}\n";
159   });
160   OS << "#endif\n";
161 }
162 
163 void ClangOpcodesEmitter::EmitDisasm(raw_ostream &OS, StringRef N, Record *R) {
164   OS << "#ifdef GET_DISASM\n";
165   Enumerate(R, N, [R, &OS](ArrayRef<Record *>, const Twine &ID) {
166     OS << "case OP_" << ID << ":\n";
167     OS << "  PrintName(\"" << ID << "\");\n";
168     OS << "  OS << \"\\t\"";
169 
170     for (auto *Arg : R->getValueAsListOfDefs("Args")) {
171       OS << " << ReadArg<" << Arg->getValueAsString("Name") << ">(P, PC)";
172       OS << " << \" \"";
173     }
174 
175     OS << " << \"\\n\";\n";
176     OS << "  continue;\n";
177   });
178   OS << "#endif\n";
179 }
180 
181 void ClangOpcodesEmitter::EmitEmitter(raw_ostream &OS, StringRef N, Record *R) {
182   if (R->getValueAsBit("HasCustomLink"))
183     return;
184 
185   OS << "#ifdef GET_LINK_IMPL\n";
186   Enumerate(R, N, [R, &OS](ArrayRef<Record *>, const Twine &ID) {
187     auto Args = R->getValueAsListOfDefs("Args");
188 
189     // Emit the list of arguments.
190     OS << "bool ByteCodeEmitter::emit" << ID << "(";
191     for (size_t I = 0, N = Args.size(); I < N; ++I)
192       OS << Args[I]->getValueAsString("Name") << " A" << I << ", ";
193     OS << "const SourceInfo &L) {\n";
194 
195     // Emit a call to write the opcodes.
196     OS << "  return emitOp<";
197     for (size_t I = 0, N = Args.size(); I < N; ++I) {
198       if (I != 0)
199         OS << ", ";
200       OS << Args[I]->getValueAsString("Name");
201     }
202     OS << ">(OP_" << ID;
203     for (size_t I = 0, N = Args.size(); I < N; ++I)
204       OS << ", A" << I;
205     OS << ", L);\n";
206     OS << "}\n";
207   });
208   OS << "#endif\n";
209 }
210 
211 void ClangOpcodesEmitter::EmitProto(raw_ostream &OS, StringRef N, Record *R) {
212   OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n";
213   auto Args = R->getValueAsListOfDefs("Args");
214   Enumerate(R, N, [&OS, &Args](ArrayRef<Record *> TS, const Twine &ID) {
215     OS << "bool emit" << ID << "(";
216     for (auto *Arg : Args)
217       OS << Arg->getValueAsString("Name") << ", ";
218     OS << "const SourceInfo &);\n";
219   });
220 
221   // Emit a template method for custom emitters to have less to implement.
222   auto TypeCount = R->getValueAsListInit("Types")->size();
223   if (R->getValueAsBit("HasCustomEval") && TypeCount) {
224     OS << "#if defined(GET_EVAL_PROTO)\n";
225     OS << "template<";
226     for (size_t I = 0; I < TypeCount; ++I) {
227       if (I != 0)
228         OS << ", ";
229       OS << "PrimType";
230     }
231     OS << ">\n";
232     OS << "bool emit" << N << "(";
233     for (auto *Arg : Args)
234       OS << Arg->getValueAsString("Name") << ", ";
235     OS << "const SourceInfo &);\n";
236     OS << "#endif\n";
237   }
238 
239   OS << "#endif\n";
240 }
241 
242 void ClangOpcodesEmitter::EmitGroup(raw_ostream &OS, StringRef N, Record *R) {
243   if (!R->getValueAsBit("HasGroup"))
244     return;
245 
246   auto *Types = R->getValueAsListInit("Types");
247   auto Args = R->getValueAsListOfDefs("Args");
248 
249   // Emit the prototype of the group emitter in the header.
250   OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n";
251   OS << "bool emit" << N << "(";
252   for (size_t I = 0, N = Types->size(); I < N; ++I)
253     OS << "PrimType, ";
254   for (auto *Arg : Args)
255     OS << Arg->getValueAsString("Name") << ", ";
256   OS << "const SourceInfo &I);\n";
257   OS << "#endif\n";
258 
259   // Emit the dispatch implementation in the source.
260   OS << "#if defined(GET_EVAL_IMPL) || defined(GET_LINK_IMPL)\n";
261   OS << "bool\n";
262   OS << "#if defined(GET_EVAL_IMPL)\n";
263   OS << "EvalEmitter\n";
264   OS << "#else\n";
265   OS << "ByteCodeEmitter\n";
266   OS << "#endif\n";
267   OS << "::emit" << N << "(";
268   for (size_t I = 0, N = Types->size(); I < N; ++I)
269     OS << "PrimType T" << I << ", ";
270   for (size_t I = 0, N = Args.size(); I < N; ++I)
271     OS << Args[I]->getValueAsString("Name") << " A" << I << ", ";
272   OS << "const SourceInfo &I) {\n";
273 
274   std::function<void(size_t, const Twine &)> Rec;
275   llvm::SmallVector<Record *, 2> TS;
276   Rec = [this, &Rec, &OS, Types, &Args, R, &TS, N](size_t I, const Twine &ID) {
277     if (I >= Types->size()) {
278       // Print a call to the emitter method.
279       // Custom evaluator methods dispatch to template methods.
280       if (R->getValueAsBit("HasCustomEval")) {
281         OS << "#ifdef GET_LINK_IMPL\n";
282         OS << "    return emit" << ID << "\n";
283         OS << "#else\n";
284         OS << "    return emit" << N;
285         PrintTypes(OS, TS);
286         OS << "\n#endif\n";
287         OS << "      ";
288       } else {
289         OS << "    return emit" << ID;
290       }
291 
292       OS << "(";
293       for (size_t I = 0; I < Args.size(); ++I) {
294         OS << "A" << I << ", ";
295       }
296       OS << "I);\n";
297       return;
298     }
299 
300     // Print a switch statement selecting T.
301     if (auto *TypeClass = dyn_cast<DefInit>(Types->getElement(I))) {
302       OS << "  switch (T" << I << ") {\n";
303       auto Cases = TypeClass->getDef()->getValueAsListOfDefs("Types");
304       for (auto *Case : Cases) {
305         OS << "  case PT_" << Case->getName() << ":\n";
306         TS.push_back(Case);
307         Rec(I + 1, ID + Case->getName());
308         TS.pop_back();
309       }
310       // Emit a default case if not all types are present.
311       if (Cases.size() < NumTypes)
312         OS << "  default: llvm_unreachable(\"invalid type\");\n";
313       OS << "  }\n";
314       OS << "  llvm_unreachable(\"invalid enum value\");\n";
315     } else {
316       PrintFatalError("Expected a type class");
317     }
318   };
319   Rec(0, N);
320 
321   OS << "}\n";
322   OS << "#endif\n";
323 }
324 
325 void ClangOpcodesEmitter::EmitEval(raw_ostream &OS, StringRef N, Record *R) {
326   if (R->getValueAsBit("HasCustomEval"))
327     return;
328 
329   OS << "#ifdef GET_EVAL_IMPL\n";
330   Enumerate(R, N, [this, R, &N, &OS](ArrayRef<Record *> TS, const Twine &ID) {
331     auto Args = R->getValueAsListOfDefs("Args");
332 
333     OS << "bool EvalEmitter::emit" << ID << "(";
334     for (size_t I = 0, N = Args.size(); I < N; ++I)
335       OS << Args[I]->getValueAsString("Name") << " A" << I << ", ";
336     OS << "const SourceInfo &L) {\n";
337     OS << "  if (!isActive()) return true;\n";
338     OS << "  CurrentSource = L;\n";
339 
340     OS << "  return " << N;
341     PrintTypes(OS, TS);
342     OS << "(S, OpPC";
343     for (size_t I = 0, N = Args.size(); I < N; ++I)
344       OS << ", A" << I;
345     OS << ");\n";
346     OS << "}\n";
347   });
348 
349   OS << "#endif\n";
350 }
351 
352 void ClangOpcodesEmitter::PrintTypes(raw_ostream &OS, ArrayRef<Record *> Types) {
353   if (Types.empty())
354     return;
355   OS << "<";
356   for (size_t I = 0, N = Types.size(); I < N; ++I) {
357     if (I != 0)
358       OS << ", ";
359     OS << "PT_" << Types[I]->getName();
360   }
361   OS << ">";
362 }
363 
364 void clang::EmitClangOpcodes(RecordKeeper &Records, raw_ostream &OS) {
365   ClangOpcodesEmitter(Records).run(OS);
366 }
367