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:
ClangOpcodesEmitter(RecordKeeper & R)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
Enumerate(const Record * R,StringRef N,std::function<void (ArrayRef<Record * >,Twine)> && F)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
run(raw_ostream & OS)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
EmitEnum(raw_ostream & OS,StringRef N,Record * R)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
EmitInterp(raw_ostream & OS,StringRef N,Record * R)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
EmitDisasm(raw_ostream & OS,StringRef N,Record * R)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
EmitEmitter(raw_ostream & OS,StringRef N,Record * R)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
EmitProto(raw_ostream & OS,StringRef N,Record * R)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
EmitGroup(raw_ostream & OS,StringRef N,Record * R)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
EmitEval(raw_ostream & OS,StringRef N,Record * R)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
PrintTypes(raw_ostream & OS,ArrayRef<Record * > Types)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
EmitClangOpcodes(RecordKeeper & Records,raw_ostream & OS)364 void clang::EmitClangOpcodes(RecordKeeper &Records, raw_ostream &OS) {
365 ClangOpcodesEmitter(Records).run(OS);
366 }
367