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