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