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