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