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