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 123 // Emit calls to read arguments. 124 for (size_t I = 0, N = Args.size(); I < N; ++I) { 125 OS << "\tauto V" << I; 126 OS << " = "; 127 OS << "PC.read<" << Args[I]->getValueAsString("Name") << ">();\n"; 128 } 129 130 // Emit a call to the template method and pass arguments. 131 OS << "\tif (!" << N; 132 PrintTypes(OS, TS); 133 OS << "(S"; 134 if (ChangesPC) 135 OS << ", PC"; 136 else 137 OS << ", OpPC"; 138 if (CanReturn) 139 OS << ", Result"; 140 for (size_t I = 0, N = Args.size(); I < N; ++I) 141 OS << ", V" << I; 142 OS << "))\n"; 143 OS << "\t\treturn false;\n"; 144 145 // Bail out if interpreter returned. 146 if (CanReturn) { 147 OS << "\tif (!S.Current || S.Current->isRoot())\n"; 148 OS << "\t\treturn true;\n"; 149 } 150 151 OS << "\tcontinue;\n"; 152 OS << "}\n"; 153 }); 154 OS << "#endif\n"; 155 } 156 157 void ClangOpcodesEmitter::EmitDisasm(raw_ostream &OS, StringRef N, Record *R) { 158 OS << "#ifdef GET_DISASM\n"; 159 Enumerate(R, N, [R, &OS](ArrayRef<Record *>, const Twine &ID) { 160 OS << "case OP_" << ID << ":\n"; 161 OS << "\tPrintName(\"" << ID << "\");\n"; 162 OS << "\tOS << \"\\t\""; 163 164 for (auto *Arg : R->getValueAsListOfDefs("Args")) 165 OS << " << PC.read<" << Arg->getValueAsString("Name") << ">() << \" \""; 166 167 OS << "<< \"\\n\";\n"; 168 OS << "\tcontinue;\n"; 169 }); 170 OS << "#endif\n"; 171 } 172 173 void ClangOpcodesEmitter::EmitEmitter(raw_ostream &OS, StringRef N, Record *R) { 174 if (R->getValueAsBit("HasCustomLink")) 175 return; 176 177 OS << "#ifdef GET_LINK_IMPL\n"; 178 Enumerate(R, N, [R, &OS](ArrayRef<Record *>, const Twine &ID) { 179 auto Args = R->getValueAsListOfDefs("Args"); 180 181 // Emit the list of arguments. 182 OS << "bool ByteCodeEmitter::emit" << ID << "("; 183 for (size_t I = 0, N = Args.size(); I < N; ++I) 184 OS << Args[I]->getValueAsString("Name") << " A" << I << ","; 185 OS << "const SourceInfo &L) {\n"; 186 187 // Emit a call to write the opcodes. 188 OS << "\treturn emitOp<"; 189 for (size_t I = 0, N = Args.size(); I < N; ++I) { 190 if (I != 0) 191 OS << ", "; 192 OS << Args[I]->getValueAsString("Name"); 193 } 194 OS << ">(OP_" << ID; 195 for (size_t I = 0, N = Args.size(); I < N; ++I) 196 OS << ", A" << I; 197 OS << ", L);\n"; 198 OS << "}\n"; 199 }); 200 OS << "#endif\n"; 201 } 202 203 void ClangOpcodesEmitter::EmitProto(raw_ostream &OS, StringRef N, Record *R) { 204 OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n"; 205 auto Args = R->getValueAsListOfDefs("Args"); 206 Enumerate(R, N, [&OS, &Args](ArrayRef<Record *> TS, const Twine &ID) { 207 OS << "bool emit" << ID << "("; 208 for (auto *Arg : Args) 209 OS << Arg->getValueAsString("Name") << ", "; 210 OS << "const SourceInfo &);\n"; 211 }); 212 213 // Emit a template method for custom emitters to have less to implement. 214 auto TypeCount = R->getValueAsListInit("Types")->size(); 215 if (R->getValueAsBit("HasCustomEval") && TypeCount) { 216 OS << "#if defined(GET_EVAL_PROTO)\n"; 217 OS << "template<"; 218 for (size_t I = 0; I < TypeCount; ++I) { 219 if (I != 0) 220 OS << ", "; 221 OS << "PrimType"; 222 } 223 OS << ">\n"; 224 OS << "bool emit" << N << "("; 225 for (auto *Arg : Args) 226 OS << Arg->getValueAsString("Name") << ", "; 227 OS << "const SourceInfo &);\n"; 228 OS << "#endif\n"; 229 } 230 231 OS << "#endif\n"; 232 } 233 234 void ClangOpcodesEmitter::EmitGroup(raw_ostream &OS, StringRef N, Record *R) { 235 if (!R->getValueAsBit("HasGroup")) 236 return; 237 238 auto *Types = R->getValueAsListInit("Types"); 239 auto Args = R->getValueAsListOfDefs("Args"); 240 241 // Emit the prototype of the group emitter in the header. 242 OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n"; 243 OS << "bool emit" << N << "("; 244 for (size_t I = 0, N = Types->size(); I < N; ++I) 245 OS << "PrimType, "; 246 for (auto *Arg : Args) 247 OS << Arg->getValueAsString("Name") << ", "; 248 OS << "const SourceInfo &I);\n"; 249 OS << "#endif\n"; 250 251 // Emit the dispatch implementation in the source. 252 OS << "#if defined(GET_EVAL_IMPL) || defined(GET_LINK_IMPL)\n"; 253 OS << "bool \n"; 254 OS << "#if defined(GET_EVAL_IMPL)\n"; 255 OS << "EvalEmitter\n"; 256 OS << "#else\n"; 257 OS << "ByteCodeEmitter\n"; 258 OS << "#endif\n"; 259 OS << "::emit" << N << "("; 260 for (size_t I = 0, N = Types->size(); I < N; ++I) 261 OS << "PrimType T" << I << ", "; 262 for (size_t I = 0, N = Args.size(); I < N; ++I) 263 OS << Args[I]->getValueAsString("Name") << " A" << I << ", "; 264 OS << "const SourceInfo &I) {\n"; 265 266 std::function<void(size_t, const Twine &)> Rec; 267 llvm::SmallVector<Record *, 2> TS; 268 Rec = [this, &Rec, &OS, Types, &Args, R, &TS, N](size_t I, const Twine &ID) { 269 if (I >= Types->size()) { 270 // Print a call to the emitter method. 271 // Custom evaluator methods dispatch to template methods. 272 if (R->getValueAsBit("HasCustomEval")) { 273 OS << "#ifdef GET_LINK_IMPL\n"; 274 OS << "return emit" << ID << "\n"; 275 OS << "#else\n"; 276 OS << "return emit" << N; 277 PrintTypes(OS, TS); 278 OS << "\n#endif\n"; 279 } else { 280 OS << "return emit" << ID; 281 } 282 283 OS << "("; 284 for (size_t I = 0; I < Args.size(); ++I) { 285 OS << "A" << I << ", "; 286 } 287 OS << "I);\n"; 288 return; 289 } 290 291 // Print a switch statement selecting T. 292 if (auto *TypeClass = dyn_cast<DefInit>(Types->getElement(I))) { 293 OS << "switch (T" << I << "){\n"; 294 auto Cases = TypeClass->getDef()->getValueAsListOfDefs("Types"); 295 for (auto *Case : Cases) { 296 OS << "case PT_" << Case->getName() << ":\n"; 297 TS.push_back(Case); 298 Rec(I + 1, ID + Case->getName()); 299 TS.pop_back(); 300 } 301 // Emit a default case if not all types are present. 302 if (Cases.size() < NumTypes) 303 OS << "default: llvm_unreachable(\"invalid type\");\n"; 304 OS << "}\n"; 305 OS << "llvm_unreachable(\"invalid enum value\");\n"; 306 } else { 307 PrintFatalError("Expected a type class"); 308 } 309 }; 310 Rec(0, N); 311 312 OS << "}\n"; 313 OS << "#endif\n"; 314 } 315 316 void ClangOpcodesEmitter::EmitEval(raw_ostream &OS, StringRef N, Record *R) { 317 if (R->getValueAsBit("HasCustomEval")) 318 return; 319 320 OS << "#ifdef GET_EVAL_IMPL\n"; 321 Enumerate(R, N, [this, R, &N, &OS](ArrayRef<Record *> TS, const Twine &ID) { 322 auto Args = R->getValueAsListOfDefs("Args"); 323 324 OS << "bool EvalEmitter::emit" << ID << "("; 325 for (size_t I = 0, N = Args.size(); I < N; ++I) 326 OS << Args[I]->getValueAsString("Name") << " A" << I << ","; 327 OS << "const SourceInfo &L) {\n"; 328 OS << "if (!isActive()) return true;\n"; 329 OS << "CurrentSource = L;\n"; 330 331 OS << "return " << N; 332 PrintTypes(OS, TS); 333 OS << "(S, OpPC"; 334 for (size_t I = 0, N = Args.size(); I < N; ++I) 335 OS << ", A" << I; 336 OS << ");\n"; 337 OS << "}\n"; 338 }); 339 340 OS << "#endif\n"; 341 } 342 343 void ClangOpcodesEmitter::PrintTypes(raw_ostream &OS, ArrayRef<Record *> Types) { 344 if (Types.empty()) 345 return; 346 OS << "<"; 347 for (size_t I = 0, N = Types.size(); I < N; ++I) { 348 if (I != 0) 349 OS << ", "; 350 OS << "PT_" << Types[I]->getName(); 351 } 352 OS << ">"; 353 } 354 355 void clang::EmitClangOpcodes(RecordKeeper &Records, raw_ostream &OS) { 356 ClangOpcodesEmitter(Records).run(OS); 357 } 358