brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.7 KiB · d26122a Raw
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