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