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: |
27 | ClangOpcodesEmitter(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 | llvm::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(i: 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 | 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 | |
171 | void ClangOpcodesEmitter::EmitDisasm(raw_ostream &OS, StringRef N, |
172 | const Record *R) { |
173 | OS << "#ifdef GET_DISASM\n" ; |
174 | Enumerate(R, N, F: [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(FieldName: "Args" )) { |
180 | OS << " << ReadArg<" << Arg->getValueAsString(FieldName: "Name" ) << ">(P, PC)" ; |
181 | OS << " << \" \"" ; |
182 | } |
183 | |
184 | OS << " << \"\\n\";\n" ; |
185 | OS << " continue;\n" ; |
186 | }); |
187 | OS << "#endif\n" ; |
188 | } |
189 | |
190 | void ClangOpcodesEmitter::EmitEmitter(raw_ostream &OS, StringRef N, |
191 | const Record *R) { |
192 | if (R->getValueAsBit(FieldName: "HasCustomLink" )) |
193 | return; |
194 | |
195 | OS << "#ifdef GET_LINK_IMPL\n" ; |
196 | Enumerate(R, N, F: [R, &OS](ArrayRef<const Record *>, const Twine &ID) { |
197 | const auto &Args = R->getValueAsListOfDefs(FieldName: "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(FieldName: "AsRef" ); |
204 | auto Name = Arg->getValueAsString(FieldName: "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(FieldName: "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 | |
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(FieldName: "Args" ); |
231 | Enumerate(R, N, F: [&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(FieldName: "AsRef" ); |
236 | auto Name = Arg->getValueAsString(FieldName: "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(FieldName: "Types" )->size(); |
246 | if (R->getValueAsBit(FieldName: "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(FieldName: "Name" ) << ", " ; |
258 | OS << "const SourceInfo &);\n" ; |
259 | OS << "#endif\n" ; |
260 | } |
261 | |
262 | OS << "#endif\n" ; |
263 | } |
264 | |
265 | void ClangOpcodesEmitter::EmitGroup(raw_ostream &OS, StringRef N, |
266 | const Record *R) { |
267 | if (!R->getValueAsBit(FieldName: "HasGroup" )) |
268 | return; |
269 | |
270 | const auto *Types = R->getValueAsListInit(FieldName: "Types" ); |
271 | const auto &Args = R->getValueAsListOfDefs(FieldName: "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(FieldName: "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(FieldName: "AsRef" ); |
299 | auto Name = Arg->getValueAsString(FieldName: "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(FieldName: "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, Types: 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>(Val: Types->getElement(i: I))) { |
335 | OS << " switch (T" << I << ") {\n" ; |
336 | auto Cases = TypeClass->getDef()->getValueAsListOfDefs(FieldName: "Types" ); |
337 | for (auto *Case : Cases) { |
338 | OS << " case PT_" << Case->getName() << ":\n" ; |
339 | TS.push_back(Elt: 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(Msg: "Expected a type class" ); |
351 | } |
352 | }; |
353 | Rec(0, N); |
354 | |
355 | OS << "}\n" ; |
356 | OS << "#endif\n" ; |
357 | } |
358 | |
359 | void ClangOpcodesEmitter::EmitEval(raw_ostream &OS, StringRef N, |
360 | const Record *R) { |
361 | if (R->getValueAsBit(FieldName: "HasCustomEval" )) |
362 | return; |
363 | |
364 | OS << "#ifdef GET_EVAL_IMPL\n" ; |
365 | Enumerate(R, N, |
366 | F: [this, R, &N, &OS](ArrayRef<const Record *> TS, const Twine &ID) { |
367 | auto Args = R->getValueAsListOfDefs(FieldName: "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(FieldName: "AsRef" ); |
373 | auto Name = Arg->getValueAsString(FieldName: "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, Types: 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 | |
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 | |
407 | void clang::EmitClangOpcodes(RecordKeeper &Records, raw_ostream &OS) { |
408 | ClangOpcodesEmitter(Records).run(OS); |
409 | } |
410 | |