Coverage Report

Created: 2021-08-24 07:12

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