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 if (CanReturn) 124 OS << " bool DoReturn = (S.Current == StartFrame);\n"; 125 126 // Emit calls to read arguments. 127 for (size_t I = 0, N = Args.size(); I < N; ++I) { 128 OS << " auto V" << I; 129 OS << " = "; 130 OS << "ReadArg<" << Args[I]->getValueAsString("Name") << ">(S, PC);\n"; 131 } 132 133 // Emit a call to the template method and pass arguments. 134 OS << " if (!" << N; 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"; 146 OS << " return false;\n"; 147 148 // Bail out if interpreter returned. 149 if (CanReturn) { 150 OS << " if (!S.Current || S.Current->isRoot())\n"; 151 OS << " return true;\n"; 152 153 OS << " if (DoReturn)\n"; 154 OS << " return true;\n"; 155 } 156 157 OS << " continue;\n"; 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"; 167 OS << " PrintName(\"" << ID << "\");\n"; 168 OS << " OS << \"\\t\""; 169 170 for (auto *Arg : R->getValueAsListOfDefs("Args")) { 171 OS << " << ReadArg<" << Arg->getValueAsString("Name") << ">(P, PC)"; 172 OS << " << \" \""; 173 } 174 175 OS << " << \"\\n\";\n"; 176 OS << " continue;\n"; 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) 192 OS << Args[I]->getValueAsString("Name") << " A" << I << ", "; 193 OS << "const SourceInfo &L) {\n"; 194 195 // Emit a call to write the opcodes. 196 OS << " return emitOp<"; 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"; 261 OS << "bool\n"; 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"; 282 OS << " return emit" << ID << "\n"; 283 OS << "#else\n"; 284 OS << " return emit" << N; 285 PrintTypes(OS, TS); 286 OS << "\n#endif\n"; 287 OS << " "; 288 } else { 289 OS << " return emit" << ID; 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))) { 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"; 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) 312 OS << " default: llvm_unreachable(\"invalid type\");\n"; 313 OS << " }\n"; 314 OS << " llvm_unreachable(\"invalid enum value\");\n"; 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) 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"; 339 340 OS << " return " << N; 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 } 367