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