123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- //=== ClangOpcodesEmitter.cpp - constexpr interpreter opcodes ---*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // These tablegen backends emit Clang AST node tables
- //
- //===----------------------------------------------------------------------===//
- #include "TableGenBackends.h"
- #include "llvm/TableGen/Error.h"
- #include "llvm/TableGen/Record.h"
- #include "llvm/TableGen/StringMatcher.h"
- #include "llvm/TableGen/TableGenBackend.h"
- using namespace llvm;
- namespace {
- class ClangOpcodesEmitter {
- RecordKeeper &Records;
- Record Root;
- unsigned NumTypes;
- public:
- ClangOpcodesEmitter(RecordKeeper &R)
- : Records(R), Root("Opcode", SMLoc(), R),
- NumTypes(Records.getAllDerivedDefinitions("Type").size()) {}
- void run(raw_ostream &OS);
- private:
- /// Emits the opcode name for the opcode enum.
- /// The name is obtained by concatenating the name with the list of types.
- void EmitEnum(raw_ostream &OS, StringRef N, Record *R);
- /// Emits the switch case and the invocation in the interpreter.
- void EmitInterp(raw_ostream &OS, StringRef N, Record *R);
- /// Emits the disassembler.
- void EmitDisasm(raw_ostream &OS, StringRef N, Record *R);
- /// Emits the byte code emitter method.
- void EmitEmitter(raw_ostream &OS, StringRef N, Record *R);
- /// Emits the prototype.
- void EmitProto(raw_ostream &OS, StringRef N, Record *R);
- /// Emits the prototype to dispatch from a type.
- void EmitGroup(raw_ostream &OS, StringRef N, Record *R);
- /// Emits the evaluator method.
- void EmitEval(raw_ostream &OS, StringRef N, Record *R);
- void PrintTypes(raw_ostream &OS, ArrayRef<Record *> Types);
- };
- void Enumerate(const Record *R,
- StringRef N,
- std::function<void(ArrayRef<Record *>, Twine)> &&F) {
- llvm::SmallVector<Record *, 2> TypePath;
- auto *Types = R->getValueAsListInit("Types");
- std::function<void(size_t, const Twine &)> Rec;
- Rec = [&TypePath, Types, &Rec, &F](size_t I, const Twine &ID) {
- if (I >= Types->size()) {
- F(TypePath, ID);
- return;
- }
- if (auto *TypeClass = dyn_cast<DefInit>(Types->getElement(I))) {
- for (auto *Type : TypeClass->getDef()->getValueAsListOfDefs("Types")) {
- TypePath.push_back(Type);
- Rec(I + 1, ID + Type->getName());
- TypePath.pop_back();
- }
- } else {
- PrintFatalError("Expected a type class");
- }
- };
- Rec(0, N);
- }
- } // namespace
- void ClangOpcodesEmitter::run(raw_ostream &OS) {
- for (auto *Opcode : Records.getAllDerivedDefinitions(Root.getName())) {
- // The name is the record name, unless overriden.
- StringRef N = Opcode->getValueAsString("Name");
- if (N.empty())
- N = Opcode->getName();
- EmitEnum(OS, N, Opcode);
- EmitInterp(OS, N, Opcode);
- EmitDisasm(OS, N, Opcode);
- EmitProto(OS, N, Opcode);
- EmitGroup(OS, N, Opcode);
- EmitEmitter(OS, N, Opcode);
- EmitEval(OS, N, Opcode);
- }
- }
- void ClangOpcodesEmitter::EmitEnum(raw_ostream &OS, StringRef N, Record *R) {
- OS << "#ifdef GET_OPCODE_NAMES\n";
- Enumerate(R, N, [&OS](ArrayRef<Record *>, const Twine &ID) {
- OS << "OP_" << ID << ",\n";
- });
- OS << "#endif\n";
- }
- void ClangOpcodesEmitter::EmitInterp(raw_ostream &OS, StringRef N, Record *R) {
- OS << "#ifdef GET_INTERP\n";
- Enumerate(R, N, [this, R, &OS, &N](ArrayRef<Record *> TS, const Twine &ID) {
- bool CanReturn = R->getValueAsBit("CanReturn");
- bool ChangesPC = R->getValueAsBit("ChangesPC");
- auto Args = R->getValueAsListOfDefs("Args");
- OS << "case OP_" << ID << ": {\n";
- if (CanReturn)
- OS << " bool DoReturn = (S.Current == StartFrame);\n";
- // Emit calls to read arguments.
- for (size_t I = 0, N = Args.size(); I < N; ++I) {
- OS << " auto V" << I;
- OS << " = ";
- OS << "ReadArg<" << Args[I]->getValueAsString("Name") << ">(S, PC);\n";
- }
- // Emit a call to the template method and pass arguments.
- OS << " if (!" << N;
- PrintTypes(OS, TS);
- OS << "(S";
- if (ChangesPC)
- OS << ", PC";
- else
- OS << ", OpPC";
- if (CanReturn)
- OS << ", Result";
- for (size_t I = 0, N = Args.size(); I < N; ++I)
- OS << ", V" << I;
- OS << "))\n";
- OS << " return false;\n";
- // Bail out if interpreter returned.
- if (CanReturn) {
- OS << " if (!S.Current || S.Current->isRoot())\n";
- OS << " return true;\n";
- OS << " if (DoReturn)\n";
- OS << " return true;\n";
- }
- OS << " continue;\n";
- OS << "}\n";
- });
- OS << "#endif\n";
- }
- void ClangOpcodesEmitter::EmitDisasm(raw_ostream &OS, StringRef N, Record *R) {
- OS << "#ifdef GET_DISASM\n";
- Enumerate(R, N, [R, &OS](ArrayRef<Record *>, const Twine &ID) {
- OS << "case OP_" << ID << ":\n";
- OS << " PrintName(\"" << ID << "\");\n";
- OS << " OS << \"\\t\"";
- for (auto *Arg : R->getValueAsListOfDefs("Args")) {
- OS << " << ReadArg<" << Arg->getValueAsString("Name") << ">(P, PC)";
- OS << " << \" \"";
- }
- OS << " << \"\\n\";\n";
- OS << " continue;\n";
- });
- OS << "#endif\n";
- }
- void ClangOpcodesEmitter::EmitEmitter(raw_ostream &OS, StringRef N, Record *R) {
- if (R->getValueAsBit("HasCustomLink"))
- return;
- OS << "#ifdef GET_LINK_IMPL\n";
- Enumerate(R, N, [R, &OS](ArrayRef<Record *>, const Twine &ID) {
- auto Args = R->getValueAsListOfDefs("Args");
- // Emit the list of arguments.
- OS << "bool ByteCodeEmitter::emit" << ID << "(";
- for (size_t I = 0, N = Args.size(); I < N; ++I)
- OS << Args[I]->getValueAsString("Name") << " A" << I << ", ";
- OS << "const SourceInfo &L) {\n";
- // Emit a call to write the opcodes.
- OS << " return emitOp<";
- for (size_t I = 0, N = Args.size(); I < N; ++I) {
- if (I != 0)
- OS << ", ";
- OS << Args[I]->getValueAsString("Name");
- }
- OS << ">(OP_" << ID;
- for (size_t I = 0, N = Args.size(); I < N; ++I)
- OS << ", A" << I;
- OS << ", L);\n";
- OS << "}\n";
- });
- OS << "#endif\n";
- }
- void ClangOpcodesEmitter::EmitProto(raw_ostream &OS, StringRef N, Record *R) {
- OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n";
- auto Args = R->getValueAsListOfDefs("Args");
- Enumerate(R, N, [&OS, &Args](ArrayRef<Record *> TS, const Twine &ID) {
- OS << "bool emit" << ID << "(";
- for (auto *Arg : Args)
- OS << Arg->getValueAsString("Name") << ", ";
- OS << "const SourceInfo &);\n";
- });
- // Emit a template method for custom emitters to have less to implement.
- auto TypeCount = R->getValueAsListInit("Types")->size();
- if (R->getValueAsBit("HasCustomEval") && TypeCount) {
- OS << "#if defined(GET_EVAL_PROTO)\n";
- OS << "template<";
- for (size_t I = 0; I < TypeCount; ++I) {
- if (I != 0)
- OS << ", ";
- OS << "PrimType";
- }
- OS << ">\n";
- OS << "bool emit" << N << "(";
- for (auto *Arg : Args)
- OS << Arg->getValueAsString("Name") << ", ";
- OS << "const SourceInfo &);\n";
- OS << "#endif\n";
- }
- OS << "#endif\n";
- }
- void ClangOpcodesEmitter::EmitGroup(raw_ostream &OS, StringRef N, Record *R) {
- if (!R->getValueAsBit("HasGroup"))
- return;
- auto *Types = R->getValueAsListInit("Types");
- auto Args = R->getValueAsListOfDefs("Args");
- // Emit the prototype of the group emitter in the header.
- OS << "#if defined(GET_EVAL_PROTO) || defined(GET_LINK_PROTO)\n";
- OS << "bool emit" << N << "(";
- for (size_t I = 0, N = Types->size(); I < N; ++I)
- OS << "PrimType, ";
- for (auto *Arg : Args)
- OS << Arg->getValueAsString("Name") << ", ";
- OS << "const SourceInfo &I);\n";
- OS << "#endif\n";
- // Emit the dispatch implementation in the source.
- OS << "#if defined(GET_EVAL_IMPL) || defined(GET_LINK_IMPL)\n";
- OS << "bool\n";
- OS << "#if defined(GET_EVAL_IMPL)\n";
- OS << "EvalEmitter\n";
- OS << "#else\n";
- OS << "ByteCodeEmitter\n";
- OS << "#endif\n";
- OS << "::emit" << N << "(";
- for (size_t I = 0, N = Types->size(); I < N; ++I)
- OS << "PrimType T" << I << ", ";
- for (size_t I = 0, N = Args.size(); I < N; ++I)
- OS << Args[I]->getValueAsString("Name") << " A" << I << ", ";
- OS << "const SourceInfo &I) {\n";
- std::function<void(size_t, const Twine &)> Rec;
- llvm::SmallVector<Record *, 2> TS;
- Rec = [this, &Rec, &OS, Types, &Args, R, &TS, N](size_t I, const Twine &ID) {
- if (I >= Types->size()) {
- // Print a call to the emitter method.
- // Custom evaluator methods dispatch to template methods.
- if (R->getValueAsBit("HasCustomEval")) {
- OS << "#ifdef GET_LINK_IMPL\n";
- OS << " return emit" << ID << "\n";
- OS << "#else\n";
- OS << " return emit" << N;
- PrintTypes(OS, TS);
- OS << "\n#endif\n";
- OS << " ";
- } else {
- OS << " return emit" << ID;
- }
- OS << "(";
- for (size_t I = 0; I < Args.size(); ++I) {
- OS << "A" << I << ", ";
- }
- OS << "I);\n";
- return;
- }
- // Print a switch statement selecting T.
- if (auto *TypeClass = dyn_cast<DefInit>(Types->getElement(I))) {
- OS << " switch (T" << I << ") {\n";
- auto Cases = TypeClass->getDef()->getValueAsListOfDefs("Types");
- for (auto *Case : Cases) {
- OS << " case PT_" << Case->getName() << ":\n";
- TS.push_back(Case);
- Rec(I + 1, ID + Case->getName());
- TS.pop_back();
- }
- // Emit a default case if not all types are present.
- if (Cases.size() < NumTypes)
- OS << " default: llvm_unreachable(\"invalid type\");\n";
- OS << " }\n";
- OS << " llvm_unreachable(\"invalid enum value\");\n";
- } else {
- PrintFatalError("Expected a type class");
- }
- };
- Rec(0, N);
- OS << "}\n";
- OS << "#endif\n";
- }
- void ClangOpcodesEmitter::EmitEval(raw_ostream &OS, StringRef N, Record *R) {
- if (R->getValueAsBit("HasCustomEval"))
- return;
- OS << "#ifdef GET_EVAL_IMPL\n";
- Enumerate(R, N, [this, R, &N, &OS](ArrayRef<Record *> TS, const Twine &ID) {
- auto Args = R->getValueAsListOfDefs("Args");
- OS << "bool EvalEmitter::emit" << ID << "(";
- for (size_t I = 0, N = Args.size(); I < N; ++I)
- OS << Args[I]->getValueAsString("Name") << " A" << I << ", ";
- OS << "const SourceInfo &L) {\n";
- OS << " if (!isActive()) return true;\n";
- OS << " CurrentSource = L;\n";
- OS << " return " << N;
- PrintTypes(OS, TS);
- OS << "(S, OpPC";
- for (size_t I = 0, N = Args.size(); I < N; ++I)
- OS << ", A" << I;
- OS << ");\n";
- OS << "}\n";
- });
- OS << "#endif\n";
- }
- void ClangOpcodesEmitter::PrintTypes(raw_ostream &OS, ArrayRef<Record *> Types) {
- if (Types.empty())
- return;
- OS << "<";
- for (size_t I = 0, N = Types.size(); I < N; ++I) {
- if (I != 0)
- OS << ", ";
- OS << "PT_" << Types[I]->getName();
- }
- OS << ">";
- }
- void clang::EmitClangOpcodes(RecordKeeper &Records, raw_ostream &OS) {
- ClangOpcodesEmitter(Records).run(OS);
- }
|