xref: /freebsd-src/contrib/llvm-project/clang/utils/TableGen/ClangOpcodesEmitter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1a7dea167SDimitry Andric //=== ClangOpcodesEmitter.cpp - constexpr interpreter opcodes ---*- C++ -*-===//
2a7dea167SDimitry Andric //
3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a7dea167SDimitry Andric //
7a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
8a7dea167SDimitry Andric //
9a7dea167SDimitry Andric // These tablegen backends emit Clang AST node tables
10a7dea167SDimitry Andric //
11a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
12a7dea167SDimitry Andric 
13a7dea167SDimitry Andric #include "TableGenBackends.h"
14a7dea167SDimitry Andric #include "llvm/TableGen/Error.h"
15a7dea167SDimitry Andric #include "llvm/TableGen/Record.h"
16a7dea167SDimitry Andric #include "llvm/TableGen/StringMatcher.h"
17a7dea167SDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
18a7dea167SDimitry Andric 
19a7dea167SDimitry Andric using namespace llvm;
20a7dea167SDimitry Andric 
21a7dea167SDimitry Andric namespace {
22a7dea167SDimitry Andric class ClangOpcodesEmitter {
23a7dea167SDimitry Andric   RecordKeeper &Records;
24a7dea167SDimitry Andric   unsigned NumTypes;
25a7dea167SDimitry Andric 
26a7dea167SDimitry Andric public:
27a7dea167SDimitry Andric   ClangOpcodesEmitter(RecordKeeper &R)
28*0fca6ea1SDimitry Andric       : Records(R), NumTypes(Records.getAllDerivedDefinitions("Type").size()) {}
29a7dea167SDimitry Andric 
30a7dea167SDimitry Andric   void run(raw_ostream &OS);
31a7dea167SDimitry Andric 
32a7dea167SDimitry Andric private:
33a7dea167SDimitry Andric   /// Emits the opcode name for the opcode enum.
34a7dea167SDimitry Andric   /// The name is obtained by concatenating the name with the list of types.
3506c3fb27SDimitry Andric   void EmitEnum(raw_ostream &OS, StringRef N, const Record *R);
36a7dea167SDimitry Andric 
37a7dea167SDimitry Andric   /// Emits the switch case and the invocation in the interpreter.
3806c3fb27SDimitry Andric   void EmitInterp(raw_ostream &OS, StringRef N, const Record *R);
39a7dea167SDimitry Andric 
40a7dea167SDimitry Andric   /// Emits the disassembler.
4106c3fb27SDimitry Andric   void EmitDisasm(raw_ostream &OS, StringRef N, const Record *R);
42a7dea167SDimitry Andric 
43a7dea167SDimitry Andric   /// Emits the byte code emitter method.
4406c3fb27SDimitry Andric   void EmitEmitter(raw_ostream &OS, StringRef N, const Record *R);
45a7dea167SDimitry Andric 
46a7dea167SDimitry Andric   /// Emits the prototype.
4706c3fb27SDimitry Andric   void EmitProto(raw_ostream &OS, StringRef N, const Record *R);
48a7dea167SDimitry Andric 
49a7dea167SDimitry Andric   /// Emits the prototype to dispatch from a type.
5006c3fb27SDimitry Andric   void EmitGroup(raw_ostream &OS, StringRef N, const Record *R);
51a7dea167SDimitry Andric 
52a7dea167SDimitry Andric   /// Emits the evaluator method.
5306c3fb27SDimitry Andric   void EmitEval(raw_ostream &OS, StringRef N, const Record *R);
54a7dea167SDimitry Andric 
5506c3fb27SDimitry Andric   void PrintTypes(raw_ostream &OS, ArrayRef<const Record *> Types);
56a7dea167SDimitry Andric };
57a7dea167SDimitry Andric 
5806c3fb27SDimitry Andric void Enumerate(const Record *R, StringRef N,
5906c3fb27SDimitry Andric                std::function<void(ArrayRef<const Record *>, Twine)> &&F) {
6006c3fb27SDimitry Andric   llvm::SmallVector<const Record *, 2> TypePath;
61*0fca6ea1SDimitry Andric   const auto *Types = R->getValueAsListInit("Types");
62a7dea167SDimitry Andric 
63a7dea167SDimitry Andric   std::function<void(size_t, const Twine &)> Rec;
64a7dea167SDimitry Andric   Rec = [&TypePath, Types, &Rec, &F](size_t I, const Twine &ID) {
65a7dea167SDimitry Andric     if (I >= Types->size()) {
66a7dea167SDimitry Andric       F(TypePath, ID);
67a7dea167SDimitry Andric       return;
68a7dea167SDimitry Andric     }
69a7dea167SDimitry Andric 
70*0fca6ea1SDimitry Andric     if (const auto *TypeClass = dyn_cast<DefInit>(Types->getElement(I))) {
71*0fca6ea1SDimitry Andric       for (const auto *Type :
72*0fca6ea1SDimitry Andric            TypeClass->getDef()->getValueAsListOfDefs("Types")) {
73a7dea167SDimitry Andric         TypePath.push_back(Type);
74a7dea167SDimitry Andric         Rec(I + 1, ID + Type->getName());
75a7dea167SDimitry Andric         TypePath.pop_back();
76a7dea167SDimitry Andric       }
77a7dea167SDimitry Andric     } else {
78a7dea167SDimitry Andric       PrintFatalError("Expected a type class");
79a7dea167SDimitry Andric     }
80a7dea167SDimitry Andric   };
81a7dea167SDimitry Andric   Rec(0, N);
82a7dea167SDimitry Andric }
83a7dea167SDimitry Andric 
84a7dea167SDimitry Andric } // namespace
85a7dea167SDimitry Andric 
86a7dea167SDimitry Andric void ClangOpcodesEmitter::run(raw_ostream &OS) {
87*0fca6ea1SDimitry Andric   for (const auto *Opcode : Records.getAllDerivedDefinitions("Opcode")) {
88a7dea167SDimitry Andric     // The name is the record name, unless overriden.
89a7dea167SDimitry Andric     StringRef N = Opcode->getValueAsString("Name");
90a7dea167SDimitry Andric     if (N.empty())
91a7dea167SDimitry Andric       N = Opcode->getName();
92a7dea167SDimitry Andric 
93a7dea167SDimitry Andric     EmitEnum(OS, N, Opcode);
94a7dea167SDimitry Andric     EmitInterp(OS, N, Opcode);
95a7dea167SDimitry Andric     EmitDisasm(OS, N, Opcode);
96a7dea167SDimitry Andric     EmitProto(OS, N, Opcode);
97a7dea167SDimitry Andric     EmitGroup(OS, N, Opcode);
98a7dea167SDimitry Andric     EmitEmitter(OS, N, Opcode);
99a7dea167SDimitry Andric     EmitEval(OS, N, Opcode);
100a7dea167SDimitry Andric   }
101a7dea167SDimitry Andric }
102a7dea167SDimitry Andric 
10306c3fb27SDimitry Andric void ClangOpcodesEmitter::EmitEnum(raw_ostream &OS, StringRef N,
10406c3fb27SDimitry Andric                                    const Record *R) {
105a7dea167SDimitry Andric   OS << "#ifdef GET_OPCODE_NAMES\n";
10606c3fb27SDimitry Andric   Enumerate(R, N, [&OS](ArrayRef<const Record *>, const Twine &ID) {
107a7dea167SDimitry Andric     OS << "OP_" << ID << ",\n";
108a7dea167SDimitry Andric   });
109a7dea167SDimitry Andric   OS << "#endif\n";
110a7dea167SDimitry Andric }
111a7dea167SDimitry Andric 
11206c3fb27SDimitry Andric void ClangOpcodesEmitter::EmitInterp(raw_ostream &OS, StringRef N,
11306c3fb27SDimitry Andric                                      const Record *R) {
114a7dea167SDimitry Andric   OS << "#ifdef GET_INTERP\n";
115a7dea167SDimitry Andric 
11606c3fb27SDimitry Andric   Enumerate(R, N,
11706c3fb27SDimitry Andric             [this, R, &OS, &N](ArrayRef<const Record *> TS, const Twine &ID) {
118a7dea167SDimitry Andric               bool CanReturn = R->getValueAsBit("CanReturn");
119a7dea167SDimitry Andric               bool ChangesPC = R->getValueAsBit("ChangesPC");
120*0fca6ea1SDimitry Andric               const auto &Args = R->getValueAsListOfDefs("Args");
121a7dea167SDimitry Andric 
122a7dea167SDimitry Andric               OS << "case OP_" << ID << ": {\n";
123a7dea167SDimitry Andric 
124bdd1243dSDimitry Andric               if (CanReturn)
125bdd1243dSDimitry Andric                 OS << "  bool DoReturn = (S.Current == StartFrame);\n";
126bdd1243dSDimitry Andric 
127a7dea167SDimitry Andric               // Emit calls to read arguments.
128a7dea167SDimitry Andric               for (size_t I = 0, N = Args.size(); I < N; ++I) {
129*0fca6ea1SDimitry Andric                 const auto *Arg = Args[I];
130*0fca6ea1SDimitry Andric                 bool AsRef = Arg->getValueAsBit("AsRef");
131*0fca6ea1SDimitry Andric 
132*0fca6ea1SDimitry Andric                 if (AsRef)
133*0fca6ea1SDimitry Andric                   OS << "  const auto &V" << I;
134*0fca6ea1SDimitry Andric                 else
135*0fca6ea1SDimitry Andric                   OS << "  const auto V" << I;
136a7dea167SDimitry Andric                 OS << " = ";
137*0fca6ea1SDimitry Andric                 OS << "ReadArg<" << Arg->getValueAsString("Name")
13806c3fb27SDimitry Andric                    << ">(S, PC);\n";
139a7dea167SDimitry Andric               }
140a7dea167SDimitry Andric 
141a7dea167SDimitry Andric               // Emit a call to the template method and pass arguments.
142fe6060f1SDimitry Andric               OS << "  if (!" << N;
143a7dea167SDimitry Andric               PrintTypes(OS, TS);
144a7dea167SDimitry Andric               OS << "(S";
145a7dea167SDimitry Andric               if (ChangesPC)
146a7dea167SDimitry Andric                 OS << ", PC";
147a7dea167SDimitry Andric               else
148a7dea167SDimitry Andric                 OS << ", OpPC";
149a7dea167SDimitry Andric               if (CanReturn)
150a7dea167SDimitry Andric                 OS << ", Result";
151a7dea167SDimitry Andric               for (size_t I = 0, N = Args.size(); I < N; ++I)
152a7dea167SDimitry Andric                 OS << ", V" << I;
153a7dea167SDimitry Andric               OS << "))\n";
154fe6060f1SDimitry Andric               OS << "    return false;\n";
155a7dea167SDimitry Andric 
156a7dea167SDimitry Andric               // Bail out if interpreter returned.
157a7dea167SDimitry Andric               if (CanReturn) {
158fe6060f1SDimitry Andric                 OS << "  if (!S.Current || S.Current->isRoot())\n";
159fe6060f1SDimitry Andric                 OS << "    return true;\n";
160bdd1243dSDimitry Andric 
161bdd1243dSDimitry Andric                 OS << "  if (DoReturn)\n";
162bdd1243dSDimitry Andric                 OS << "    return true;\n";
163a7dea167SDimitry Andric               }
164a7dea167SDimitry Andric 
165fe6060f1SDimitry Andric               OS << "  continue;\n";
166a7dea167SDimitry Andric               OS << "}\n";
167a7dea167SDimitry Andric             });
168a7dea167SDimitry Andric   OS << "#endif\n";
169a7dea167SDimitry Andric }
170a7dea167SDimitry Andric 
17106c3fb27SDimitry Andric void ClangOpcodesEmitter::EmitDisasm(raw_ostream &OS, StringRef N,
17206c3fb27SDimitry Andric                                      const Record *R) {
173a7dea167SDimitry Andric   OS << "#ifdef GET_DISASM\n";
17406c3fb27SDimitry Andric   Enumerate(R, N, [R, &OS](ArrayRef<const Record *>, const Twine &ID) {
175a7dea167SDimitry Andric     OS << "case OP_" << ID << ":\n";
176fe6060f1SDimitry Andric     OS << "  PrintName(\"" << ID << "\");\n";
177fe6060f1SDimitry Andric     OS << "  OS << \"\\t\"";
178a7dea167SDimitry Andric 
179*0fca6ea1SDimitry Andric     for (const auto *Arg : R->getValueAsListOfDefs("Args")) {
180349cc55cSDimitry Andric       OS << " << ReadArg<" << Arg->getValueAsString("Name") << ">(P, PC)";
181349cc55cSDimitry Andric       OS << " << \" \"";
182349cc55cSDimitry Andric     }
183a7dea167SDimitry Andric 
184a7dea167SDimitry Andric     OS << " << \"\\n\";\n";
185fe6060f1SDimitry Andric     OS << "  continue;\n";
186a7dea167SDimitry Andric   });
187a7dea167SDimitry Andric   OS << "#endif\n";
188a7dea167SDimitry Andric }
189a7dea167SDimitry Andric 
19006c3fb27SDimitry Andric void ClangOpcodesEmitter::EmitEmitter(raw_ostream &OS, StringRef N,
19106c3fb27SDimitry Andric                                       const Record *R) {
192a7dea167SDimitry Andric   if (R->getValueAsBit("HasCustomLink"))
193a7dea167SDimitry Andric     return;
194a7dea167SDimitry Andric 
195a7dea167SDimitry Andric   OS << "#ifdef GET_LINK_IMPL\n";
19606c3fb27SDimitry Andric   Enumerate(R, N, [R, &OS](ArrayRef<const Record *>, const Twine &ID) {
197*0fca6ea1SDimitry Andric     const auto &Args = R->getValueAsListOfDefs("Args");
198a7dea167SDimitry Andric 
199a7dea167SDimitry Andric     // Emit the list of arguments.
200a7dea167SDimitry Andric     OS << "bool ByteCodeEmitter::emit" << ID << "(";
201*0fca6ea1SDimitry Andric     for (size_t I = 0, N = Args.size(); I < N; ++I) {
202*0fca6ea1SDimitry Andric       const auto *Arg = Args[I];
203*0fca6ea1SDimitry Andric       bool AsRef = Arg->getValueAsBit("AsRef");
204*0fca6ea1SDimitry Andric       auto Name = Arg->getValueAsString("Name");
205*0fca6ea1SDimitry Andric 
206*0fca6ea1SDimitry Andric       OS << (AsRef ? "const " : " ") << Name << " " << (AsRef ? "&" : "") << "A"
207*0fca6ea1SDimitry Andric          << I << ", ";
208*0fca6ea1SDimitry Andric     }
209a7dea167SDimitry Andric     OS << "const SourceInfo &L) {\n";
210a7dea167SDimitry Andric 
211a7dea167SDimitry Andric     // Emit a call to write the opcodes.
212fe6060f1SDimitry Andric     OS << "  return emitOp<";
213a7dea167SDimitry Andric     for (size_t I = 0, N = Args.size(); I < N; ++I) {
214a7dea167SDimitry Andric       if (I != 0)
215a7dea167SDimitry Andric         OS << ", ";
216a7dea167SDimitry Andric       OS << Args[I]->getValueAsString("Name");
217a7dea167SDimitry Andric     }
218a7dea167SDimitry Andric     OS << ">(OP_" << ID;
219a7dea167SDimitry Andric     for (size_t I = 0, N = Args.size(); I < N; ++I)
220a7dea167SDimitry Andric       OS << ", A" << I;
221a7dea167SDimitry Andric     OS << ", L);\n";
222a7dea167SDimitry Andric     OS << "}\n";
223a7dea167SDimitry Andric   });
224a7dea167SDimitry Andric   OS << "#endif\n";
225a7dea167SDimitry Andric }
226a7dea167SDimitry Andric 
22706c3fb27SDimitry Andric void ClangOpcodesEmitter::EmitProto(raw_ostream &OS, StringRef N,
22806c3fb27SDimitry Andric                                     const Record *R) {
229a7dea167SDimitry Andric   OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n";
230a7dea167SDimitry Andric   auto Args = R->getValueAsListOfDefs("Args");
23106c3fb27SDimitry Andric   Enumerate(R, N, [&OS, &Args](ArrayRef<const Record *> TS, const Twine &ID) {
232a7dea167SDimitry Andric     OS << "bool emit" << ID << "(";
233*0fca6ea1SDimitry Andric     for (size_t I = 0, N = Args.size(); I < N; ++I) {
234*0fca6ea1SDimitry Andric       const auto *Arg = Args[I];
235*0fca6ea1SDimitry Andric       bool AsRef = Arg->getValueAsBit("AsRef");
236*0fca6ea1SDimitry Andric       auto Name = Arg->getValueAsString("Name");
237*0fca6ea1SDimitry Andric 
238*0fca6ea1SDimitry Andric       OS << (AsRef ? "const " : " ") << Name << " " << (AsRef ? "&" : "")
239*0fca6ea1SDimitry Andric          << ", ";
240*0fca6ea1SDimitry Andric     }
241a7dea167SDimitry Andric     OS << "const SourceInfo &);\n";
242a7dea167SDimitry Andric   });
243a7dea167SDimitry Andric 
244a7dea167SDimitry Andric   // Emit a template method for custom emitters to have less to implement.
245a7dea167SDimitry Andric   auto TypeCount = R->getValueAsListInit("Types")->size();
246a7dea167SDimitry Andric   if (R->getValueAsBit("HasCustomEval") && TypeCount) {
247a7dea167SDimitry Andric     OS << "#if defined(GET_EVAL_PROTO)\n";
248a7dea167SDimitry Andric     OS << "template<";
249a7dea167SDimitry Andric     for (size_t I = 0; I < TypeCount; ++I) {
250a7dea167SDimitry Andric       if (I != 0)
251a7dea167SDimitry Andric         OS << ", ";
252a7dea167SDimitry Andric       OS << "PrimType";
253a7dea167SDimitry Andric     }
254a7dea167SDimitry Andric     OS << ">\n";
255a7dea167SDimitry Andric     OS << "bool emit" << N << "(";
256*0fca6ea1SDimitry Andric     for (const auto *Arg : Args)
257a7dea167SDimitry Andric       OS << Arg->getValueAsString("Name") << ", ";
258a7dea167SDimitry Andric     OS << "const SourceInfo &);\n";
259a7dea167SDimitry Andric     OS << "#endif\n";
260a7dea167SDimitry Andric   }
261a7dea167SDimitry Andric 
262a7dea167SDimitry Andric   OS << "#endif\n";
263a7dea167SDimitry Andric }
264a7dea167SDimitry Andric 
26506c3fb27SDimitry Andric void ClangOpcodesEmitter::EmitGroup(raw_ostream &OS, StringRef N,
26606c3fb27SDimitry Andric                                     const Record *R) {
267a7dea167SDimitry Andric   if (!R->getValueAsBit("HasGroup"))
268a7dea167SDimitry Andric     return;
269a7dea167SDimitry Andric 
270*0fca6ea1SDimitry Andric   const auto *Types = R->getValueAsListInit("Types");
271*0fca6ea1SDimitry Andric   const auto &Args = R->getValueAsListOfDefs("Args");
272a7dea167SDimitry Andric 
27306c3fb27SDimitry Andric   Twine EmitFuncName = "emit" + N;
27406c3fb27SDimitry Andric 
275a7dea167SDimitry Andric   // Emit the prototype of the group emitter in the header.
276a7dea167SDimitry Andric   OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n";
277*0fca6ea1SDimitry Andric   OS << "[[nodiscard]] bool " << EmitFuncName << "(";
278a7dea167SDimitry Andric   for (size_t I = 0, N = Types->size(); I < N; ++I)
279a7dea167SDimitry Andric     OS << "PrimType, ";
280a7dea167SDimitry Andric   for (auto *Arg : Args)
281a7dea167SDimitry Andric     OS << Arg->getValueAsString("Name") << ", ";
282a7dea167SDimitry Andric   OS << "const SourceInfo &I);\n";
283a7dea167SDimitry Andric   OS << "#endif\n";
284a7dea167SDimitry Andric 
285a7dea167SDimitry Andric   // Emit the dispatch implementation in the source.
286a7dea167SDimitry Andric   OS << "#if defined(GET_EVAL_IMPL) || defined(GET_LINK_IMPL)\n";
287a7dea167SDimitry Andric   OS << "bool\n";
288a7dea167SDimitry Andric   OS << "#if defined(GET_EVAL_IMPL)\n";
289a7dea167SDimitry Andric   OS << "EvalEmitter\n";
290a7dea167SDimitry Andric   OS << "#else\n";
291a7dea167SDimitry Andric   OS << "ByteCodeEmitter\n";
292a7dea167SDimitry Andric   OS << "#endif\n";
29306c3fb27SDimitry Andric   OS << "::" << EmitFuncName << "(";
294a7dea167SDimitry Andric   for (size_t I = 0, N = Types->size(); I < N; ++I)
295a7dea167SDimitry Andric     OS << "PrimType T" << I << ", ";
296*0fca6ea1SDimitry Andric   for (size_t I = 0, N = Args.size(); I < N; ++I) {
297*0fca6ea1SDimitry Andric     const auto *Arg = Args[I];
298*0fca6ea1SDimitry Andric     bool AsRef = Arg->getValueAsBit("AsRef");
299*0fca6ea1SDimitry Andric     auto Name = Arg->getValueAsString("Name");
300*0fca6ea1SDimitry Andric 
301*0fca6ea1SDimitry Andric     OS << (AsRef ? "const " : " ") << Name << " " << (AsRef ? "&" : "") << "A"
302*0fca6ea1SDimitry Andric        << I << ", ";
303*0fca6ea1SDimitry Andric   }
304a7dea167SDimitry Andric   OS << "const SourceInfo &I) {\n";
305a7dea167SDimitry Andric 
306a7dea167SDimitry Andric   std::function<void(size_t, const Twine &)> Rec;
30706c3fb27SDimitry Andric   llvm::SmallVector<const Record *, 2> TS;
30806c3fb27SDimitry Andric   Rec = [this, &Rec, &OS, Types, &Args, R, &TS, N,
30906c3fb27SDimitry Andric          EmitFuncName](size_t I, const Twine &ID) {
310a7dea167SDimitry Andric     if (I >= Types->size()) {
311a7dea167SDimitry Andric       // Print a call to the emitter method.
312a7dea167SDimitry Andric       // Custom evaluator methods dispatch to template methods.
313a7dea167SDimitry Andric       if (R->getValueAsBit("HasCustomEval")) {
314a7dea167SDimitry Andric         OS << "#ifdef GET_LINK_IMPL\n";
315a7dea167SDimitry Andric         OS << "    return emit" << ID << "\n";
316a7dea167SDimitry Andric         OS << "#else\n";
317a7dea167SDimitry Andric         OS << "    return emit" << N;
318a7dea167SDimitry Andric         PrintTypes(OS, TS);
319a7dea167SDimitry Andric         OS << "\n#endif\n";
320fe6060f1SDimitry Andric         OS << "      ";
321a7dea167SDimitry Andric       } else {
322a7dea167SDimitry Andric         OS << "    return emit" << ID;
323a7dea167SDimitry Andric       }
324a7dea167SDimitry Andric 
325a7dea167SDimitry Andric       OS << "(";
326a7dea167SDimitry Andric       for (size_t I = 0; I < Args.size(); ++I) {
327a7dea167SDimitry Andric         OS << "A" << I << ", ";
328a7dea167SDimitry Andric       }
329a7dea167SDimitry Andric       OS << "I);\n";
330a7dea167SDimitry Andric       return;
331a7dea167SDimitry Andric     }
332a7dea167SDimitry Andric 
333a7dea167SDimitry Andric     // Print a switch statement selecting T.
334a7dea167SDimitry Andric     if (auto *TypeClass = dyn_cast<DefInit>(Types->getElement(I))) {
335a7dea167SDimitry Andric       OS << "  switch (T" << I << ") {\n";
336a7dea167SDimitry Andric       auto Cases = TypeClass->getDef()->getValueAsListOfDefs("Types");
337a7dea167SDimitry Andric       for (auto *Case : Cases) {
338a7dea167SDimitry Andric         OS << "  case PT_" << Case->getName() << ":\n";
339a7dea167SDimitry Andric         TS.push_back(Case);
340a7dea167SDimitry Andric         Rec(I + 1, ID + Case->getName());
341a7dea167SDimitry Andric         TS.pop_back();
342a7dea167SDimitry Andric       }
343a7dea167SDimitry Andric       // Emit a default case if not all types are present.
344a7dea167SDimitry Andric       if (Cases.size() < NumTypes)
34506c3fb27SDimitry Andric         OS << "  default: llvm_unreachable(\"invalid type: " << EmitFuncName
34606c3fb27SDimitry Andric            << "\");\n";
347a7dea167SDimitry Andric       OS << "  }\n";
348a7dea167SDimitry Andric       OS << "  llvm_unreachable(\"invalid enum value\");\n";
349a7dea167SDimitry Andric     } else {
350a7dea167SDimitry Andric       PrintFatalError("Expected a type class");
351a7dea167SDimitry Andric     }
352a7dea167SDimitry Andric   };
353a7dea167SDimitry Andric   Rec(0, N);
354a7dea167SDimitry Andric 
355a7dea167SDimitry Andric   OS << "}\n";
356a7dea167SDimitry Andric   OS << "#endif\n";
357a7dea167SDimitry Andric }
358a7dea167SDimitry Andric 
35906c3fb27SDimitry Andric void ClangOpcodesEmitter::EmitEval(raw_ostream &OS, StringRef N,
36006c3fb27SDimitry Andric                                    const Record *R) {
361a7dea167SDimitry Andric   if (R->getValueAsBit("HasCustomEval"))
362a7dea167SDimitry Andric     return;
363a7dea167SDimitry Andric 
364a7dea167SDimitry Andric   OS << "#ifdef GET_EVAL_IMPL\n";
36506c3fb27SDimitry Andric   Enumerate(R, N,
36606c3fb27SDimitry Andric             [this, R, &N, &OS](ArrayRef<const Record *> TS, const Twine &ID) {
367a7dea167SDimitry Andric               auto Args = R->getValueAsListOfDefs("Args");
368a7dea167SDimitry Andric 
369a7dea167SDimitry Andric               OS << "bool EvalEmitter::emit" << ID << "(";
370*0fca6ea1SDimitry Andric               for (size_t I = 0, N = Args.size(); I < N; ++I) {
371*0fca6ea1SDimitry Andric                 const auto *Arg = Args[I];
372*0fca6ea1SDimitry Andric                 bool AsRef = Arg->getValueAsBit("AsRef");
373*0fca6ea1SDimitry Andric                 auto Name = Arg->getValueAsString("Name");
374*0fca6ea1SDimitry Andric 
375*0fca6ea1SDimitry Andric                 OS << (AsRef ? "const " : " ") << Name << " "
376*0fca6ea1SDimitry Andric                    << (AsRef ? "&" : "") << "A" << I << ", ";
377*0fca6ea1SDimitry Andric               }
378a7dea167SDimitry Andric               OS << "const SourceInfo &L) {\n";
379a7dea167SDimitry Andric               OS << "  if (!isActive()) return true;\n";
380a7dea167SDimitry Andric               OS << "  CurrentSource = L;\n";
381a7dea167SDimitry Andric 
382a7dea167SDimitry Andric               OS << "  return " << N;
383a7dea167SDimitry Andric               PrintTypes(OS, TS);
384a7dea167SDimitry Andric               OS << "(S, OpPC";
385a7dea167SDimitry Andric               for (size_t I = 0, N = Args.size(); I < N; ++I)
386a7dea167SDimitry Andric                 OS << ", A" << I;
387a7dea167SDimitry Andric               OS << ");\n";
388a7dea167SDimitry Andric               OS << "}\n";
389a7dea167SDimitry Andric             });
390a7dea167SDimitry Andric 
391a7dea167SDimitry Andric   OS << "#endif\n";
392a7dea167SDimitry Andric }
393a7dea167SDimitry Andric 
39406c3fb27SDimitry Andric void ClangOpcodesEmitter::PrintTypes(raw_ostream &OS,
39506c3fb27SDimitry Andric                                      ArrayRef<const Record *> Types) {
396a7dea167SDimitry Andric   if (Types.empty())
397a7dea167SDimitry Andric     return;
398a7dea167SDimitry Andric   OS << "<";
399a7dea167SDimitry Andric   for (size_t I = 0, N = Types.size(); I < N; ++I) {
400a7dea167SDimitry Andric     if (I != 0)
401a7dea167SDimitry Andric       OS << ", ";
402a7dea167SDimitry Andric     OS << "PT_" << Types[I]->getName();
403a7dea167SDimitry Andric   }
404a7dea167SDimitry Andric   OS << ">";
405a7dea167SDimitry Andric }
406a7dea167SDimitry Andric 
407a7dea167SDimitry Andric void clang::EmitClangOpcodes(RecordKeeper &Records, raw_ostream &OS) {
408a7dea167SDimitry Andric   ClangOpcodesEmitter(Records).run(OS);
409a7dea167SDimitry Andric }
410