Path: blob/main/contrib/llvm-project/clang/utils/TableGen/ClangOpcodesEmitter.cpp
35230 views
//=== ClangOpcodesEmitter.cpp - constexpr interpreter opcodes ---*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// These tablegen backends emit Clang AST node tables9//10//===----------------------------------------------------------------------===//1112#include "TableGenBackends.h"13#include "llvm/TableGen/Error.h"14#include "llvm/TableGen/Record.h"15#include "llvm/TableGen/StringMatcher.h"16#include "llvm/TableGen/TableGenBackend.h"1718using namespace llvm;1920namespace {21class ClangOpcodesEmitter {22RecordKeeper &Records;23unsigned NumTypes;2425public:26ClangOpcodesEmitter(RecordKeeper &R)27: Records(R), NumTypes(Records.getAllDerivedDefinitions("Type").size()) {}2829void run(raw_ostream &OS);3031private:32/// Emits the opcode name for the opcode enum.33/// The name is obtained by concatenating the name with the list of types.34void EmitEnum(raw_ostream &OS, StringRef N, const Record *R);3536/// Emits the switch case and the invocation in the interpreter.37void EmitInterp(raw_ostream &OS, StringRef N, const Record *R);3839/// Emits the disassembler.40void EmitDisasm(raw_ostream &OS, StringRef N, const Record *R);4142/// Emits the byte code emitter method.43void EmitEmitter(raw_ostream &OS, StringRef N, const Record *R);4445/// Emits the prototype.46void EmitProto(raw_ostream &OS, StringRef N, const Record *R);4748/// Emits the prototype to dispatch from a type.49void EmitGroup(raw_ostream &OS, StringRef N, const Record *R);5051/// Emits the evaluator method.52void EmitEval(raw_ostream &OS, StringRef N, const Record *R);5354void PrintTypes(raw_ostream &OS, ArrayRef<const Record *> Types);55};5657void Enumerate(const Record *R, StringRef N,58std::function<void(ArrayRef<const Record *>, Twine)> &&F) {59llvm::SmallVector<const Record *, 2> TypePath;60const auto *Types = R->getValueAsListInit("Types");6162std::function<void(size_t, const Twine &)> Rec;63Rec = [&TypePath, Types, &Rec, &F](size_t I, const Twine &ID) {64if (I >= Types->size()) {65F(TypePath, ID);66return;67}6869if (const auto *TypeClass = dyn_cast<DefInit>(Types->getElement(I))) {70for (const auto *Type :71TypeClass->getDef()->getValueAsListOfDefs("Types")) {72TypePath.push_back(Type);73Rec(I + 1, ID + Type->getName());74TypePath.pop_back();75}76} else {77PrintFatalError("Expected a type class");78}79};80Rec(0, N);81}8283} // namespace8485void ClangOpcodesEmitter::run(raw_ostream &OS) {86for (const auto *Opcode : Records.getAllDerivedDefinitions("Opcode")) {87// The name is the record name, unless overriden.88StringRef N = Opcode->getValueAsString("Name");89if (N.empty())90N = Opcode->getName();9192EmitEnum(OS, N, Opcode);93EmitInterp(OS, N, Opcode);94EmitDisasm(OS, N, Opcode);95EmitProto(OS, N, Opcode);96EmitGroup(OS, N, Opcode);97EmitEmitter(OS, N, Opcode);98EmitEval(OS, N, Opcode);99}100}101102void ClangOpcodesEmitter::EmitEnum(raw_ostream &OS, StringRef N,103const Record *R) {104OS << "#ifdef GET_OPCODE_NAMES\n";105Enumerate(R, N, [&OS](ArrayRef<const Record *>, const Twine &ID) {106OS << "OP_" << ID << ",\n";107});108OS << "#endif\n";109}110111void ClangOpcodesEmitter::EmitInterp(raw_ostream &OS, StringRef N,112const Record *R) {113OS << "#ifdef GET_INTERP\n";114115Enumerate(R, N,116[this, R, &OS, &N](ArrayRef<const Record *> TS, const Twine &ID) {117bool CanReturn = R->getValueAsBit("CanReturn");118bool ChangesPC = R->getValueAsBit("ChangesPC");119const auto &Args = R->getValueAsListOfDefs("Args");120121OS << "case OP_" << ID << ": {\n";122123if (CanReturn)124OS << " bool DoReturn = (S.Current == StartFrame);\n";125126// Emit calls to read arguments.127for (size_t I = 0, N = Args.size(); I < N; ++I) {128const auto *Arg = Args[I];129bool AsRef = Arg->getValueAsBit("AsRef");130131if (AsRef)132OS << " const auto &V" << I;133else134OS << " const auto V" << I;135OS << " = ";136OS << "ReadArg<" << Arg->getValueAsString("Name")137<< ">(S, PC);\n";138}139140// Emit a call to the template method and pass arguments.141OS << " if (!" << N;142PrintTypes(OS, TS);143OS << "(S";144if (ChangesPC)145OS << ", PC";146else147OS << ", OpPC";148if (CanReturn)149OS << ", Result";150for (size_t I = 0, N = Args.size(); I < N; ++I)151OS << ", V" << I;152OS << "))\n";153OS << " return false;\n";154155// Bail out if interpreter returned.156if (CanReturn) {157OS << " if (!S.Current || S.Current->isRoot())\n";158OS << " return true;\n";159160OS << " if (DoReturn)\n";161OS << " return true;\n";162}163164OS << " continue;\n";165OS << "}\n";166});167OS << "#endif\n";168}169170void ClangOpcodesEmitter::EmitDisasm(raw_ostream &OS, StringRef N,171const Record *R) {172OS << "#ifdef GET_DISASM\n";173Enumerate(R, N, [R, &OS](ArrayRef<const Record *>, const Twine &ID) {174OS << "case OP_" << ID << ":\n";175OS << " PrintName(\"" << ID << "\");\n";176OS << " OS << \"\\t\"";177178for (const auto *Arg : R->getValueAsListOfDefs("Args")) {179OS << " << ReadArg<" << Arg->getValueAsString("Name") << ">(P, PC)";180OS << " << \" \"";181}182183OS << " << \"\\n\";\n";184OS << " continue;\n";185});186OS << "#endif\n";187}188189void ClangOpcodesEmitter::EmitEmitter(raw_ostream &OS, StringRef N,190const Record *R) {191if (R->getValueAsBit("HasCustomLink"))192return;193194OS << "#ifdef GET_LINK_IMPL\n";195Enumerate(R, N, [R, &OS](ArrayRef<const Record *>, const Twine &ID) {196const auto &Args = R->getValueAsListOfDefs("Args");197198// Emit the list of arguments.199OS << "bool ByteCodeEmitter::emit" << ID << "(";200for (size_t I = 0, N = Args.size(); I < N; ++I) {201const auto *Arg = Args[I];202bool AsRef = Arg->getValueAsBit("AsRef");203auto Name = Arg->getValueAsString("Name");204205OS << (AsRef ? "const " : " ") << Name << " " << (AsRef ? "&" : "") << "A"206<< I << ", ";207}208OS << "const SourceInfo &L) {\n";209210// Emit a call to write the opcodes.211OS << " return emitOp<";212for (size_t I = 0, N = Args.size(); I < N; ++I) {213if (I != 0)214OS << ", ";215OS << Args[I]->getValueAsString("Name");216}217OS << ">(OP_" << ID;218for (size_t I = 0, N = Args.size(); I < N; ++I)219OS << ", A" << I;220OS << ", L);\n";221OS << "}\n";222});223OS << "#endif\n";224}225226void ClangOpcodesEmitter::EmitProto(raw_ostream &OS, StringRef N,227const Record *R) {228OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n";229auto Args = R->getValueAsListOfDefs("Args");230Enumerate(R, N, [&OS, &Args](ArrayRef<const Record *> TS, const Twine &ID) {231OS << "bool emit" << ID << "(";232for (size_t I = 0, N = Args.size(); I < N; ++I) {233const auto *Arg = Args[I];234bool AsRef = Arg->getValueAsBit("AsRef");235auto Name = Arg->getValueAsString("Name");236237OS << (AsRef ? "const " : " ") << Name << " " << (AsRef ? "&" : "")238<< ", ";239}240OS << "const SourceInfo &);\n";241});242243// Emit a template method for custom emitters to have less to implement.244auto TypeCount = R->getValueAsListInit("Types")->size();245if (R->getValueAsBit("HasCustomEval") && TypeCount) {246OS << "#if defined(GET_EVAL_PROTO)\n";247OS << "template<";248for (size_t I = 0; I < TypeCount; ++I) {249if (I != 0)250OS << ", ";251OS << "PrimType";252}253OS << ">\n";254OS << "bool emit" << N << "(";255for (const auto *Arg : Args)256OS << Arg->getValueAsString("Name") << ", ";257OS << "const SourceInfo &);\n";258OS << "#endif\n";259}260261OS << "#endif\n";262}263264void ClangOpcodesEmitter::EmitGroup(raw_ostream &OS, StringRef N,265const Record *R) {266if (!R->getValueAsBit("HasGroup"))267return;268269const auto *Types = R->getValueAsListInit("Types");270const auto &Args = R->getValueAsListOfDefs("Args");271272Twine EmitFuncName = "emit" + N;273274// Emit the prototype of the group emitter in the header.275OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n";276OS << "[[nodiscard]] bool " << EmitFuncName << "(";277for (size_t I = 0, N = Types->size(); I < N; ++I)278OS << "PrimType, ";279for (auto *Arg : Args)280OS << Arg->getValueAsString("Name") << ", ";281OS << "const SourceInfo &I);\n";282OS << "#endif\n";283284// Emit the dispatch implementation in the source.285OS << "#if defined(GET_EVAL_IMPL) || defined(GET_LINK_IMPL)\n";286OS << "bool\n";287OS << "#if defined(GET_EVAL_IMPL)\n";288OS << "EvalEmitter\n";289OS << "#else\n";290OS << "ByteCodeEmitter\n";291OS << "#endif\n";292OS << "::" << EmitFuncName << "(";293for (size_t I = 0, N = Types->size(); I < N; ++I)294OS << "PrimType T" << I << ", ";295for (size_t I = 0, N = Args.size(); I < N; ++I) {296const auto *Arg = Args[I];297bool AsRef = Arg->getValueAsBit("AsRef");298auto Name = Arg->getValueAsString("Name");299300OS << (AsRef ? "const " : " ") << Name << " " << (AsRef ? "&" : "") << "A"301<< I << ", ";302}303OS << "const SourceInfo &I) {\n";304305std::function<void(size_t, const Twine &)> Rec;306llvm::SmallVector<const Record *, 2> TS;307Rec = [this, &Rec, &OS, Types, &Args, R, &TS, N,308EmitFuncName](size_t I, const Twine &ID) {309if (I >= Types->size()) {310// Print a call to the emitter method.311// Custom evaluator methods dispatch to template methods.312if (R->getValueAsBit("HasCustomEval")) {313OS << "#ifdef GET_LINK_IMPL\n";314OS << " return emit" << ID << "\n";315OS << "#else\n";316OS << " return emit" << N;317PrintTypes(OS, TS);318OS << "\n#endif\n";319OS << " ";320} else {321OS << " return emit" << ID;322}323324OS << "(";325for (size_t I = 0; I < Args.size(); ++I) {326OS << "A" << I << ", ";327}328OS << "I);\n";329return;330}331332// Print a switch statement selecting T.333if (auto *TypeClass = dyn_cast<DefInit>(Types->getElement(I))) {334OS << " switch (T" << I << ") {\n";335auto Cases = TypeClass->getDef()->getValueAsListOfDefs("Types");336for (auto *Case : Cases) {337OS << " case PT_" << Case->getName() << ":\n";338TS.push_back(Case);339Rec(I + 1, ID + Case->getName());340TS.pop_back();341}342// Emit a default case if not all types are present.343if (Cases.size() < NumTypes)344OS << " default: llvm_unreachable(\"invalid type: " << EmitFuncName345<< "\");\n";346OS << " }\n";347OS << " llvm_unreachable(\"invalid enum value\");\n";348} else {349PrintFatalError("Expected a type class");350}351};352Rec(0, N);353354OS << "}\n";355OS << "#endif\n";356}357358void ClangOpcodesEmitter::EmitEval(raw_ostream &OS, StringRef N,359const Record *R) {360if (R->getValueAsBit("HasCustomEval"))361return;362363OS << "#ifdef GET_EVAL_IMPL\n";364Enumerate(R, N,365[this, R, &N, &OS](ArrayRef<const Record *> TS, const Twine &ID) {366auto Args = R->getValueAsListOfDefs("Args");367368OS << "bool EvalEmitter::emit" << ID << "(";369for (size_t I = 0, N = Args.size(); I < N; ++I) {370const auto *Arg = Args[I];371bool AsRef = Arg->getValueAsBit("AsRef");372auto Name = Arg->getValueAsString("Name");373374OS << (AsRef ? "const " : " ") << Name << " "375<< (AsRef ? "&" : "") << "A" << I << ", ";376}377OS << "const SourceInfo &L) {\n";378OS << " if (!isActive()) return true;\n";379OS << " CurrentSource = L;\n";380381OS << " return " << N;382PrintTypes(OS, TS);383OS << "(S, OpPC";384for (size_t I = 0, N = Args.size(); I < N; ++I)385OS << ", A" << I;386OS << ");\n";387OS << "}\n";388});389390OS << "#endif\n";391}392393void ClangOpcodesEmitter::PrintTypes(raw_ostream &OS,394ArrayRef<const Record *> Types) {395if (Types.empty())396return;397OS << "<";398for (size_t I = 0, N = Types.size(); I < N; ++I) {399if (I != 0)400OS << ", ";401OS << "PT_" << Types[I]->getName();402}403OS << ">";404}405406void clang::EmitClangOpcodes(RecordKeeper &Records, raw_ostream &OS) {407ClangOpcodesEmitter(Records).run(OS);408}409410411