150
|
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:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
236
|
123 if (CanReturn)
|
|
124 OS << " bool DoReturn = (S.Current == StartFrame);\n";
|
|
125
|
150
|
126 // Emit calls to read arguments.
|
|
127 for (size_t I = 0, N = Args.size(); I < N; ++I) {
|
221
|
128 OS << " auto V" << I;
|
150
|
129 OS << " = ";
|
236
|
130 OS << "ReadArg<" << Args[I]->getValueAsString("Name") << ">(S, PC);\n";
|
150
|
131 }
|
|
132
|
|
133 // Emit a call to the template method and pass arguments.
|
221
|
134 OS << " if (!" << N;
|
150
|
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";
|
221
|
146 OS << " return false;\n";
|
150
|
147
|
|
148 // Bail out if interpreter returned.
|
|
149 if (CanReturn) {
|
221
|
150 OS << " if (!S.Current || S.Current->isRoot())\n";
|
|
151 OS << " return true;\n";
|
236
|
152
|
|
153 OS << " if (DoReturn)\n";
|
|
154 OS << " return true;\n";
|
150
|
155 }
|
|
156
|
221
|
157 OS << " continue;\n";
|
150
|
158 OS << "}\n";
|
|
159 });
|
|
160 OS << "#endif\n";
|
|
161 }
|
|
162
|
|
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";
|
221
|
167 OS << " PrintName(\"" << ID << "\");\n";
|
|
168 OS << " OS << \"\\t\"";
|
150
|
169
|
236
|
170 for (auto *Arg : R->getValueAsListOfDefs("Args")) {
|
|
171 OS << " << ReadArg<" << Arg->getValueAsString("Name") << ">(P, PC)";
|
|
172 OS << " << \" \"";
|
|
173 }
|
150
|
174
|
221
|
175 OS << " << \"\\n\";\n";
|
|
176 OS << " continue;\n";
|
150
|
177 });
|
|
178 OS << "#endif\n";
|
|
179 }
|
|
180
|
|
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)
|
221
|
192 OS << Args[I]->getValueAsString("Name") << " A" << I << ", ";
|
150
|
193 OS << "const SourceInfo &L) {\n";
|
|
194
|
|
195 // Emit a call to write the opcodes.
|
221
|
196 OS << " return emitOp<";
|
150
|
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
|
|
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
|
|
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";
|
221
|
261 OS << "bool\n";
|
150
|
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";
|
221
|
282 OS << " return emit" << ID << "\n";
|
150
|
283 OS << "#else\n";
|
221
|
284 OS << " return emit" << N;
|
150
|
285 PrintTypes(OS, TS);
|
|
286 OS << "\n#endif\n";
|
221
|
287 OS << " ";
|
150
|
288 } else {
|
221
|
289 OS << " return emit" << ID;
|
150
|
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))) {
|
221
|
302 OS << " switch (T" << I << ") {\n";
|
150
|
303 auto Cases = TypeClass->getDef()->getValueAsListOfDefs("Types");
|
|
304 for (auto *Case : Cases) {
|
221
|
305 OS << " case PT_" << Case->getName() << ":\n";
|
150
|
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)
|
221
|
312 OS << " default: llvm_unreachable(\"invalid type\");\n";
|
|
313 OS << " }\n";
|
|
314 OS << " llvm_unreachable(\"invalid enum value\");\n";
|
150
|
315 } else {
|
|
316 PrintFatalError("Expected a type class");
|
|
317 }
|
|
318 };
|
|
319 Rec(0, N);
|
|
320
|
|
321 OS << "}\n";
|
|
322 OS << "#endif\n";
|
|
323 }
|
|
324
|
|
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)
|
221
|
335 OS << Args[I]->getValueAsString("Name") << " A" << I << ", ";
|
150
|
336 OS << "const SourceInfo &L) {\n";
|
221
|
337 OS << " if (!isActive()) return true;\n";
|
|
338 OS << " CurrentSource = L;\n";
|
150
|
339
|
221
|
340 OS << " return " << N;
|
150
|
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
|
|
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
|
|
364 void clang::EmitClangOpcodes(RecordKeeper &Records, raw_ostream &OS) {
|
|
365 ClangOpcodesEmitter(Records).run(OS);
|
|
366 }
|