1*a7dea167SDimitry Andric //=== ClangOpcodesEmitter.cpp - constexpr interpreter opcodes ---*- C++ -*-===// 2*a7dea167SDimitry Andric // 3*a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*a7dea167SDimitry Andric // 7*a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 8*a7dea167SDimitry Andric // 9*a7dea167SDimitry Andric // These tablegen backends emit Clang AST node tables 10*a7dea167SDimitry Andric // 11*a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 12*a7dea167SDimitry Andric 13*a7dea167SDimitry Andric #include "TableGenBackends.h" 14*a7dea167SDimitry Andric #include "llvm/TableGen/Error.h" 15*a7dea167SDimitry Andric #include "llvm/TableGen/Record.h" 16*a7dea167SDimitry Andric #include "llvm/TableGen/StringMatcher.h" 17*a7dea167SDimitry Andric #include "llvm/TableGen/TableGenBackend.h" 18*a7dea167SDimitry Andric 19*a7dea167SDimitry Andric using namespace llvm; 20*a7dea167SDimitry Andric 21*a7dea167SDimitry Andric namespace { 22*a7dea167SDimitry Andric class ClangOpcodesEmitter { 23*a7dea167SDimitry Andric RecordKeeper &Records; 24*a7dea167SDimitry Andric Record Root; 25*a7dea167SDimitry Andric unsigned NumTypes; 26*a7dea167SDimitry Andric 27*a7dea167SDimitry Andric public: 28*a7dea167SDimitry Andric ClangOpcodesEmitter(RecordKeeper &R) 29*a7dea167SDimitry Andric : Records(R), Root("Opcode", SMLoc(), R), 30*a7dea167SDimitry Andric NumTypes(Records.getAllDerivedDefinitions("Type").size()) {} 31*a7dea167SDimitry Andric 32*a7dea167SDimitry Andric void run(raw_ostream &OS); 33*a7dea167SDimitry Andric 34*a7dea167SDimitry Andric private: 35*a7dea167SDimitry Andric /// Emits the opcode name for the opcode enum. 36*a7dea167SDimitry Andric /// The name is obtained by concatenating the name with the list of types. 37*a7dea167SDimitry Andric void EmitEnum(raw_ostream &OS, StringRef N, Record *R); 38*a7dea167SDimitry Andric 39*a7dea167SDimitry Andric /// Emits the switch case and the invocation in the interpreter. 40*a7dea167SDimitry Andric void EmitInterp(raw_ostream &OS, StringRef N, Record *R); 41*a7dea167SDimitry Andric 42*a7dea167SDimitry Andric /// Emits the disassembler. 43*a7dea167SDimitry Andric void EmitDisasm(raw_ostream &OS, StringRef N, Record *R); 44*a7dea167SDimitry Andric 45*a7dea167SDimitry Andric /// Emits the byte code emitter method. 46*a7dea167SDimitry Andric void EmitEmitter(raw_ostream &OS, StringRef N, Record *R); 47*a7dea167SDimitry Andric 48*a7dea167SDimitry Andric /// Emits the prototype. 49*a7dea167SDimitry Andric void EmitProto(raw_ostream &OS, StringRef N, Record *R); 50*a7dea167SDimitry Andric 51*a7dea167SDimitry Andric /// Emits the prototype to dispatch from a type. 52*a7dea167SDimitry Andric void EmitGroup(raw_ostream &OS, StringRef N, Record *R); 53*a7dea167SDimitry Andric 54*a7dea167SDimitry Andric /// Emits the evaluator method. 55*a7dea167SDimitry Andric void EmitEval(raw_ostream &OS, StringRef N, Record *R); 56*a7dea167SDimitry Andric 57*a7dea167SDimitry Andric void PrintTypes(raw_ostream &OS, ArrayRef<Record *> Types); 58*a7dea167SDimitry Andric }; 59*a7dea167SDimitry Andric 60*a7dea167SDimitry Andric void Enumerate(const Record *R, 61*a7dea167SDimitry Andric StringRef N, 62*a7dea167SDimitry Andric std::function<void(ArrayRef<Record *>, Twine)> &&F) { 63*a7dea167SDimitry Andric llvm::SmallVector<Record *, 2> TypePath; 64*a7dea167SDimitry Andric auto *Types = R->getValueAsListInit("Types"); 65*a7dea167SDimitry Andric 66*a7dea167SDimitry Andric std::function<void(size_t, const Twine &)> Rec; 67*a7dea167SDimitry Andric Rec = [&TypePath, Types, &Rec, &F](size_t I, const Twine &ID) { 68*a7dea167SDimitry Andric if (I >= Types->size()) { 69*a7dea167SDimitry Andric F(TypePath, ID); 70*a7dea167SDimitry Andric return; 71*a7dea167SDimitry Andric } 72*a7dea167SDimitry Andric 73*a7dea167SDimitry Andric if (auto *TypeClass = dyn_cast<DefInit>(Types->getElement(I))) { 74*a7dea167SDimitry Andric for (auto *Type : TypeClass->getDef()->getValueAsListOfDefs("Types")) { 75*a7dea167SDimitry Andric TypePath.push_back(Type); 76*a7dea167SDimitry Andric Rec(I + 1, ID + Type->getName()); 77*a7dea167SDimitry Andric TypePath.pop_back(); 78*a7dea167SDimitry Andric } 79*a7dea167SDimitry Andric } else { 80*a7dea167SDimitry Andric PrintFatalError("Expected a type class"); 81*a7dea167SDimitry Andric } 82*a7dea167SDimitry Andric }; 83*a7dea167SDimitry Andric Rec(0, N); 84*a7dea167SDimitry Andric } 85*a7dea167SDimitry Andric 86*a7dea167SDimitry Andric } // namespace 87*a7dea167SDimitry Andric 88*a7dea167SDimitry Andric void ClangOpcodesEmitter::run(raw_ostream &OS) { 89*a7dea167SDimitry Andric for (auto *Opcode : Records.getAllDerivedDefinitions(Root.getName())) { 90*a7dea167SDimitry Andric // The name is the record name, unless overriden. 91*a7dea167SDimitry Andric StringRef N = Opcode->getValueAsString("Name"); 92*a7dea167SDimitry Andric if (N.empty()) 93*a7dea167SDimitry Andric N = Opcode->getName(); 94*a7dea167SDimitry Andric 95*a7dea167SDimitry Andric EmitEnum(OS, N, Opcode); 96*a7dea167SDimitry Andric EmitInterp(OS, N, Opcode); 97*a7dea167SDimitry Andric EmitDisasm(OS, N, Opcode); 98*a7dea167SDimitry Andric EmitProto(OS, N, Opcode); 99*a7dea167SDimitry Andric EmitGroup(OS, N, Opcode); 100*a7dea167SDimitry Andric EmitEmitter(OS, N, Opcode); 101*a7dea167SDimitry Andric EmitEval(OS, N, Opcode); 102*a7dea167SDimitry Andric } 103*a7dea167SDimitry Andric } 104*a7dea167SDimitry Andric 105*a7dea167SDimitry Andric void ClangOpcodesEmitter::EmitEnum(raw_ostream &OS, StringRef N, Record *R) { 106*a7dea167SDimitry Andric OS << "#ifdef GET_OPCODE_NAMES\n"; 107*a7dea167SDimitry Andric Enumerate(R, N, [&OS](ArrayRef<Record *>, const Twine &ID) { 108*a7dea167SDimitry Andric OS << "OP_" << ID << ",\n"; 109*a7dea167SDimitry Andric }); 110*a7dea167SDimitry Andric OS << "#endif\n"; 111*a7dea167SDimitry Andric } 112*a7dea167SDimitry Andric 113*a7dea167SDimitry Andric void ClangOpcodesEmitter::EmitInterp(raw_ostream &OS, StringRef N, Record *R) { 114*a7dea167SDimitry Andric OS << "#ifdef GET_INTERP\n"; 115*a7dea167SDimitry Andric 116*a7dea167SDimitry Andric Enumerate(R, N, [this, R, &OS, &N](ArrayRef<Record *> TS, const Twine &ID) { 117*a7dea167SDimitry Andric bool CanReturn = R->getValueAsBit("CanReturn"); 118*a7dea167SDimitry Andric bool ChangesPC = R->getValueAsBit("ChangesPC"); 119*a7dea167SDimitry Andric auto Args = R->getValueAsListOfDefs("Args"); 120*a7dea167SDimitry Andric 121*a7dea167SDimitry Andric OS << "case OP_" << ID << ": {\n"; 122*a7dea167SDimitry Andric 123*a7dea167SDimitry Andric // Emit calls to read arguments. 124*a7dea167SDimitry Andric for (size_t I = 0, N = Args.size(); I < N; ++I) { 125*a7dea167SDimitry Andric OS << "\tauto V" << I; 126*a7dea167SDimitry Andric OS << " = "; 127*a7dea167SDimitry Andric OS << "PC.read<" << Args[I]->getValueAsString("Name") << ">();\n"; 128*a7dea167SDimitry Andric } 129*a7dea167SDimitry Andric 130*a7dea167SDimitry Andric // Emit a call to the template method and pass arguments. 131*a7dea167SDimitry Andric OS << "\tif (!" << N; 132*a7dea167SDimitry Andric PrintTypes(OS, TS); 133*a7dea167SDimitry Andric OS << "(S"; 134*a7dea167SDimitry Andric if (ChangesPC) 135*a7dea167SDimitry Andric OS << ", PC"; 136*a7dea167SDimitry Andric else 137*a7dea167SDimitry Andric OS << ", OpPC"; 138*a7dea167SDimitry Andric if (CanReturn) 139*a7dea167SDimitry Andric OS << ", Result"; 140*a7dea167SDimitry Andric for (size_t I = 0, N = Args.size(); I < N; ++I) 141*a7dea167SDimitry Andric OS << ", V" << I; 142*a7dea167SDimitry Andric OS << "))\n"; 143*a7dea167SDimitry Andric OS << "\t\treturn false;\n"; 144*a7dea167SDimitry Andric 145*a7dea167SDimitry Andric // Bail out if interpreter returned. 146*a7dea167SDimitry Andric if (CanReturn) { 147*a7dea167SDimitry Andric OS << "\tif (!S.Current || S.Current->isRoot())\n"; 148*a7dea167SDimitry Andric OS << "\t\treturn true;\n"; 149*a7dea167SDimitry Andric } 150*a7dea167SDimitry Andric 151*a7dea167SDimitry Andric OS << "\tcontinue;\n"; 152*a7dea167SDimitry Andric OS << "}\n"; 153*a7dea167SDimitry Andric }); 154*a7dea167SDimitry Andric OS << "#endif\n"; 155*a7dea167SDimitry Andric } 156*a7dea167SDimitry Andric 157*a7dea167SDimitry Andric void ClangOpcodesEmitter::EmitDisasm(raw_ostream &OS, StringRef N, Record *R) { 158*a7dea167SDimitry Andric OS << "#ifdef GET_DISASM\n"; 159*a7dea167SDimitry Andric Enumerate(R, N, [R, &OS](ArrayRef<Record *>, const Twine &ID) { 160*a7dea167SDimitry Andric OS << "case OP_" << ID << ":\n"; 161*a7dea167SDimitry Andric OS << "\tPrintName(\"" << ID << "\");\n"; 162*a7dea167SDimitry Andric OS << "\tOS << \"\\t\""; 163*a7dea167SDimitry Andric 164*a7dea167SDimitry Andric for (auto *Arg : R->getValueAsListOfDefs("Args")) 165*a7dea167SDimitry Andric OS << " << PC.read<" << Arg->getValueAsString("Name") << ">() << \" \""; 166*a7dea167SDimitry Andric 167*a7dea167SDimitry Andric OS << "<< \"\\n\";\n"; 168*a7dea167SDimitry Andric OS << "\tcontinue;\n"; 169*a7dea167SDimitry Andric }); 170*a7dea167SDimitry Andric OS << "#endif\n"; 171*a7dea167SDimitry Andric } 172*a7dea167SDimitry Andric 173*a7dea167SDimitry Andric void ClangOpcodesEmitter::EmitEmitter(raw_ostream &OS, StringRef N, Record *R) { 174*a7dea167SDimitry Andric if (R->getValueAsBit("HasCustomLink")) 175*a7dea167SDimitry Andric return; 176*a7dea167SDimitry Andric 177*a7dea167SDimitry Andric OS << "#ifdef GET_LINK_IMPL\n"; 178*a7dea167SDimitry Andric Enumerate(R, N, [R, &OS](ArrayRef<Record *>, const Twine &ID) { 179*a7dea167SDimitry Andric auto Args = R->getValueAsListOfDefs("Args"); 180*a7dea167SDimitry Andric 181*a7dea167SDimitry Andric // Emit the list of arguments. 182*a7dea167SDimitry Andric OS << "bool ByteCodeEmitter::emit" << ID << "("; 183*a7dea167SDimitry Andric for (size_t I = 0, N = Args.size(); I < N; ++I) 184*a7dea167SDimitry Andric OS << Args[I]->getValueAsString("Name") << " A" << I << ","; 185*a7dea167SDimitry Andric OS << "const SourceInfo &L) {\n"; 186*a7dea167SDimitry Andric 187*a7dea167SDimitry Andric // Emit a call to write the opcodes. 188*a7dea167SDimitry Andric OS << "\treturn emitOp<"; 189*a7dea167SDimitry Andric for (size_t I = 0, N = Args.size(); I < N; ++I) { 190*a7dea167SDimitry Andric if (I != 0) 191*a7dea167SDimitry Andric OS << ", "; 192*a7dea167SDimitry Andric OS << Args[I]->getValueAsString("Name"); 193*a7dea167SDimitry Andric } 194*a7dea167SDimitry Andric OS << ">(OP_" << ID; 195*a7dea167SDimitry Andric for (size_t I = 0, N = Args.size(); I < N; ++I) 196*a7dea167SDimitry Andric OS << ", A" << I; 197*a7dea167SDimitry Andric OS << ", L);\n"; 198*a7dea167SDimitry Andric OS << "}\n"; 199*a7dea167SDimitry Andric }); 200*a7dea167SDimitry Andric OS << "#endif\n"; 201*a7dea167SDimitry Andric } 202*a7dea167SDimitry Andric 203*a7dea167SDimitry Andric void ClangOpcodesEmitter::EmitProto(raw_ostream &OS, StringRef N, Record *R) { 204*a7dea167SDimitry Andric OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n"; 205*a7dea167SDimitry Andric auto Args = R->getValueAsListOfDefs("Args"); 206*a7dea167SDimitry Andric Enumerate(R, N, [&OS, &Args](ArrayRef<Record *> TS, const Twine &ID) { 207*a7dea167SDimitry Andric OS << "bool emit" << ID << "("; 208*a7dea167SDimitry Andric for (auto *Arg : Args) 209*a7dea167SDimitry Andric OS << Arg->getValueAsString("Name") << ", "; 210*a7dea167SDimitry Andric OS << "const SourceInfo &);\n"; 211*a7dea167SDimitry Andric }); 212*a7dea167SDimitry Andric 213*a7dea167SDimitry Andric // Emit a template method for custom emitters to have less to implement. 214*a7dea167SDimitry Andric auto TypeCount = R->getValueAsListInit("Types")->size(); 215*a7dea167SDimitry Andric if (R->getValueAsBit("HasCustomEval") && TypeCount) { 216*a7dea167SDimitry Andric OS << "#if defined(GET_EVAL_PROTO)\n"; 217*a7dea167SDimitry Andric OS << "template<"; 218*a7dea167SDimitry Andric for (size_t I = 0; I < TypeCount; ++I) { 219*a7dea167SDimitry Andric if (I != 0) 220*a7dea167SDimitry Andric OS << ", "; 221*a7dea167SDimitry Andric OS << "PrimType"; 222*a7dea167SDimitry Andric } 223*a7dea167SDimitry Andric OS << ">\n"; 224*a7dea167SDimitry Andric OS << "bool emit" << N << "("; 225*a7dea167SDimitry Andric for (auto *Arg : Args) 226*a7dea167SDimitry Andric OS << Arg->getValueAsString("Name") << ", "; 227*a7dea167SDimitry Andric OS << "const SourceInfo &);\n"; 228*a7dea167SDimitry Andric OS << "#endif\n"; 229*a7dea167SDimitry Andric } 230*a7dea167SDimitry Andric 231*a7dea167SDimitry Andric OS << "#endif\n"; 232*a7dea167SDimitry Andric } 233*a7dea167SDimitry Andric 234*a7dea167SDimitry Andric void ClangOpcodesEmitter::EmitGroup(raw_ostream &OS, StringRef N, Record *R) { 235*a7dea167SDimitry Andric if (!R->getValueAsBit("HasGroup")) 236*a7dea167SDimitry Andric return; 237*a7dea167SDimitry Andric 238*a7dea167SDimitry Andric auto *Types = R->getValueAsListInit("Types"); 239*a7dea167SDimitry Andric auto Args = R->getValueAsListOfDefs("Args"); 240*a7dea167SDimitry Andric 241*a7dea167SDimitry Andric // Emit the prototype of the group emitter in the header. 242*a7dea167SDimitry Andric OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n"; 243*a7dea167SDimitry Andric OS << "bool emit" << N << "("; 244*a7dea167SDimitry Andric for (size_t I = 0, N = Types->size(); I < N; ++I) 245*a7dea167SDimitry Andric OS << "PrimType, "; 246*a7dea167SDimitry Andric for (auto *Arg : Args) 247*a7dea167SDimitry Andric OS << Arg->getValueAsString("Name") << ", "; 248*a7dea167SDimitry Andric OS << "const SourceInfo &I);\n"; 249*a7dea167SDimitry Andric OS << "#endif\n"; 250*a7dea167SDimitry Andric 251*a7dea167SDimitry Andric // Emit the dispatch implementation in the source. 252*a7dea167SDimitry Andric OS << "#if defined(GET_EVAL_IMPL) || defined(GET_LINK_IMPL)\n"; 253*a7dea167SDimitry Andric OS << "bool \n"; 254*a7dea167SDimitry Andric OS << "#if defined(GET_EVAL_IMPL)\n"; 255*a7dea167SDimitry Andric OS << "EvalEmitter\n"; 256*a7dea167SDimitry Andric OS << "#else\n"; 257*a7dea167SDimitry Andric OS << "ByteCodeEmitter\n"; 258*a7dea167SDimitry Andric OS << "#endif\n"; 259*a7dea167SDimitry Andric OS << "::emit" << N << "("; 260*a7dea167SDimitry Andric for (size_t I = 0, N = Types->size(); I < N; ++I) 261*a7dea167SDimitry Andric OS << "PrimType T" << I << ", "; 262*a7dea167SDimitry Andric for (size_t I = 0, N = Args.size(); I < N; ++I) 263*a7dea167SDimitry Andric OS << Args[I]->getValueAsString("Name") << " A" << I << ", "; 264*a7dea167SDimitry Andric OS << "const SourceInfo &I) {\n"; 265*a7dea167SDimitry Andric 266*a7dea167SDimitry Andric std::function<void(size_t, const Twine &)> Rec; 267*a7dea167SDimitry Andric llvm::SmallVector<Record *, 2> TS; 268*a7dea167SDimitry Andric Rec = [this, &Rec, &OS, Types, &Args, R, &TS, N](size_t I, const Twine &ID) { 269*a7dea167SDimitry Andric if (I >= Types->size()) { 270*a7dea167SDimitry Andric // Print a call to the emitter method. 271*a7dea167SDimitry Andric // Custom evaluator methods dispatch to template methods. 272*a7dea167SDimitry Andric if (R->getValueAsBit("HasCustomEval")) { 273*a7dea167SDimitry Andric OS << "#ifdef GET_LINK_IMPL\n"; 274*a7dea167SDimitry Andric OS << "return emit" << ID << "\n"; 275*a7dea167SDimitry Andric OS << "#else\n"; 276*a7dea167SDimitry Andric OS << "return emit" << N; 277*a7dea167SDimitry Andric PrintTypes(OS, TS); 278*a7dea167SDimitry Andric OS << "\n#endif\n"; 279*a7dea167SDimitry Andric } else { 280*a7dea167SDimitry Andric OS << "return emit" << ID; 281*a7dea167SDimitry Andric } 282*a7dea167SDimitry Andric 283*a7dea167SDimitry Andric OS << "("; 284*a7dea167SDimitry Andric for (size_t I = 0; I < Args.size(); ++I) { 285*a7dea167SDimitry Andric OS << "A" << I << ", "; 286*a7dea167SDimitry Andric } 287*a7dea167SDimitry Andric OS << "I);\n"; 288*a7dea167SDimitry Andric return; 289*a7dea167SDimitry Andric } 290*a7dea167SDimitry Andric 291*a7dea167SDimitry Andric // Print a switch statement selecting T. 292*a7dea167SDimitry Andric if (auto *TypeClass = dyn_cast<DefInit>(Types->getElement(I))) { 293*a7dea167SDimitry Andric OS << "switch (T" << I << "){\n"; 294*a7dea167SDimitry Andric auto Cases = TypeClass->getDef()->getValueAsListOfDefs("Types"); 295*a7dea167SDimitry Andric for (auto *Case : Cases) { 296*a7dea167SDimitry Andric OS << "case PT_" << Case->getName() << ":\n"; 297*a7dea167SDimitry Andric TS.push_back(Case); 298*a7dea167SDimitry Andric Rec(I + 1, ID + Case->getName()); 299*a7dea167SDimitry Andric TS.pop_back(); 300*a7dea167SDimitry Andric } 301*a7dea167SDimitry Andric // Emit a default case if not all types are present. 302*a7dea167SDimitry Andric if (Cases.size() < NumTypes) 303*a7dea167SDimitry Andric OS << "default: llvm_unreachable(\"invalid type\");\n"; 304*a7dea167SDimitry Andric OS << "}\n"; 305*a7dea167SDimitry Andric OS << "llvm_unreachable(\"invalid enum value\");\n"; 306*a7dea167SDimitry Andric } else { 307*a7dea167SDimitry Andric PrintFatalError("Expected a type class"); 308*a7dea167SDimitry Andric } 309*a7dea167SDimitry Andric }; 310*a7dea167SDimitry Andric Rec(0, N); 311*a7dea167SDimitry Andric 312*a7dea167SDimitry Andric OS << "}\n"; 313*a7dea167SDimitry Andric OS << "#endif\n"; 314*a7dea167SDimitry Andric } 315*a7dea167SDimitry Andric 316*a7dea167SDimitry Andric void ClangOpcodesEmitter::EmitEval(raw_ostream &OS, StringRef N, Record *R) { 317*a7dea167SDimitry Andric if (R->getValueAsBit("HasCustomEval")) 318*a7dea167SDimitry Andric return; 319*a7dea167SDimitry Andric 320*a7dea167SDimitry Andric OS << "#ifdef GET_EVAL_IMPL\n"; 321*a7dea167SDimitry Andric Enumerate(R, N, [this, R, &N, &OS](ArrayRef<Record *> TS, const Twine &ID) { 322*a7dea167SDimitry Andric auto Args = R->getValueAsListOfDefs("Args"); 323*a7dea167SDimitry Andric 324*a7dea167SDimitry Andric OS << "bool EvalEmitter::emit" << ID << "("; 325*a7dea167SDimitry Andric for (size_t I = 0, N = Args.size(); I < N; ++I) 326*a7dea167SDimitry Andric OS << Args[I]->getValueAsString("Name") << " A" << I << ","; 327*a7dea167SDimitry Andric OS << "const SourceInfo &L) {\n"; 328*a7dea167SDimitry Andric OS << "if (!isActive()) return true;\n"; 329*a7dea167SDimitry Andric OS << "CurrentSource = L;\n"; 330*a7dea167SDimitry Andric 331*a7dea167SDimitry Andric OS << "return " << N; 332*a7dea167SDimitry Andric PrintTypes(OS, TS); 333*a7dea167SDimitry Andric OS << "(S, OpPC"; 334*a7dea167SDimitry Andric for (size_t I = 0, N = Args.size(); I < N; ++I) 335*a7dea167SDimitry Andric OS << ", A" << I; 336*a7dea167SDimitry Andric OS << ");\n"; 337*a7dea167SDimitry Andric OS << "}\n"; 338*a7dea167SDimitry Andric }); 339*a7dea167SDimitry Andric 340*a7dea167SDimitry Andric OS << "#endif\n"; 341*a7dea167SDimitry Andric } 342*a7dea167SDimitry Andric 343*a7dea167SDimitry Andric void ClangOpcodesEmitter::PrintTypes(raw_ostream &OS, ArrayRef<Record *> Types) { 344*a7dea167SDimitry Andric if (Types.empty()) 345*a7dea167SDimitry Andric return; 346*a7dea167SDimitry Andric OS << "<"; 347*a7dea167SDimitry Andric for (size_t I = 0, N = Types.size(); I < N; ++I) { 348*a7dea167SDimitry Andric if (I != 0) 349*a7dea167SDimitry Andric OS << ", "; 350*a7dea167SDimitry Andric OS << "PT_" << Types[I]->getName(); 351*a7dea167SDimitry Andric } 352*a7dea167SDimitry Andric OS << ">"; 353*a7dea167SDimitry Andric } 354*a7dea167SDimitry Andric 355*a7dea167SDimitry Andric void clang::EmitClangOpcodes(RecordKeeper &Records, raw_ostream &OS) { 356*a7dea167SDimitry Andric ClangOpcodesEmitter(Records).run(OS); 357*a7dea167SDimitry Andric } 358