1 //=== ClangOpcodesEmitter.cpp - constexpr interpreter opcodes ---*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // These tablegen backends emit Clang AST node tables
11 //===----------------------------------------------------------------------===//
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"
22 class ClangOpcodesEmitter
{
23 RecordKeeper
&Records
;
28 ClangOpcodesEmitter(RecordKeeper
&R
)
29 : Records(R
), Root("Opcode", SMLoc(), R
),
30 NumTypes(Records
.getAllDerivedDefinitions("Type").size()) {}
32 void run(raw_ostream
&OS
);
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
);
39 /// Emits the switch case and the invocation in the interpreter.
40 void EmitInterp(raw_ostream
&OS
, StringRef N
, Record
*R
);
42 /// Emits the disassembler.
43 void EmitDisasm(raw_ostream
&OS
, StringRef N
, Record
*R
);
45 /// Emits the byte code emitter method.
46 void EmitEmitter(raw_ostream
&OS
, StringRef N
, Record
*R
);
48 /// Emits the prototype.
49 void EmitProto(raw_ostream
&OS
, StringRef N
, Record
*R
);
51 /// Emits the prototype to dispatch from a type.
52 void EmitGroup(raw_ostream
&OS
, StringRef N
, Record
*R
);
54 /// Emits the evaluator method.
55 void EmitEval(raw_ostream
&OS
, StringRef N
, Record
*R
);
57 void PrintTypes(raw_ostream
&OS
, ArrayRef
<Record
*> Types
);
60 void Enumerate(const Record
*R
,
62 std::function
<void(ArrayRef
<Record
*>, Twine
)> &&F
) {
63 llvm::SmallVector
<Record
*, 2> TypePath
;
64 auto *Types
= R
->getValueAsListInit("Types");
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()) {
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());
80 PrintFatalError("Expected a type class");
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");
93 N
= Opcode
->getName();
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
);
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";
113 void ClangOpcodesEmitter::EmitInterp(raw_ostream
&OS
, StringRef N
, Record
*R
) {
114 OS
<< "#ifdef GET_INTERP\n";
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");
121 OS
<< "case OP_" << ID
<< ": {\n";
124 OS
<< " bool DoReturn = (S.Current == StartFrame);\n";
126 // Emit calls to read arguments.
127 for (size_t I
= 0, N
= Args
.size(); I
< N
; ++I
) {
128 OS
<< " auto V" << I
;
130 OS
<< "ReadArg<" << Args
[I
]->getValueAsString("Name") << ">(S, PC);\n";
133 // Emit a call to the template method and pass arguments.
143 for (size_t I
= 0, N
= Args
.size(); I
< N
; ++I
)
146 OS
<< " return false;\n";
148 // Bail out if interpreter returned.
150 OS
<< " if (!S.Current || S.Current->isRoot())\n";
151 OS
<< " return true;\n";
153 OS
<< " if (DoReturn)\n";
154 OS
<< " return true;\n";
157 OS
<< " continue;\n";
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\"";
170 for (auto *Arg
: R
->getValueAsListOfDefs("Args")) {
171 OS
<< " << ReadArg<" << Arg
->getValueAsString("Name") << ">(P, PC)";
175 OS
<< " << \"\\n\";\n";
176 OS
<< " continue;\n";
181 void ClangOpcodesEmitter::EmitEmitter(raw_ostream
&OS
, StringRef N
, Record
*R
) {
182 if (R
->getValueAsBit("HasCustomLink"))
185 OS
<< "#ifdef GET_LINK_IMPL\n";
186 Enumerate(R
, N
, [R
, &OS
](ArrayRef
<Record
*>, const Twine
&ID
) {
187 auto Args
= R
->getValueAsListOfDefs("Args");
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";
195 // Emit a call to write the opcodes.
196 OS
<< " return emitOp<";
197 for (size_t I
= 0, N
= Args
.size(); I
< N
; ++I
) {
200 OS
<< Args
[I
]->getValueAsString("Name");
203 for (size_t I
= 0, N
= Args
.size(); I
< N
; ++I
)
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";
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";
226 for (size_t I
= 0; I
< TypeCount
; ++I
) {
232 OS
<< "bool emit" << N
<< "(";
233 for (auto *Arg
: Args
)
234 OS
<< Arg
->getValueAsString("Name") << ", ";
235 OS
<< "const SourceInfo &);\n";
242 void ClangOpcodesEmitter::EmitGroup(raw_ostream
&OS
, StringRef N
, Record
*R
) {
243 if (!R
->getValueAsBit("HasGroup"))
246 auto *Types
= R
->getValueAsListInit("Types");
247 auto Args
= R
->getValueAsListOfDefs("Args");
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
)
254 for (auto *Arg
: Args
)
255 OS
<< Arg
->getValueAsString("Name") << ", ";
256 OS
<< "const SourceInfo &I);\n";
259 // Emit the dispatch implementation in the source.
260 OS
<< "#if defined(GET_EVAL_IMPL) || defined(GET_LINK_IMPL)\n";
262 OS
<< "#if defined(GET_EVAL_IMPL)\n";
263 OS
<< "EvalEmitter\n";
265 OS
<< "ByteCodeEmitter\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";
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";
284 OS
<< " return emit" << N
;
289 OS
<< " return emit" << ID
;
293 for (size_t I
= 0; I
< Args
.size(); ++I
) {
294 OS
<< "A" << I
<< ", ";
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";
307 Rec(I
+ 1, ID
+ Case
->getName());
310 // Emit a default case if not all types are present.
311 if (Cases
.size() < NumTypes
)
312 OS
<< " default: llvm_unreachable(\"invalid type\");\n";
314 OS
<< " llvm_unreachable(\"invalid enum value\");\n";
316 PrintFatalError("Expected a type class");
325 void ClangOpcodesEmitter::EmitEval(raw_ostream
&OS
, StringRef N
, Record
*R
) {
326 if (R
->getValueAsBit("HasCustomEval"))
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");
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";
340 OS
<< " return " << N
;
343 for (size_t I
= 0, N
= Args
.size(); I
< N
; ++I
)
352 void ClangOpcodesEmitter::PrintTypes(raw_ostream
&OS
, ArrayRef
<Record
*> Types
) {
356 for (size_t I
= 0, N
= Types
.size(); I
< N
; ++I
) {
359 OS
<< "PT_" << Types
[I
]->getName();
364 void clang::EmitClangOpcodes(RecordKeeper
&Records
, raw_ostream
&OS
) {
365 ClangOpcodesEmitter(Records
).run(OS
);