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